1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include <linux/btrfs.h>
4 #include <linux/magic.h>
8 #include "blockdev-util.h"
10 #include "missing_fs.h"
11 #include "missing_magic.h"
12 #include "missing_xfs.h"
13 #include "resize-fs.h"
14 #include "stat-util.h"
16 int resize_fs(int fd
, uint64_t sz
, uint64_t *ret_size
) {
22 /* Rounds down to next block size */
24 if (sz
<= 0 || sz
== UINT64_MAX
)
27 if (fstatfs(fd
, &sfs
) < 0)
30 if (is_fs_type(&sfs
, EXT4_SUPER_MAGIC
)) {
33 if (sz
< EXT4_MINIMAL_SIZE
)
38 if (ioctl(fd
, EXT4_IOC_RESIZE_FS
, &u
) < 0)
42 *ret_size
= u
* sfs
.f_bsize
;
44 } else if (is_fs_type(&sfs
, BTRFS_SUPER_MAGIC
)) {
45 struct btrfs_ioctl_vol_args args
= {};
47 /* 256M is the minimize size enforced by the btrfs kernel code when resizing (which is
48 * strange btw, as mkfs.btrfs is fine creating file systems > 109M). It will return EINVAL in
49 * that case, let's catch this error beforehand though, and report a more explanatory
52 if (sz
< BTRFS_MINIMAL_SIZE
)
55 sz
-= sz
% sfs
.f_bsize
;
57 r
= snprintf(args
.name
, sizeof(args
.name
), "%" PRIu64
, sz
);
58 assert((size_t) r
< sizeof(args
.name
));
60 if (ioctl(fd
, BTRFS_IOC_RESIZE
, &args
) < 0)
66 } else if (is_fs_type(&sfs
, XFS_SB_MAGIC
)) {
70 if (sz
< XFS_MINIMAL_SIZE
)
73 if (ioctl(fd
, XFS_IOC_FSGEOMETRY
, &geo
) < 0)
76 d
= (xfs_growfs_data_t
) {
77 .imaxpct
= geo
.imaxpct
,
78 .newblocks
= sz
/ geo
.blocksize
,
81 if (ioctl(fd
, XFS_IOC_FSGROWFSDATA
, &d
) < 0)
85 *ret_size
= d
.newblocks
* geo
.blocksize
;
93 uint64_t minimal_size_by_fs_magic(statfs_f_type_t magic
) {
97 case (statfs_f_type_t
) EXT4_SUPER_MAGIC
:
98 return EXT4_MINIMAL_SIZE
;
100 case (statfs_f_type_t
) XFS_SB_MAGIC
:
101 return XFS_MINIMAL_SIZE
;
103 case (statfs_f_type_t
) BTRFS_SUPER_MAGIC
:
104 return BTRFS_MINIMAL_SIZE
;
111 uint64_t minimal_size_by_fs_name(const char *name
) {
113 if (streq_ptr(name
, "ext4"))
114 return EXT4_MINIMAL_SIZE
;
116 if (streq_ptr(name
, "xfs"))
117 return XFS_MINIMAL_SIZE
;
119 if (streq_ptr(name
, "btrfs"))
120 return BTRFS_MINIMAL_SIZE
;