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