2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
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
7 * published by the Free Software Foundation.
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.
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
19 #include "xfs/libxfs.h"
26 "Usage: %s [options] mountpoint\n\n\
28 -d grow data/metadata section\n\
29 -l grow log section\n\
30 -r grow realtime section\n\
31 -n don't change anything, just show geometry\n\
32 -i convert log from external to internal format\n\
33 -t alternate location for mount table (/etc/mtab)\n\
34 -x convert log from internal to external format\n\
35 -D size grow data/metadata section to size blks\n\
36 -L size grow/shrink log section to size blks\n\
37 -R size grow realtime section to size blks\n\
38 -e size set realtime extent size to size blks\n\
39 -m imaxpct set inode max percent to imaxpct\n\
40 -V print version information\n"),
63 "meta-data=%-22s isize=%-6u agcount=%u, agsize=%u blks\n"
64 " =%-22s sectsz=%-5u attr=%u, projid32bit=%u\n"
65 " =%-22s crc=%-8u finobt=%u\n"
66 "data =%-22s bsize=%-6u blocks=%llu, imaxpct=%u\n"
67 " =%-22s sunit=%-6u swidth=%u blks\n"
68 "naming =version %-14u bsize=%-6u ascii-ci=%d ftype=%d\n"
69 "log =%-22s bsize=%-6u blocks=%u, version=%u\n"
70 " =%-22s sectsz=%-5u sunit=%u blks, lazy-count=%u\n"
71 "realtime =%-22s extsz=%-6u blocks=%llu, rtextents=%llu\n"),
73 mntpoint
, geo
.inodesize
, geo
.agcount
, geo
.agblocks
,
74 "", geo
.sectsize
, attrversion
, projid32bit
,
75 "", crcs_enabled
, finobt_enabled
,
76 "", geo
.blocksize
, (unsigned long long)geo
.datablocks
,
78 "", geo
.sunit
, geo
.swidth
,
79 dirversion
, geo
.dirblocksize
, cimode
, ftype_enabled
,
80 isint
? _("internal") : logname
? logname
: _("external"),
81 geo
.blocksize
, geo
.logblocks
, logversion
,
82 "", geo
.logsectsize
, geo
.logsunit
/ geo
.blocksize
, lazycount
,
83 !geo
.rtblocks
? _("none") : rtname
? rtname
: _("external"),
84 geo
.rtextsize
* geo
.blocksize
, (unsigned long long)geo
.rtblocks
,
85 (unsigned long long)geo
.rtextents
);
89 main(int argc
, char **argv
)
91 int aflag
; /* fake flag, do all pieces */
92 int c
; /* current option character */
93 long long ddsize
; /* device size in 512-byte blocks */
94 int dflag
; /* -d flag */
95 int attrversion
;/* attribute version number */
96 int dirversion
; /* directory version number */
97 int logversion
; /* log version number */
98 long long dlsize
; /* device size in 512-byte blocks */
99 long long drsize
; /* device size in 512-byte blocks */
100 long long dsize
; /* new data size in fs blocks */
101 int error
; /* we have hit an error */
102 long esize
; /* new rt extent size */
103 int ffd
; /* mount point file descriptor */
104 xfs_fsop_geom_t geo
; /* current fs geometry */
105 int iflag
; /* -i flag */
106 int isint
; /* log is currently internal */
107 int lflag
; /* -l flag */
108 long long lsize
; /* new log size in fs blocks */
109 int maxpct
; /* -m flag value */
110 int mflag
; /* -m flag */
111 int nflag
; /* -n flag */
112 xfs_fsop_geom_t ngeo
; /* new fs geometry */
113 int rflag
; /* -r flag */
114 long long rsize
; /* new rt size in fs blocks */
115 int ci
; /* ASCII case-insensitive fs */
116 int lazycount
; /* lazy superblock counters */
117 int xflag
; /* -x flag */
118 char *fname
; /* mount point name */
119 char *datadev
; /* data device name */
120 char *logdev
; /* log device name */
121 char *rtdev
; /* RT device name */
122 fs_path_t
*fs
; /* mount point information */
123 libxfs_init_t xi
; /* libxfs structure */
126 int ftype_enabled
= 0;
127 int finobt_enabled
; /* free inode btree */
129 progname
= basename(argv
[0]);
130 setlocale(LC_ALL
, "");
131 bindtextdomain(PACKAGE
, LOCALEDIR
);
135 dsize
= lsize
= rsize
= 0LL;
136 aflag
= dflag
= iflag
= lflag
= mflag
= nflag
= rflag
= xflag
= 0;
138 while ((c
= getopt(argc
, argv
, "dD:e:ilL:m:np:rR:t:xV")) != EOF
) {
141 dsize
= strtoll(optarg
, NULL
, 10);
147 esize
= atol(optarg
);
154 lsize
= strtoll(optarg
, NULL
, 10);
161 maxpct
= atoi(optarg
);
170 rsize
= strtoll(optarg
, NULL
, 10);
182 printf(_("%s version %s\n"), progname
, VERSION
);
189 if (argc
- optind
!= 1)
193 if (dflag
+ lflag
+ rflag
+ mflag
== 0)
196 fs_table_initialise(0, NULL
, 0, NULL
);
197 fs
= fs_table_lookup(argv
[optind
], FS_MOUNT_POINT
);
199 fprintf(stderr
, _("%s: %s is not a mounted XFS filesystem\n"),
200 progname
, argv
[optind
]);
205 datadev
= fs
->fs_name
;
209 ffd
= open(fname
, O_RDONLY
);
215 if (!platform_test_xfs_fd(ffd
)) {
216 fprintf(stderr
, _("%s: specified file "
217 "[\"%s\"] is not on an XFS filesystem\n"),
222 /* get the current filesystem size & geometry */
223 if (xfsctl(fname
, ffd
, XFS_IOC_FSGEOMETRY
, &geo
) < 0) {
225 * OK, new xfsctl barfed - back off and try earlier version
226 * as we're probably running an older kernel version.
227 * Only field added in the v2 geometry xfsctl is "logsunit"
228 * so we'll zero that out for later display (as zero).
231 if (xfsctl(fname
, ffd
, XFS_IOC_FSGEOMETRY_V1
, &geo
) < 0) {
233 "%s: cannot determine geometry of filesystem"
234 " mounted at %s: %s\n"),
235 progname
, fname
, strerror(errno
));
239 isint
= geo
.logstart
> 0;
240 lazycount
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_LAZYSB
? 1 : 0;
241 dirversion
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_DIRV2
? 2 : 1;
242 logversion
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_LOGV2
? 2 : 1;
243 attrversion
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_ATTR2
? 2 : \
244 (geo
.flags
& XFS_FSOP_GEOM_FLAGS_ATTR
? 1 : 0);
245 ci
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_DIRV2CI
? 1 : 0;
246 projid32bit
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_PROJID32
? 1 : 0;
247 crcs_enabled
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_V5SB
? 1 : 0;
248 ftype_enabled
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_FTYPE
? 1 : 0;
249 finobt_enabled
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_FINOBT
? 1 : 0;
251 report_info(geo
, datadev
, isint
, logdev
, rtdev
,
252 lazycount
, dirversion
, logversion
,
253 attrversion
, projid32bit
, crcs_enabled
, ci
,
254 ftype_enabled
, finobt_enabled
);
259 * Need root access from here on (using raw devices)...
262 memset(&xi
, 0, sizeof(xi
));
266 xi
.isreadonly
= LIBXFS_ISREADONLY
;
268 if (!libxfs_init(&xi
))
271 /* check we got the info for all the sections we are trying to modify */
273 fprintf(stderr
, _("%s: failed to access data device for %s\n"),
277 if (lflag
&& !isint
&& !xi
.logdev
) {
278 fprintf(stderr
, _("%s: failed to access external log for %s\n"),
282 if (rflag
&& !xi
.rtdev
) {
284 _("%s: failed to access realtime device for %s\n"),
289 report_info(geo
, datadev
, isint
, logdev
, rtdev
,
290 lazycount
, dirversion
, logversion
,
291 attrversion
, projid32bit
, crcs_enabled
, ci
, ftype_enabled
,
295 dlsize
= ( xi
.logBBsize
? xi
.logBBsize
:
296 geo
.logblocks
* (geo
.blocksize
/ BBSIZE
) );
300 * Ok, Linux only has a 1024-byte resolution on device _size_,
301 * and the sizes below are in basic 512-byte blocks,
302 * so if we have (size % 2), on any partition, we can't get
303 * to the last 512 bytes. Just chop it down by a block.
306 ddsize
-= (ddsize
% 2);
307 dlsize
-= (dlsize
% 2);
308 drsize
-= (drsize
% 2);
312 if (dflag
| mflag
| aflag
) {
313 xfs_growfs_data_t in
;
316 maxpct
= geo
.imaxpct
;
317 if (!dflag
&& !aflag
) /* Only mflag, no data size change */
318 dsize
= geo
.datablocks
;
320 dsize
= ddsize
/ (geo
.blocksize
/ BBSIZE
);
321 else if (dsize
> ddsize
/ (geo
.blocksize
/ BBSIZE
)) {
323 "data size %lld too large, maximum is %lld\n"),
325 (long long)(ddsize
/(geo
.blocksize
/BBSIZE
)));
329 if (!error
&& dsize
< geo
.datablocks
) {
330 fprintf(stderr
, _("data size %lld too small,"
331 " old size is %lld\n"),
332 (long long)dsize
, (long long)geo
.datablocks
);
335 dsize
== geo
.datablocks
&& maxpct
== geo
.imaxpct
) {
338 "data size unchanged, skipping\n"));
341 "inode max pct unchanged, skipping\n"));
342 } else if (!error
&& !nflag
) {
343 in
.newblocks
= (__u64
)dsize
;
344 in
.imaxpct
= (__u32
)maxpct
;
345 if (xfsctl(fname
, ffd
, XFS_IOC_FSGROWFSDATA
, &in
) < 0) {
346 if (errno
== EWOULDBLOCK
)
348 "%s: growfs operation in progress already\n"),
352 "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n"),
353 progname
, strerror(errno
));
359 if (!error
&& (rflag
| aflag
)) {
363 esize
= (__u32
)geo
.rtextsize
;
365 rsize
= drsize
/ (geo
.blocksize
/ BBSIZE
);
366 else if (rsize
> drsize
/ (geo
.blocksize
/ BBSIZE
)) {
368 "realtime size %lld too large, maximum is %lld\n"),
369 rsize
, drsize
/ (geo
.blocksize
/ BBSIZE
));
372 if (!error
&& rsize
< geo
.rtblocks
) {
374 "realtime size %lld too small, old size is %lld\n"),
375 (long long)rsize
, (long long)geo
.rtblocks
);
377 } else if (!error
&& rsize
== geo
.rtblocks
) {
380 "realtime size unchanged, skipping\n"));
381 } else if (!error
&& !nflag
) {
382 in
.newblocks
= (__u64
)rsize
;
383 in
.extsize
= (__u32
)esize
;
384 if (xfsctl(fname
, ffd
, XFS_IOC_FSGROWFSRT
, &in
) < 0) {
385 if (errno
== EWOULDBLOCK
)
387 "%s: growfs operation in progress already\n"),
389 else if (errno
== ENOSYS
)
391 "%s: realtime growth not implemented\n"),
395 "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n"),
396 progname
, strerror(errno
));
402 if (!error
&& (lflag
| aflag
)) {
406 lsize
= dlsize
/ (geo
.blocksize
/ BBSIZE
);
412 in
.isint
= xi
.logBBsize
== 0;
413 if (lsize
== geo
.logblocks
&& (in
.isint
== isint
)) {
416 _("log size unchanged, skipping\n"));
418 in
.newblocks
= (__u32
)lsize
;
419 if (xfsctl(fname
, ffd
, XFS_IOC_FSGROWFSLOG
, &in
) < 0) {
420 if (errno
== EWOULDBLOCK
)
422 _("%s: growfs operation in progress already\n"),
424 else if (errno
== ENOSYS
)
426 _("%s: log growth not supported yet\n"),
430 _("%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n"),
431 progname
, strerror(errno
));
437 if (xfsctl(fname
, ffd
, XFS_IOC_FSGEOMETRY_V1
, &ngeo
) < 0) {
438 fprintf(stderr
, _("%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n"),
439 progname
, strerror(errno
));
442 if (geo
.datablocks
!= ngeo
.datablocks
)
443 printf(_("data blocks changed from %lld to %lld\n"),
444 (long long)geo
.datablocks
, (long long)ngeo
.datablocks
);
445 if (geo
.imaxpct
!= ngeo
.imaxpct
)
446 printf(_("inode max percent changed from %d to %d\n"),
447 geo
.imaxpct
, ngeo
.imaxpct
);
448 if (geo
.logblocks
!= ngeo
.logblocks
)
449 printf(_("log blocks changed from %d to %d\n"),
450 geo
.logblocks
, ngeo
.logblocks
);
451 if ((geo
.logstart
== 0) != (ngeo
.logstart
== 0))
452 printf(_("log changed from %s to %s\n"),
453 geo
.logstart
? _("internal") : _("external"),
454 ngeo
.logstart
? _("internal") : _("external"));
455 if (geo
.rtblocks
!= ngeo
.rtblocks
)
456 printf(_("realtime blocks changed from %lld to %lld\n"),
457 (long long)geo
.rtblocks
, (long long)ngeo
.rtblocks
);
458 if (geo
.rtextsize
!= ngeo
.rtextsize
)
459 printf(_("realtime extent size changed from %d to %d\n"),
460 geo
.rtextsize
, ngeo
.rtextsize
);