summaryrefslogtreecommitdiff
path: root/cmds-subvolume.c
diff options
context:
space:
mode:
authorMisono, Tomohiro <misono.tomohiro@jp.fujitsu.com>2017-09-27 11:03:48 +0900
committerDavid Sterba <dsterba@suse.com>2017-10-06 13:23:31 +0200
commit8d93d71f6aa521e0a3e078d2c4ab2c406ebd884c (patch)
treef20a40e8bd130e4daeeb33b2d790381ff06f607e /cmds-subvolume.c
parent26908f61461c1897198b457a76856c78e849153f (diff)
btrfs-progs: subvol: fix subvol del --commit-after
Fix 'subvolume delete --commit-after' to work properly: - SYNC ioctl will be issued even when last delete fails - SYNC ioctl will be issued on each file system only once in the end To achieve this, get_fsid() and add_seen_fsid() are called after each delete to keep only one fd for each fs. In the end, seen_fsid_hash will be traversed and SYNC is issued on each fs. Signed-off-by: Tomohiro Misono <misono.tomohiro@jp.fujitsu.com> Reviewed-by: Qu Wenruo <quwenruo.btrfs@gmx.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'cmds-subvolume.c')
-rw-r--r--cmds-subvolume.c72
1 files changed, 59 insertions, 13 deletions
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index 8b24de37..69c50387 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -263,6 +263,9 @@ static int cmd_subvol_delete(int argc, char **argv)
DIR *dirstream = NULL;
int verbose = 0;
int commit_mode = 0;
+ u8 fsid[BTRFS_FSID_SIZE];
+ char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
+ struct seen_fsid *seen_fsid_hash[SEEN_FSID_HASH_SIZE] = { NULL, };
enum { COMMIT_AFTER = 1, COMMIT_EACH = 2 };
while (1) {
@@ -358,31 +361,74 @@ again:
path, strerror(errno));
ret = 1;
}
+ } else if (commit_mode == COMMIT_AFTER) {
+ res = get_fsid(dname, fsid, 0);
+ if (res < 0) {
+ error("unable to get fsid for '%s': %s",
+ path, strerror(-res));
+ error(
+ "delete suceeded but commit may not be done in the end");
+ ret = 1;
+ goto out;
+ }
+
+ if (add_seen_fsid(fsid, seen_fsid_hash, fd, dirstream) == 0) {
+ if (verbose > 0) {
+ uuid_unparse(fsid, uuidbuf);
+ printf(" new fs is found for '%s', fsid: %s\n",
+ path, uuidbuf);
+ }
+ /*
+ * This is the first time a subvolume on this
+ * filesystem is deleted, keep fd in order to issue
+ * SYNC ioctl in the end
+ */
+ goto keep_fd;
+ }
}
out:
+ close_file_or_dir(fd, dirstream);
+keep_fd:
+ fd = -1;
+ dirstream = NULL;
free(dupdname);
free(dupvname);
dupdname = NULL;
dupvname = NULL;
cnt++;
- if (cnt < argc) {
- close_file_or_dir(fd, dirstream);
- /* avoid double free */
- fd = -1;
- dirstream = NULL;
+ if (cnt < argc)
goto again;
- }
- if (commit_mode == COMMIT_AFTER && fd != -1) {
- res = wait_for_commit(fd);
- if (res < 0) {
- error("unable to do final sync after deletion: %s",
- strerror(errno));
- ret = 1;
+ if (commit_mode == COMMIT_AFTER) {
+ int slot;
+
+ /*
+ * Traverse seen_fsid_hash and issue SYNC ioctl on each
+ * filesystem
+ */
+ for (slot = 0; slot < SEEN_FSID_HASH_SIZE; slot++) {
+ struct seen_fsid *seen = seen_fsid_hash[slot];
+
+ while (seen) {
+ res = wait_for_commit(seen->fd);
+ if (res < 0) {
+ uuid_unparse(seen->fsid, uuidbuf);
+ error(
+ "unable to do final sync after deletion: %s, fsid: %s",
+ strerror(errno), uuidbuf);
+ ret = 1;
+ } else if (verbose > 0) {
+ uuid_unparse(seen->fsid, uuidbuf);
+ printf("final sync is done for fsid: %s\n",
+ uuidbuf);
+ }
+ seen = seen->next;
+ }
}
+ /* fd will also be closed in free_seen_fsid */
+ free_seen_fsid(seen_fsid_hash);
}
- close_file_or_dir(fd, dirstream);
return ret;
}