From: Lennart Poettering Date: Wed, 22 Apr 2015 14:52:53 +0000 (+0200) Subject: btrfs-util: fix creating recursive read-only snapshots X-Git-Tag: v226.4~1^2~440 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=15925386d387b6ed9c1f174d4b08c767acad8117;hp=95889ba3d6c212459d8ec946b6cbaed64ba648fc btrfs-util: fix creating recursive read-only snapshots When creating recursive read-only snapshots we need to mark the snapshot writable immediately before creating subsnapshots within it, otherwise the operation for it will fail. --- diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index ac1907daf..3ed14dc0f 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -948,6 +948,7 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum .fd = old_fd, }; int r; + _cleanup_close_ int subvolume_fd = -1; assert(old_fd >= 0); assert(new_fd >= 0); @@ -1028,14 +1029,47 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum if (new_child_fd < 0) return -errno; + if (flags & BTRFS_SNAPSHOT_READ_ONLY) { + /* If the snapshot is read-only we + * need to mark it writable + * temporarily, to put the subsnapshot + * into place. */ + + if (subvolume_fd < 0) { + subvolume_fd = openat(new_fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + if (subvolume_fd < 0) + return -errno; + } + + r = btrfs_subvol_set_read_only_fd(subvolume_fd, false); + if (r < 0) + return r; + } + /* When btrfs clones the subvolumes, child * subvolumes appear as directories. Remove * them, so that we can create a new snapshot * in their place */ - if (unlinkat(new_child_fd, p, AT_REMOVEDIR) < 0) - return -errno; + if (unlinkat(new_child_fd, p, AT_REMOVEDIR) < 0) { + int k = -errno; + + if (flags & BTRFS_SNAPSHOT_READ_ONLY) + (void) btrfs_subvol_set_read_only_fd(subvolume_fd, true); + + return k; + } r = subvol_snapshot_children(old_child_fd, new_child_fd, p, sh->objectid, flags & ~BTRFS_SNAPSHOT_FALLBACK_COPY); + + /* Restore the readonly flag */ + if (flags & BTRFS_SNAPSHOT_READ_ONLY) { + int k; + + k = btrfs_subvol_set_read_only_fd(subvolume_fd, true); + if (r >= 0 && k < 0) + return k; + } + if (r < 0) return r; }