]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - growfs/xfs_growfs.c
progs: clean up libxfs.h includes
[thirdparty/xfsprogs-dev.git] / growfs / xfs_growfs.c
1 /*
2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "xfs/libxfs.h"
20 #include <xfs/path.h>
21
22 static void
23 usage(void)
24 {
25 fprintf(stderr, _(
26 "Usage: %s [options] mountpoint\n\n\
27 Options:\n\
28 -d grow data/metadata section\n\
29 -l grow log section\n\
30 -r grow realtime section\n\
31 -n don't change anything, just show geometry\n\
32 -i convert log from external to internal format\n\
33 -t alternate location for mount table (/etc/mtab)\n\
34 -x convert log from internal to external format\n\
35 -D size grow data/metadata section to size blks\n\
36 -L size grow/shrink log section to size blks\n\
37 -R size grow realtime section to size blks\n\
38 -e size set realtime extent size to size blks\n\
39 -m imaxpct set inode max percent to imaxpct\n\
40 -V print version information\n"),
41 progname);
42 exit(2);
43 }
44
45 void
46 report_info(
47 xfs_fsop_geom_t geo,
48 char *mntpoint,
49 int isint,
50 char *logname,
51 char *rtname,
52 int lazycount,
53 int dirversion,
54 int logversion,
55 int attrversion,
56 int projid32bit,
57 int crcs_enabled,
58 int cimode,
59 int ftype_enabled,
60 int finobt_enabled)
61 {
62 printf(_(
63 "meta-data=%-22s isize=%-6u agcount=%u, agsize=%u blks\n"
64 " =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n"
65 " =%-22s crc=%-8u finobt=%u\n"
66 "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
67 " =%-22s sunit=%-6u swidth=%u blks\n"
68 "naming =version %-14u bsize=%-6u ascii-ci=%d ftype=%d\n"
69 "log =%-22s bsize=%-6u blocks=%u, version=%u\n"
70 " =%-22s sectsz=%-5u sunit=%u blks, lazy-count=%u\n"
71 "realtime =%-22s extsz=%-6u blocks=%llu, rtextents=%llu\n"),
72
73 mntpoint, geo.inodesize, geo.agcount, geo.agblocks,
74 "", geo.sectsize, attrversion, projid32bit,
75 "", crcs_enabled, finobt_enabled,
76 "", geo.blocksize, (unsigned long long)geo.datablocks,
77 geo.imaxpct,
78 "", geo.sunit, geo.swidth,
79 dirversion, geo.dirblocksize, cimode, ftype_enabled,
80 isint ? _("internal") : logname ? logname : _("external"),
81 geo.blocksize, geo.logblocks, logversion,
82 "", geo.logsectsize, geo.logsunit / geo.blocksize, lazycount,
83 !geo.rtblocks ? _("none") : rtname ? rtname : _("external"),
84 geo.rtextsize * geo.blocksize, (unsigned long long)geo.rtblocks,
85 (unsigned long long)geo.rtextents);
86 }
87
88 int
89 main(int argc, char **argv)
90 {
91 int aflag; /* fake flag, do all pieces */
92 int c; /* current option character */
93 long long ddsize; /* device size in 512-byte blocks */
94 int dflag; /* -d flag */
95 int attrversion;/* attribute version number */
96 int dirversion; /* directory version number */
97 int logversion; /* log version number */
98 long long dlsize; /* device size in 512-byte blocks */
99 long long drsize; /* device size in 512-byte blocks */
100 long long dsize; /* new data size in fs blocks */
101 int error; /* we have hit an error */
102 long esize; /* new rt extent size */
103 int ffd; /* mount point file descriptor */
104 xfs_fsop_geom_t geo; /* current fs geometry */
105 int iflag; /* -i flag */
106 int isint; /* log is currently internal */
107 int lflag; /* -l flag */
108 long long lsize; /* new log size in fs blocks */
109 int maxpct; /* -m flag value */
110 int mflag; /* -m flag */
111 int nflag; /* -n flag */
112 xfs_fsop_geom_t ngeo; /* new fs geometry */
113 int rflag; /* -r flag */
114 long long rsize; /* new rt size in fs blocks */
115 int ci; /* ASCII case-insensitive fs */
116 int lazycount; /* lazy superblock counters */
117 int xflag; /* -x flag */
118 char *fname; /* mount point name */
119 char *datadev; /* data device name */
120 char *logdev; /* log device name */
121 char *rtdev; /* RT device name */
122 fs_path_t *fs; /* mount point information */
123 libxfs_init_t xi; /* libxfs structure */
124 int projid32bit;
125 int crcs_enabled;
126 int ftype_enabled = 0;
127 int finobt_enabled; /* free inode btree */
128
129 progname = basename(argv[0]);
130 setlocale(LC_ALL, "");
131 bindtextdomain(PACKAGE, LOCALEDIR);
132 textdomain(PACKAGE);
133
134 maxpct = esize = 0;
135 dsize = lsize = rsize = 0LL;
136 aflag = dflag = iflag = lflag = mflag = nflag = rflag = xflag = 0;
137
138 while ((c = getopt(argc, argv, "dD:e:ilL:m:np:rR:t:xV")) != EOF) {
139 switch (c) {
140 case 'D':
141 dsize = strtoll(optarg, NULL, 10);
142 /* fall through */
143 case 'd':
144 dflag = 1;
145 break;
146 case 'e':
147 esize = atol(optarg);
148 rflag = 1;
149 break;
150 case 'i':
151 lflag = iflag = 1;
152 break;
153 case 'L':
154 lsize = strtoll(optarg, NULL, 10);
155 /* fall through */
156 case 'l':
157 lflag = 1;
158 break;
159 case 'm':
160 mflag = 1;
161 maxpct = atoi(optarg);
162 break;
163 case 'n':
164 nflag = 1;
165 break;
166 case 'p':
167 progname = optarg;
168 break;
169 case 'R':
170 rsize = strtoll(optarg, NULL, 10);
171 /* fall through */
172 case 'r':
173 rflag = 1;
174 break;
175 case 't':
176 mtab_file = optarg;
177 break;
178 case 'x':
179 lflag = xflag = 1;
180 break;
181 case 'V':
182 printf(_("%s version %s\n"), progname, VERSION);
183 exit(0);
184 case '?':
185 default:
186 usage();
187 }
188 }
189 if (argc - optind != 1)
190 usage();
191 if (iflag && xflag)
192 usage();
193 if (dflag + lflag + rflag + mflag == 0)
194 aflag = 1;
195
196 fs_table_initialise(0, NULL, 0, NULL);
197 fs = fs_table_lookup(argv[optind], FS_MOUNT_POINT);
198 if (!fs) {
199 fprintf(stderr, _("%s: %s is not a mounted XFS filesystem\n"),
200 progname, argv[optind]);
201 return 1;
202 }
203
204 fname = fs->fs_dir;
205 datadev = fs->fs_name;
206 logdev = fs->fs_log;
207 rtdev = fs->fs_rt;
208
209 ffd = open(fname, O_RDONLY);
210 if (ffd < 0) {
211 perror(fname);
212 return 1;
213 }
214
215 if (!platform_test_xfs_fd(ffd)) {
216 fprintf(stderr, _("%s: specified file "
217 "[\"%s\"] is not on an XFS filesystem\n"),
218 progname, fname);
219 exit(1);
220 }
221
222 /* get the current filesystem size & geometry */
223 if (xfsctl(fname, ffd, XFS_IOC_FSGEOMETRY, &geo) < 0) {
224 /*
225 * OK, new xfsctl barfed - back off and try earlier version
226 * as we're probably running an older kernel version.
227 * Only field added in the v2 geometry xfsctl is "logsunit"
228 * so we'll zero that out for later display (as zero).
229 */
230 geo.logsunit = 0;
231 if (xfsctl(fname, ffd, XFS_IOC_FSGEOMETRY_V1, &geo) < 0) {
232 fprintf(stderr, _(
233 "%s: cannot determine geometry of filesystem"
234 " mounted at %s: %s\n"),
235 progname, fname, strerror(errno));
236 exit(1);
237 }
238 }
239 isint = geo.logstart > 0;
240 lazycount = geo.flags & XFS_FSOP_GEOM_FLAGS_LAZYSB ? 1 : 0;
241 dirversion = geo.flags & XFS_FSOP_GEOM_FLAGS_DIRV2 ? 2 : 1;
242 logversion = geo.flags & XFS_FSOP_GEOM_FLAGS_LOGV2 ? 2 : 1;
243 attrversion = geo.flags & XFS_FSOP_GEOM_FLAGS_ATTR2 ? 2 : \
244 (geo.flags & XFS_FSOP_GEOM_FLAGS_ATTR ? 1 : 0);
245 ci = geo.flags & XFS_FSOP_GEOM_FLAGS_DIRV2CI ? 1 : 0;
246 projid32bit = geo.flags & XFS_FSOP_GEOM_FLAGS_PROJID32 ? 1 : 0;
247 crcs_enabled = geo.flags & XFS_FSOP_GEOM_FLAGS_V5SB ? 1 : 0;
248 ftype_enabled = geo.flags & XFS_FSOP_GEOM_FLAGS_FTYPE ? 1 : 0;
249 finobt_enabled = geo.flags & XFS_FSOP_GEOM_FLAGS_FINOBT ? 1 : 0;
250 if (nflag) {
251 report_info(geo, datadev, isint, logdev, rtdev,
252 lazycount, dirversion, logversion,
253 attrversion, projid32bit, crcs_enabled, ci,
254 ftype_enabled, finobt_enabled);
255 exit(0);
256 }
257
258 /*
259 * Need root access from here on (using raw devices)...
260 */
261
262 memset(&xi, 0, sizeof(xi));
263 xi.dname = datadev;
264 xi.logname = logdev;
265 xi.rtname = rtdev;
266 xi.isreadonly = LIBXFS_ISREADONLY;
267
268 if (!libxfs_init(&xi))
269 usage();
270
271 /* check we got the info for all the sections we are trying to modify */
272 if (!xi.ddev) {
273 fprintf(stderr, _("%s: failed to access data device for %s\n"),
274 progname, fname);
275 exit(1);
276 }
277 if (lflag && !isint && !xi.logdev) {
278 fprintf(stderr, _("%s: failed to access external log for %s\n"),
279 progname, fname);
280 exit(1);
281 }
282 if (rflag && !xi.rtdev) {
283 fprintf(stderr,
284 _("%s: failed to access realtime device for %s\n"),
285 progname, fname);
286 exit(1);
287 }
288
289 report_info(geo, datadev, isint, logdev, rtdev,
290 lazycount, dirversion, logversion,
291 attrversion, projid32bit, crcs_enabled, ci, ftype_enabled,
292 finobt_enabled);
293
294 ddsize = xi.dsize;
295 dlsize = ( xi.logBBsize? xi.logBBsize :
296 geo.logblocks * (geo.blocksize / BBSIZE) );
297 drsize = xi.rtsize;
298
299 /*
300 * Ok, Linux only has a 1024-byte resolution on device _size_,
301 * and the sizes below are in basic 512-byte blocks,
302 * so if we have (size % 2), on any partition, we can't get
303 * to the last 512 bytes. Just chop it down by a block.
304 */
305
306 ddsize -= (ddsize % 2);
307 dlsize -= (dlsize % 2);
308 drsize -= (drsize % 2);
309
310 error = 0;
311
312 if (dflag | mflag | aflag) {
313 xfs_growfs_data_t in;
314
315 if (!mflag)
316 maxpct = geo.imaxpct;
317 if (!dflag && !aflag) /* Only mflag, no data size change */
318 dsize = geo.datablocks;
319 else if (!dsize)
320 dsize = ddsize / (geo.blocksize / BBSIZE);
321 else if (dsize > ddsize / (geo.blocksize / BBSIZE)) {
322 fprintf(stderr, _(
323 "data size %lld too large, maximum is %lld\n"),
324 (long long)dsize,
325 (long long)(ddsize/(geo.blocksize/BBSIZE)));
326 error = 1;
327 }
328
329 if (!error && dsize < geo.datablocks) {
330 fprintf(stderr, _("data size %lld too small,"
331 " old size is %lld\n"),
332 (long long)dsize, (long long)geo.datablocks);
333 error = 1;
334 } else if (!error &&
335 dsize == geo.datablocks && maxpct == geo.imaxpct) {
336 if (dflag)
337 fprintf(stderr, _(
338 "data size unchanged, skipping\n"));
339 if (mflag)
340 fprintf(stderr, _(
341 "inode max pct unchanged, skipping\n"));
342 } else if (!error && !nflag) {
343 in.newblocks = (__u64)dsize;
344 in.imaxpct = (__u32)maxpct;
345 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSDATA, &in) < 0) {
346 if (errno == EWOULDBLOCK)
347 fprintf(stderr, _(
348 "%s: growfs operation in progress already\n"),
349 progname);
350 else
351 fprintf(stderr, _(
352 "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n"),
353 progname, strerror(errno));
354 error = 1;
355 }
356 }
357 }
358
359 if (!error && (rflag | aflag)) {
360 xfs_growfs_rt_t in;
361
362 if (!esize)
363 esize = (__u32)geo.rtextsize;
364 if (!rsize)
365 rsize = drsize / (geo.blocksize / BBSIZE);
366 else if (rsize > drsize / (geo.blocksize / BBSIZE)) {
367 fprintf(stderr, _(
368 "realtime size %lld too large, maximum is %lld\n"),
369 rsize, drsize / (geo.blocksize / BBSIZE));
370 error = 1;
371 }
372 if (!error && rsize < geo.rtblocks) {
373 fprintf(stderr, _(
374 "realtime size %lld too small, old size is %lld\n"),
375 (long long)rsize, (long long)geo.rtblocks);
376 error = 1;
377 } else if (!error && rsize == geo.rtblocks) {
378 if (rflag)
379 fprintf(stderr, _(
380 "realtime size unchanged, skipping\n"));
381 } else if (!error && !nflag) {
382 in.newblocks = (__u64)rsize;
383 in.extsize = (__u32)esize;
384 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSRT, &in) < 0) {
385 if (errno == EWOULDBLOCK)
386 fprintf(stderr, _(
387 "%s: growfs operation in progress already\n"),
388 progname);
389 else if (errno == ENOSYS)
390 fprintf(stderr, _(
391 "%s: realtime growth not implemented\n"),
392 progname);
393 else
394 fprintf(stderr, _(
395 "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n"),
396 progname, strerror(errno));
397 error = 1;
398 }
399 }
400 }
401
402 if (!error && (lflag | aflag)) {
403 xfs_growfs_log_t in;
404
405 if (!lsize)
406 lsize = dlsize / (geo.blocksize / BBSIZE);
407 if (iflag)
408 in.isint = 1;
409 else if (xflag)
410 in.isint = 0;
411 else
412 in.isint = xi.logBBsize == 0;
413 if (lsize == geo.logblocks && (in.isint == isint)) {
414 if (lflag)
415 fprintf(stderr,
416 _("log size unchanged, skipping\n"));
417 } else if (!nflag) {
418 in.newblocks = (__u32)lsize;
419 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSLOG, &in) < 0) {
420 if (errno == EWOULDBLOCK)
421 fprintf(stderr,
422 _("%s: growfs operation in progress already\n"),
423 progname);
424 else if (errno == ENOSYS)
425 fprintf(stderr,
426 _("%s: log growth not supported yet\n"),
427 progname);
428 else
429 fprintf(stderr,
430 _("%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n"),
431 progname, strerror(errno));
432 error = 1;
433 }
434 }
435 }
436
437 if (xfsctl(fname, ffd, XFS_IOC_FSGEOMETRY_V1, &ngeo) < 0) {
438 fprintf(stderr, _("%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n"),
439 progname, strerror(errno));
440 exit(1);
441 }
442 if (geo.datablocks != ngeo.datablocks)
443 printf(_("data blocks changed from %lld to %lld\n"),
444 (long long)geo.datablocks, (long long)ngeo.datablocks);
445 if (geo.imaxpct != ngeo.imaxpct)
446 printf(_("inode max percent changed from %d to %d\n"),
447 geo.imaxpct, ngeo.imaxpct);
448 if (geo.logblocks != ngeo.logblocks)
449 printf(_("log blocks changed from %d to %d\n"),
450 geo.logblocks, ngeo.logblocks);
451 if ((geo.logstart == 0) != (ngeo.logstart == 0))
452 printf(_("log changed from %s to %s\n"),
453 geo.logstart ? _("internal") : _("external"),
454 ngeo.logstart ? _("internal") : _("external"));
455 if (geo.rtblocks != ngeo.rtblocks)
456 printf(_("realtime blocks changed from %lld to %lld\n"),
457 (long long)geo.rtblocks, (long long)ngeo.rtblocks);
458 if (geo.rtextsize != ngeo.rtextsize)
459 printf(_("realtime extent size changed from %d to %d\n"),
460 geo.rtextsize, ngeo.rtextsize);
461 exit(error);
462 }