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