X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Fbtrfs-util.c;h=62b1eff6aecdfa36dfaf620d06b34ee2e6b4b8fd;hb=0daa5666da6fab8864e313dd594a2648d882e0cf;hp=52fc5f4a177ded0122d20b694c7df9408c753f03;hpb=efe0286285a7432f738fafae840fa4eda51c2986;p=elogind.git diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index 52fc5f4a1..62b1eff6a 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -101,48 +101,42 @@ int btrfs_is_snapshot(int fd) { return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC); } -int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy) { +int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, bool read_only, bool fallback_copy) { struct btrfs_ioctl_vol_args_v2 args = { .flags = read_only ? BTRFS_SUBVOL_RDONLY : 0, }; - _cleanup_close_ int old_fd = -1, new_fd = -1; + _cleanup_close_ int new_fd = -1; const char *subvolume; int r; - assert(old_path); - - old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); - if (old_fd < 0) - return -errno; + assert(new_path); r = btrfs_is_snapshot(old_fd); if (r < 0) return r; if (r == 0) { + if (!fallback_copy) + return -EISDIR; - if (fallback_copy) { - r = btrfs_subvol_make(new_path); - if (r < 0) - return r; + r = btrfs_subvol_make(new_path); + if (r < 0) + return r; - r = copy_directory_fd(old_fd, new_path, true); + r = copy_directory_fd(old_fd, new_path, true); + if (r < 0) { + btrfs_subvol_remove(new_path); + return r; + } + + if (read_only) { + r = btrfs_subvol_set_read_only(new_path, true); if (r < 0) { btrfs_subvol_remove(new_path); return r; } - - if (read_only) { - r = btrfs_subvol_set_read_only(new_path, true); - if (r < 0) { - btrfs_subvol_remove(new_path); - return r; - } - } - - return 0; } - return -EISDIR; + return 0; } r = extract_subvolume_name(new_path, &subvolume); @@ -162,6 +156,19 @@ int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_ return 0; } +int btrfs_subvol_snapshot(const char *old_path, const char *new_path, bool read_only, bool fallback_copy) { + _cleanup_close_ int old_fd = -1; + + assert(old_path); + assert(new_path); + + old_fd = open(old_path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + if (old_fd < 0) + return -errno; + + return btrfs_subvol_snapshot_fd(old_fd, new_path, read_only, fallback_copy); +} + int btrfs_subvol_make(const char *path) { struct btrfs_ioctl_vol_args args = {}; _cleanup_close_ int fd = -1; @@ -592,7 +599,7 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) { if (sh->type == BTRFS_QGROUP_INFO_KEY) { const struct btrfs_qgroup_info_item *qii = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh); - ret->referred = le64toh(qii->rfer); + ret->referenced = le64toh(qii->rfer); ret->exclusive = le64toh(qii->excl); found_info = true; @@ -600,11 +607,11 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) { } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) { const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh); - ret->referred_max = le64toh(qli->max_rfer); + ret->referenced_max = le64toh(qli->max_rfer); ret->exclusive_max = le64toh(qli->max_excl); - if (ret->referred_max == 0) - ret->referred_max = (uint64_t) -1; + if (ret->referenced_max == 0) + ret->referenced_max = (uint64_t) -1; if (ret->exclusive_max == 0) ret->exclusive_max = (uint64_t) -1; @@ -625,12 +632,12 @@ finish: return -ENODATA; if (!found_info) { - ret->referred = (uint64_t) -1; + ret->referenced = (uint64_t) -1; ret->exclusive = (uint64_t) -1; } if (!found_limit) { - ret->referred_max = (uint64_t) -1; + ret->referenced_max = (uint64_t) -1; ret->exclusive_max = (uint64_t) -1; } @@ -679,11 +686,11 @@ int btrfs_quota_enable(const char *path, bool b) { return btrfs_quota_enable_fd(fd, b); } -int btrfs_quota_limit_fd(int fd, uint64_t referred_max) { +int btrfs_quota_limit_fd(int fd, uint64_t referenced_max) { struct btrfs_ioctl_qgroup_limit_args args = { .lim.max_rfer = - referred_max == (uint64_t) -1 ? 0 : - referred_max == 0 ? 1 : referred_max, + referenced_max == (uint64_t) -1 ? 0 : + referenced_max == 0 ? 1 : referenced_max, .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER, }; @@ -695,17 +702,17 @@ int btrfs_quota_limit_fd(int fd, uint64_t referred_max) { return 0; } -int btrfs_quota_limit(const char *path, uint64_t referred_max) { +int btrfs_quota_limit(const char *path, uint64_t referenced_max) { _cleanup_close_ int fd = -1; fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); if (fd < 0) return -errno; - return btrfs_quota_limit_fd(fd, referred_max); + return btrfs_quota_limit_fd(fd, referenced_max); } -int btrfs_resize_loopback_fd(int fd, uint64_t new_size) { +int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) { struct btrfs_ioctl_vol_args args = {}; _cleanup_free_ char *p = NULL, *loop = NULL, *backing = NULL; _cleanup_close_ int loop_fd = -1, backing_fd = -1; @@ -726,6 +733,8 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size) { if (asprintf(&p, "/sys/dev/block/%u:%u/loop/backing_file", major(dev), minor(dev)) < 0) return -ENOMEM; r = read_one_line_file(p, &backing); + if (r == -ENOENT) + return -ENODEV; if (r < 0) return r; if (isempty(backing) || !path_is_absolute(backing)) @@ -743,6 +752,9 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size) { if (new_size == (uint64_t) st.st_size) return 0; + if (grow_only && new_size < (uint64_t) st.st_size) + return -EINVAL; + if (asprintf(&loop, "/dev/block/%u:%u", major(dev), minor(dev)) < 0) return -ENOMEM; loop_fd = open(loop, O_RDWR|O_CLOEXEC|O_NOCTTY); @@ -770,15 +782,19 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size) { return -errno; } - return 0; + /* Make sure the free disk space is correctly updated for both file systems */ + (void) fsync(fd); + (void) fsync(backing_fd); + + return 1; } -int btrfs_resize_loopback(const char *p, uint64_t new_size) { +int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) { _cleanup_close_ int fd = -1; fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC); if (fd < 0) return -errno; - return btrfs_resize_loopback_fd(fd, new_size); + return btrfs_resize_loopback_fd(fd, new_size, grow_only); }