diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2019-12-05 10:17:10 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-12-05 10:17:10 +0100 |
commit | 68296b8b838cbbf7be48eda024cfa5506661d1d4 (patch) | |
tree | d7fdcc647590bf5a95fbe95a71784fc3258a13f9 | |
parent | ec34e7d1ab75dd4b7fc9e5d2b5e59c01b3e5f85f (diff) | |
parent | 28937bcc6ca150b84d422a23b951c35bbf25b455 (diff) | |
download | systemd-68296b8b838cbbf7be48eda024cfa5506661d1d4.tar.gz |
Merge pull request #14221 from poettering/homed-preparatory-resizefs
preparatory fs resizing support split out of homed PR
-rw-r--r-- | src/basic/missing_magic.h | 5 | ||||
-rw-r--r-- | src/basic/missing_xfs.h | 42 | ||||
-rw-r--r-- | src/shared/meson.build | 2 | ||||
-rw-r--r-- | src/shared/resize-fs.c | 112 | ||||
-rw-r--r-- | src/shared/resize-fs.h | 15 |
5 files changed, 176 insertions, 0 deletions
diff --git a/src/basic/missing_magic.h b/src/basic/missing_magic.h index 4910cd368f..a05b5b5c3c 100644 --- a/src/basic/missing_magic.h +++ b/src/basic/missing_magic.h @@ -32,3 +32,8 @@ #ifndef MQUEUE_MAGIC #define MQUEUE_MAGIC 0x19800202 #endif + +/* Not exposed yet (as of Linux 5.4). Defined in fs/xfs/libxfs/xfs_format.h */ +#ifndef XFS_SB_MAGIC +#define XFS_SB_MAGIC 0x58465342 +#endif diff --git a/src/basic/missing_xfs.h b/src/basic/missing_xfs.h new file mode 100644 index 0000000000..9eac76dd67 --- /dev/null +++ b/src/basic/missing_xfs.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +/* This is currently not exported in the public kernel headers, but the libxfs library code part of xfsprogs + * defines it as public header */ + +#ifndef XFS_IOC_FSGEOMETRY +#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom) + +typedef struct xfs_fsop_geom { + uint32_t blocksize; + uint32_t rtextsize; + uint32_t agblocks; + uint32_t agcount; + uint32_t logblocks; + uint32_t sectsize; + uint32_t inodesize; + uint32_t imaxpct; + uint64_t datablocks; + uint64_t rtblocks; + uint64_t rtextents; + uint64_t logstart; + unsigned char uuid[16]; + uint32_t sunit; + uint32_t swidth; + int32_t version; + uint32_t flags; + uint32_t logsectsize; + uint32_t rtsectsize; + uint32_t dirblocksize; + uint32_t logsunit; +} xfs_fsop_geom_t; +#endif + +#ifndef XFS_IOC_FSGROWFSDATA +#define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct xfs_growfs_data) + +typedef struct xfs_growfs_data { + uint64_t newblocks; + uint32_t imaxpct; +} xfs_growfs_data_t; +#endif diff --git a/src/shared/meson.build b/src/shared/meson.build index b3ae259b22..fc0ee28f55 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -147,6 +147,8 @@ shared_sources = files(''' ptyfwd.h reboot-util.c reboot-util.h + resize-fs.c + resize-fs.h resolve-util.c resolve-util.h seccomp-util.h diff --git a/src/shared/resize-fs.c b/src/shared/resize-fs.c new file mode 100644 index 0000000000..9f33dd77d8 --- /dev/null +++ b/src/shared/resize-fs.c @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include <linux/btrfs.h> +#include <linux/magic.h> +#include <sys/ioctl.h> +#include <sys/vfs.h> + +#include "blockdev-util.h" +#include "fs-util.h" +#include "missing_fs.h" +#include "missing_magic.h" +#include "missing_xfs.h" +#include "resize-fs.h" +#include "stat-util.h" + +int resize_fs(int fd, uint64_t sz) { + struct statfs sfs; + int r; + + assert(fd >= 0); + + /* Rounds down to next block size */ + + if (sz <= 0 || sz == UINT64_MAX) + return -ERANGE; + + if (fstatfs(fd, &sfs) < 0) + return -errno; + + if (is_fs_type(&sfs, EXT4_SUPER_MAGIC)) { + uint64_t u; + + if (sz < EXT4_MINIMAL_SIZE) + return -ERANGE; + + u = sz / sfs.f_bsize; + + if (ioctl(fd, EXT4_IOC_RESIZE_FS, &u) < 0) + return -errno; + + } else if (is_fs_type(&sfs, BTRFS_SUPER_MAGIC)) { + struct btrfs_ioctl_vol_args args = {}; + + /* 256M is the minimize size enforced by the btrfs kernel code when resizing (which is + * strange btw, as mkfs.btrfs is fine creating file systems > 109M). It will return EINVAL in + * that case, let's catch this error beforehand though, and report a more explanatory + * error. */ + + if (sz < BTRFS_MINIMAL_SIZE) + return -ERANGE; + + r = snprintf(args.name, sizeof(args.name), "%" PRIu64, sz); + assert((size_t) r < sizeof(args.name)); + + if (ioctl(fd, BTRFS_IOC_RESIZE, &args) < 0) + return -errno; + + } else if (is_fs_type(&sfs, XFS_SB_MAGIC)) { + xfs_fsop_geom_t geo; + xfs_growfs_data_t d; + + if (sz < XFS_MINIMAL_SIZE) + return -ERANGE; + + if (ioctl(fd, XFS_IOC_FSGEOMETRY, &geo) < 0) + return -errno; + + d = (xfs_growfs_data_t) { + .imaxpct = geo.imaxpct, + .newblocks = sz / geo.blocksize, + }; + + if (ioctl(fd, XFS_IOC_FSGROWFSDATA, &d) < 0) + return -errno; + + } else + return -EOPNOTSUPP; + + return 0; +} + +uint64_t minimal_size_by_fs_magic(statfs_f_type_t magic) { + + switch (magic) { + + case (statfs_f_type_t) EXT4_SUPER_MAGIC: + return EXT4_MINIMAL_SIZE; + + case (statfs_f_type_t) XFS_SB_MAGIC: + return XFS_MINIMAL_SIZE; + + case (statfs_f_type_t) BTRFS_SUPER_MAGIC: + return BTRFS_MINIMAL_SIZE; + + default: + return UINT64_MAX; + } +} + +uint64_t minimal_size_by_fs_name(const char *name) { + + if (streq_ptr(name, "ext4")) + return EXT4_MINIMAL_SIZE; + + if (streq_ptr(name, "xfs")) + return XFS_MINIMAL_SIZE; + + if (streq_ptr(name, "btrfs")) + return BTRFS_MINIMAL_SIZE; + + return UINT64_MAX; +} diff --git a/src/shared/resize-fs.h b/src/shared/resize-fs.h new file mode 100644 index 0000000000..b544176528 --- /dev/null +++ b/src/shared/resize-fs.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <inttypes.h> + +#include "stat-util.h" + +int resize_fs(int fd, uint64_t sz); + +#define BTRFS_MINIMAL_SIZE (256U*1024U*1024U) +#define XFS_MINIMAL_SIZE (14U*1024U*1024U) +#define EXT4_MINIMAL_SIZE (1024U*1024U) + +uint64_t minimal_size_by_fs_magic(statfs_f_type_t magic); +uint64_t minimal_size_by_fs_name(const char *str); |