]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - growfs/xfs_growfs.c
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
27 "Usage: %s [options] mountpoint\n\n\
29 -d grow data/metadata section\n\
30 -l grow log section\n\
31 -r grow realtime section\n\
32 -n don't change anything, just show geometry\n\
33 -i convert log from external to internal format\n\
34 -t alternate location for mount table (/etc/mtab)\n\
35 -x convert log from internal to external format\n\
36 -D size grow data/metadata section to size blks\n\
37 -L size grow/shrink log section to size blks\n\
38 -R size grow realtime section to size blks\n\
39 -e size set realtime extent size to size blks\n\
40 -m imaxpct set inode max percent to imaxpct\n\
41 -V print version information\n"),
47 main(int argc
, char **argv
)
49 int aflag
; /* fake flag, do all pieces */
50 int c
; /* current option character */
51 long long ddsize
; /* device size in 512-byte blocks */
52 int dflag
; /* -d flag */
53 long long dlsize
; /* device size in 512-byte blocks */
54 long long drsize
; /* device size in 512-byte blocks */
55 long long dsize
; /* new data size in fs blocks */
56 int error
; /* we have hit an error */
57 long esize
; /* new rt extent size */
58 int ffd
; /* mount point file descriptor */
59 xfs_fsop_geom_t geo
; /* current fs geometry */
60 int iflag
; /* -i flag */
61 int isint
; /* log is currently internal */
62 int lflag
; /* -l flag */
63 long long lsize
; /* new log size in fs blocks */
64 int maxpct
; /* -m flag value */
65 int mflag
; /* -m flag */
66 int nflag
; /* -n flag */
67 xfs_fsop_geom_t ngeo
; /* new fs geometry */
68 int rflag
; /* -r flag */
69 long long rsize
; /* new rt size in fs blocks */
70 int xflag
; /* -x flag */
71 char *fname
; /* mount point name */
72 char *datadev
; /* data device name */
73 char *logdev
; /* log device name */
74 char *rtdev
; /* RT device name */
75 fs_path_t
*fs
; /* mount point information */
76 libxfs_init_t xi
; /* libxfs structure */
79 progname
= basename(argv
[0]);
80 setlocale(LC_ALL
, "");
81 bindtextdomain(PACKAGE
, LOCALEDIR
);
85 dsize
= lsize
= rsize
= 0LL;
86 aflag
= dflag
= iflag
= lflag
= mflag
= nflag
= rflag
= xflag
= 0;
88 while ((c
= getopt(argc
, argv
, "dD:e:ilL:m:np:rR:t:xV")) != EOF
) {
91 dsize
= strtoll(optarg
, NULL
, 10);
104 lsize
= strtoll(optarg
, NULL
, 10);
111 maxpct
= atoi(optarg
);
120 rsize
= strtoll(optarg
, NULL
, 10);
132 printf(_("%s version %s\n"), progname
, VERSION
);
139 if (argc
- optind
!= 1)
143 if (dflag
+ lflag
+ rflag
+ mflag
== 0)
146 fs_table_initialise(0, NULL
, 0, NULL
);
148 if (!realpath(argv
[optind
], rpath
)) {
149 fprintf(stderr
, _("%s: path resolution failed for %s: %s\n"),
150 progname
, argv
[optind
], strerror(errno
));
154 fs
= fs_table_lookup_mount(rpath
);
156 fprintf(stderr
, _("%s: %s is not a mounted XFS filesystem\n"),
157 progname
, argv
[optind
]);
162 datadev
= fs
->fs_name
;
166 ffd
= open(fname
, O_RDONLY
);
172 if (!platform_test_xfs_fd(ffd
)) {
173 fprintf(stderr
, _("%s: specified file "
174 "[\"%s\"] is not on an XFS filesystem\n"),
179 /* get the current filesystem size & geometry */
180 if (xfsctl(fname
, ffd
, XFS_IOC_FSGEOMETRY
, &geo
) < 0) {
182 * OK, new xfsctl barfed - back off and try earlier version
183 * as we're probably running an older kernel version.
184 * Only field added in the v2 geometry xfsctl is "logsunit"
185 * so we'll zero that out for later display (as zero).
188 if (xfsctl(fname
, ffd
, XFS_IOC_FSGEOMETRY_V1
, &geo
) < 0) {
190 "%s: cannot determine geometry of filesystem"
191 " mounted at %s: %s\n"),
192 progname
, fname
, strerror(errno
));
196 isint
= geo
.logstart
> 0;
199 * Need root access from here on (using raw devices)...
202 memset(&xi
, 0, sizeof(xi
));
206 xi
.isreadonly
= LIBXFS_ISREADONLY
;
208 if (!libxfs_init(&xi
))
211 /* check we got the info for all the sections we are trying to modify */
213 fprintf(stderr
, _("%s: failed to access data device for %s\n"),
217 if (lflag
&& !isint
&& !xi
.logdev
) {
218 fprintf(stderr
, _("%s: failed to access external log for %s\n"),
222 if (rflag
&& !xi
.rtdev
) {
224 _("%s: failed to access realtime device for %s\n"),
229 xfs_report_geom(&geo
, datadev
, logdev
, rtdev
);
232 dlsize
= ( xi
.logBBsize
? xi
.logBBsize
:
233 geo
.logblocks
* (geo
.blocksize
/ BBSIZE
) );
237 * Ok, Linux only has a 1024-byte resolution on device _size_,
238 * and the sizes below are in basic 512-byte blocks,
239 * so if we have (size % 2), on any partition, we can't get
240 * to the last 512 bytes. Just chop it down by a block.
243 ddsize
-= (ddsize
% 2);
244 dlsize
-= (dlsize
% 2);
245 drsize
-= (drsize
% 2);
249 if (dflag
| mflag
| aflag
) {
250 xfs_growfs_data_t in
;
253 maxpct
= geo
.imaxpct
;
254 if (!dflag
&& !aflag
) /* Only mflag, no data size change */
255 dsize
= geo
.datablocks
;
257 dsize
= ddsize
/ (geo
.blocksize
/ BBSIZE
);
258 else if (dsize
> ddsize
/ (geo
.blocksize
/ BBSIZE
)) {
260 "data size %lld too large, maximum is %lld\n"),
262 (long long)(ddsize
/(geo
.blocksize
/BBSIZE
)));
266 if (!error
&& dsize
< geo
.datablocks
) {
267 fprintf(stderr
, _("data size %lld too small,"
268 " old size is %lld\n"),
269 (long long)dsize
, (long long)geo
.datablocks
);
272 dsize
== geo
.datablocks
&& maxpct
== geo
.imaxpct
) {
275 "data size unchanged, skipping\n"));
278 "inode max pct unchanged, skipping\n"));
279 } else if (!error
&& !nflag
) {
280 in
.newblocks
= (__u64
)dsize
;
281 in
.imaxpct
= (__u32
)maxpct
;
282 if (xfsctl(fname
, ffd
, XFS_IOC_FSGROWFSDATA
, &in
) < 0) {
283 if (errno
== EWOULDBLOCK
)
285 "%s: growfs operation in progress already\n"),
289 "%s: XFS_IOC_FSGROWFSDATA xfsctl failed: %s\n"),
290 progname
, strerror(errno
));
296 if (!error
&& (rflag
| aflag
)) {
300 esize
= (__u32
)geo
.rtextsize
;
302 rsize
= drsize
/ (geo
.blocksize
/ BBSIZE
);
303 else if (rsize
> drsize
/ (geo
.blocksize
/ BBSIZE
)) {
305 "realtime size %lld too large, maximum is %lld\n"),
306 rsize
, drsize
/ (geo
.blocksize
/ BBSIZE
));
309 if (!error
&& rsize
< geo
.rtblocks
) {
311 "realtime size %lld too small, old size is %lld\n"),
312 (long long)rsize
, (long long)geo
.rtblocks
);
314 } else if (!error
&& rsize
== geo
.rtblocks
) {
317 "realtime size unchanged, skipping\n"));
318 } else if (!error
&& !nflag
) {
319 in
.newblocks
= (__u64
)rsize
;
320 in
.extsize
= (__u32
)esize
;
321 if (xfsctl(fname
, ffd
, XFS_IOC_FSGROWFSRT
, &in
) < 0) {
322 if (errno
== EWOULDBLOCK
)
324 "%s: growfs operation in progress already\n"),
326 else if (errno
== ENOSYS
)
328 "%s: realtime growth not implemented\n"),
332 "%s: XFS_IOC_FSGROWFSRT xfsctl failed: %s\n"),
333 progname
, strerror(errno
));
339 if (!error
&& (lflag
| aflag
)) {
343 lsize
= dlsize
/ (geo
.blocksize
/ BBSIZE
);
349 in
.isint
= xi
.logBBsize
== 0;
350 if (lsize
== geo
.logblocks
&& (in
.isint
== isint
)) {
353 _("log size unchanged, skipping\n"));
355 in
.newblocks
= (__u32
)lsize
;
356 if (xfsctl(fname
, ffd
, XFS_IOC_FSGROWFSLOG
, &in
) < 0) {
357 if (errno
== EWOULDBLOCK
)
359 _("%s: growfs operation in progress already\n"),
361 else if (errno
== ENOSYS
)
363 _("%s: log growth not supported yet\n"),
367 _("%s: XFS_IOC_FSGROWFSLOG xfsctl failed: %s\n"),
368 progname
, strerror(errno
));
374 if (xfsctl(fname
, ffd
, XFS_IOC_FSGEOMETRY_V1
, &ngeo
) < 0) {
375 fprintf(stderr
, _("%s: XFS_IOC_FSGEOMETRY xfsctl failed: %s\n"),
376 progname
, strerror(errno
));
379 if (geo
.datablocks
!= ngeo
.datablocks
)
380 printf(_("data blocks changed from %lld to %lld\n"),
381 (long long)geo
.datablocks
, (long long)ngeo
.datablocks
);
382 if (geo
.imaxpct
!= ngeo
.imaxpct
)
383 printf(_("inode max percent changed from %d to %d\n"),
384 geo
.imaxpct
, ngeo
.imaxpct
);
385 if (geo
.logblocks
!= ngeo
.logblocks
)
386 printf(_("log blocks changed from %d to %d\n"),
387 geo
.logblocks
, ngeo
.logblocks
);
388 if ((geo
.logstart
== 0) != (ngeo
.logstart
== 0))
389 printf(_("log changed from %s to %s\n"),
390 geo
.logstart
? _("internal") : _("external"),
391 ngeo
.logstart
? _("internal") : _("external"));
392 if (geo
.rtblocks
!= ngeo
.rtblocks
)
393 printf(_("realtime blocks changed from %lld to %lld\n"),
394 (long long)geo
.rtblocks
, (long long)ngeo
.rtblocks
);
395 if (geo
.rtextsize
!= ngeo
.rtextsize
)
396 printf(_("realtime extent size changed from %d to %d\n"),
397 geo
.rtextsize
, ngeo
.rtextsize
);