]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - growfs/xfs_growfs.c
xfs_scrub: use datadev parallelization estimates for thread count
[thirdparty/xfsprogs-dev.git] / growfs / xfs_growfs.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
2bd0ea18 2/*
da23017d
NS
3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
2bd0ea18
NS
5 */
6
6b803e5a
CH
7#include "libxfs.h"
8#include "path.h"
35f7c5b3 9#include "fsgeom.h"
2bd0ea18 10
2bd0ea18
NS
11static void
12usage(void)
13{
9440d84d 14 fprintf(stderr, _(
2bd0ea18
NS
15"Usage: %s [options] mountpoint\n\n\
16Options:\n\
dfc130f3
RC
17 -d grow data/metadata section\n\
18 -l grow log section\n\
19 -r grow realtime section\n\
20 -n don't change anything, just show geometry\n\
dfc130f3
RC
21 -i convert log from external to internal format\n\
22 -t alternate location for mount table (/etc/mtab)\n\
23 -x convert log from internal to external format\n\
24 -D size grow data/metadata section to size blks\n\
25 -L size grow/shrink log section to size blks\n\
26 -R size grow realtime section to size blks\n\
27 -e size set realtime extent size to size blks\n\
28 -m imaxpct set inode max percent to imaxpct\n\
29 -V print version information\n"),
30626ef6 30 progname);
2bd0ea18
NS
31 exit(2);
32}
33
2bd0ea18
NS
34int
35main(int argc, char **argv)
36{
37 int aflag; /* fake flag, do all pieces */
38 int c; /* current option character */
39 long long ddsize; /* device size in 512-byte blocks */
40 int dflag; /* -d flag */
2bd0ea18
NS
41 long long dlsize; /* device size in 512-byte blocks */
42 long long drsize; /* device size in 512-byte blocks */
43 long long dsize; /* new data size in fs blocks */
44 int error; /* we have hit an error */
45 long esize; /* new rt extent size */
46 int ffd; /* mount point file descriptor */
47 xfs_fsop_geom_t geo; /* current fs geometry */
48 int iflag; /* -i flag */
49 int isint; /* log is currently internal */
50 int lflag; /* -l flag */
51 long long lsize; /* new log size in fs blocks */
52 int maxpct; /* -m flag value */
53 int mflag; /* -m flag */
2bd0ea18
NS
54 int nflag; /* -n flag */
55 xfs_fsop_geom_t ngeo; /* new fs geometry */
56 int rflag; /* -r flag */
57 long long rsize; /* new rt size in fs blocks */
2bd0ea18 58 int xflag; /* -x flag */
3d93ccb7
NS
59 char *fname; /* mount point name */
60 char *datadev; /* data device name */
61 char *logdev; /* log device name */
62 char *rtdev; /* RT device name */
63 fs_path_t *fs; /* mount point information */
2bd0ea18 64 libxfs_init_t xi; /* libxfs structure */
b97815a0 65 char rpath[PATH_MAX];
2bd0ea18 66
2bd0ea18 67 progname = basename(argv[0]);
9440d84d
NS
68 setlocale(LC_ALL, "");
69 bindtextdomain(PACKAGE, LOCALEDIR);
70 textdomain(PACKAGE);
53f8ad6d 71
2bd0ea18
NS
72 maxpct = esize = 0;
73 dsize = lsize = rsize = 0LL;
53f8ad6d
NS
74 aflag = dflag = iflag = lflag = mflag = nflag = rflag = xflag = 0;
75
6d1d29a7 76 while ((c = getopt(argc, argv, "dD:e:ilL:m:np:rR:t:xV")) != EOF) {
2bd0ea18
NS
77 switch (c) {
78 case 'D':
53f8ad6d 79 dsize = strtoll(optarg, NULL, 10);
2bd0ea18
NS
80 /* fall through */
81 case 'd':
82 dflag = 1;
83 break;
84 case 'e':
85 esize = atol(optarg);
86 rflag = 1;
87 break;
88 case 'i':
89 lflag = iflag = 1;
90 break;
91 case 'L':
53f8ad6d 92 lsize = strtoll(optarg, NULL, 10);
2bd0ea18
NS
93 /* fall through */
94 case 'l':
95 lflag = 1;
96 break;
97 case 'm':
98 mflag = 1;
99 maxpct = atoi(optarg);
100 break;
101 case 'n':
102 nflag = 1;
103 break;
104 case 'p':
105 progname = optarg;
106 break;
107 case 'R':
53f8ad6d 108 rsize = strtoll(optarg, NULL, 10);
2bd0ea18
NS
109 /* fall through */
110 case 'r':
111 rflag = 1;
112 break;
113 case 't':
3d93ccb7 114 mtab_file = optarg;
2bd0ea18
NS
115 break;
116 case 'x':
117 lflag = xflag = 1;
118 break;
119 case 'V':
9440d84d 120 printf(_("%s version %s\n"), progname, VERSION);
3d98fe63 121 exit(0);
2bd0ea18
NS
122 case '?':
123 default:
124 usage();
125 }
126 }
127 if (argc - optind != 1)
128 usage();
129 if (iflag && xflag)
130 usage();
17d7016e 131 if (dflag + lflag + rflag + mflag == 0)
2bd0ea18
NS
132 aflag = 1;
133
0900efe4 134 fs_table_initialise(0, NULL, 0, NULL);
b97815a0
BD
135
136 if (!realpath(argv[optind], rpath)) {
137 fprintf(stderr, _("%s: path resolution failed for %s: %s\n"),
138 progname, argv[optind], strerror(errno));
139 return 1;
140 }
141
142 fs = fs_table_lookup_mount(rpath);
3d93ccb7
NS
143 if (!fs) {
144 fprintf(stderr, _("%s: %s is not a mounted XFS filesystem\n"),
145 progname, argv[optind]);
146 return 1;
147 }
148
149 fname = fs->fs_dir;
150 datadev = fs->fs_name;
151 logdev = fs->fs_log;
152 rtdev = fs->fs_rt;
2bd0ea18
NS
153
154 ffd = open(fname, O_RDONLY);
155 if (ffd < 0) {
156 perror(fname);
157 return 1;
158 }
159
93d9f139
NS
160 if (!platform_test_xfs_fd(ffd)) {
161 fprintf(stderr, _("%s: specified file "
162 "[\"%s\"] is not on an XFS filesystem\n"),
163 progname, fname);
164 exit(1);
165 }
166
2bd0ea18 167 /* get the current filesystem size & geometry */
93d9f139 168 if (xfsctl(fname, ffd, XFS_IOC_FSGEOMETRY, &geo) < 0) {
9d77aadd 169 /*
93d9f139 170 * OK, new xfsctl barfed - back off and try earlier version
9d77aadd 171 * as we're probably running an older kernel version.
93d9f139 172 * Only field added in the v2 geometry xfsctl is "logsunit"
9d77aadd
NS
173 * so we'll zero that out for later display (as zero).
174 */
9440d84d 175 geo.logsunit = 0;
93d9f139 176 if (xfsctl(fname, ffd, XFS_IOC_FSGEOMETRY_V1, &geo) < 0) {
9440d84d 177 fprintf(stderr, _(
9d77aadd 178 "%s: cannot determine geometry of filesystem"
9440d84d 179 " mounted at %s: %s\n"),
9d77aadd
NS
180 progname, fname, strerror(errno));
181 exit(1);
182 }
2bd0ea18
NS
183 }
184 isint = geo.logstart > 0;
2bd0ea18
NS
185
186 /*
187 * Need root access from here on (using raw devices)...
188 */
189
dab9b8d6 190 memset(&xi, 0, sizeof(xi));
2bd0ea18
NS
191 xi.dname = datadev;
192 xi.logname = logdev;
193 xi.rtname = rtdev;
2bd0ea18
NS
194 xi.isreadonly = LIBXFS_ISREADONLY;
195
196 if (!libxfs_init(&xi))
197 usage();
198
199 /* check we got the info for all the sections we are trying to modify */
200 if (!xi.ddev) {
9440d84d 201 fprintf(stderr, _("%s: failed to access data device for %s\n"),
2bd0ea18
NS
202 progname, fname);
203 exit(1);
204 }
205 if (lflag && !isint && !xi.logdev) {
9440d84d 206 fprintf(stderr, _("%s: failed to access external log for %s\n"),
2bd0ea18
NS
207 progname, fname);
208 exit(1);
209 }
210 if (rflag && !xi.rtdev) {
9440d84d
NS
211 fprintf(stderr,
212 _("%s: failed to access realtime device for %s\n"),
2bd0ea18
NS
213 progname, fname);
214 exit(1);
215 }
216
35f7c5b3 217 xfs_report_geom(&geo, datadev, logdev, rtdev);
2bd0ea18
NS
218
219 ddsize = xi.dsize;
220 dlsize = ( xi.logBBsize? xi.logBBsize :
221 geo.logblocks * (geo.blocksize / BBSIZE) );
222 drsize = xi.rtsize;
223
b7abc846
ES
224 /*
225 * Ok, Linux only has a 1024-byte resolution on device _size_,
226 * and the sizes below are in basic 512-byte blocks,
227 * so if we have (size % 2), on any partition, we can't get
228 * to the last 512 bytes. Just chop it down by a block.
229 */
dfc130f3 230
b7abc846
ES
231 ddsize -= (ddsize % 2);
232 dlsize -= (dlsize % 2);
233 drsize -= (drsize % 2);
234
2bd0ea18 235 error = 0;
17d7016e
ES
236
237 if (dflag | mflag | aflag) {
2bd0ea18 238 xfs_growfs_data_t in;
8e4b2fda 239
2bd0ea18
NS
240 if (!mflag)
241 maxpct = geo.imaxpct;
17d7016e
ES
242 if (!dflag && !aflag) /* Only mflag, no data size change */
243 dsize = geo.datablocks;
244 else if (!dsize)
2bd0ea18
NS
245 dsize = ddsize / (geo.blocksize / BBSIZE);
246 else if (dsize > ddsize / (geo.blocksize / BBSIZE)) {
9440d84d
NS
247 fprintf(stderr, _(
248 "data size %lld too large, maximum is %lld\n"),
5b64e00a
NS
249 (long long)dsize,
250 (long long)(ddsize/(geo.blocksize/BBSIZE)));
2bd0ea18
NS
251 error = 1;
252 }
8e4b2fda 253
2bd0ea18 254 if (!error && dsize < geo.datablocks) {
9440d84d
NS
255 fprintf(stderr, _("data size %lld too small,"
256 " old size is %lld\n"),
5b64e00a 257 (long long)dsize, (long long)geo.datablocks);
2bd0ea18
NS
258 error = 1;
259 } else if (!error &&
260 dsize == geo.datablocks && maxpct == geo.imaxpct) {
261 if (dflag)
9440d84d
NS
262 fprintf(stderr, _(
263 "data size unchanged, skipping\n"));
2bd0ea18 264 if (mflag)
9440d84d
NS
265 fprintf(stderr, _(
266 "inode max pct unchanged, skipping\n"));
2bd0ea18
NS
267 } else if (!error && !nflag) {
268 in.newblocks = (__u64)dsize;
269 in.imaxpct = (__u32)maxpct;
93d9f139 270 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSDATA, &in) < 0) {
2bd0ea18 271 if (errno == EWOULDBLOCK)
9440d84d
NS
272 fprintf(stderr, _(
273 "%s: growfs operation in progress already\n"),
2bd0ea18
NS
274 progname);
275 else
9440d84d 276 fprintf(stderr, _(
93d9f139 277 "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n"),
2bd0ea18
NS
278 progname, strerror(errno));
279 error = 1;
280 }
281 }
282 }
283
284 if (!error && (rflag | aflag)) {
285 xfs_growfs_rt_t in;
286
287 if (!esize)
288 esize = (__u32)geo.rtextsize;
289 if (!rsize)
290 rsize = drsize / (geo.blocksize / BBSIZE);
291 else if (rsize > drsize / (geo.blocksize / BBSIZE)) {
9440d84d
NS
292 fprintf(stderr, _(
293 "realtime size %lld too large, maximum is %lld\n"),
2bd0ea18
NS
294 rsize, drsize / (geo.blocksize / BBSIZE));
295 error = 1;
296 }
297 if (!error && rsize < geo.rtblocks) {
9440d84d
NS
298 fprintf(stderr, _(
299 "realtime size %lld too small, old size is %lld\n"),
5b64e00a 300 (long long)rsize, (long long)geo.rtblocks);
2bd0ea18
NS
301 error = 1;
302 } else if (!error && rsize == geo.rtblocks) {
303 if (rflag)
9440d84d
NS
304 fprintf(stderr, _(
305 "realtime size unchanged, skipping\n"));
2bd0ea18
NS
306 } else if (!error && !nflag) {
307 in.newblocks = (__u64)rsize;
308 in.extsize = (__u32)esize;
93d9f139 309 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSRT, &in) < 0) {
2bd0ea18 310 if (errno == EWOULDBLOCK)
9440d84d
NS
311 fprintf(stderr, _(
312 "%s: growfs operation in progress already\n"),
2bd0ea18
NS
313 progname);
314 else if (errno == ENOSYS)
9440d84d
NS
315 fprintf(stderr, _(
316 "%s: realtime growth not implemented\n"),
2bd0ea18
NS
317 progname);
318 else
9440d84d 319 fprintf(stderr, _(
93d9f139 320 "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n"),
2bd0ea18
NS
321 progname, strerror(errno));
322 error = 1;
323 }
324 }
325 }
326
327 if (!error && (lflag | aflag)) {
328 xfs_growfs_log_t in;
329
330 if (!lsize)
331 lsize = dlsize / (geo.blocksize / BBSIZE);
332 if (iflag)
333 in.isint = 1;
334 else if (xflag)
335 in.isint = 0;
dfc130f3 336 else
2bd0ea18
NS
337 in.isint = xi.logBBsize == 0;
338 if (lsize == geo.logblocks && (in.isint == isint)) {
339 if (lflag)
340 fprintf(stderr,
9440d84d 341 _("log size unchanged, skipping\n"));
2bd0ea18
NS
342 } else if (!nflag) {
343 in.newblocks = (__u32)lsize;
93d9f139 344 if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSLOG, &in) < 0) {
2bd0ea18
NS
345 if (errno == EWOULDBLOCK)
346 fprintf(stderr,
9440d84d 347 _("%s: growfs operation in progress already\n"),
2bd0ea18
NS
348 progname);
349 else if (errno == ENOSYS)
350 fprintf(stderr,
9440d84d
NS
351 _("%s: log growth not supported yet\n"),
352 progname);
2bd0ea18
NS
353 else
354 fprintf(stderr,
93d9f139 355 _("%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n"),
2bd0ea18
NS
356 progname, strerror(errno));
357 error = 1;
358 }
359 }
360 }
361
93d9f139
NS
362 if (xfsctl(fname, ffd, XFS_IOC_FSGEOMETRY_V1, &ngeo) < 0) {
363 fprintf(stderr, _("%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n"),
2bd0ea18
NS
364 progname, strerror(errno));
365 exit(1);
366 }
367 if (geo.datablocks != ngeo.datablocks)
9440d84d 368 printf(_("data blocks changed from %lld to %lld\n"),
5b64e00a 369 (long long)geo.datablocks, (long long)ngeo.datablocks);
2bd0ea18 370 if (geo.imaxpct != ngeo.imaxpct)
9440d84d 371 printf(_("inode max percent changed from %d to %d\n"),
2bd0ea18
NS
372 geo.imaxpct, ngeo.imaxpct);
373 if (geo.logblocks != ngeo.logblocks)
9440d84d 374 printf(_("log blocks changed from %d to %d\n"),
2bd0ea18
NS
375 geo.logblocks, ngeo.logblocks);
376 if ((geo.logstart == 0) != (ngeo.logstart == 0))
9440d84d
NS
377 printf(_("log changed from %s to %s\n"),
378 geo.logstart ? _("internal") : _("external"),
379 ngeo.logstart ? _("internal") : _("external"));
2bd0ea18 380 if (geo.rtblocks != ngeo.rtblocks)
9440d84d 381 printf(_("realtime blocks changed from %lld to %lld\n"),
5b64e00a 382 (long long)geo.rtblocks, (long long)ngeo.rtblocks);
2bd0ea18 383 if (geo.rtextsize != ngeo.rtextsize)
9440d84d 384 printf(_("realtime extent size changed from %d to %d\n"),
2bd0ea18 385 geo.rtextsize, ngeo.rtextsize);
9beae830 386 exit(error);
2bd0ea18 387}