From 28937bcc6ca150b84d422a23b951c35bbf25b455 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 27 Dec 2018 14:31:27 +0100 Subject: [PATCH] shared: add new wrapper for online fs resizing ioctls --- src/shared/meson.build | 2 + src/shared/resize-fs.c | 112 +++++++++++++++++++++++++++++++++++++++++ src/shared/resize-fs.h | 15 ++++++ 3 files changed, 129 insertions(+) create mode 100644 src/shared/resize-fs.c create mode 100644 src/shared/resize-fs.h diff --git a/src/shared/meson.build b/src/shared/meson.build index b3ae259b228..fc0ee28f55e 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 00000000000..9f33dd77d88 --- /dev/null +++ b/src/shared/resize-fs.c @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include +#include +#include +#include + +#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 00000000000..b5441765289 --- /dev/null +++ b/src/shared/resize-fs.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include + +#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); -- 2.39.5