2 * Copyright (c) 2000 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
);
82 printf("meta-data=%-22s isize=%-6d agcount=%d, agsize=%d blks\n"
83 "data =%-22s bsize=%-6d blocks=%lld, imaxpct=%d\n"
84 " =%-22s sunit=%-6d swidth=%d blks, unwritten=%d\n"
85 "naming =version %-14d bsize=%-6d\n"
86 "log =%-22s bsize=%-6d blocks=%d\n"
87 "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n",
88 mntpoint
, geo
.inodesize
, geo
.agcount
, geo
.agblocks
,
89 "", geo
.blocksize
, (long long)geo
.datablocks
, geo
.imaxpct
,
90 "", geo
.sunit
, geo
.swidth
, unwritten
,
91 dirversion
, geo
.dirblocksize
,
92 isint
? "internal" : "external", geo
.blocksize
, geo
.logblocks
,
93 geo
.rtblocks
? "external" : "none",
94 geo
.rtextsize
* geo
.blocksize
,
95 (long long)geo
.rtblocks
, (long long)geo
.rtextents
);
99 explore_mtab(char *mtab
, char *mntpoint
)
102 struct stat64 statuser
;
103 struct stat64 statmtab
;
108 if ((mtp
= setmntent(mtab
, "r")) == NULL
) {
109 fprintf(stderr
, "%s: cannot access mount list %s: %s\n",
110 progname
, MOUNTED
, strerror(errno
));
113 if (stat64(mntpoint
, &statuser
) < 0) {
114 fprintf(stderr
, "%s: cannot access mount point %s: %s\n",
115 progname
, mntpoint
, strerror(errno
));
119 while ((mnt
= getmntent(mtp
)) != NULL
) {
120 if (stat64(mnt
->mnt_dir
, &statmtab
) < 0) {
121 fprintf(stderr
, "%s: ignoring entry %s in %s: %s\n",
122 progname
, mnt
->mnt_dir
, mtab
, strerror(errno
));
125 if (statuser
.st_ino
!= statmtab
.st_ino
||
126 statuser
.st_dev
!= statmtab
.st_dev
)
128 else if (strcmp(mnt
->mnt_type
, "xfs") != 0) {
129 fprintf(stderr
, "%s: %s is not an XFS filesystem\n",
133 break; /* we've found it */
138 "%s: %s is not a filesystem mount point, according to %s\n",
139 progname
, mntpoint
, MOUNTED
);
143 /* find the data, log (logdev=), and realtime (rtdev=) devices */
144 rtend
= logend
= NULL
;
145 fname
= mnt
->mnt_dir
;
146 datadev
= mnt
->mnt_fsname
;
147 if ((logdev
= hasmntopt(mnt
, "logdev="))) {
149 logend
= strtok(logdev
, " ,");
151 if ((rtdev
= hasmntopt(mnt
, "rtdev="))) {
153 rtend
= strtok(rtdev
, " ,");
156 /* Do this only after we've finished processing mount options */
157 if (logdev
&& logend
!= logdev
)
158 *logend
= '\0'; /* terminate end of log device name */
159 if (rtdev
&& rtend
!= rtdev
)
160 *rtend
= '\0'; /* terminate end of rt device name */
166 main(int argc
, char **argv
)
168 int aflag
; /* fake flag, do all pieces */
169 int c
; /* current option character */
170 long long ddsize
; /* device size in 512-byte blocks */
171 int dflag
; /* -d flag */
172 int dirversion
; /* directory version number */
173 long long dlsize
; /* device size in 512-byte blocks */
174 long long drsize
; /* device size in 512-byte blocks */
175 long long dsize
; /* new data size in fs blocks */
176 int error
; /* we have hit an error */
177 long esize
; /* new rt extent size */
178 int ffd
; /* mount point file descriptor */
179 xfs_fsop_geom_t geo
; /* current fs geometry */
180 int iflag
; /* -i flag */
181 int isint
; /* log is currently internal */
182 int lflag
; /* -l flag */
183 long long lsize
; /* new log size in fs blocks */
184 int maxpct
; /* -m flag value */
185 int mflag
; /* -m flag */
186 char *mtab
; /* mount table file (/etc/mtab) */
187 int nflag
; /* -n flag */
188 xfs_fsop_geom_t ngeo
; /* new fs geometry */
189 int rflag
; /* -r flag */
190 long long rsize
; /* new rt size in fs blocks */
191 int unwritten
; /* unwritten extent flag */
192 int xflag
; /* -x flag */
193 libxfs_init_t xi
; /* libxfs structure */
196 progname
= basename(argv
[0]);
197 aflag
= dflag
= iflag
= lflag
= mflag
= nflag
= rflag
= xflag
= 0;
199 dsize
= lsize
= rsize
= 0LL;
200 while ((c
= getopt(argc
, argv
, "dD:e:ilL:m:np:rR:t:xV")) != EOF
) {
203 dsize
= atoll(optarg
);
209 esize
= atol(optarg
);
216 lsize
= atoll(optarg
);
223 maxpct
= atoi(optarg
);
232 rsize
= atoll(optarg
);
244 printf("%s version %s\n", progname
, VERSION
);
251 if (argc
- optind
!= 1)
255 if (dflag
+ lflag
+ rflag
== 0)
258 explore_mtab(mtab
, argv
[optind
]);
260 ffd
= open(fname
, O_RDONLY
);
266 /* get the current filesystem size & geometry */
267 if (ioctl(ffd
, XFS_IOC_FSGEOMETRY
, &geo
) < 0) {
268 fprintf(stderr
, "%s: cannot determine geometry of filesystem"
269 " mounted at %s: %s\n",
270 progname
, fname
, strerror(errno
));
273 isint
= geo
.logstart
> 0;
274 unwritten
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_EXTFLG
? 1 : 0;
275 dirversion
= geo
.flags
& XFS_FSOP_GEOM_FLAGS_DIRV2
? 2 : 1;
278 report_info(geo
, fname
, unwritten
, dirversion
, isint
);
283 * Need root access from here on (using raw devices)...
286 bzero(&xi
, sizeof(xi
));
291 xi
.isreadonly
= LIBXFS_ISREADONLY
;
293 if (!libxfs_init(&xi
))
296 /* check we got the info for all the sections we are trying to modify */
298 fprintf(stderr
, "%s: failed to access data device for %s\n",
302 if (lflag
&& !isint
&& !xi
.logdev
) {
303 fprintf(stderr
, "%s: failed to access external log for %s\n",
307 if (rflag
&& !xi
.rtdev
) {
308 fprintf(stderr
, "%s: failed to access realtime device for %s\n",
313 report_info(geo
, fname
, unwritten
, dirversion
, isint
);
316 dlsize
= ( xi
.logBBsize
? xi
.logBBsize
:
317 geo
.logblocks
* (geo
.blocksize
/ BBSIZE
) );
321 * Ok, Linux only has a 1024-byte resolution on device _size_,
322 * and the sizes below are in basic 512-byte blocks,
323 * so if we have (size % 2), on any partition, we can't get
324 * to the last 512 bytes. Just chop it down by a block.
327 ddsize
-= (ddsize
% 2);
328 dlsize
-= (dlsize
% 2);
329 drsize
-= (drsize
% 2);
333 xfs_growfs_data_t in
;
334 __uint64_t new_agcount
;
337 maxpct
= geo
.imaxpct
;
339 dsize
= ddsize
/ (geo
.blocksize
/ BBSIZE
);
340 else if (dsize
> ddsize
/ (geo
.blocksize
/ BBSIZE
)) {
342 "data size %lld too large, maximum is %lld\n",
344 (long long)(ddsize
/(geo
.blocksize
/BBSIZE
)));
348 new_agcount
= dsize
/ geo
.agblocks
349 + (dsize
% geo
.agblocks
!= 0);
351 if (!error
&& dsize
< geo
.datablocks
) {
352 fprintf(stderr
, "data size %lld too small,"
353 " old size is %lld\n",
354 (long long)dsize
, (long long)geo
.datablocks
);
357 dsize
== geo
.datablocks
&& maxpct
== geo
.imaxpct
) {
360 "data size unchanged, skipping\n");
363 "inode max pct unchanged, skipping\n");
364 } else if (!error
&& !nflag
) {
365 in
.newblocks
= (__u64
)dsize
;
366 in
.imaxpct
= (__u32
)maxpct
;
367 if (ioctl(ffd
, XFS_IOC_FSGROWFSDATA
, &in
) < 0) {
368 if (errno
== EWOULDBLOCK
)
370 "%s: growfs operation in progress already\n",
374 "%s: ioctl failed - XFS_IOC_FSGROWFSDATA: %s\n",
375 progname
, strerror(errno
));
381 if (!error
&& (rflag
| aflag
)) {
385 esize
= (__u32
)geo
.rtextsize
;
387 rsize
= drsize
/ (geo
.blocksize
/ BBSIZE
);
388 else if (rsize
> drsize
/ (geo
.blocksize
/ BBSIZE
)) {
390 "realtime size %lld too large, maximum is %lld\n",
391 rsize
, drsize
/ (geo
.blocksize
/ BBSIZE
));
394 if (!error
&& rsize
< geo
.rtblocks
) {
396 "realtime size %lld too small, old size is %lld\n",
397 (long long)rsize
, (long long)geo
.rtblocks
);
399 } else if (!error
&& rsize
== geo
.rtblocks
) {
402 "realtime size unchanged, skipping\n");
403 } else if (!error
&& !nflag
) {
404 in
.newblocks
= (__u64
)rsize
;
405 in
.extsize
= (__u32
)esize
;
406 if (ioctl(ffd
, XFS_IOC_FSGROWFSRT
, &in
) < 0) {
407 if (errno
== EWOULDBLOCK
)
409 "%s: growfs operation in progress already\n",
411 else if (errno
== ENOSYS
)
413 "%s: realtime growth not implemented\n",
417 "%s: ioctl failed - XFS_IOC_FSGROWFSRT: %s\n",
418 progname
, strerror(errno
));
424 if (!error
&& (lflag
| aflag
)) {
428 lsize
= dlsize
/ (geo
.blocksize
/ BBSIZE
);
434 in
.isint
= xi
.logBBsize
== 0;
435 if (lsize
== geo
.logblocks
&& (in
.isint
== isint
)) {
438 "log size unchanged, skipping\n");
440 in
.newblocks
= (__u32
)lsize
;
441 if (ioctl(ffd
, XFS_IOC_FSGROWFSLOG
, &in
) < 0) {
442 if (errno
== EWOULDBLOCK
)
444 "%s: growfs operation in progress already\n",
446 else if (errno
== ENOSYS
)
448 "%s: log growth not supported yet\n", progname
);
451 "%s: ioctl failed - XFS_IOC_FSGROWFSLOG: %s\n",
452 progname
, strerror(errno
));
458 if (ioctl(ffd
, XFS_IOC_FSGEOMETRY
, &ngeo
) < 0) {
459 fprintf(stderr
, "%s: ioctl failed - XFS_IOC_FSGEOMETRY: %s\n",
460 progname
, strerror(errno
));
463 if (geo
.datablocks
!= ngeo
.datablocks
)
464 printf("data blocks changed from %lld to %lld\n",
465 (long long)geo
.datablocks
, (long long)ngeo
.datablocks
);
466 if (geo
.imaxpct
!= ngeo
.imaxpct
)
467 printf("inode max percent changed from %d to %d\n",
468 geo
.imaxpct
, ngeo
.imaxpct
);
469 if (geo
.logblocks
!= ngeo
.logblocks
)
470 printf("log blocks changed from %d to %d\n",
471 geo
.logblocks
, ngeo
.logblocks
);
472 if ((geo
.logstart
== 0) != (ngeo
.logstart
== 0))
473 printf("log changed from %s to %s\n",
474 geo
.logstart
? "internal" : "external",
475 ngeo
.logstart
? "internal" : "external");
476 if (geo
.rtblocks
!= ngeo
.rtblocks
)
477 printf("realtime blocks changed from %lld to %lld\n",
478 (long long)geo
.rtblocks
, (long long)ngeo
.rtblocks
);
479 if (geo
.rtextsize
!= ngeo
.rtextsize
)
480 printf("realtime extent size changed from %d to %d\n",
481 geo
.rtextsize
, ngeo
.rtextsize
);