]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/resize-fs.c
Merge pull request #13915 from ddstreet/ipv6_mtu
[thirdparty/systemd.git] / src / shared / resize-fs.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <linux/btrfs.h>
4 #include <linux/magic.h>
5 #include <sys/ioctl.h>
6 #include <sys/vfs.h>
7
8 #include "blockdev-util.h"
9 #include "fs-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"
15
16 int resize_fs(int fd, uint64_t sz, uint64_t *ret_size) {
17 struct statfs sfs;
18 int r;
19
20 assert(fd >= 0);
21
22 /* Rounds down to next block size */
23
24 if (sz <= 0 || sz == UINT64_MAX)
25 return -ERANGE;
26
27 if (fstatfs(fd, &sfs) < 0)
28 return -errno;
29
30 if (is_fs_type(&sfs, EXT4_SUPER_MAGIC)) {
31 uint64_t u;
32
33 if (sz < EXT4_MINIMAL_SIZE)
34 return -ERANGE;
35
36 u = sz / sfs.f_bsize;
37
38 if (ioctl(fd, EXT4_IOC_RESIZE_FS, &u) < 0)
39 return -errno;
40
41 if (ret_size)
42 *ret_size = u * sfs.f_bsize;
43
44 } else if (is_fs_type(&sfs, BTRFS_SUPER_MAGIC)) {
45 struct btrfs_ioctl_vol_args args = {};
46
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
50 * error. */
51
52 if (sz < BTRFS_MINIMAL_SIZE)
53 return -ERANGE;
54
55 sz -= sz % sfs.f_bsize;
56
57 r = snprintf(args.name, sizeof(args.name), "%" PRIu64, sz);
58 assert((size_t) r < sizeof(args.name));
59
60 if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0)
61 return -errno;
62
63 if (ret_size)
64 *ret_size = sz;
65
66 } else if (is_fs_type(&sfs, XFS_SB_MAGIC)) {
67 xfs_fsop_geom_t geo;
68 xfs_growfs_data_t d;
69
70 if (sz < XFS_MINIMAL_SIZE)
71 return -ERANGE;
72
73 if (ioctl(fd, XFS_IOC_FSGEOMETRY, &geo) < 0)
74 return -errno;
75
76 d = (xfs_growfs_data_t) {
77 .imaxpct = geo.imaxpct,
78 .newblocks = sz / geo.blocksize,
79 };
80
81 if (ioctl(fd, XFS_IOC_FSGROWFSDATA, &d) < 0)
82 return -errno;
83
84 if (ret_size)
85 *ret_size = d.newblocks * geo.blocksize;
86
87 } else
88 return -EOPNOTSUPP;
89
90 return 0;
91 }
92
93 uint64_t minimal_size_by_fs_magic(statfs_f_type_t magic) {
94
95 switch (magic) {
96
97 case (statfs_f_type_t) EXT4_SUPER_MAGIC:
98 return EXT4_MINIMAL_SIZE;
99
100 case (statfs_f_type_t) XFS_SB_MAGIC:
101 return XFS_MINIMAL_SIZE;
102
103 case (statfs_f_type_t) BTRFS_SUPER_MAGIC:
104 return BTRFS_MINIMAL_SIZE;
105
106 default:
107 return UINT64_MAX;
108 }
109 }
110
111 uint64_t minimal_size_by_fs_name(const char *name) {
112
113 if (streq_ptr(name, "ext4"))
114 return EXT4_MINIMAL_SIZE;
115
116 if (streq_ptr(name, "xfs"))
117 return XFS_MINIMAL_SIZE;
118
119 if (streq_ptr(name, "btrfs"))
120 return BTRFS_MINIMAL_SIZE;
121
122 return UINT64_MAX;
123 }