]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - growfs/xfs_growfs.c
bump minor version number.
[thirdparty/xfsprogs-dev.git] / growfs / xfs_growfs.c
CommitLineData
2bd0ea18
NS
1/*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33#include <errno.h>
34#include <fcntl.h>
35#include <libxfs.h>
36#include <mntent.h>
37#include <sys/ioctl.h>
38
39static char *fname; /* mount point name */
40static char *datadev; /* data device name */
41static char *logdev; /* log device name */
42static char *rtdev; /* RT device name */
43
44static void
45usage(void)
46{
47 fprintf(stderr,
48"Usage: %s [options] mountpoint\n\n\
49Options:\n\
50 -d grow data/metadata section\n\
51 -l grow log section\n\
52 -r grow realtime section\n\
53 -n don't change anything, just show geometry\n\
54 -i convert log from external to internal format\n\
55 -t alternate location for mount table (/etc/mtab)\n\
56 -x convert log from internal to external format\n\
57 -D size grow data/metadata section to size blks\n\
58 -L size grow/shrink log section to size blks\n\
59 -R size grow realtime section to size blks\n\
60 -e size set realtime extent size to size blks\n\
61 -m imaxpct set inode max percent to imaxpct\n\
62 -V print version information\n",
63 progname);
64 exit(2);
65}
66
67void
68report_info(
69 xfs_fsop_geom_t geo,
70 char *mntpoint,
71 int unwritten,
72 int dirversion,
73 int isint)
74{
75 printf("meta-data=%-22s isize=%-6d agcount=%d, agsize=%d blks\n"
76 "data =%-22s bsize=%-6d blocks=%lld, imaxpct=%d\n"
77 " =%-22s sunit=%-6d swidth=%d blks, unwritten=%d\n"
78 "naming =version %-14d bsize=%-6d\n"
79 "log =%-22s bsize=%-6d blocks=%d\n"
80 "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n",
81 mntpoint, geo.inodesize, geo.agcount, geo.agblocks,
5b64e00a 82 "", geo.blocksize, (long long)geo.datablocks, geo.imaxpct,
2bd0ea18
NS
83 "", geo.sunit, geo.swidth, unwritten,
84 dirversion, geo.dirblocksize,
85 isint ? "internal" : "external", geo.blocksize, geo.logblocks,
86 geo.rtblocks ? "external" : "none",
5b64e00a
NS
87 geo.rtextsize * geo.blocksize,
88 (long long)geo.rtblocks, (long long)geo.rtextents);
2bd0ea18
NS
89}
90
91void
92explore_mtab(char *mtab, char *mntpoint)
93{
94 struct mntent *mnt;
95 struct stat64 statuser;
96 struct stat64 statmtab;
97 FILE *mtp;
98 char *rtend;
99 char *logend;
100
101 if ((mtp = setmntent(mtab, "r")) == NULL) {
102 fprintf(stderr, "%s: cannot access mount list %s: %s\n",
103 progname, MOUNTED, strerror(errno));
104 exit(1);
105 }
106 if (stat64(mntpoint, &statuser) < 0) {
107 fprintf(stderr, "%s: cannot access mount point %s: %s\n",
108 progname, mntpoint, strerror(errno));
109 exit(1);
110 }
111
112 while ((mnt = getmntent(mtp)) != NULL) {
113 if (stat64(mnt->mnt_dir, &statmtab) < 0) {
114 fprintf(stderr, "%s: ignoring entry %s in %s: %s\n",
115 progname, mnt->mnt_dir, mtab, strerror(errno));
116 continue;
117 }
118 if (statuser.st_ino != statmtab.st_ino ||
119 statuser.st_dev != statmtab.st_dev)
120 continue;
121 else if (strcmp(mnt->mnt_type, "xfs") != 0) {
122 fprintf(stderr, "%s: %s is not an XFS filesystem\n",
123 progname, mntpoint);
124 exit(1);
125 }
126 break; /* we've found it */
127 }
128
129 if (mnt == NULL) {
130 fprintf(stderr,
131 "%s: %s is not a filesystem mount point, according to %s\n",
132 progname, mntpoint, MOUNTED);
133 exit(1);
134 }
135
136 /* find the data, log (logdev=), and realtime (rtdev=) devices */
137 rtend = logend = NULL;
138 fname = mnt->mnt_dir;
139 datadev = mnt->mnt_fsname;
140 if (logdev = hasmntopt(mnt, "logdev=")) {
141 logdev += 7;
142 logend = strtok(logdev, " ");
143 }
144 if (rtdev = hasmntopt(mnt, "rtdev=")) {
145 rtdev += 6;
146 rtend = strtok(rtdev, " ");
147 }
148
149 /* Do this only after we've finished processing mount options */
150 if (logdev && logend != logdev)
151 *logend = '\0'; /* terminate end of log device name */
152 if (rtdev && rtend != rtdev)
153 *rtend = '\0'; /* terminate end of rt device name */
154
155 endmntent(mtp);
156}
157
158int
159main(int argc, char **argv)
160{
161 int aflag; /* fake flag, do all pieces */
162 int c; /* current option character */
163 long long ddsize; /* device size in 512-byte blocks */
164 int dflag; /* -d flag */
165 int dirversion; /* directory version number */
166 long long dlsize; /* device size in 512-byte blocks */
167 long long drsize; /* device size in 512-byte blocks */
168 long long dsize; /* new data size in fs blocks */
169 int error; /* we have hit an error */
170 long esize; /* new rt extent size */
171 int ffd; /* mount point file descriptor */
172 xfs_fsop_geom_t geo; /* current fs geometry */
173 int iflag; /* -i flag */
174 int isint; /* log is currently internal */
175 int lflag; /* -l flag */
176 long long lsize; /* new log size in fs blocks */
177 int maxpct; /* -m flag value */
178 int mflag; /* -m flag */
179 char *mtab; /* mount table file (/etc/mtab) */
180 int nflag; /* -n flag */
181 xfs_fsop_geom_t ngeo; /* new fs geometry */
182 int rflag; /* -r flag */
183 long long rsize; /* new rt size in fs blocks */
184 int unwritten; /* unwritten extent flag */
185 int xflag; /* -x flag */
186 libxfs_init_t xi; /* libxfs structure */
187
188 mtab = MOUNTED;
189 progname = basename(argv[0]);
190 aflag = dflag = iflag = lflag = mflag = nflag = rflag = xflag = 0;
191 maxpct = esize = 0;
192 dsize = lsize = rsize = 0LL;
193 while ((c = getopt(argc, argv, "dD:e:ilL:m:np:rR:t:xV")) != EOF) {
194 switch (c) {
195 case 'D':
196 dsize = atoll(optarg);
197 /* fall through */
198 case 'd':
199 dflag = 1;
200 break;
201 case 'e':
202 esize = atol(optarg);
203 rflag = 1;
204 break;
205 case 'i':
206 lflag = iflag = 1;
207 break;
208 case 'L':
209 lsize = atoll(optarg);
210 /* fall through */
211 case 'l':
212 lflag = 1;
213 break;
214 case 'm':
215 mflag = 1;
216 maxpct = atoi(optarg);
217 break;
218 case 'n':
219 nflag = 1;
220 break;
221 case 'p':
222 progname = optarg;
223 break;
224 case 'R':
225 rsize = atoll(optarg);
226 /* fall through */
227 case 'r':
228 rflag = 1;
229 break;
230 case 't':
231 mtab = optarg;
232 break;
233 case 'x':
234 lflag = xflag = 1;
235 break;
236 case 'V':
237 printf("%s version %s\n", progname, VERSION);
238 break;
239 case '?':
240 default:
241 usage();
242 }
243 }
244 if (argc - optind != 1)
245 usage();
246 if (iflag && xflag)
247 usage();
248 if (dflag + lflag + rflag == 0)
249 aflag = 1;
250
251 explore_mtab(mtab, argv[optind]);
252
253 ffd = open(fname, O_RDONLY);
254 if (ffd < 0) {
255 perror(fname);
256 return 1;
257 }
258
259 /* get the current filesystem size & geometry */
260 if (ioctl(ffd, XFS_IOC_FSGEOMETRY, &geo) < 0) {
261 fprintf(stderr, "%s: cannot determine geometry of filesystem"
262 " mounted at %s: %s\n",
263 progname, fname, strerror(errno));
264 exit(1);
265 }
266 isint = geo.logstart > 0;
267 unwritten = geo.flags & XFS_FSOP_GEOM_FLAGS_EXTFLG ? 1 : 0;
268 dirversion = geo.flags & XFS_FSOP_GEOM_FLAGS_DIRV2 ? 2 : 1;
269
270 if (nflag) {
271 report_info(geo, fname, unwritten, dirversion, isint);
272 exit(0);
273 }
274
275 /*
276 * Need root access from here on (using raw devices)...
277 */
278
279 bzero(&xi, sizeof(xi));
280 xi.dname = datadev;
281 xi.logname = logdev;
282 xi.rtname = rtdev;
283 xi.notvolok = 1;
284 xi.isreadonly = LIBXFS_ISREADONLY;
285
286 if (!libxfs_init(&xi))
287 usage();
288
289 /* check we got the info for all the sections we are trying to modify */
290 if (!xi.ddev) {
291 fprintf(stderr, "%s: failed to access data device for %s\n",
292 progname, fname);
293 exit(1);
294 }
295 if (lflag && !isint && !xi.logdev) {
296 fprintf(stderr, "%s: failed to access external log for %s\n",
297 progname, fname);
298 exit(1);
299 }
300 if (rflag && !xi.rtdev) {
301 fprintf(stderr, "%s: failed to access realtime device for %s\n",
302 progname, fname);
303 exit(1);
304 }
305
306 report_info(geo, fname, unwritten, dirversion, isint);
307
308 ddsize = xi.dsize;
309 dlsize = ( xi.logBBsize? xi.logBBsize :
310 geo.logblocks * (geo.blocksize / BBSIZE) );
311 drsize = xi.rtsize;
312
313 error = 0;
314 if (dflag | aflag) {
315 xfs_growfs_data_t in;
316
317 if (!mflag)
318 maxpct = geo.imaxpct;
319 if (!dsize)
320 dsize = ddsize / (geo.blocksize / BBSIZE);
321 else if (dsize > ddsize / (geo.blocksize / BBSIZE)) {
322 fprintf(stderr,
5b64e00a
NS
323 "data size %lld too large, maximum is %lld\n",
324 (long long)dsize,
325 (long long)(ddsize/(geo.blocksize/BBSIZE)));
2bd0ea18
NS
326 error = 1;
327 }
328 if (!error && dsize < geo.datablocks) {
5b64e00a 329 fprintf(stderr, "data size %lld too small,"
2bd0ea18 330 " old size is %lld\n",
5b64e00a 331 (long long)dsize, (long long)geo.datablocks);
2bd0ea18
NS
332 error = 1;
333 } else if (!error &&
334 dsize == geo.datablocks && maxpct == geo.imaxpct) {
335 if (dflag)
336 fprintf(stderr,
337 "data size unchanged, skipping\n");
338 if (mflag)
339 fprintf(stderr,
340 "inode max pct unchanged, skipping\n");
341 } else if (!error && !nflag) {
342 in.newblocks = (__u64)dsize;
343 in.imaxpct = (__u32)maxpct;
344 if (ioctl(ffd, XFS_IOC_FSGROWFSDATA, &in) < 0) {
345 if (errno == EWOULDBLOCK)
346 fprintf(stderr,
347 "%s: growfs operation in progress already\n",
348 progname);
349 else
350 fprintf(stderr,
351 "%s: ioctl failed - XFS_IOC_FSGROWFSDATA: %s\n",
352 progname, strerror(errno));
353 error = 1;
354 }
355 }
356 }
357
358 if (!error && (rflag | aflag)) {
359 xfs_growfs_rt_t in;
360
361 if (!esize)
362 esize = (__u32)geo.rtextsize;
363 if (!rsize)
364 rsize = drsize / (geo.blocksize / BBSIZE);
365 else if (rsize > drsize / (geo.blocksize / BBSIZE)) {
366 fprintf(stderr,
367 "realtime size %lld too large, maximum is %lld\n",
368 rsize, drsize / (geo.blocksize / BBSIZE));
369 error = 1;
370 }
371 if (!error && rsize < geo.rtblocks) {
372 fprintf(stderr,
373 "realtime size %lld too small, old size is %lld\n",
5b64e00a 374 (long long)rsize, (long long)geo.rtblocks);
2bd0ea18
NS
375 error = 1;
376 } else if (!error && rsize == geo.rtblocks) {
377 if (rflag)
378 fprintf(stderr,
379 "realtime size unchanged, skipping\n");
380 } else if (!error && !nflag) {
381 in.newblocks = (__u64)rsize;
382 in.extsize = (__u32)esize;
383 if (ioctl(ffd, XFS_IOC_FSGROWFSRT, &in) < 0) {
384 if (errno == EWOULDBLOCK)
385 fprintf(stderr,
386 "%s: growfs operation in progress already\n",
387 progname);
388 else if (errno == ENOSYS)
389 fprintf(stderr,
390 "%s: realtime growth not implemented\n",
391 progname);
392 else
393 fprintf(stderr,
394 "%s: ioctl failed - XFS_IOC_FSGROWFSRT: %s\n",
395 progname, strerror(errno));
396 error = 1;
397 }
398 }
399 }
400
401 if (!error && (lflag | aflag)) {
402 xfs_growfs_log_t in;
403
404 if (!lsize)
405 lsize = dlsize / (geo.blocksize / BBSIZE);
406 if (iflag)
407 in.isint = 1;
408 else if (xflag)
409 in.isint = 0;
410 else
411 in.isint = xi.logBBsize == 0;
412 if (lsize == geo.logblocks && (in.isint == isint)) {
413 if (lflag)
414 fprintf(stderr,
415 "log size unchanged, skipping\n");
416 } else if (!nflag) {
417 in.newblocks = (__u32)lsize;
418 if (ioctl(ffd, XFS_IOC_FSGROWFSLOG, &in) < 0) {
419 if (errno == EWOULDBLOCK)
420 fprintf(stderr,
421 "%s: growfs operation in progress already\n",
422 progname);
423 else if (errno == ENOSYS)
424 fprintf(stderr,
425 "%s: log growth not supported yet\n", progname);
426 else
427 fprintf(stderr,
428 "%s: ioctl failed - XFS_IOC_FSGROWFSLOG: %s\n",
429 progname, strerror(errno));
430 error = 1;
431 }
432 }
433 }
434
435 if (ioctl(ffd, XFS_IOC_FSGEOMETRY, &ngeo) < 0) {
436 fprintf(stderr, "%s: ioctl failed - XFS_IOC_FSGEOMETRY: %s\n",
437 progname, strerror(errno));
438 exit(1);
439 }
440 if (geo.datablocks != ngeo.datablocks)
441 printf("data blocks changed from %lld to %lld\n",
5b64e00a 442 (long long)geo.datablocks, (long long)ngeo.datablocks);
2bd0ea18
NS
443 if (geo.imaxpct != ngeo.imaxpct)
444 printf("inode max percent changed from %d to %d\n",
445 geo.imaxpct, ngeo.imaxpct);
446 if (geo.logblocks != ngeo.logblocks)
447 printf("log blocks changed from %d to %d\n",
448 geo.logblocks, ngeo.logblocks);
449 if ((geo.logstart == 0) != (ngeo.logstart == 0))
450 printf("log changed from %s to %s\n",
451 geo.logstart ? "internal" : "external",
452 ngeo.logstart ? "internal" : "external");
453 if (geo.rtblocks != ngeo.rtblocks)
454 printf("realtime blocks changed from %lld to %lld\n",
5b64e00a 455 (long long)geo.rtblocks, (long long)ngeo.rtblocks);
2bd0ea18
NS
456 if (geo.rtextsize != ngeo.rtextsize)
457 printf("realtime extent size changed from %d to %d\n",
458 geo.rtextsize, ngeo.rtextsize);
459 exit(0);
460}