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