2 * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
37 * When growing a filesystem, this is the most significant
38 * bits we'll accept in the resulting inode numbers
39 * without warning the user.
42 #define XFS_MAX_INODE_SIG_BITS 32
44 char *fname
; /* mount point name */
45 char *datadev
; /* data device name */
46 char *logdev
; /* log device name */
47 char *rtdev
; /* RT device name */
53 "Usage: %s [options] mountpoint\n\n\
55 -d grow data/metadata section\n\
56 -l grow log section\n\
57 -r grow realtime section\n\
58 -n don't change anything, just show geometry\n\
59 -I allow inode numbers to exceed %d significant bits\n\
60 -i convert log from external to internal format\n\
61 -t alternate location for mount table (/etc/mtab)\n\
62 -x convert log from internal to external format\n\
63 -D size grow data/metadata section to size blks\n\
64 -L size grow/shrink log section to size blks\n\
65 -R size grow realtime section to size blks\n\
66 -e size set realtime extent size to size blks\n\
67 -m imaxpct set inode max percent to imaxpct\n\
68 -V print version information\n"),
69 progname
, XFS_MAX_INODE_SIG_BITS
);
83 "meta-data=%-22s isize=%-6u agcount=%u, agsize=%u blks\n"
84 " =%-22s sectsz=%-5u\n"
85 "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
86 " =%-22s sunit=%-6u swidth=%u blks, unwritten=%u\n"
87 "naming =version %-14u bsize=%-6u\n"
88 "log =%-22s bsize=%-6u blocks=%u, version=%u\n"
89 " =%-22s sectsz=%-5u sunit=%u blks\n"
90 "realtime =%-22s extsz=%-6u blocks=%llu, rtextents=%llu\n"),
92 mntpoint
, geo
.inodesize
, geo
.agcount
, geo
.agblocks
,
94 "", geo
.blocksize
, (unsigned long long)geo
.datablocks
,
96 "", geo
.sunit
, geo
.swidth
, unwritten
,
97 dirversion
, geo
.dirblocksize
,
98 isint
? _("internal") : _("external"), geo
.blocksize
,
99 geo
.logblocks
, logversion
,
100 "", geo
.logsectsize
, geo
.logsunit
/ geo
.blocksize
,
101 geo
.rtblocks
? _("external") : _("none"),
102 geo
.rtextsize
* geo
.blocksize
, (unsigned long long)geo
.rtblocks
,
103 (unsigned long long)geo
.rtextents
);
107 main(int argc
, char **argv
)
109 int aflag
; /* fake flag, do all pieces */
110 int c
; /* current option character */
111 long long ddsize
; /* device size in 512-byte blocks */
112 int dflag
; /* -d flag */
113 int dirversion
; /* directory version number */
114 int logversion
; /* log version number */
115 long long dlsize
; /* device size in 512-byte blocks */
116 long long drsize
; /* device size in 512-byte blocks */
117 long long dsize
; /* new data size in fs blocks */
118 int error
; /* we have hit an error */
119 long esize
; /* new rt extent size */
120 int ffd
; /* mount point file descriptor */
121 xfs_fsop_geom_t geo
; /* current fs geometry */
122 int iflag
; /* -i flag */
123 int isint
; /* log is currently internal */
124 int lflag
; /* -l flag */
125 long long lsize
; /* new log size in fs blocks */
126 int maxpct
; /* -m flag value */
127 int mflag
; /* -m flag */
128 char *mtab
; /* mount table file (/etc/mtab) */
129 int nflag
; /* -n flag */
130 xfs_fsop_geom_t ngeo
; /* new fs geometry */
131 int rflag
; /* -r flag */
132 long long rsize
; /* new rt size in fs blocks */
133 int unwritten
; /* unwritten extent flag */
134 int xflag
; /* -x flag */
135 libxfs_init_t xi
; /* libxfs structure */
137 progname
= basename(argv
[0]);
138 setlocale(LC_ALL
, "");
139 bindtextdomain(PACKAGE
, LOCALEDIR
);
144 dsize
= lsize
= rsize
= 0LL;
145 aflag
= dflag
= iflag
= lflag
= mflag
= nflag
= rflag
= xflag
= 0;
147 while ((c
= getopt(argc
, argv
, "dD:e:ilL:m:np:rR:t:xV")) != EOF
) {
150 dsize
= strtoll(optarg
, NULL
, 10);
156 esize
= atol(optarg
);
163 lsize
= strtoll(optarg
, NULL
, 10);
170 maxpct
= atoi(optarg
);
179 rsize
= strtoll(optarg
, NULL
, 10);
191 printf(_("%s version %s\n"), progname
, VERSION
);
198 if (argc
- optind
!= 1)
202 if (dflag
+ lflag
+ rflag
== 0)
205 explore_mtab(mtab
, argv
[optind
]);
207 ffd
= open(fname
, O_RDONLY
);
213 if (!platform_test_xfs_fd(ffd
)) {
214 fprintf(stderr
, _("%s: specified file "
215 "[\"%s\"] is not on an XFS filesystem\n"),
220 /* get the current filesystem size & geometry */
221 if (xfsctl(fname
, ffd
, XFS_IOC_FSGEOMETRY
, &geo
) < 0) {
223 * OK, new xfsctl barfed - back off and try earlier version
224 * as we're probably running an older kernel version.
225 * Only field added in the v2 geometry xfsctl is "logsunit"
226 * so we'll zero that out for later display (as zero).
229 if (xfsctl(fname
, ffd
, XFS_IOC_FSGEOMETRY_V1
, &geo
) < 0) {
231 "%s: cannot determine geometry of filesystem"
232 " mounted at %s: %s\n"),
233 progname
, fname
, strerror(errno
));
237 isint
= geo
.logstart
> 0;
238 unwritten
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_EXTFLG
? 1 : 0;
239 dirversion
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_DIRV2
? 2 : 1;
240 logversion
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_LOGV2
? 2 : 1;
243 report_info(geo
, fname
, unwritten
, dirversion
, logversion
,
249 * Need root access from here on (using raw devices)...
252 bzero(&xi
, sizeof(xi
));
257 xi
.isreadonly
= LIBXFS_ISREADONLY
;
259 if (!libxfs_init(&xi
))
262 /* check we got the info for all the sections we are trying to modify */
264 fprintf(stderr
, _("%s: failed to access data device for %s\n"),
268 if (lflag
&& !isint
&& !xi
.logdev
) {
269 fprintf(stderr
, _("%s: failed to access external log for %s\n"),
273 if (rflag
&& !xi
.rtdev
) {
275 _("%s: failed to access realtime device for %s\n"),
280 report_info(geo
, fname
, unwritten
, dirversion
, logversion
, isint
);
283 dlsize
= ( xi
.logBBsize
? xi
.logBBsize
:
284 geo
.logblocks
* (geo
.blocksize
/ BBSIZE
) );
288 * Ok, Linux only has a 1024-byte resolution on device _size_,
289 * and the sizes below are in basic 512-byte blocks,
290 * so if we have (size % 2), on any partition, we can't get
291 * to the last 512 bytes. Just chop it down by a block.
294 ddsize
-= (ddsize
% 2);
295 dlsize
-= (dlsize
% 2);
296 drsize
-= (drsize
% 2);
300 xfs_growfs_data_t in
;
301 __uint64_t new_agcount
;
304 maxpct
= geo
.imaxpct
;
306 dsize
= ddsize
/ (geo
.blocksize
/ BBSIZE
);
307 else if (dsize
> ddsize
/ (geo
.blocksize
/ BBSIZE
)) {
309 "data size %lld too large, maximum is %lld\n"),
311 (long long)(ddsize
/(geo
.blocksize
/BBSIZE
)));
315 new_agcount
= dsize
/ geo
.agblocks
316 + (dsize
% geo
.agblocks
!= 0);
318 if (!error
&& dsize
< geo
.datablocks
) {
319 fprintf(stderr
, _("data size %lld too small,"
320 " old size is %lld\n"),
321 (long long)dsize
, (long long)geo
.datablocks
);
324 dsize
== geo
.datablocks
&& maxpct
== geo
.imaxpct
) {
327 "data size unchanged, skipping\n"));
330 "inode max pct unchanged, skipping\n"));
331 } else if (!error
&& !nflag
) {
332 in
.newblocks
= (__u64
)dsize
;
333 in
.imaxpct
= (__u32
)maxpct
;
334 if (xfsctl(fname
, ffd
, XFS_IOC_FSGROWFSDATA
, &in
) < 0) {
335 if (errno
== EWOULDBLOCK
)
337 "%s: growfs operation in progress already\n"),
341 "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n"),
342 progname
, strerror(errno
));
348 if (!error
&& (rflag
| aflag
)) {
352 esize
= (__u32
)geo
.rtextsize
;
354 rsize
= drsize
/ (geo
.blocksize
/ BBSIZE
);
355 else if (rsize
> drsize
/ (geo
.blocksize
/ BBSIZE
)) {
357 "realtime size %lld too large, maximum is %lld\n"),
358 rsize
, drsize
/ (geo
.blocksize
/ BBSIZE
));
361 if (!error
&& rsize
< geo
.rtblocks
) {
363 "realtime size %lld too small, old size is %lld\n"),
364 (long long)rsize
, (long long)geo
.rtblocks
);
366 } else if (!error
&& rsize
== geo
.rtblocks
) {
369 "realtime size unchanged, skipping\n"));
370 } else if (!error
&& !nflag
) {
371 in
.newblocks
= (__u64
)rsize
;
372 in
.extsize
= (__u32
)esize
;
373 if (xfsctl(fname
, ffd
, XFS_IOC_FSGROWFSRT
, &in
) < 0) {
374 if (errno
== EWOULDBLOCK
)
376 "%s: growfs operation in progress already\n"),
378 else if (errno
== ENOSYS
)
380 "%s: realtime growth not implemented\n"),
384 "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n"),
385 progname
, strerror(errno
));
391 if (!error
&& (lflag
| aflag
)) {
395 lsize
= dlsize
/ (geo
.blocksize
/ BBSIZE
);
401 in
.isint
= xi
.logBBsize
== 0;
402 if (lsize
== geo
.logblocks
&& (in
.isint
== isint
)) {
405 _("log size unchanged, skipping\n"));
407 in
.newblocks
= (__u32
)lsize
;
408 if (xfsctl(fname
, ffd
, XFS_IOC_FSGROWFSLOG
, &in
) < 0) {
409 if (errno
== EWOULDBLOCK
)
411 _("%s: growfs operation in progress already\n"),
413 else if (errno
== ENOSYS
)
415 _("%s: log growth not supported yet\n"),
419 _("%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n"),
420 progname
, strerror(errno
));
426 if (xfsctl(fname
, ffd
, XFS_IOC_FSGEOMETRY_V1
, &ngeo
) < 0) {
427 fprintf(stderr
, _("%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n"),
428 progname
, strerror(errno
));
431 if (geo
.datablocks
!= ngeo
.datablocks
)
432 printf(_("data blocks changed from %lld to %lld\n"),
433 (long long)geo
.datablocks
, (long long)ngeo
.datablocks
);
434 if (geo
.imaxpct
!= ngeo
.imaxpct
)
435 printf(_("inode max percent changed from %d to %d\n"),
436 geo
.imaxpct
, ngeo
.imaxpct
);
437 if (geo
.logblocks
!= ngeo
.logblocks
)
438 printf(_("log blocks changed from %d to %d\n"),
439 geo
.logblocks
, ngeo
.logblocks
);
440 if ((geo
.logstart
== 0) != (ngeo
.logstart
== 0))
441 printf(_("log changed from %s to %s\n"),
442 geo
.logstart
? _("internal") : _("external"),
443 ngeo
.logstart
? _("internal") : _("external"));
444 if (geo
.rtblocks
!= ngeo
.rtblocks
)
445 printf(_("realtime blocks changed from %lld to %lld\n"),
446 (long long)geo
.rtblocks
, (long long)ngeo
.rtblocks
);
447 if (geo
.rtextsize
!= ngeo
.rtextsize
)
448 printf(_("realtime extent size changed from %d to %d\n"),
449 geo
.rtextsize
, ngeo
.rtextsize
);