]>
Commit | Line | Data |
---|---|---|
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 |
11 | static void |
12 | usage(void) | |
13 | { | |
9440d84d | 14 | fprintf(stderr, _( |
2bd0ea18 NS |
15 | "Usage: %s [options] mountpoint\n\n\ |
16 | Options:\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 |
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 */ | |
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 */ | |
2668d323 | 47 | struct xfs_fsop_geom geo; /* current fs geometry */ |
2bd0ea18 NS |
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 | 54 | int nflag; /* -n flag */ |
2668d323 | 55 | struct xfs_fsop_geom ngeo; /* new fs geometry */ |
2bd0ea18 NS |
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]; |
9612817d | 66 | int ret; |
2bd0ea18 | 67 | |
2bd0ea18 | 68 | progname = basename(argv[0]); |
9440d84d NS |
69 | setlocale(LC_ALL, ""); |
70 | bindtextdomain(PACKAGE, LOCALEDIR); | |
71 | textdomain(PACKAGE); | |
53f8ad6d | 72 | |
2bd0ea18 NS |
73 | maxpct = esize = 0; |
74 | dsize = lsize = rsize = 0LL; | |
53f8ad6d NS |
75 | aflag = dflag = iflag = lflag = mflag = nflag = rflag = xflag = 0; |
76 | ||
6d1d29a7 | 77 | while ((c = getopt(argc, argv, "dD:e:ilL:m:np:rR:t:xV")) != EOF) { |
2bd0ea18 NS |
78 | switch (c) { |
79 | case 'D': | |
53f8ad6d | 80 | dsize = strtoll(optarg, NULL, 10); |
2bd0ea18 NS |
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': | |
53f8ad6d | 93 | lsize = strtoll(optarg, NULL, 10); |
2bd0ea18 NS |
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': | |
53f8ad6d | 109 | rsize = strtoll(optarg, NULL, 10); |
2bd0ea18 NS |
110 | /* fall through */ |
111 | case 'r': | |
112 | rflag = 1; | |
113 | break; | |
114 | case 't': | |
3d93ccb7 | 115 | mtab_file = optarg; |
2bd0ea18 NS |
116 | break; |
117 | case 'x': | |
118 | lflag = xflag = 1; | |
119 | break; | |
120 | case 'V': | |
9440d84d | 121 | printf(_("%s version %s\n"), progname, VERSION); |
3d98fe63 | 122 | exit(0); |
2bd0ea18 NS |
123 | case '?': |
124 | default: | |
125 | usage(); | |
126 | } | |
127 | } | |
128 | if (argc - optind != 1) | |
129 | usage(); | |
130 | if (iflag && xflag) | |
131 | usage(); | |
17d7016e | 132 | if (dflag + lflag + rflag + mflag == 0) |
2bd0ea18 NS |
133 | aflag = 1; |
134 | ||
0900efe4 | 135 | fs_table_initialise(0, NULL, 0, NULL); |
b97815a0 BD |
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); | |
3d93ccb7 NS |
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; | |
2bd0ea18 NS |
154 | |
155 | ffd = open(fname, O_RDONLY); | |
156 | if (ffd < 0) { | |
157 | perror(fname); | |
158 | return 1; | |
159 | } | |
160 | ||
93d9f139 NS |
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 | ||
2bd0ea18 | 168 | /* get the current filesystem size & geometry */ |
9612817d DW |
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); | |
2bd0ea18 | 175 | } |
9612817d | 176 | |
2bd0ea18 | 177 | isint = geo.logstart > 0; |
2bd0ea18 NS |
178 | |
179 | /* | |
180 | * Need root access from here on (using raw devices)... | |
181 | */ | |
182 | ||
dab9b8d6 | 183 | memset(&xi, 0, sizeof(xi)); |
2bd0ea18 NS |
184 | xi.dname = datadev; |
185 | xi.logname = logdev; | |
186 | xi.rtname = rtdev; | |
2bd0ea18 NS |
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) { | |
9440d84d | 194 | fprintf(stderr, _("%s: failed to access data device for %s\n"), |
2bd0ea18 NS |
195 | progname, fname); |
196 | exit(1); | |
197 | } | |
198 | if (lflag && !isint && !xi.logdev) { | |
9440d84d | 199 | fprintf(stderr, _("%s: failed to access external log for %s\n"), |
2bd0ea18 NS |
200 | progname, fname); |
201 | exit(1); | |
202 | } | |
203 | if (rflag && !xi.rtdev) { | |
9440d84d NS |
204 | fprintf(stderr, |
205 | _("%s: failed to access realtime device for %s\n"), | |
2bd0ea18 NS |
206 | progname, fname); |
207 | exit(1); | |
208 | } | |
209 | ||
35f7c5b3 | 210 | xfs_report_geom(&geo, datadev, logdev, rtdev); |
2bd0ea18 NS |
211 | |
212 | ddsize = xi.dsize; | |
213 | dlsize = ( xi.logBBsize? xi.logBBsize : | |
214 | geo.logblocks * (geo.blocksize / BBSIZE) ); | |
215 | drsize = xi.rtsize; | |
216 | ||
b7abc846 ES |
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 | */ | |
dfc130f3 | 223 | |
b7abc846 ES |
224 | ddsize -= (ddsize % 2); |
225 | dlsize -= (dlsize % 2); | |
226 | drsize -= (drsize % 2); | |
227 | ||
2bd0ea18 | 228 | error = 0; |
17d7016e ES |
229 | |
230 | if (dflag | mflag | aflag) { | |
2bd0ea18 | 231 | xfs_growfs_data_t in; |
8e4b2fda | 232 | |
2bd0ea18 NS |
233 | if (!mflag) |
234 | maxpct = geo.imaxpct; | |
17d7016e ES |
235 | if (!dflag && !aflag) /* Only mflag, no data size change */ |
236 | dsize = geo.datablocks; | |
237 | else if (!dsize) | |
2bd0ea18 NS |
238 | dsize = ddsize / (geo.blocksize / BBSIZE); |
239 | else if (dsize > ddsize / (geo.blocksize / BBSIZE)) { | |
9440d84d NS |
240 | fprintf(stderr, _( |
241 | "data size %lld too large, maximum is %lld\n"), | |
5b64e00a NS |
242 | (long long)dsize, |
243 | (long long)(ddsize/(geo.blocksize/BBSIZE))); | |
2bd0ea18 NS |
244 | error = 1; |
245 | } | |
8e4b2fda | 246 | |
2bd0ea18 | 247 | if (!error && dsize < geo.datablocks) { |
9440d84d NS |
248 | fprintf(stderr, _("data size %lld too small," |
249 | " old size is %lld\n"), | |
5b64e00a | 250 | (long long)dsize, (long long)geo.datablocks); |
2bd0ea18 NS |
251 | error = 1; |
252 | } else if (!error && | |
253 | dsize == geo.datablocks && maxpct == geo.imaxpct) { | |
254 | if (dflag) | |
9440d84d NS |
255 | fprintf(stderr, _( |
256 | "data size unchanged, skipping\n")); | |
2bd0ea18 | 257 | if (mflag) |
9440d84d NS |
258 | fprintf(stderr, _( |
259 | "inode max pct unchanged, skipping\n")); | |
2bd0ea18 NS |
260 | } else if (!error && !nflag) { |
261 | in.newblocks = (__u64)dsize; | |
262 | in.imaxpct = (__u32)maxpct; | |
93d9f139 | 263 | if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSDATA, &in) < 0) { |
2bd0ea18 | 264 | if (errno == EWOULDBLOCK) |
9440d84d NS |
265 | fprintf(stderr, _( |
266 | "%s: growfs operation in progress already\n"), | |
2bd0ea18 NS |
267 | progname); |
268 | else | |
9440d84d | 269 | fprintf(stderr, _( |
93d9f139 | 270 | "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n"), |
2bd0ea18 NS |
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)) { | |
9440d84d NS |
285 | fprintf(stderr, _( |
286 | "realtime size %lld too large, maximum is %lld\n"), | |
2bd0ea18 NS |
287 | rsize, drsize / (geo.blocksize / BBSIZE)); |
288 | error = 1; | |
289 | } | |
290 | if (!error && rsize < geo.rtblocks) { | |
9440d84d NS |
291 | fprintf(stderr, _( |
292 | "realtime size %lld too small, old size is %lld\n"), | |
5b64e00a | 293 | (long long)rsize, (long long)geo.rtblocks); |
2bd0ea18 NS |
294 | error = 1; |
295 | } else if (!error && rsize == geo.rtblocks) { | |
296 | if (rflag) | |
9440d84d NS |
297 | fprintf(stderr, _( |
298 | "realtime size unchanged, skipping\n")); | |
2bd0ea18 NS |
299 | } else if (!error && !nflag) { |
300 | in.newblocks = (__u64)rsize; | |
301 | in.extsize = (__u32)esize; | |
93d9f139 | 302 | if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSRT, &in) < 0) { |
2bd0ea18 | 303 | if (errno == EWOULDBLOCK) |
9440d84d NS |
304 | fprintf(stderr, _( |
305 | "%s: growfs operation in progress already\n"), | |
2bd0ea18 NS |
306 | progname); |
307 | else if (errno == ENOSYS) | |
9440d84d NS |
308 | fprintf(stderr, _( |
309 | "%s: realtime growth not implemented\n"), | |
2bd0ea18 NS |
310 | progname); |
311 | else | |
9440d84d | 312 | fprintf(stderr, _( |
93d9f139 | 313 | "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n"), |
2bd0ea18 NS |
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; | |
dfc130f3 | 329 | else |
2bd0ea18 NS |
330 | in.isint = xi.logBBsize == 0; |
331 | if (lsize == geo.logblocks && (in.isint == isint)) { | |
332 | if (lflag) | |
333 | fprintf(stderr, | |
9440d84d | 334 | _("log size unchanged, skipping\n")); |
2bd0ea18 NS |
335 | } else if (!nflag) { |
336 | in.newblocks = (__u32)lsize; | |
93d9f139 | 337 | if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSLOG, &in) < 0) { |
2bd0ea18 NS |
338 | if (errno == EWOULDBLOCK) |
339 | fprintf(stderr, | |
9440d84d | 340 | _("%s: growfs operation in progress already\n"), |
2bd0ea18 NS |
341 | progname); |
342 | else if (errno == ENOSYS) | |
343 | fprintf(stderr, | |
9440d84d NS |
344 | _("%s: log growth not supported yet\n"), |
345 | progname); | |
2bd0ea18 NS |
346 | else |
347 | fprintf(stderr, | |
93d9f139 | 348 | _("%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n"), |
2bd0ea18 NS |
349 | progname, strerror(errno)); |
350 | error = 1; | |
351 | } | |
352 | } | |
353 | } | |
354 | ||
9612817d DW |
355 | ret = xfrog_geometry(ffd, &ngeo); |
356 | if (ret) { | |
93d9f139 | 357 | fprintf(stderr, _("%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n"), |
9612817d | 358 | progname, strerror(ret)); |
2bd0ea18 NS |
359 | exit(1); |
360 | } | |
361 | if (geo.datablocks != ngeo.datablocks) | |
9440d84d | 362 | printf(_("data blocks changed from %lld to %lld\n"), |
5b64e00a | 363 | (long long)geo.datablocks, (long long)ngeo.datablocks); |
2bd0ea18 | 364 | if (geo.imaxpct != ngeo.imaxpct) |
9440d84d | 365 | printf(_("inode max percent changed from %d to %d\n"), |
2bd0ea18 NS |
366 | geo.imaxpct, ngeo.imaxpct); |
367 | if (geo.logblocks != ngeo.logblocks) | |
9440d84d | 368 | printf(_("log blocks changed from %d to %d\n"), |
2bd0ea18 NS |
369 | geo.logblocks, ngeo.logblocks); |
370 | if ((geo.logstart == 0) != (ngeo.logstart == 0)) | |
9440d84d NS |
371 | printf(_("log changed from %s to %s\n"), |
372 | geo.logstart ? _("internal") : _("external"), | |
373 | ngeo.logstart ? _("internal") : _("external")); | |
2bd0ea18 | 374 | if (geo.rtblocks != ngeo.rtblocks) |
9440d84d | 375 | printf(_("realtime blocks changed from %lld to %lld\n"), |
5b64e00a | 376 | (long long)geo.rtblocks, (long long)ngeo.rtblocks); |
2bd0ea18 | 377 | if (geo.rtextsize != ngeo.rtextsize) |
9440d84d | 378 | printf(_("realtime extent size changed from %d to %d\n"), |
2bd0ea18 | 379 | geo.rtextsize, ngeo.rtextsize); |
9beae830 | 380 | exit(error); |
2bd0ea18 | 381 | } |