]>
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 | 7 | #include "libxfs.h" |
42b4c8e8 | 8 | #include "libfrog/paths.h" |
fee68490 | 9 | #include "libfrog/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 | 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); | |
7e8275f8 ES |
143 | if (!fs) |
144 | fs = fs_table_lookup_blkdev(rpath); | |
145 | ||
3d93ccb7 NS |
146 | if (!fs) { |
147 | fprintf(stderr, _("%s: %s is not a mounted XFS filesystem\n"), | |
148 | progname, argv[optind]); | |
149 | return 1; | |
150 | } | |
151 | ||
152 | fname = fs->fs_dir; | |
153 | datadev = fs->fs_name; | |
154 | logdev = fs->fs_log; | |
155 | rtdev = fs->fs_rt; | |
2bd0ea18 NS |
156 | |
157 | ffd = open(fname, O_RDONLY); | |
158 | if (ffd < 0) { | |
159 | perror(fname); | |
160 | return 1; | |
161 | } | |
162 | ||
93d9f139 NS |
163 | if (!platform_test_xfs_fd(ffd)) { |
164 | fprintf(stderr, _("%s: specified file " | |
165 | "[\"%s\"] is not on an XFS filesystem\n"), | |
166 | progname, fname); | |
167 | exit(1); | |
168 | } | |
169 | ||
2bd0ea18 | 170 | /* get the current filesystem size & geometry */ |
03d96c64 | 171 | ret = -xfrog_geometry(ffd, &geo); |
9612817d DW |
172 | if (ret) { |
173 | fprintf(stderr, | |
174 | _("%s: cannot determine geometry of filesystem mounted at %s: %s\n"), | |
175 | progname, fname, strerror(ret)); | |
176 | exit(1); | |
2bd0ea18 | 177 | } |
9612817d | 178 | |
2bd0ea18 | 179 | isint = geo.logstart > 0; |
2bd0ea18 NS |
180 | |
181 | /* | |
182 | * Need root access from here on (using raw devices)... | |
183 | */ | |
184 | ||
dab9b8d6 | 185 | memset(&xi, 0, sizeof(xi)); |
2bd0ea18 NS |
186 | xi.dname = datadev; |
187 | xi.logname = logdev; | |
188 | xi.rtname = rtdev; | |
2bd0ea18 NS |
189 | xi.isreadonly = LIBXFS_ISREADONLY; |
190 | ||
191 | if (!libxfs_init(&xi)) | |
192 | usage(); | |
193 | ||
194 | /* check we got the info for all the sections we are trying to modify */ | |
195 | if (!xi.ddev) { | |
9440d84d | 196 | fprintf(stderr, _("%s: failed to access data device for %s\n"), |
2bd0ea18 NS |
197 | progname, fname); |
198 | exit(1); | |
199 | } | |
200 | if (lflag && !isint && !xi.logdev) { | |
9440d84d | 201 | fprintf(stderr, _("%s: failed to access external log for %s\n"), |
2bd0ea18 NS |
202 | progname, fname); |
203 | exit(1); | |
204 | } | |
205 | if (rflag && !xi.rtdev) { | |
9440d84d NS |
206 | fprintf(stderr, |
207 | _("%s: failed to access realtime device for %s\n"), | |
2bd0ea18 NS |
208 | progname, fname); |
209 | exit(1); | |
210 | } | |
211 | ||
35f7c5b3 | 212 | xfs_report_geom(&geo, datadev, logdev, rtdev); |
2bd0ea18 NS |
213 | |
214 | ddsize = xi.dsize; | |
215 | dlsize = ( xi.logBBsize? xi.logBBsize : | |
216 | geo.logblocks * (geo.blocksize / BBSIZE) ); | |
217 | drsize = xi.rtsize; | |
218 | ||
b7abc846 ES |
219 | /* |
220 | * Ok, Linux only has a 1024-byte resolution on device _size_, | |
221 | * and the sizes below are in basic 512-byte blocks, | |
222 | * so if we have (size % 2), on any partition, we can't get | |
223 | * to the last 512 bytes. Just chop it down by a block. | |
224 | */ | |
dfc130f3 | 225 | |
b7abc846 ES |
226 | ddsize -= (ddsize % 2); |
227 | dlsize -= (dlsize % 2); | |
228 | drsize -= (drsize % 2); | |
229 | ||
2bd0ea18 | 230 | error = 0; |
17d7016e ES |
231 | |
232 | if (dflag | mflag | aflag) { | |
2bd0ea18 | 233 | xfs_growfs_data_t in; |
8e4b2fda | 234 | |
2bd0ea18 NS |
235 | if (!mflag) |
236 | maxpct = geo.imaxpct; | |
17d7016e ES |
237 | if (!dflag && !aflag) /* Only mflag, no data size change */ |
238 | dsize = geo.datablocks; | |
239 | else if (!dsize) | |
2bd0ea18 NS |
240 | dsize = ddsize / (geo.blocksize / BBSIZE); |
241 | else if (dsize > ddsize / (geo.blocksize / BBSIZE)) { | |
9440d84d NS |
242 | fprintf(stderr, _( |
243 | "data size %lld too large, maximum is %lld\n"), | |
5b64e00a NS |
244 | (long long)dsize, |
245 | (long long)(ddsize/(geo.blocksize/BBSIZE))); | |
2bd0ea18 NS |
246 | error = 1; |
247 | } | |
8e4b2fda | 248 | |
272480fa GX |
249 | if (!error && dsize < geo.datablocks) |
250 | fprintf(stderr, | |
251 | _("[EXPERIMENTAL] try to shrink unused space %lld, old size is %lld\n"), | |
5b64e00a | 252 | (long long)dsize, (long long)geo.datablocks); |
272480fa | 253 | if (!error && |
2bd0ea18 NS |
254 | dsize == geo.datablocks && maxpct == geo.imaxpct) { |
255 | if (dflag) | |
9440d84d NS |
256 | fprintf(stderr, _( |
257 | "data size unchanged, skipping\n")); | |
2bd0ea18 | 258 | if (mflag) |
9440d84d NS |
259 | fprintf(stderr, _( |
260 | "inode max pct unchanged, skipping\n")); | |
2bd0ea18 NS |
261 | } else if (!error && !nflag) { |
262 | in.newblocks = (__u64)dsize; | |
263 | in.imaxpct = (__u32)maxpct; | |
93d9f139 | 264 | if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSDATA, &in) < 0) { |
2bd0ea18 | 265 | if (errno == EWOULDBLOCK) |
9440d84d NS |
266 | fprintf(stderr, _( |
267 | "%s: growfs operation in progress already\n"), | |
2bd0ea18 NS |
268 | progname); |
269 | else | |
9440d84d | 270 | fprintf(stderr, _( |
93d9f139 | 271 | "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n"), |
2bd0ea18 NS |
272 | progname, strerror(errno)); |
273 | error = 1; | |
274 | } | |
275 | } | |
276 | } | |
277 | ||
278 | if (!error && (rflag | aflag)) { | |
279 | xfs_growfs_rt_t in; | |
280 | ||
281 | if (!esize) | |
282 | esize = (__u32)geo.rtextsize; | |
283 | if (!rsize) | |
284 | rsize = drsize / (geo.blocksize / BBSIZE); | |
285 | else if (rsize > drsize / (geo.blocksize / BBSIZE)) { | |
9440d84d NS |
286 | fprintf(stderr, _( |
287 | "realtime size %lld too large, maximum is %lld\n"), | |
2bd0ea18 NS |
288 | rsize, drsize / (geo.blocksize / BBSIZE)); |
289 | error = 1; | |
290 | } | |
291 | if (!error && rsize < geo.rtblocks) { | |
9440d84d NS |
292 | fprintf(stderr, _( |
293 | "realtime size %lld too small, old size is %lld\n"), | |
5b64e00a | 294 | (long long)rsize, (long long)geo.rtblocks); |
2bd0ea18 NS |
295 | error = 1; |
296 | } else if (!error && rsize == geo.rtblocks) { | |
297 | if (rflag) | |
9440d84d NS |
298 | fprintf(stderr, _( |
299 | "realtime size unchanged, skipping\n")); | |
2bd0ea18 NS |
300 | } else if (!error && !nflag) { |
301 | in.newblocks = (__u64)rsize; | |
302 | in.extsize = (__u32)esize; | |
93d9f139 | 303 | if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSRT, &in) < 0) { |
2bd0ea18 | 304 | if (errno == EWOULDBLOCK) |
9440d84d NS |
305 | fprintf(stderr, _( |
306 | "%s: growfs operation in progress already\n"), | |
2bd0ea18 NS |
307 | progname); |
308 | else if (errno == ENOSYS) | |
9440d84d NS |
309 | fprintf(stderr, _( |
310 | "%s: realtime growth not implemented\n"), | |
2bd0ea18 NS |
311 | progname); |
312 | else | |
9440d84d | 313 | fprintf(stderr, _( |
93d9f139 | 314 | "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n"), |
2bd0ea18 NS |
315 | progname, strerror(errno)); |
316 | error = 1; | |
317 | } | |
318 | } | |
319 | } | |
320 | ||
321 | if (!error && (lflag | aflag)) { | |
322 | xfs_growfs_log_t in; | |
323 | ||
324 | if (!lsize) | |
325 | lsize = dlsize / (geo.blocksize / BBSIZE); | |
326 | if (iflag) | |
327 | in.isint = 1; | |
328 | else if (xflag) | |
329 | in.isint = 0; | |
dfc130f3 | 330 | else |
2bd0ea18 NS |
331 | in.isint = xi.logBBsize == 0; |
332 | if (lsize == geo.logblocks && (in.isint == isint)) { | |
333 | if (lflag) | |
334 | fprintf(stderr, | |
9440d84d | 335 | _("log size unchanged, skipping\n")); |
2bd0ea18 NS |
336 | } else if (!nflag) { |
337 | in.newblocks = (__u32)lsize; | |
93d9f139 | 338 | if (xfsctl(fname, ffd, XFS_IOC_FSGROWFSLOG, &in) < 0) { |
2bd0ea18 NS |
339 | if (errno == EWOULDBLOCK) |
340 | fprintf(stderr, | |
9440d84d | 341 | _("%s: growfs operation in progress already\n"), |
2bd0ea18 NS |
342 | progname); |
343 | else if (errno == ENOSYS) | |
344 | fprintf(stderr, | |
9440d84d NS |
345 | _("%s: log growth not supported yet\n"), |
346 | progname); | |
2bd0ea18 NS |
347 | else |
348 | fprintf(stderr, | |
93d9f139 | 349 | _("%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n"), |
2bd0ea18 NS |
350 | progname, strerror(errno)); |
351 | error = 1; | |
352 | } | |
353 | } | |
354 | } | |
355 | ||
03d96c64 | 356 | ret = -xfrog_geometry(ffd, &ngeo); |
9612817d | 357 | if (ret) { |
93d9f139 | 358 | fprintf(stderr, _("%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n"), |
9612817d | 359 | progname, strerror(ret)); |
2bd0ea18 NS |
360 | exit(1); |
361 | } | |
362 | if (geo.datablocks != ngeo.datablocks) | |
9440d84d | 363 | printf(_("data blocks changed from %lld to %lld\n"), |
5b64e00a | 364 | (long long)geo.datablocks, (long long)ngeo.datablocks); |
2bd0ea18 | 365 | if (geo.imaxpct != ngeo.imaxpct) |
9440d84d | 366 | printf(_("inode max percent changed from %d to %d\n"), |
2bd0ea18 NS |
367 | geo.imaxpct, ngeo.imaxpct); |
368 | if (geo.logblocks != ngeo.logblocks) | |
9440d84d | 369 | printf(_("log blocks changed from %d to %d\n"), |
2bd0ea18 NS |
370 | geo.logblocks, ngeo.logblocks); |
371 | if ((geo.logstart == 0) != (ngeo.logstart == 0)) | |
9440d84d NS |
372 | printf(_("log changed from %s to %s\n"), |
373 | geo.logstart ? _("internal") : _("external"), | |
374 | ngeo.logstart ? _("internal") : _("external")); | |
2bd0ea18 | 375 | if (geo.rtblocks != ngeo.rtblocks) |
9440d84d | 376 | printf(_("realtime blocks changed from %lld to %lld\n"), |
5b64e00a | 377 | (long long)geo.rtblocks, (long long)ngeo.rtblocks); |
2bd0ea18 | 378 | if (geo.rtextsize != ngeo.rtextsize) |
9440d84d | 379 | printf(_("realtime extent size changed from %d to %d\n"), |
2bd0ea18 | 380 | geo.rtextsize, ngeo.rtextsize); |
9beae830 | 381 | exit(error); |
2bd0ea18 | 382 | } |