]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - growfs/xfs_growfs.c
do some additional cleanup after autoconf has run.
[thirdparty/xfsprogs-dev.git] / growfs / xfs_growfs.c
1 /*
2 * Copyright (c) 2000-2002 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 <libxfs.h>
34 #include <mntent.h>
35 #include <sys/ioctl.h>
36
37 /*
38 * When growing a filesystem, this is the most significant
39 * bits we'll accept in the resulting inode numbers
40 * without warning the user.
41 */
42
43 #define XFS_MAX_INODE_SIG_BITS 32
44
45 static char *fname; /* mount point name */
46 static char *datadev; /* data device name */
47 static char *logdev; /* log device name */
48 static char *rtdev; /* RT device name */
49
50 static void
51 usage(void)
52 {
53 fprintf(stderr,
54 "Usage: %s [options] mountpoint\n\n\
55 Options:\n\
56 -d grow data/metadata section\n\
57 -l grow log section\n\
58 -r grow realtime section\n\
59 -n don't change anything, just show geometry\n\
60 -I allow inode numbers to exceed %d significant bits\n\
61 -i convert log from external to internal format\n\
62 -t alternate location for mount table (/etc/mtab)\n\
63 -x convert log from internal to external format\n\
64 -D size grow data/metadata section to size blks\n\
65 -L size grow/shrink log section to size blks\n\
66 -R size grow realtime section to size blks\n\
67 -e size set realtime extent size to size blks\n\
68 -m imaxpct set inode max percent to imaxpct\n\
69 -V print version information\n",
70 progname, XFS_MAX_INODE_SIG_BITS);
71 exit(2);
72 }
73
74 void
75 report_info(
76 xfs_fsop_geom_t geo,
77 char *mntpoint,
78 int unwritten,
79 int dirversion,
80 int logversion,
81 int isint)
82 {
83 printf("meta-data=%-22s isize=%-6d agcount=%d, agsize=%d blks\n"
84 "data =%-22s bsize=%-6d blocks=%lld, imaxpct=%d\n"
85 " =%-22s sunit=%-6d swidth=%d blks, unwritten=%d\n"
86 "naming =version %-14d bsize=%-6d\n"
87 "log =%-22s bsize=%-6d blocks=%d version=%d\n"
88 " =%-22s sunit=%d blks\n"
89 "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n",
90 mntpoint, geo.inodesize, geo.agcount, geo.agblocks,
91 "", geo.blocksize, (long long)geo.datablocks, geo.imaxpct,
92 "", geo.sunit, geo.swidth, unwritten,
93 dirversion, geo.dirblocksize,
94 isint ? "internal" : "external", geo.blocksize, geo.logblocks,
95 logversion,
96 "", geo.logsunit / geo.blocksize,
97 geo.rtblocks ? "external" : "none",
98 geo.rtextsize * geo.blocksize,
99 (long long)geo.rtblocks, (long long)geo.rtextents);
100 }
101
102 void
103 explore_mtab(char *mtab, char *mntpoint)
104 {
105 struct mntent *mnt;
106 struct stat64 statuser;
107 struct stat64 statmtab;
108 FILE *mtp;
109 char *rtend;
110 char *logend;
111
112 if ((mtp = setmntent(mtab, "r")) == NULL) {
113 fprintf(stderr, "%s: cannot access mount list %s: %s\n",
114 progname, MOUNTED, strerror(errno));
115 exit(1);
116 }
117 if (stat64(mntpoint, &statuser) < 0) {
118 fprintf(stderr, "%s: cannot access mount point %s: %s\n",
119 progname, mntpoint, strerror(errno));
120 exit(1);
121 }
122
123 while ((mnt = getmntent(mtp)) != NULL) {
124 if (stat64(mnt->mnt_dir, &statmtab) < 0) {
125 fprintf(stderr, "%s: ignoring entry %s in %s: %s\n",
126 progname, mnt->mnt_dir, mtab, strerror(errno));
127 continue;
128 }
129 if (statuser.st_ino != statmtab.st_ino ||
130 statuser.st_dev != statmtab.st_dev)
131 continue;
132 else if (strcmp(mnt->mnt_type, "xfs") != 0) {
133 fprintf(stderr, "%s: %s is not an XFS filesystem\n",
134 progname, mntpoint);
135 exit(1);
136 }
137 break; /* we've found it */
138 }
139
140 if (mnt == NULL) {
141 fprintf(stderr,
142 "%s: %s is not a filesystem mount point, according to %s\n",
143 progname, mntpoint, MOUNTED);
144 exit(1);
145 }
146
147 /* find the data, log (logdev=), and realtime (rtdev=) devices */
148 rtend = logend = NULL;
149 fname = mnt->mnt_dir;
150 datadev = mnt->mnt_fsname;
151 if ((logdev = hasmntopt(mnt, "logdev="))) {
152 logdev += 7;
153 logend = strtok(logdev, " ,");
154 }
155 if ((rtdev = hasmntopt(mnt, "rtdev="))) {
156 rtdev += 6;
157 rtend = strtok(rtdev, " ,");
158 }
159
160 /* Do this only after we've finished processing mount options */
161 if (logdev && logend != logdev)
162 *logend = '\0'; /* terminate end of log device name */
163 if (rtdev && rtend != rtdev)
164 *rtend = '\0'; /* terminate end of rt device name */
165
166 endmntent(mtp);
167 }
168
169 int
170 main(int argc, char **argv)
171 {
172 int aflag; /* fake flag, do all pieces */
173 int c; /* current option character */
174 long long ddsize; /* device size in 512-byte blocks */
175 int dflag; /* -d flag */
176 int dirversion; /* directory version number */
177 int logversion; /* log version number */
178 long long dlsize; /* device size in 512-byte blocks */
179 long long drsize; /* device size in 512-byte blocks */
180 long long dsize; /* new data size in fs blocks */
181 int error; /* we have hit an error */
182 long esize; /* new rt extent size */
183 int ffd; /* mount point file descriptor */
184 xfs_fsop_geom_t geo; /* current fs geometry */
185 int iflag; /* -i flag */
186 int isint; /* log is currently internal */
187 int lflag; /* -l flag */
188 long long lsize; /* new log size in fs blocks */
189 int maxpct; /* -m flag value */
190 int mflag; /* -m flag */
191 char *mtab; /* mount table file (/etc/mtab) */
192 int nflag; /* -n flag */
193 xfs_fsop_geom_t ngeo; /* new fs geometry */
194 int rflag; /* -r flag */
195 long long rsize; /* new rt size in fs blocks */
196 int unwritten; /* unwritten extent flag */
197 int xflag; /* -x flag */
198 libxfs_init_t xi; /* libxfs structure */
199
200 mtab = MOUNTED;
201 progname = basename(argv[0]);
202 aflag = dflag = iflag = lflag = mflag = nflag = rflag = xflag = 0;
203 maxpct = esize = 0;
204 dsize = lsize = rsize = 0LL;
205 while ((c = getopt(argc, argv, "dD:e:ilL:m:np:rR:t:xV")) != EOF) {
206 switch (c) {
207 case 'D':
208 dsize = atoll(optarg);
209 /* fall through */
210 case 'd':
211 dflag = 1;
212 break;
213 case 'e':
214 esize = atol(optarg);
215 rflag = 1;
216 break;
217 case 'i':
218 lflag = iflag = 1;
219 break;
220 case 'L':
221 lsize = atoll(optarg);
222 /* fall through */
223 case 'l':
224 lflag = 1;
225 break;
226 case 'm':
227 mflag = 1;
228 maxpct = atoi(optarg);
229 break;
230 case 'n':
231 nflag = 1;
232 break;
233 case 'p':
234 progname = optarg;
235 break;
236 case 'R':
237 rsize = atoll(optarg);
238 /* fall through */
239 case 'r':
240 rflag = 1;
241 break;
242 case 't':
243 mtab = optarg;
244 break;
245 case 'x':
246 lflag = xflag = 1;
247 break;
248 case 'V':
249 printf("%s version %s\n", progname, VERSION);
250 exit(0);
251 case '?':
252 default:
253 usage();
254 }
255 }
256 if (argc - optind != 1)
257 usage();
258 if (iflag && xflag)
259 usage();
260 if (dflag + lflag + rflag == 0)
261 aflag = 1;
262
263 explore_mtab(mtab, argv[optind]);
264
265 ffd = open(fname, O_RDONLY);
266 if (ffd < 0) {
267 perror(fname);
268 return 1;
269 }
270
271 /* get the current filesystem size & geometry */
272 if (ioctl(ffd, XFS_IOC_FSGEOMETRY, &geo) < 0) {
273 /*
274 * OK, new ioctl barfed - back off and try earlier version
275 * as we're probably running an older kernel version.
276 * Only field added in the v2 geometry ioctl is "logsunit"
277 * so we'll zero that out for later display (as zero).
278 */
279 geo.logsunit = 1; /* 1 BB */
280 if (ioctl(ffd, XFS_IOC_FSGEOMETRY_V1, &geo) < 0) {
281 fprintf(stderr,
282 "%s: cannot determine geometry of filesystem"
283 " mounted at %s: %s\n",
284 progname, fname, strerror(errno));
285 exit(1);
286 }
287 }
288 isint = geo.logstart > 0;
289 unwritten = geo.flags & XFS_FSOP_GEOM_FLAGS_EXTFLG ? 1 : 0;
290 dirversion = geo.flags & XFS_FSOP_GEOM_FLAGS_DIRV2 ? 2 : 1;
291 logversion = geo.flags & XFS_FSOP_GEOM_FLAGS_LOGV2 ? 2 : 1;
292
293 if (nflag) {
294 report_info(geo, fname, unwritten, dirversion, logversion,
295 isint);
296 exit(0);
297 }
298
299 /*
300 * Need root access from here on (using raw devices)...
301 */
302
303 bzero(&xi, sizeof(xi));
304 xi.dname = datadev;
305 xi.logname = logdev;
306 xi.rtname = rtdev;
307 xi.notvolok = 1;
308 xi.isreadonly = LIBXFS_ISREADONLY;
309
310 if (!libxfs_init(&xi))
311 usage();
312
313 /* check we got the info for all the sections we are trying to modify */
314 if (!xi.ddev) {
315 fprintf(stderr, "%s: failed to access data device for %s\n",
316 progname, fname);
317 exit(1);
318 }
319 if (lflag && !isint && !xi.logdev) {
320 fprintf(stderr, "%s: failed to access external log for %s\n",
321 progname, fname);
322 exit(1);
323 }
324 if (rflag && !xi.rtdev) {
325 fprintf(stderr, "%s: failed to access realtime device for %s\n",
326 progname, fname);
327 exit(1);
328 }
329
330 report_info(geo, fname, unwritten, dirversion, logversion, isint);
331
332 ddsize = xi.dsize;
333 dlsize = ( xi.logBBsize? xi.logBBsize :
334 geo.logblocks * (geo.blocksize / BBSIZE) );
335 drsize = xi.rtsize;
336
337 /*
338 * Ok, Linux only has a 1024-byte resolution on device _size_,
339 * and the sizes below are in basic 512-byte blocks,
340 * so if we have (size % 2), on any partition, we can't get
341 * to the last 512 bytes. Just chop it down by a block.
342 */
343
344 ddsize -= (ddsize % 2);
345 dlsize -= (dlsize % 2);
346 drsize -= (drsize % 2);
347
348 error = 0;
349 if (dflag | aflag) {
350 xfs_growfs_data_t in;
351 __uint64_t new_agcount;
352
353 if (!mflag)
354 maxpct = geo.imaxpct;
355 if (!dsize)
356 dsize = ddsize / (geo.blocksize / BBSIZE);
357 else if (dsize > ddsize / (geo.blocksize / BBSIZE)) {
358 fprintf(stderr,
359 "data size %lld too large, maximum is %lld\n",
360 (long long)dsize,
361 (long long)(ddsize/(geo.blocksize/BBSIZE)));
362 error = 1;
363 }
364
365 new_agcount = dsize / geo.agblocks
366 + (dsize % geo.agblocks != 0);
367
368 if (!error && dsize < geo.datablocks) {
369 fprintf(stderr, "data size %lld too small,"
370 " old size is %lld\n",
371 (long long)dsize, (long long)geo.datablocks);
372 error = 1;
373 } else if (!error &&
374 dsize == geo.datablocks && maxpct == geo.imaxpct) {
375 if (dflag)
376 fprintf(stderr,
377 "data size unchanged, skipping\n");
378 if (mflag)
379 fprintf(stderr,
380 "inode max pct unchanged, skipping\n");
381 } else if (!error && !nflag) {
382 in.newblocks = (__u64)dsize;
383 in.imaxpct = (__u32)maxpct;
384 if (ioctl(ffd, XFS_IOC_FSGROWFSDATA, &in) < 0) {
385 if (errno == EWOULDBLOCK)
386 fprintf(stderr,
387 "%s: growfs operation in progress already\n",
388 progname);
389 else
390 fprintf(stderr,
391 "%s: ioctl failed - XFS_IOC_FSGROWFSDATA: %s\n",
392 progname, strerror(errno));
393 error = 1;
394 }
395 }
396 }
397
398 if (!error && (rflag | aflag)) {
399 xfs_growfs_rt_t in;
400
401 if (!esize)
402 esize = (__u32)geo.rtextsize;
403 if (!rsize)
404 rsize = drsize / (geo.blocksize / BBSIZE);
405 else if (rsize > drsize / (geo.blocksize / BBSIZE)) {
406 fprintf(stderr,
407 "realtime size %lld too large, maximum is %lld\n",
408 rsize, drsize / (geo.blocksize / BBSIZE));
409 error = 1;
410 }
411 if (!error && rsize < geo.rtblocks) {
412 fprintf(stderr,
413 "realtime size %lld too small, old size is %lld\n",
414 (long long)rsize, (long long)geo.rtblocks);
415 error = 1;
416 } else if (!error && rsize == geo.rtblocks) {
417 if (rflag)
418 fprintf(stderr,
419 "realtime size unchanged, skipping\n");
420 } else if (!error && !nflag) {
421 in.newblocks = (__u64)rsize;
422 in.extsize = (__u32)esize;
423 if (ioctl(ffd, XFS_IOC_FSGROWFSRT, &in) < 0) {
424 if (errno == EWOULDBLOCK)
425 fprintf(stderr,
426 "%s: growfs operation in progress already\n",
427 progname);
428 else if (errno == ENOSYS)
429 fprintf(stderr,
430 "%s: realtime growth not implemented\n",
431 progname);
432 else
433 fprintf(stderr,
434 "%s: ioctl failed - XFS_IOC_FSGROWFSRT: %s\n",
435 progname, strerror(errno));
436 error = 1;
437 }
438 }
439 }
440
441 if (!error && (lflag | aflag)) {
442 xfs_growfs_log_t in;
443
444 if (!lsize)
445 lsize = dlsize / (geo.blocksize / BBSIZE);
446 if (iflag)
447 in.isint = 1;
448 else if (xflag)
449 in.isint = 0;
450 else
451 in.isint = xi.logBBsize == 0;
452 if (lsize == geo.logblocks && (in.isint == isint)) {
453 if (lflag)
454 fprintf(stderr,
455 "log size unchanged, skipping\n");
456 } else if (!nflag) {
457 in.newblocks = (__u32)lsize;
458 if (ioctl(ffd, XFS_IOC_FSGROWFSLOG, &in) < 0) {
459 if (errno == EWOULDBLOCK)
460 fprintf(stderr,
461 "%s: growfs operation in progress already\n",
462 progname);
463 else if (errno == ENOSYS)
464 fprintf(stderr,
465 "%s: log growth not supported yet\n", progname);
466 else
467 fprintf(stderr,
468 "%s: ioctl failed - XFS_IOC_FSGROWFSLOG: %s\n",
469 progname, strerror(errno));
470 error = 1;
471 }
472 }
473 }
474
475 if (ioctl(ffd, XFS_IOC_FSGEOMETRY_V1, &ngeo) < 0) {
476 fprintf(stderr, "%s: ioctl failed - XFS_IOC_FSGEOMETRY: %s\n",
477 progname, strerror(errno));
478 exit(1);
479 }
480 if (geo.datablocks != ngeo.datablocks)
481 printf("data blocks changed from %lld to %lld\n",
482 (long long)geo.datablocks, (long long)ngeo.datablocks);
483 if (geo.imaxpct != ngeo.imaxpct)
484 printf("inode max percent changed from %d to %d\n",
485 geo.imaxpct, ngeo.imaxpct);
486 if (geo.logblocks != ngeo.logblocks)
487 printf("log blocks changed from %d to %d\n",
488 geo.logblocks, ngeo.logblocks);
489 if ((geo.logstart == 0) != (ngeo.logstart == 0))
490 printf("log changed from %s to %s\n",
491 geo.logstart ? "internal" : "external",
492 ngeo.logstart ? "internal" : "external");
493 if (geo.rtblocks != ngeo.rtblocks)
494 printf("realtime blocks changed from %lld to %lld\n",
495 (long long)geo.rtblocks, (long long)ngeo.rtblocks);
496 if (geo.rtextsize != ngeo.rtextsize)
497 printf("realtime extent size changed from %d to %d\n",
498 geo.rtextsize, ngeo.rtextsize);
499 exit(0);
500 }