]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - growfs/xfs_growfs.c
Correct parsing of mount options from hasmntopt() - parse on ","
[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 <libxfs.h>
34 #include <mntent.h>
35 #include <sys/ioctl.h>
36
37 static char *fname; /* mount point name */
38 static char *datadev; /* data device name */
39 static char *logdev; /* log device name */
40 static char *rtdev; /* RT device name */
41
42 static void
43 usage(void)
44 {
45 fprintf(stderr,
46 "Usage: %s [options] mountpoint\n\n\
47 Options:\n\
48 -d grow data/metadata section\n\
49 -l grow log section\n\
50 -r grow realtime section\n\
51 -n don't change anything, just show geometry\n\
52 -i convert log from external to internal format\n\
53 -t alternate location for mount table (/etc/mtab)\n\
54 -x convert log from internal to external format\n\
55 -D size grow data/metadata section to size blks\n\
56 -L size grow/shrink log section to size blks\n\
57 -R size grow realtime section to size blks\n\
58 -e size set realtime extent size to size blks\n\
59 -m imaxpct set inode max percent to imaxpct\n\
60 -V print version information\n",
61 progname);
62 exit(2);
63 }
64
65 void
66 report_info(
67 xfs_fsop_geom_t geo,
68 char *mntpoint,
69 int unwritten,
70 int dirversion,
71 int isint)
72 {
73 printf("meta-data=%-22s isize=%-6d agcount=%d, agsize=%d blks\n"
74 "data =%-22s bsize=%-6d blocks=%lld, imaxpct=%d\n"
75 " =%-22s sunit=%-6d swidth=%d blks, unwritten=%d\n"
76 "naming =version %-14d bsize=%-6d\n"
77 "log =%-22s bsize=%-6d blocks=%d\n"
78 "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n",
79 mntpoint, geo.inodesize, geo.agcount, geo.agblocks,
80 "", geo.blocksize, (long long)geo.datablocks, geo.imaxpct,
81 "", geo.sunit, geo.swidth, unwritten,
82 dirversion, geo.dirblocksize,
83 isint ? "internal" : "external", geo.blocksize, geo.logblocks,
84 geo.rtblocks ? "external" : "none",
85 geo.rtextsize * geo.blocksize,
86 (long long)geo.rtblocks, (long long)geo.rtextents);
87 }
88
89 void
90 explore_mtab(char *mtab, char *mntpoint)
91 {
92 struct mntent *mnt;
93 struct stat64 statuser;
94 struct stat64 statmtab;
95 FILE *mtp;
96 char *rtend;
97 char *logend;
98
99 if ((mtp = setmntent(mtab, "r")) == NULL) {
100 fprintf(stderr, "%s: cannot access mount list %s: %s\n",
101 progname, MOUNTED, strerror(errno));
102 exit(1);
103 }
104 if (stat64(mntpoint, &statuser) < 0) {
105 fprintf(stderr, "%s: cannot access mount point %s: %s\n",
106 progname, mntpoint, strerror(errno));
107 exit(1);
108 }
109
110 while ((mnt = getmntent(mtp)) != NULL) {
111 if (stat64(mnt->mnt_dir, &statmtab) < 0) {
112 fprintf(stderr, "%s: ignoring entry %s in %s: %s\n",
113 progname, mnt->mnt_dir, mtab, strerror(errno));
114 continue;
115 }
116 if (statuser.st_ino != statmtab.st_ino ||
117 statuser.st_dev != statmtab.st_dev)
118 continue;
119 else if (strcmp(mnt->mnt_type, "xfs") != 0) {
120 fprintf(stderr, "%s: %s is not an XFS filesystem\n",
121 progname, mntpoint);
122 exit(1);
123 }
124 break; /* we've found it */
125 }
126
127 if (mnt == NULL) {
128 fprintf(stderr,
129 "%s: %s is not a filesystem mount point, according to %s\n",
130 progname, mntpoint, MOUNTED);
131 exit(1);
132 }
133
134 /* find the data, log (logdev=), and realtime (rtdev=) devices */
135 rtend = logend = NULL;
136 fname = mnt->mnt_dir;
137 datadev = mnt->mnt_fsname;
138 if ((logdev = hasmntopt(mnt, "logdev="))) {
139 logdev += 7;
140 logend = strtok(logdev, " ,");
141 }
142 if ((rtdev = hasmntopt(mnt, "rtdev="))) {
143 rtdev += 6;
144 rtend = strtok(rtdev, " ,");
145 }
146
147 /* Do this only after we've finished processing mount options */
148 if (logdev && logend != logdev)
149 *logend = '\0'; /* terminate end of log device name */
150 if (rtdev && rtend != rtdev)
151 *rtend = '\0'; /* terminate end of rt device name */
152
153 endmntent(mtp);
154 }
155
156 int
157 main(int argc, char **argv)
158 {
159 int aflag; /* fake flag, do all pieces */
160 int c; /* current option character */
161 long long ddsize; /* device size in 512-byte blocks */
162 int dflag; /* -d flag */
163 int dirversion; /* directory version number */
164 long long dlsize; /* device size in 512-byte blocks */
165 long long drsize; /* device size in 512-byte blocks */
166 long long dsize; /* new data size in fs blocks */
167 int error; /* we have hit an error */
168 long esize; /* new rt extent size */
169 int ffd; /* mount point file descriptor */
170 xfs_fsop_geom_t geo; /* current fs geometry */
171 int iflag; /* -i flag */
172 int isint; /* log is currently internal */
173 int lflag; /* -l flag */
174 long long lsize; /* new log size in fs blocks */
175 int maxpct; /* -m flag value */
176 int mflag; /* -m flag */
177 char *mtab; /* mount table file (/etc/mtab) */
178 int nflag; /* -n flag */
179 xfs_fsop_geom_t ngeo; /* new fs geometry */
180 int rflag; /* -r flag */
181 long long rsize; /* new rt size in fs blocks */
182 int unwritten; /* unwritten extent flag */
183 int xflag; /* -x flag */
184 libxfs_init_t xi; /* libxfs structure */
185
186 mtab = MOUNTED;
187 progname = basename(argv[0]);
188 aflag = dflag = iflag = lflag = mflag = nflag = rflag = xflag = 0;
189 maxpct = esize = 0;
190 dsize = lsize = rsize = 0LL;
191 while ((c = getopt(argc, argv, "dD:e:ilL:m:np:rR:t:xV")) != EOF) {
192 switch (c) {
193 case 'D':
194 dsize = atoll(optarg);
195 /* fall through */
196 case 'd':
197 dflag = 1;
198 break;
199 case 'e':
200 esize = atol(optarg);
201 rflag = 1;
202 break;
203 case 'i':
204 lflag = iflag = 1;
205 break;
206 case 'L':
207 lsize = atoll(optarg);
208 /* fall through */
209 case 'l':
210 lflag = 1;
211 break;
212 case 'm':
213 mflag = 1;
214 maxpct = atoi(optarg);
215 break;
216 case 'n':
217 nflag = 1;
218 break;
219 case 'p':
220 progname = optarg;
221 break;
222 case 'R':
223 rsize = atoll(optarg);
224 /* fall through */
225 case 'r':
226 rflag = 1;
227 break;
228 case 't':
229 mtab = optarg;
230 break;
231 case 'x':
232 lflag = xflag = 1;
233 break;
234 case 'V':
235 printf("%s version %s\n", progname, VERSION);
236 break;
237 case '?':
238 default:
239 usage();
240 }
241 }
242 if (argc - optind != 1)
243 usage();
244 if (iflag && xflag)
245 usage();
246 if (dflag + lflag + rflag == 0)
247 aflag = 1;
248
249 explore_mtab(mtab, argv[optind]);
250
251 ffd = open(fname, O_RDONLY);
252 if (ffd < 0) {
253 perror(fname);
254 return 1;
255 }
256
257 /* get the current filesystem size & geometry */
258 if (ioctl(ffd, XFS_IOC_FSGEOMETRY, &geo) < 0) {
259 fprintf(stderr, "%s: cannot determine geometry of filesystem"
260 " mounted at %s: %s\n",
261 progname, fname, strerror(errno));
262 exit(1);
263 }
264 isint = geo.logstart > 0;
265 unwritten = geo.flags & XFS_FSOP_GEOM_FLAGS_EXTFLG ? 1 : 0;
266 dirversion = geo.flags & XFS_FSOP_GEOM_FLAGS_DIRV2 ? 2 : 1;
267
268 if (nflag) {
269 report_info(geo, fname, unwritten, dirversion, isint);
270 exit(0);
271 }
272
273 /*
274 * Need root access from here on (using raw devices)...
275 */
276
277 bzero(&xi, sizeof(xi));
278 xi.dname = datadev;
279 xi.logname = logdev;
280 xi.rtname = rtdev;
281 xi.notvolok = 1;
282 xi.isreadonly = LIBXFS_ISREADONLY;
283
284 if (!libxfs_init(&xi))
285 usage();
286
287 /* check we got the info for all the sections we are trying to modify */
288 if (!xi.ddev) {
289 fprintf(stderr, "%s: failed to access data device for %s\n",
290 progname, fname);
291 exit(1);
292 }
293 if (lflag && !isint && !xi.logdev) {
294 fprintf(stderr, "%s: failed to access external log for %s\n",
295 progname, fname);
296 exit(1);
297 }
298 if (rflag && !xi.rtdev) {
299 fprintf(stderr, "%s: failed to access realtime device for %s\n",
300 progname, fname);
301 exit(1);
302 }
303
304 report_info(geo, fname, unwritten, dirversion, isint);
305
306 ddsize = xi.dsize;
307 dlsize = ( xi.logBBsize? xi.logBBsize :
308 geo.logblocks * (geo.blocksize / BBSIZE) );
309 drsize = xi.rtsize;
310
311 error = 0;
312 if (dflag | aflag) {
313 xfs_growfs_data_t in;
314
315 if (!mflag)
316 maxpct = geo.imaxpct;
317 if (!dsize)
318 dsize = ddsize / (geo.blocksize / BBSIZE);
319 else if (dsize > ddsize / (geo.blocksize / BBSIZE)) {
320 fprintf(stderr,
321 "data size %lld too large, maximum is %lld\n",
322 (long long)dsize,
323 (long long)(ddsize/(geo.blocksize/BBSIZE)));
324 error = 1;
325 }
326 if (!error && dsize < geo.datablocks) {
327 fprintf(stderr, "data size %lld too small,"
328 " old size is %lld\n",
329 (long long)dsize, (long long)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 (long long)rsize, (long long)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 (long long)geo.datablocks, (long long)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 (long long)geo.rtblocks, (long long)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 }