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