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