2 * Copyright (c) 2000-2002 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/
35 #include <sys/ioctl.h>
38 * When growing a filesystem, this is the most significant
39 * bits we'll accept in the resulting inode numbers
40 * without warning the user.
43 #define XFS_MAX_INODE_SIG_BITS 32
45 static char *fname
; /* mount point name */
46 static char *datadev
; /* data device name */
47 static char *logdev
; /* log device name */
48 static char *rtdev
; /* RT device name */
54 "Usage: %s [options] mountpoint\n\n\
56 -d grow data/metadata section\n\
57 -l grow log section\n\
58 -r grow realtime section\n\
59 -n don't change anything, just show geometry\n\
60 -I allow inode numbers to exceed %d significant bits\n\
61 -i convert log from external to internal format\n\
62 -t alternate location for mount table (/etc/mtab)\n\
63 -x convert log from internal to external format\n\
64 -D size grow data/metadata section to size blks\n\
65 -L size grow/shrink log section to size blks\n\
66 -R size grow realtime section to size blks\n\
67 -e size set realtime extent size to size blks\n\
68 -m imaxpct set inode max percent to imaxpct\n\
69 -V print version information\n",
70 progname
, XFS_MAX_INODE_SIG_BITS
);
83 printf("meta-data=%-22s isize=%-6d agcount=%d, agsize=%d blks\n"
84 "data =%-22s bsize=%-6d blocks=%lld, imaxpct=%d\n"
85 " =%-22s sunit=%-6d swidth=%d blks, unwritten=%d\n"
86 "naming =version %-14d bsize=%-6d\n"
87 "log =%-22s bsize=%-6d blocks=%d version=%d\n"
88 " =%-22s sunit=%d blks\n"
89 "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n",
90 mntpoint
, geo
.inodesize
, geo
.agcount
, geo
.agblocks
,
91 "", geo
.blocksize
, (long long)geo
.datablocks
, geo
.imaxpct
,
92 "", geo
.sunit
, geo
.swidth
, unwritten
,
93 dirversion
, geo
.dirblocksize
,
94 isint
? "internal" : "external", geo
.blocksize
, geo
.logblocks
,
96 "", geo
.logsunit
/ geo
.blocksize
,
97 geo
.rtblocks
? "external" : "none",
98 geo
.rtextsize
* geo
.blocksize
,
99 (long long)geo
.rtblocks
, (long long)geo
.rtextents
);
103 explore_mtab(char *mtab
, char *mntpoint
)
106 struct stat64 statuser
;
107 struct stat64 statmtab
;
112 if ((mtp
= setmntent(mtab
, "r")) == NULL
) {
113 fprintf(stderr
, "%s: cannot access mount list %s: %s\n",
114 progname
, MOUNTED
, strerror(errno
));
117 if (stat64(mntpoint
, &statuser
) < 0) {
118 fprintf(stderr
, "%s: cannot access mount point %s: %s\n",
119 progname
, mntpoint
, strerror(errno
));
123 while ((mnt
= getmntent(mtp
)) != NULL
) {
124 if (stat64(mnt
->mnt_dir
, &statmtab
) < 0) {
125 fprintf(stderr
, "%s: ignoring entry %s in %s: %s\n",
126 progname
, mnt
->mnt_dir
, mtab
, strerror(errno
));
129 if (statuser
.st_ino
!= statmtab
.st_ino
||
130 statuser
.st_dev
!= statmtab
.st_dev
)
132 else if (strcmp(mnt
->mnt_type
, "xfs") != 0) {
133 fprintf(stderr
, "%s: %s is not an XFS filesystem\n",
137 break; /* we've found it */
142 "%s: %s is not a filesystem mount point, according to %s\n",
143 progname
, mntpoint
, MOUNTED
);
147 /* find the data, log (logdev=), and realtime (rtdev=) devices */
148 rtend
= logend
= NULL
;
149 fname
= mnt
->mnt_dir
;
150 datadev
= mnt
->mnt_fsname
;
151 if ((logdev
= hasmntopt(mnt
, "logdev="))) {
153 logend
= strtok(logdev
, " ,");
155 if ((rtdev
= hasmntopt(mnt
, "rtdev="))) {
157 rtend
= strtok(rtdev
, " ,");
160 /* Do this only after we've finished processing mount options */
161 if (logdev
&& logend
!= logdev
)
162 *logend
= '\0'; /* terminate end of log device name */
163 if (rtdev
&& rtend
!= rtdev
)
164 *rtend
= '\0'; /* terminate end of rt device name */
170 main(int argc
, char **argv
)
172 int aflag
; /* fake flag, do all pieces */
173 int c
; /* current option character */
174 long long ddsize
; /* device size in 512-byte blocks */
175 int dflag
; /* -d flag */
176 int dirversion
; /* directory version number */
177 int logversion
; /* log version number */
178 long long dlsize
; /* device size in 512-byte blocks */
179 long long drsize
; /* device size in 512-byte blocks */
180 long long dsize
; /* new data size in fs blocks */
181 int error
; /* we have hit an error */
182 long esize
; /* new rt extent size */
183 int ffd
; /* mount point file descriptor */
184 xfs_fsop_geom_t geo
; /* current fs geometry */
185 int iflag
; /* -i flag */
186 int isint
; /* log is currently internal */
187 int lflag
; /* -l flag */
188 long long lsize
; /* new log size in fs blocks */
189 int maxpct
; /* -m flag value */
190 int mflag
; /* -m flag */
191 char *mtab
; /* mount table file (/etc/mtab) */
192 int nflag
; /* -n flag */
193 xfs_fsop_geom_t ngeo
; /* new fs geometry */
194 int rflag
; /* -r flag */
195 long long rsize
; /* new rt size in fs blocks */
196 int unwritten
; /* unwritten extent flag */
197 int xflag
; /* -x flag */
198 libxfs_init_t xi
; /* libxfs structure */
201 progname
= basename(argv
[0]);
202 aflag
= dflag
= iflag
= lflag
= mflag
= nflag
= rflag
= xflag
= 0;
204 dsize
= lsize
= rsize
= 0LL;
205 while ((c
= getopt(argc
, argv
, "dD:e:ilL:m:np:rR:t:xV")) != EOF
) {
208 dsize
= atoll(optarg
);
214 esize
= atol(optarg
);
221 lsize
= atoll(optarg
);
228 maxpct
= atoi(optarg
);
237 rsize
= atoll(optarg
);
249 printf("%s version %s\n", progname
, VERSION
);
256 if (argc
- optind
!= 1)
260 if (dflag
+ lflag
+ rflag
== 0)
263 explore_mtab(mtab
, argv
[optind
]);
265 ffd
= open(fname
, O_RDONLY
);
271 /* get the current filesystem size & geometry */
272 if (ioctl(ffd
, XFS_IOC_FSGEOMETRY
, &geo
) < 0) {
274 * OK, new ioctl barfed - back off and try earlier version
275 * as we're probably running an older kernel version.
276 * Only field added in the v2 geometry ioctl is "logsunit"
277 * so we'll zero that out for later display (as zero).
279 geo
.logsunit
= 1; /* 1 BB */
280 if (ioctl(ffd
, XFS_IOC_FSGEOMETRY_V1
, &geo
) < 0) {
282 "%s: cannot determine geometry of filesystem"
283 " mounted at %s: %s\n",
284 progname
, fname
, strerror(errno
));
288 isint
= geo
.logstart
> 0;
289 unwritten
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_EXTFLG
? 1 : 0;
290 dirversion
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_DIRV2
? 2 : 1;
291 logversion
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_LOGV2
? 2 : 1;
294 report_info(geo
, fname
, unwritten
, dirversion
, logversion
,
300 * Need root access from here on (using raw devices)...
303 bzero(&xi
, sizeof(xi
));
308 xi
.isreadonly
= LIBXFS_ISREADONLY
;
310 if (!libxfs_init(&xi
))
313 /* check we got the info for all the sections we are trying to modify */
315 fprintf(stderr
, "%s: failed to access data device for %s\n",
319 if (lflag
&& !isint
&& !xi
.logdev
) {
320 fprintf(stderr
, "%s: failed to access external log for %s\n",
324 if (rflag
&& !xi
.rtdev
) {
325 fprintf(stderr
, "%s: failed to access realtime device for %s\n",
330 report_info(geo
, fname
, unwritten
, dirversion
, logversion
, isint
);
333 dlsize
= ( xi
.logBBsize
? xi
.logBBsize
:
334 geo
.logblocks
* (geo
.blocksize
/ BBSIZE
) );
338 * Ok, Linux only has a 1024-byte resolution on device _size_,
339 * and the sizes below are in basic 512-byte blocks,
340 * so if we have (size % 2), on any partition, we can't get
341 * to the last 512 bytes. Just chop it down by a block.
344 ddsize
-= (ddsize
% 2);
345 dlsize
-= (dlsize
% 2);
346 drsize
-= (drsize
% 2);
350 xfs_growfs_data_t in
;
351 __uint64_t new_agcount
;
354 maxpct
= geo
.imaxpct
;
356 dsize
= ddsize
/ (geo
.blocksize
/ BBSIZE
);
357 else if (dsize
> ddsize
/ (geo
.blocksize
/ BBSIZE
)) {
359 "data size %lld too large, maximum is %lld\n",
361 (long long)(ddsize
/(geo
.blocksize
/BBSIZE
)));
365 new_agcount
= dsize
/ geo
.agblocks
366 + (dsize
% geo
.agblocks
!= 0);
368 if (!error
&& dsize
< geo
.datablocks
) {
369 fprintf(stderr
, "data size %lld too small,"
370 " old size is %lld\n",
371 (long long)dsize
, (long long)geo
.datablocks
);
374 dsize
== geo
.datablocks
&& maxpct
== geo
.imaxpct
) {
377 "data size unchanged, skipping\n");
380 "inode max pct unchanged, skipping\n");
381 } else if (!error
&& !nflag
) {
382 in
.newblocks
= (__u64
)dsize
;
383 in
.imaxpct
= (__u32
)maxpct
;
384 if (ioctl(ffd
, XFS_IOC_FSGROWFSDATA
, &in
) < 0) {
385 if (errno
== EWOULDBLOCK
)
387 "%s: growfs operation in progress already\n",
391 "%s: ioctl failed - XFS_IOC_FSGROWFSDATA: %s\n",
392 progname
, strerror(errno
));
398 if (!error
&& (rflag
| aflag
)) {
402 esize
= (__u32
)geo
.rtextsize
;
404 rsize
= drsize
/ (geo
.blocksize
/ BBSIZE
);
405 else if (rsize
> drsize
/ (geo
.blocksize
/ BBSIZE
)) {
407 "realtime size %lld too large, maximum is %lld\n",
408 rsize
, drsize
/ (geo
.blocksize
/ BBSIZE
));
411 if (!error
&& rsize
< geo
.rtblocks
) {
413 "realtime size %lld too small, old size is %lld\n",
414 (long long)rsize
, (long long)geo
.rtblocks
);
416 } else if (!error
&& rsize
== geo
.rtblocks
) {
419 "realtime size unchanged, skipping\n");
420 } else if (!error
&& !nflag
) {
421 in
.newblocks
= (__u64
)rsize
;
422 in
.extsize
= (__u32
)esize
;
423 if (ioctl(ffd
, XFS_IOC_FSGROWFSRT
, &in
) < 0) {
424 if (errno
== EWOULDBLOCK
)
426 "%s: growfs operation in progress already\n",
428 else if (errno
== ENOSYS
)
430 "%s: realtime growth not implemented\n",
434 "%s: ioctl failed - XFS_IOC_FSGROWFSRT: %s\n",
435 progname
, strerror(errno
));
441 if (!error
&& (lflag
| aflag
)) {
445 lsize
= dlsize
/ (geo
.blocksize
/ BBSIZE
);
451 in
.isint
= xi
.logBBsize
== 0;
452 if (lsize
== geo
.logblocks
&& (in
.isint
== isint
)) {
455 "log size unchanged, skipping\n");
457 in
.newblocks
= (__u32
)lsize
;
458 if (ioctl(ffd
, XFS_IOC_FSGROWFSLOG
, &in
) < 0) {
459 if (errno
== EWOULDBLOCK
)
461 "%s: growfs operation in progress already\n",
463 else if (errno
== ENOSYS
)
465 "%s: log growth not supported yet\n", progname
);
468 "%s: ioctl failed - XFS_IOC_FSGROWFSLOG: %s\n",
469 progname
, strerror(errno
));
475 if (ioctl(ffd
, XFS_IOC_FSGEOMETRY_V1
, &ngeo
) < 0) {
476 fprintf(stderr
, "%s: ioctl failed - XFS_IOC_FSGEOMETRY: %s\n",
477 progname
, strerror(errno
));
480 if (geo
.datablocks
!= ngeo
.datablocks
)
481 printf("data blocks changed from %lld to %lld\n",
482 (long long)geo
.datablocks
, (long long)ngeo
.datablocks
);
483 if (geo
.imaxpct
!= ngeo
.imaxpct
)
484 printf("inode max percent changed from %d to %d\n",
485 geo
.imaxpct
, ngeo
.imaxpct
);
486 if (geo
.logblocks
!= ngeo
.logblocks
)
487 printf("log blocks changed from %d to %d\n",
488 geo
.logblocks
, ngeo
.logblocks
);
489 if ((geo
.logstart
== 0) != (ngeo
.logstart
== 0))
490 printf("log changed from %s to %s\n",
491 geo
.logstart
? "internal" : "external",
492 ngeo
.logstart
? "internal" : "external");
493 if (geo
.rtblocks
!= ngeo
.rtblocks
)
494 printf("realtime blocks changed from %lld to %lld\n",
495 (long long)geo
.rtblocks
, (long long)ngeo
.rtblocks
);
496 if (geo
.rtextsize
!= ngeo
.rtextsize
)
497 printf("realtime extent size changed from %d to %d\n",
498 geo
.rtextsize
, ngeo
.rtextsize
);