Goffredo Baroncelli
2013-Nov-16 17:09 UTC
[PATCH] BTRFS-PROG: recursively subvolume snapshot and delete
Hi All, the following patches implement the recursively snapshotting and deleting of a subvolume. To snapshot recursively you must pass the -R switch: # btrfs subvolume create sub1 Create subvolume ''./sub1'' # btrfs subvolume create sub1/sub2 Create subvolume ''sub1/sub2'' # btrfs subvolume snapshot -R sub1 sub1-snap Create a snapshot of ''sub1'' in ''./sub1-snap'' Create a snapshot of ''sub1/sub2'' in ''./sub1-snap/sub2'' To recursively delete subvolumes, you must pass the switch ''-R'': # btrfs subvolume create sub1 Create subvolume ''./sub1'' # btrfs subvolume create sub1/sub2 Create subvolume ''sub1/sub2'' # btrfs subvolume delete -R sub1 Delete subvolume ''/root/sub1/sub2'' Delete subvolume ''/root/sub1'' Some caveats: 1) the recursively behaviour need the root capability This because how the subvolume are discovered 2) it is not possible to recursively snapshot a subvolume in read-only mode This because when a subvolume is snapshotted, its nested subvolumes appear as directory in the snapshot. These directories are removed before snapshotting the nested subvolumes. This is incompatible with a read only subvolume. BR G.Baroncelli -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2013-Nov-16 17:09 UTC
[PATCH 1/7] Recursive btrfs sub snapshot/delete: create get_root_info() function
Move some code from cmd_subvol_show() to get_root_info(). This is a preparation for the introducing of traverse_list_subvol_rec() function. Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it> --- btrfs-list.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ btrfs-list.h | 7 +++++ cmds-subvolume.c | 71 ++++-------------------------------------- 3 files changed, 108 insertions(+), 65 deletions(-) diff --git a/btrfs-list.c b/btrfs-list.c index f3618b9..66f3127 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -33,6 +33,8 @@ #include "utils.h" #include <uuid/uuid.h> #include "btrfs-list.h" +#include "commands.h" +#include "utils.h" #define BTRFS_LIST_NFILTERS_INCREASE (2 * BTRFS_LIST_FILTER_MAX) #define BTRFS_LIST_NCOMPS_INCREASE (2 * BTRFS_LIST_COMP_MAX) @@ -1917,3 +1919,96 @@ int btrfs_list_get_path_rootid(int fd, u64 *treeid) *treeid = args.treeid; return 0; } + +/* + * Fill the root_info struct + */ +int get_root_info(char *path, struct root_info *get_ri) +{ + + char *svpath = NULL, *mnt = NULL, *fullpath=NULL; + u64 sv_id, mntid; + int fd = -1, mntfd = -1; + DIR *fddir, *mntfddir; + int ret = -1; + + fullpath = realpath(path, 0); + + ret = test_issubvolume(fullpath); + if (ret < 0) { + fprintf(stderr, "ERROR: error accessing ''%s''\n", fullpath); + goto out; + } + if (!ret) { + fprintf(stderr, "ERROR: ''%s'' is not a subvolume\n", fullpath); + ret = -1; + goto out; + } + + ret = find_mount_root(fullpath, &mnt); + if (ret < 0) { + fprintf(stderr, "ERROR: find_mount_root failed on %s: " + "%s\n", fullpath, strerror(-ret)); + goto out; + } + ret = -1; + svpath = get_subvol_name(mnt, fullpath); + + fd = open_file_or_dir(fullpath, &fddir); + if (fd < 0) { + fprintf(stderr, "ERROR: can''t access ''%s''\n", fullpath); + goto out; + } + + ret = btrfs_list_get_path_rootid(fd, &sv_id); + if (ret) { + fprintf(stderr, "ERROR: can''t get rootid for ''%s''\n", + fullpath); + goto out; + } + + mntfd = open_file_or_dir(mnt, &mntfddir); + if (mntfd < 0) { + fprintf(stderr, "ERROR: can''t access ''%s''\n", mnt); + goto out; + } + + ret = btrfs_list_get_path_rootid(mntfd, &mntid); + if (ret) { + fprintf(stderr, "ERROR: can''t get rootid for ''%s''\n", mnt); + goto out; + } + + if (sv_id == BTRFS_FS_TREE_OBJECTID) { + printf("ERROR: %s is btrfs root\n", fullpath); + goto out; + } + + memset(get_ri, 0, sizeof(*get_ri)); + get_ri->root_id = sv_id; + + if (btrfs_get_subvol(mntfd, get_ri)) { + fprintf(stderr, "ERROR: can''t find ''%s''\n", + svpath); + goto out; + } + + ret = 0; + +out: + if (mntfd >= 0) + close_file_or_dir(mntfd, mntfddir); + if (fd >= 0) + close_file_or_dir(fd, fddir); + free(mnt); + free(fullpath); + + return ret; +} + +void free_root_info(struct root_info *ri) +{ + free(ri->path); + free(ri->name); + free(ri->full_path); +} diff --git a/btrfs-list.h b/btrfs-list.h index 724e973..db32805 100644 --- a/btrfs-list.h +++ b/btrfs-list.h @@ -16,6 +16,9 @@ * Boston, MA 021110-1307, USA. */ +#ifndef __BTRFS_LIST__ +#define __BTRFS_LIST__ + #if BTRFS_FLAT_INCLUDES #include "kerncompat.h" #else @@ -163,3 +166,7 @@ int btrfs_list_get_default_subvolume(int fd, u64 *default_id); char *btrfs_list_path_for_root(int fd, u64 root); int btrfs_list_get_path_rootid(int fd, u64 *treeid); int btrfs_get_subvol(int fd, struct root_info *the_ri); +int get_root_info(char *path, struct root_info *get_ri); +void free_root_info(struct root_info *ri); + +#endif diff --git a/cmds-subvolume.c b/cmds-subvolume.c index f57694a..477919c 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -827,12 +827,11 @@ static int cmd_subvol_show(int argc, char **argv) struct btrfs_list_filter_set *filter_set; char tstr[256]; char uuidparse[37]; - char *fullpath = NULL, *svpath = NULL, *mnt = NULL; + char *fullpath = NULL; char raw_prefix[] = "\t\t\t\t"; - u64 sv_id, mntid; - int fd = -1, mntfd = -1; + int fd = -1; int ret = 1; - DIR *dirstream1 = NULL, *dirstream2 = NULL; + DIR *dirstream1 = NULL; if (check_argc_exact(argc, 2)) usage(cmd_subvol_show_usage); @@ -844,63 +843,15 @@ static int cmd_subvol_show(int argc, char **argv) goto out; } - ret = test_issubvolume(fullpath); - if (ret < 0) { - fprintf(stderr, "ERROR: error accessing ''%s''\n", fullpath); - goto out; - } - if (!ret) { - fprintf(stderr, "ERROR: ''%s'' is not a subvolume\n", fullpath); - goto out; - } - - ret = find_mount_root(fullpath, &mnt); - if (ret < 0) { - fprintf(stderr, "ERROR: find_mount_root failed on %s: " - "%s\n", fullpath, strerror(-ret)); - goto out; - } - ret = 1; - svpath = get_subvol_name(mnt, fullpath); - fd = open_file_or_dir(fullpath, &dirstream1); if (fd < 0) { fprintf(stderr, "ERROR: can''t access ''%s''\n", fullpath); goto out; } - ret = btrfs_list_get_path_rootid(fd, &sv_id); - if (ret) { - fprintf(stderr, "ERROR: can''t get rootid for ''%s''\n", - fullpath); - goto out; - } - - mntfd = open_file_or_dir(mnt, &dirstream2); - if (mntfd < 0) { - fprintf(stderr, "ERROR: can''t access ''%s''\n", mnt); - goto out; - } - - ret = btrfs_list_get_path_rootid(mntfd, &mntid); - if (ret) { - fprintf(stderr, "ERROR: can''t get rootid for ''%s''\n", mnt); + ret = get_root_info(fullpath, &get_ri); + if (ret) goto out; - } - - if (sv_id == BTRFS_FS_TREE_OBJECTID) { - printf("%s is btrfs root\n", fullpath); - goto out; - } - - memset(&get_ri, 0, sizeof(get_ri)); - get_ri.root_id = sv_id; - - if (btrfs_get_subvol(mntfd, &get_ri)) { - fprintf(stderr, "ERROR: can''t find ''%s''\n", - svpath); - goto out; - } ret = 0; /* print the info */ @@ -949,22 +900,12 @@ static int cmd_subvol_show(int argc, char **argv) 1, raw_prefix); /* clean up */ - if (get_ri.path) - free(get_ri.path); - if (get_ri.name) - free(get_ri.name); - if (get_ri.full_path) - free(get_ri.full_path); + free_root_info(&get_ri); if (filter_set) btrfs_list_free_filter_set(filter_set); out: close_file_or_dir(fd, dirstream1); - close_file_or_dir(mntfd, dirstream2); - if (mnt) - free(mnt); - if (fullpath) - free(fullpath); return !!ret; } -- 1.8.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2013-Nov-16 17:09 UTC
[PATCH 2/7] recursive btrfs sub snapshot/delete: create pathjoin() function
The pathjoin() function creates a path from a list of strings. Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it> --- utils.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ utils.h | 1 + 2 files changed, 64 insertions(+) diff --git a/utils.c b/utils.c index f499023..5f4d0ef 100644 --- a/utils.c +++ b/utils.c @@ -38,6 +38,7 @@ #include <linux/kdev_t.h> #include <limits.h> #include <blkid/blkid.h> +#include <stdarg.h> #include "kerncompat.h" #include "radix-tree.h" #include "ctree.h" @@ -2108,3 +2109,65 @@ int lookup_ino_rootid(int fd, u64 *rootid) return 0; } + +/* + * Joints a list of string. The list has to be NULL terminated + */ +char *pathjoin( char *s, ...) +{ + va_list ap; + int size; + char *dst; + + if (!s || !strlen(s)) + return NULL; + + size = strlen(s)+1; + va_start(ap, s); + + do { + char *p; + + p = va_arg(ap, char *); + if (!p) + break; + + size += strlen(p)+1; + } while(1); + + va_end(ap); + size++; + + dst = malloc(size); + if (!dst) + return NULL; + + strcpy(dst, s); + va_start(ap, s); + + do { + char *p; + int l, l2; + p = va_arg(ap, char *); + if (!p) + break; + if (*p == ''/'') + p++; + + l2 = strlen(p); + if (!l2) + continue; + if (p[l2-1] == ''/'') + p[l2-1] = 0; + + l = strlen(dst); + if (dst[l-1] != ''/'') + strcat(dst, "/"); + strcat(dst, p); + + } while(1); + va_end(ap); + + return dst; + +} \ No newline at end of file diff --git a/utils.h b/utils.h index 6f4b10c..d6c52a6 100644 --- a/utils.h +++ b/utils.h @@ -94,5 +94,6 @@ int ask_user(char *question); int lookup_ino_rootid(int fd, u64 *rootid); int btrfs_scan_lblkid(int update_kernel); int get_btrfs_mount(const char *dev, char *mp, size_t mp_size); +char *pathjoin(char *, ...); #endif -- 1.8.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2013-Nov-16 17:09 UTC
[PATCH 3/7] recursive btrfs snapshot/delete: create traverse_list_subvol_rec()
Create the traverse_list_subvol_rec() function. Its aim is to permit to process recursively the filesystems subvolumes. Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it> --- btrfs-list.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ btrfs-list.h | 3 ++ 2 files changed, 124 insertions(+) diff --git a/btrfs-list.c b/btrfs-list.c index 66f3127..b45c4d9 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -2012,3 +2012,124 @@ void free_root_info(struct root_info *ri) free(ri->name); free(ri->full_path); } + + +/* + * List and sort all subvolumes + */ +static int btrfs_list_all_subvols(int fd, struct root_lookup *root_sort, + struct root_lookup *root_lookup, int ascending) +{ + int ret = 0; + u64 top_id = 0; + struct btrfs_list_filter_set *filter_set; + struct btrfs_list_comparer_set *comp_set; + + filter_set = btrfs_list_alloc_filter_set(); + comp_set = btrfs_list_alloc_comparer_set(); + + btrfs_list_setup_filter(&filter_set, + BTRFS_LIST_FILTER_FULL_PATH, + top_id); + btrfs_list_setup_comparer(&comp_set, BTRFS_LIST_COMP_PATH, ascending); + + ret = btrfs_list_subvols(fd, root_lookup); + if (ret) + goto exit; + __filter_and_sort_subvol(root_lookup, root_sort, filter_set, + comp_set, top_id); + + ret = 0; +exit: + if (filter_set) + btrfs_list_free_filter_set(filter_set); + if (comp_set) + btrfs_list_free_comparer_set(comp_set); + + return ret; +} + +/* + * traverse the subvolumes list, calling func() for each subvolume path + * data is passed to func(). If all == true, func is called on all + * filesystem subvolumes. ascending set the order criteria + */ +int traverse_list_subvol_rec(char *path, int all, int ascending, + int (*func)(char *real_root, char *relative_root, char *path, void *data), + void *data) +{ + struct root_lookup root_lookup = {{0}}, root_to_free = {{0}}; + int ret, l=0, fd=-1; + DIR *fddir; + struct rb_node *n; + struct root_info ri = {{0}}; + char *rootpath = NULL; + + ret = 1; /* failure */ + + if (!all) { + /* search the full_path of path */ + ret = get_root_info(path, &ri); + if (ret) { + fprintf(stderr, "ERROR: cannot get info on ''%s''\n", path); + goto out; + } + } + + fd = open_file_or_dir(path, &fddir); + if (fd < 0) { + fprintf(stderr, "ERROR: can''t access to ''%s''\n", path); + goto out; + } + ret = btrfs_list_all_subvols(fd, &root_lookup, &root_to_free, ascending); + /* doesn''t leak fd & fddir */ + close_file_or_dir(fd, fddir); + + if (ret) { + fprintf(stderr, "ERROR: cannot list the subvols\n"); + goto out; + } + + if (!all) { + n = rb_first(&root_lookup.root); + while (n) { + struct root_info *entry; + + entry = rb_entry(n, struct root_info, sort_node); + if (entry->root_id == ri.root_id) { + rootpath = entry->full_path; + break; + } + n = rb_next(n); + } + BUG_ON(!rootpath); + + } else { + rootpath = "<FS_TREE>"; + } + l = strlen(rootpath); + + for (n = rb_first(&root_lookup.root) ; n ; n = rb_next(n)) { + struct root_info *entry; + + entry = rb_entry(n, struct root_info, sort_node); + if (!all && strncmp(rootpath, entry->full_path,l)) { + continue; + } + + ret = func(rootpath, path, entry->full_path+l, data); + if (ret) + goto out; + + } + ret = 0; + +out: + + __free_all_subvolumn(&root_to_free); + if (!all) + free_root_info(&ri); + + return ret; + +} diff --git a/btrfs-list.h b/btrfs-list.h index db32805..5c246e1 100644 --- a/btrfs-list.h +++ b/btrfs-list.h @@ -168,5 +168,8 @@ int btrfs_list_get_path_rootid(int fd, u64 *treeid); int btrfs_get_subvol(int fd, struct root_info *the_ri); int get_root_info(char *path, struct root_info *get_ri); void free_root_info(struct root_info *ri); +int traverse_list_subvol_rec(char *path, int all, int ascending, + int (*func)(char *real_root, char *relative_root, char *path, void *data), + void *data); #endif -- 1.8.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Add the -R switch to allow to delete recursively a subvolume. Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it> --- cmds-subvolume.c | 107 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 18 deletions(-) diff --git a/cmds-subvolume.c b/cmds-subvolume.c index 477919c..422e1fc 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -201,28 +201,15 @@ int test_issubvolume(char *path) return (st.st_ino == 256) && S_ISDIR(st.st_mode); } -static const char * const cmd_subvol_delete_usage[] = { - "btrfs subvolume delete <subvolume> [<subvolume>...]", - "Delete subvolume(s)", - NULL -}; - -static int cmd_subvol_delete(int argc, char **argv) +static int do_subvol_delete(char *path) { - int res, fd, len, e, cnt = 1, ret = 0; + int res, fd, len, e, ret = 0; struct btrfs_ioctl_vol_args args; char *dname, *vname, *cpath; char *dupdname = NULL; char *dupvname = NULL; - char *path; DIR *dirstream = NULL; - if (argc < 2) - usage(cmd_subvol_delete_usage); - -again: - path = argv[cnt]; - res = test_issubvolume(path); if (res < 0) { fprintf(stderr, "ERROR: error accessing ''%s''\n", path); @@ -290,9 +277,93 @@ out: free(dupvname); dupdname = NULL; dupvname = NULL; - cnt++; - if (cnt < argc) - goto again; + + return ret; +} + +static int do_subvol_delete_func(char *real_root, char *relative_root, + char *path, void *data) +{ + char *dpath, *real_path; + int ret; + (void)data; /* ignore the parameter */ + (void)real_root; /* ignore the parameter */ + + dpath = pathjoin(relative_root, path, NULL); + if (!dpath) { + fprintf(stderr, "ERROR: not enough memory\n"); + return -1; + } + real_path = realpath(dpath, NULL); + if (!real_path) { + free(dpath); + fprintf(stderr, "ERROR: not enough memory\n"); + return -1; + } + + ret = do_subvol_delete(real_path); + free(real_path); + free(dpath); + + return ret; +} + +static inline int do_subvol_delete_rec(char *path) +{ + return traverse_list_subvol_rec(path, /* filesystem subvolume */ + 0, /* false = only below this path */ + 1, /* ascending order */ + do_subvol_delete_func, /* func to call */ + NULL); /* parameter to pass to func */ +} + +static const char * const cmd_subvol_delete_usage[] = { + "btrfs subvolume delete [-R] <subvolume> [<subvolume>...]", + "Delete subvolume(s)", + "", + "-R delete recursively", + NULL +}; + +static int cmd_subvol_delete(int argc, char **argv) +{ + int rec = 0, ret = 0, i; + + optind = 1; + while(1) { + int c; + c = getopt_long(argc, argv, "R", NULL, NULL); + if (c < 0) + break; + + switch(c) { + case ''R'': + rec = 1; + break; + default: + ret = 2; + goto out; + } + } + + if (check_argc_min(argc - optind, 1)) { + usage(cmd_subvol_delete_usage); + ret = 1; + goto out; + } + + for ( i = optind ; i < argc ; i++ ) { + + if (rec) + ret = do_subvol_delete_rec(argv[i]); + else + ret = do_subvol_delete(argv[i]); + + if (ret) + break; + + } +out: return ret; } -- 1.8.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2013-Nov-16 17:09 UTC
[PATCH 5/7] recursively btrfs subvolume snapshot
Add a ''-R'' switch to btrfs subvolume snapshot to allow a recursively subvolume snapshotting. Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it> --- cmds-subvolume.c | 213 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 167 insertions(+), 46 deletions(-) diff --git a/cmds-subvolume.c b/cmds-subvolume.c index 422e1fc..eb14ecd 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -567,14 +567,162 @@ out: return !!ret; } +static int do_snapshot(char *subvol, char *dstdir, char *newname, + int readonly, + struct btrfs_qgroup_inherit *inherit) +{ + + int fd = -1, fddst = -1; + int res, retval = -1; + struct btrfs_ioctl_vol_args_v2 args = {0}; + DIR *dirstream1 = NULL, *dirstream2 = NULL; + + fddst = open_file_or_dir(dstdir, &dirstream1); + if (fddst < 0) { + fprintf(stderr, "ERROR: can''t access to ''%s''\n", dstdir); + goto out; + } + + fd = open_file_or_dir(subvol, &dirstream2); + if (fd < 0) { + fprintf(stderr, "ERROR: can''t access to ''%s''\n", dstdir); + goto out; + } + + if (readonly) { + args.flags |= BTRFS_SUBVOL_RDONLY; + printf("Create a readonly snapshot of ''%s'' in ''%s/%s''\n", + subvol, dstdir, newname); + } else { + printf("Create a snapshot of ''%s'' in ''%s/%s''\n", + subvol, dstdir, newname); + } + + args.fd = fd; + if (inherit) { + args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT; + args.size = qgroup_inherit_size(inherit); + args.qgroup_inherit = inherit; + } + strncpy_null(args.name, newname); + + res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args); + + if (res < 0) { + fprintf( stderr, "ERROR: cannot snapshot ''%s'' - %s\n", + subvol, strerror(errno)); + goto out; + } + + retval = 0; /* success */ + +out: + close_file_or_dir(fddst, dirstream1); + close_file_or_dir(fd, dirstream2); + + return retval; +} + + +static int cleanup_subvol_dir(char *sv_dst, char *sv_newname) +{ + char *path = pathjoin(sv_dst, sv_newname, NULL); + int ret; + + if (!path) + return -1; + + ret = rmdir(path); + free(path); + + return ret; +} + +struct rec_snapshot { + char *dstdir; + char *src; + char *newname; + int readonly:1; + int first:1; + struct btrfs_qgroup_inherit *inherit; +}; + +static int recursively_snapshot_func(char *real_root, char *relative_root, + char *path, void *data) +{ + + struct rec_snapshot *rs = (struct rec_snapshot*)data; + char *sv_src = NULL; + char *sv_dst = NULL; + char *sv_newname = NULL; + int ret=-1; + + sv_src = pathjoin(rs->src, path, NULL); + sv_dst = pathjoin(rs->dstdir, rs->newname, path, NULL); + + if (!sv_src || !sv_dst) { + free(sv_src); + free(sv_dst); + fprintf(stderr, "ERROR: not enough memory\n"); + goto out; + } + + sv_newname = strrchr(sv_dst, ''/''); + *sv_newname++ = 0; + + if (!rs->first) { + ret = cleanup_subvol_dir(sv_dst, sv_newname); + if (ret) { + fprintf(stderr, "ERROR: cannot delete %s/%s\n", + sv_dst, sv_newname); + goto out; + } + } + rs->first = 0; + + ret = do_snapshot(sv_src, sv_dst, sv_newname, + rs->readonly, rs->inherit); + +out: + free(sv_src); + free(sv_dst); + + return ret; +} + +static int recursively_snapshot(char *src, char *dstdir, char *newname, + int readonly, + struct btrfs_qgroup_inherit *inherit) +{ + + struct rec_snapshot rs = { + .dstdir = dstdir, + .src = src, + .newname = newname, + .readonly = readonly, + .inherit = inherit, + .first = 1 + }; + + int ret; + + ret = traverse_list_subvol_rec(src, 0, 0, recursively_snapshot_func, + (void *)&rs); + + return ret; + +} + static const char * const cmd_snapshot_usage[] = { "btrfs subvolume snapshot [-r] <source> <dest>|[<dest>/]<name>", - "btrfs subvolume snapshot [-r] [-i <qgroupid>] <source> <dest>|[<dest>/]<name>", + "btrfs subvolume snapshot [-r][-i <qgroupid>] <source> <dest>|[<dest>/]<name>", + "btrfs subvolume snapshot [-R][-i <qgroupid>] <source> <dest>|[<dest>/]<name>", "Create a snapshot of the subvolume", "Create a writable/readonly snapshot of the subvolume <source> with", "the name <name> in the <dest> directory. If only <dest> is given,", "the subvolume will be named the basename of <source>.", "", + "-R create snapshot recursively", "-r create a readonly snapshot", "-i <qgroupid> add the newly created snapshot to a qgroup. This", " option can be given multiple times.", @@ -585,20 +733,18 @@ static int cmd_snapshot(int argc, char **argv) { char *subvol, *dst; int res, retval; - int fd = -1, fddst = -1; - int len, readonly = 0; + int len, readonly = 0, rec=0; char *dupname = NULL; char *dupdir = NULL; char *newname; char *dstdir; struct btrfs_ioctl_vol_args_v2 args; struct btrfs_qgroup_inherit *inherit = NULL; - DIR *dirstream1 = NULL, *dirstream2 = NULL; optind = 1; memset(&args, 0, sizeof(args)); while (1) { - int c = getopt(argc, argv, "c:i:r"); + int c = getopt(argc, argv, "c:i:rR"); if (c < 0) break; @@ -620,6 +766,9 @@ static int cmd_snapshot(int argc, char **argv) case ''r'': readonly = 1; break; + case ''R'': + rec = 1; + break; case ''x'': res = qgroup_inherit_add_copy(&inherit, optarg, 1); if (res) { @@ -635,10 +784,17 @@ static int cmd_snapshot(int argc, char **argv) if (check_argc_exact(argc - optind, 2)) usage(cmd_snapshot_usage); + retval = 1; /* failure */ + + if (rec && readonly) { + fprintf(stderr, "ERROR: impossible to make a recursively " + "readonly snapshot\n"); + goto out; + } + subvol = argv[optind]; dst = argv[optind + 1]; - retval = 1; /* failure */ res = test_issubvolume(subvol); if (res < 0) { fprintf(stderr, "ERROR: error accessing ''%s''\n", subvol); @@ -680,48 +836,13 @@ static int cmd_snapshot(int argc, char **argv) goto out; } - fddst = open_file_or_dir(dstdir, &dirstream1); - if (fddst < 0) { - fprintf(stderr, "ERROR: can''t access to ''%s''\n", dstdir); - goto out; - } - - fd = open_file_or_dir(subvol, &dirstream2); - if (fd < 0) { - fprintf(stderr, "ERROR: can''t access to ''%s''\n", dstdir); - goto out; - } - - if (readonly) { - args.flags |= BTRFS_SUBVOL_RDONLY; - printf("Create a readonly snapshot of ''%s'' in ''%s/%s''\n", - subvol, dstdir, newname); - } else { - printf("Create a snapshot of ''%s'' in ''%s/%s''\n", - subvol, dstdir, newname); - } - - args.fd = fd; - if (inherit) { - args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT; - args.size = qgroup_inherit_size(inherit); - args.qgroup_inherit = inherit; - } - strncpy_null(args.name, newname); - - res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args); - - if (res < 0) { - fprintf( stderr, "ERROR: cannot snapshot ''%s'' - %s\n", - subvol, strerror(errno)); - goto out; - } - - retval = 0; /* success */ + if (rec) + retval = recursively_snapshot(subvol, dstdir, newname, + readonly, inherit); + else + retval = do_snapshot(subvol, dstdir, newname, readonly,inherit); out: - close_file_or_dir(fddst, dirstream1); - close_file_or_dir(fd, dirstream2); free(inherit); free(dupname); free(dupdir); -- 1.8.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2013-Nov-16 17:09 UTC
[PATCH 6/7] btrfs subvolume snapshot -R: update man page
Update man page of "btrfs subvolume snapshot", documenting the -R switch. Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it> --- man/btrfs.8.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/man/btrfs.8.in b/man/btrfs.8.in index b620348..aee1f70 100644 --- a/man/btrfs.8.in +++ b/man/btrfs.8.in @@ -12,7 +12,7 @@ btrfs \- control a btrfs filesystem .PP \fBbtrfs\fP \fBsubvolume list\fP [\fIoptions\fP] [-G [+|-]\fIvalue\fP] [-C [+|-]\fIvalue\fP] [--sort=rootid,gen,ogen,path] \fI<path>\fP .PP -\fBbtrfs\fP \fBsubvolume snapshot\fP [-r] \fI<source>\fP \fI<dest>\fP|[\fI<dest>\fP/]\fI<name>\fP +\fBbtrfs\fP \fBsubvolume snapshot\fP [-r][-R] \fI<source>\fP \fI<dest>\fP|[\fI<dest>\fP/]\fI<name>\fP .PP \fBbtrfs\fP \fBsubvolume get-default\fP\fI <path>\fP .PP @@ -227,12 +227,14 @@ for \fB--sort\fP you can combine some items together by '','', just like .RE .TP -\fBsubvolume snapshot\fP [-r] \fI<source>\fP \fI<dest>\fP|[\fI<dest>\fP/]\fI<name>\fP +\fBsubvolume snapshot\fP [-r][-R] \fI<source>\fP \fI<dest>\fP|[\fI<dest>\fP/]\fI<name>\fP Create a writable/readonly snapshot of the subvolume \fI<source>\fR with the name \fI<name>\fR in the \fI<dest>\fR directory. If only \fI<dest>\fR is given, the subvolume will be named the basename of \fI<source>\fR. If \fI<source>\fR is not a subvolume, \fBbtrfs\fR returns an error. If \fI-r\fR is given, the snapshot will be readonly. +If \fI-R\fR is given, the snapshot will be made recursively. \fI-R\fR and +\fI-r\fR cannot be used togheter. The -R switch requires the root capability. .TP \fBsubvolume get-default\fR\fI <path>\fR -- 1.8.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2013-Nov-16 17:09 UTC
[PATCH 7/7] Document the -R switch for the "btrfs subvolume delete" command.
Signed-off-by: Goffredo Baroncelli <kreijack@inwind.it> --- man/btrfs.8.in | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/man/btrfs.8.in b/man/btrfs.8.in index aee1f70..5ed5277 100644 --- a/man/btrfs.8.in +++ b/man/btrfs.8.in @@ -8,7 +8,7 @@ btrfs \- control a btrfs filesystem .SH SYNOPSIS \fBbtrfs\fP \fBsubvolume create\fP [-i \fI<qgroupid>\fP] [\fI<dest>\fP/]\fI<name>\fP .PP -\fBbtrfs\fP \fBsubvolume delete\fP \fI<subvolume>\fP [\fI<subvolume>...\fP] +\fBbtrfs\fP \fBsubvolume delete\fP [-R] \fI<subvolume>\fP [\fI<subvolume>...\fP] .PP \fBbtrfs\fP \fBsubvolume list\fP [\fIoptions\fP] [-G [+|-]\fIvalue\fP] [-C [+|-]\fIvalue\fP] [--sort=rootid,gen,ogen,path] \fI<path>\fP .PP @@ -168,9 +168,12 @@ times. .RE .TP -\fBsubvolume delete\fR\fI <subvolume> \fP[\fI<subvolume>...\fP]\fR +\fBsubvolume delete\fR [-R] \fI <subvolume> \fP[\fI<subvolume>...\fP]\fR Delete the subvolume \fI<subvolume>\fR. If \fI<subvolume>\fR is not a subvolume, \fBbtrfs\fR returns an error. +If \fI-R\fR is given, the subvolumes were removed recursively (otherwise it is +not possible to remove a subvolume with a nested one); the -R switch requires +the root capability. .TP \fBsubvolume list\fR [\fIoptions\fP] [-G [+|-]\fIvalue\fP] [-C [+|-]\fIvalue\fP] [--sort=rootid,gen,ogen,path] \fI<path>\fR -- 1.8.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2013-Nov-25 21:23 UTC
Re: [PATCH] BTRFS-PROG: recursively subvolume snapshot and delete
Hi all, nobody is interested in these new features ? On 2013-11-16 18:09, Goffredo Baroncelli wrote:> Hi All, > > the following patches implement the recursively snapshotting and > deleting of a subvolume. > > To snapshot recursively you must pass the -R switch: > > # btrfs subvolume create sub1 > Create subvolume ''./sub1'' > # btrfs subvolume create sub1/sub2 > Create subvolume ''sub1/sub2'' > > # btrfs subvolume snapshot -R sub1 sub1-snap > Create a snapshot of ''sub1'' in ''./sub1-snap'' > Create a snapshot of ''sub1/sub2'' in ''./sub1-snap/sub2'' > > To recursively delete subvolumes, you must pass the switch ''-R'': > > # btrfs subvolume create sub1 > Create subvolume ''./sub1'' > # btrfs subvolume create sub1/sub2 > Create subvolume ''sub1/sub2'' > > # btrfs subvolume delete -R sub1 > Delete subvolume ''/root/sub1/sub2'' > Delete subvolume ''/root/sub1'' > > > Some caveats: > 1) the recursively behaviour need the root capability > This because how the subvolume are discovered > > 2) it is not possible to recursively snapshot a subvolume > in read-only mode > This because when a subvolume is snapshotted, its > nested subvolumes appear as directory in the snapshot. > These directories are removed before snapshotting the > nested subvolumes. This is incompatible with a read > only subvolume. > > BR > G.Baroncelli > > -- > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html >-- gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it> Key fingerprint BBF5 1610 0B64 DAC6 5F7D 17B2 0EDA 9B37 8B82 E0B5 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Konstantinos Skarlatos
2013-Nov-26 15:12 UTC
Re: [PATCH] BTRFS-PROG: recursively subvolume snapshot and delete
On 25/11/2013 11:23 μμ, Goffredo Baroncelli wrote:> Hi all, > > nobody is interested in these new features ?Is this ZFS-style recursive snapshotting? If yes, i am interested, and thanks for your great work :)> > On 2013-11-16 18:09, Goffredo Baroncelli wrote: >> Hi All, >> >> the following patches implement the recursively snapshotting and >> deleting of a subvolume. >> >> To snapshot recursively you must pass the -R switch: >> >> # btrfs subvolume create sub1 >> Create subvolume ''./sub1'' >> # btrfs subvolume create sub1/sub2 >> Create subvolume ''sub1/sub2'' >> >> # btrfs subvolume snapshot -R sub1 sub1-snap >> Create a snapshot of ''sub1'' in ''./sub1-snap'' >> Create a snapshot of ''sub1/sub2'' in ''./sub1-snap/sub2'' >> >> To recursively delete subvolumes, you must pass the switch ''-R'': >> >> # btrfs subvolume create sub1 >> Create subvolume ''./sub1'' >> # btrfs subvolume create sub1/sub2 >> Create subvolume ''sub1/sub2'' >> >> # btrfs subvolume delete -R sub1 >> Delete subvolume ''/root/sub1/sub2'' >> Delete subvolume ''/root/sub1'' >> >> >> Some caveats: >> 1) the recursively behaviour need the root capability >> This because how the subvolume are discovered >> >> 2) it is not possible to recursively snapshot a subvolume >> in read-only mode >> This because when a subvolume is snapshotted, its >> nested subvolumes appear as directory in the snapshot. >> These directories are removed before snapshotting the >> nested subvolumes. This is incompatible with a read >> only subvolume. >> >> BR >> G.Baroncelli >> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> >-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2013-Nov-26 17:44 UTC
Re: [PATCH] BTRFS-PROG: recursively subvolume snapshot and delete
On 2013-11-26 16:12, Konstantinos Skarlatos wrote:> On 25/11/2013 11:23 μμ, Goffredo Baroncelli wrote: >> Hi all, >> >> nobody is interested in these new features ? > Is this ZFS-style recursive snapshotting? If yes, i am interested, and > thanks for your great work :)No it is not equal. My recursive snapshotting is not atomic as the ZFS one; every subvolume snapshot is atomic, but each snapshot is taken at different time. BR G.Baroncelli>> >> On 2013-11-16 18:09, Goffredo Baroncelli wrote: >>> Hi All, >>> >>> the following patches implement the recursively snapshotting and >>> deleting of a subvolume. >>> >>> To snapshot recursively you must pass the -R switch: >>> >>> # btrfs subvolume create sub1 >>> Create subvolume ''./sub1'' >>> # btrfs subvolume create sub1/sub2 >>> Create subvolume ''sub1/sub2'' >>> >>> # btrfs subvolume snapshot -R sub1 sub1-snap >>> Create a snapshot of ''sub1'' in ''./sub1-snap'' >>> Create a snapshot of ''sub1/sub2'' in ''./sub1-snap/sub2'' >>> >>> To recursively delete subvolumes, you must pass the switch ''-R'': >>> >>> # btrfs subvolume create sub1 >>> Create subvolume ''./sub1'' >>> # btrfs subvolume create sub1/sub2 >>> Create subvolume ''sub1/sub2'' >>> >>> # btrfs subvolume delete -R sub1 >>> Delete subvolume ''/root/sub1/sub2'' >>> Delete subvolume ''/root/sub1'' >>> >>> >>> Some caveats: >>> 1) the recursively behaviour need the root capability >>> This because how the subvolume are discovered >>> >>> 2) it is not possible to recursively snapshot a subvolume >>> in read-only mode >>> This because when a subvolume is snapshotted, its >>> nested subvolumes appear as directory in the snapshot. >>> These directories are removed before snapshotting the >>> nested subvolumes. This is incompatible with a read >>> only subvolume. >>> >>> BR >>> G.Baroncelli >>> >>> -- >>> To unsubscribe from this list: send the line "unsubscribe >>> linux-btrfs" in >>> the body of a message to majordomo@vger.kernel.org >>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>> >> > > -- > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html >-- gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it> Key fingerprint BBF5 1610 0B64 DAC6 5F7D 17B2 0EDA 9B37 8B82 E0B5 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Konstantinos Skarlatos
2013-Nov-27 09:15 UTC
Re: [PATCH] BTRFS-PROG: recursively subvolume snapshot and delete
On 26/11/2013 7:44 μμ, Goffredo Baroncelli wrote:> On 2013-11-26 16:12, Konstantinos Skarlatos wrote: >> On 25/11/2013 11:23 μμ, Goffredo Baroncelli wrote: >>> Hi all, >>> >>> nobody is interested in these new features ? >> Is this ZFS-style recursive snapshotting? If yes, i am interested, and >> thanks for your great work :) > No it is not equal. My recursive snapshotting is not atomic as the ZFS > one; every subvolume snapshot is atomic, but each snapshot is taken at > different time.For my use case that is not a problem, but others may disagree> > BR > G.Baroncelli > >>> On 2013-11-16 18:09, Goffredo Baroncelli wrote: >>>> Hi All, >>>> >>>> the following patches implement the recursively snapshotting and >>>> deleting of a subvolume. >>>> >>>> To snapshot recursively you must pass the -R switch: >>>> >>>> # btrfs subvolume create sub1 >>>> Create subvolume ''./sub1'' >>>> # btrfs subvolume create sub1/sub2 >>>> Create subvolume ''sub1/sub2'' >>>> >>>> # btrfs subvolume snapshot -R sub1 sub1-snap >>>> Create a snapshot of ''sub1'' in ''./sub1-snap'' >>>> Create a snapshot of ''sub1/sub2'' in ''./sub1-snap/sub2'' >>>> >>>> To recursively delete subvolumes, you must pass the switch ''-R'': >>>> >>>> # btrfs subvolume create sub1 >>>> Create subvolume ''./sub1'' >>>> # btrfs subvolume create sub1/sub2 >>>> Create subvolume ''sub1/sub2'' >>>> >>>> # btrfs subvolume delete -R sub1 >>>> Delete subvolume ''/root/sub1/sub2'' >>>> Delete subvolume ''/root/sub1'' >>>> >>>> >>>> Some caveats: >>>> 1) the recursively behaviour need the root capability >>>> This because how the subvolume are discovered >>>> >>>> 2) it is not possible to recursively snapshot a subvolume >>>> in read-only mode >>>> This because when a subvolume is snapshotted, its >>>> nested subvolumes appear as directory in the snapshot. >>>> These directories are removed before snapshotting the >>>> nested subvolumes. This is incompatible with a read >>>> only subvolume. >>>> >>>> BR >>>> G.Baroncelli >>>> >>>> -- >>>> To unsubscribe from this list: send the line "unsubscribe >>>> linux-btrfs" in >>>> the body of a message to majordomo@vger.kernel.org >>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>> >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> >-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2013-Nov-27 17:04 UTC
Re: [PATCH] BTRFS-PROG: recursively subvolume snapshot and delete
On 2013-11-27 10:15, Konstantinos Skarlatos wrote:> On 26/11/2013 7:44 μμ, Goffredo Baroncelli wrote: >> On 2013-11-26 16:12, Konstantinos Skarlatos wrote: >>> On 25/11/2013 11:23 μμ, Goffredo Baroncelli wrote: >>>> Hi all, >>>> >>>> nobody is interested in these new features ? >>> Is this ZFS-style recursive snapshotting? If yes, i am interested, and >>> thanks for your great work :) >> No it is not equal. My recursive snapshotting is not atomic as the ZFS >> one; every subvolume snapshot is atomic, but each snapshot is taken at >> different time. > For my use case that is not a problem, but others may disagreeUnfortunately an atomic-and-recursive snapshot is not feasible from user space. Hoping that this patch will be accepted in mainline.>> >> BR >> G.Baroncelli >> >>>> On 2013-11-16 18:09, Goffredo Baroncelli wrote: >>>>> Hi All, >>>>> >>>>> the following patches implement the recursively snapshotting and >>>>> deleting of a subvolume. >>>>> >>>>> To snapshot recursively you must pass the -R switch: >>>>> >>>>> # btrfs subvolume create sub1 >>>>> Create subvolume ''./sub1'' >>>>> # btrfs subvolume create sub1/sub2 >>>>> Create subvolume ''sub1/sub2'' >>>>> >>>>> # btrfs subvolume snapshot -R sub1 sub1-snap >>>>> Create a snapshot of ''sub1'' in ''./sub1-snap'' >>>>> Create a snapshot of ''sub1/sub2'' in ''./sub1-snap/sub2'' >>>>> >>>>> To recursively delete subvolumes, you must pass the switch ''-R'': >>>>> >>>>> # btrfs subvolume create sub1 >>>>> Create subvolume ''./sub1'' >>>>> # btrfs subvolume create sub1/sub2 >>>>> Create subvolume ''sub1/sub2'' >>>>> >>>>> # btrfs subvolume delete -R sub1 >>>>> Delete subvolume ''/root/sub1/sub2'' >>>>> Delete subvolume ''/root/sub1'' >>>>> >>>>> >>>>> Some caveats: >>>>> 1) the recursively behaviour need the root capability >>>>> This because how the subvolume are discovered >>>>> >>>>> 2) it is not possible to recursively snapshot a subvolume >>>>> in read-only mode >>>>> This because when a subvolume is snapshotted, its >>>>> nested subvolumes appear as directory in the snapshot. >>>>> These directories are removed before snapshotting the >>>>> nested subvolumes. This is incompatible with a read >>>>> only subvolume. >>>>> >>>>> BR >>>>> G.Baroncelli >>>>> >>>>> -- >>>>> To unsubscribe from this list: send the line "unsubscribe >>>>> linux-btrfs" in >>>>> the body of a message to majordomo@vger.kernel.org >>>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>>> >>> -- >>> To unsubscribe from this list: send the line "unsubscribe >>> linux-btrfs" in >>> the body of a message to majordomo@vger.kernel.org >>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>> >> > >-- gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it> Key fingerprint BBF5 1610 0B64 DAC6 5F7D 17B2 0EDA 9B37 8B82 E0B5 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
David Sterba
2013-Nov-28 18:31 UTC
Re: [PATCH] BTRFS-PROG: recursively subvolume snapshot and delete
On Sat, Nov 16, 2013 at 06:09:00PM +0100, Goffredo Baroncelli wrote:> the following patches implement the recursively snapshotting and > deleting of a subvolume.Nice feature, but can we try to make the snapshot creation atomic? This would need support from kernel of course. I''m worried about the outcome from the users'' perspective, the consistency of the whole subvolume subtree. As you''ve implemented it, there are several operations involved like traversing the subvolume list, replacing the empty-subvols with the real ones, taking the snapshots. The assumptions about existing source subvolumes may change in the meantime: renamed or deleted. The recursive deletion is safer form this point, I''ll look at the patches closer. Deleting the whole directory subtree with randomly scattered subvolumes is not easy atm, I''m using wrappers around find and maxdepth/mindepth to look for subvols and issue delete until it''s done. david -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2013-Nov-28 19:23 UTC
Re: [PATCH] BTRFS-PROG: recursively subvolume snapshot and delete
Hi David, On 2013-11-28 19:31, David Sterba wrote:> On Sat, Nov 16, 2013 at 06:09:00PM +0100, Goffredo Baroncelli wrote: >> the following patches implement the recursively snapshotting and >> deleting of a subvolume. > > Nice feature, but can we try to make the snapshot creation atomic? This > would need support from kernel of course. > > I''m worried about the outcome from the users'' perspective, the > consistency of the whole subvolume subtree. As you''ve implemented it, > there are several operations involved like traversing the subvolume > list, replacing the empty-subvols with the real ones, taking the > snapshots. The assumptions about existing source subvolumes may change > in the meantime: renamed or deleted.Definetely you are right. In fact this is true also for other tools like tar: they complaint if you remove/move/rename a file during the copy. We can work to increase the robustness of the process, to avoid strange behaviour when a subvolume is removed/moved/renamed. Anyway I am more afraid that we can''t mix recursive and readonly snapshot. Implementing the atomic recursive snapshot in the kernel, is out of my possibility; anyway basically this means that the filesystem is frozen until all the snapshot are done, which requires a finite time. In case of a high number of subvolumes this could be a problem. May be that it could be more simple to snapshot "all the filesystem", ie snapshot not from the filesystem-tree but form the root-of-tree; then we could cherry-pick the subvolume which are involved.... Another possibility is to forzen all subvolumes, then snapshot them, then unfrozen all the subvolume...> > The recursive deletion is safer form this point, I''ll look at the > patches closer. Deleting the whole directory subtree with randomly > scattered subvolumes is not easy atm, I''m using wrappers around find and > maxdepth/mindepth to look for subvols and issue delete until it''s done.The patches should be independent. Otherwise if you think that changing the order it would be more simple to merge them (even without the recursive-non-atomic-snapshot), let me know.> > > david >-- gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it> Key fingerprint BBF5 1610 0B64 DAC6 5F7D 17B2 0EDA 9B37 8B82 E0B5 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
David Sterba
2013-Nov-29 18:07 UTC
Re: [PATCH] BTRFS-PROG: recursively subvolume snapshot and delete
On Thu, Nov 28, 2013 at 08:23:13PM +0100, Goffredo Baroncelli wrote:> Definetely you are right. In fact this is true also for other tools like > tar: they complaint if you remove/move/rename a file during the copy. We > can work to increase the robustness of the process, to avoid strange > behaviour when a subvolume is removed/moved/renamed. > > Anyway I am more afraid that we can''t mix recursive and readonly snapshot.Agreed, this would eg. need to toggle RO/RW status when needed, but this does not sound very clean.> Implementing the atomic recursive snapshot in the kernel, is out of my > possibility; anyway basically this means that the filesystem is frozen > until all the snapshot are done, which requires a finite time. In case > of a high number of subvolumes this could be a problem.High number of subvolumes to snapshot atomically will always be problematic and a lazy userspace-based recursive snapshot might be actually better regarding the impact on the rest of the system, but without guaranteed atomicity. But, I don''t want to kill the whole idea just because there''s some scenario that''s possible but hard to handle. david -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2013-Nov-29 19:09 UTC
Re: [PATCH] BTRFS-PROG: recursively subvolume snapshot and delete
On 2013-11-29 19:07, David Sterba wrote:> On Thu, Nov 28, 2013 at 08:23:13PM +0100, Goffredo Baroncelli wrote: >> Definetely you are right. In fact this is true also for other tools like >> tar: they complaint if you remove/move/rename a file during the copy. We >> can work to increase the robustness of the process, to avoid strange >> behaviour when a subvolume is removed/moved/renamed. >> >> Anyway I am more afraid that we can''t mix recursive and readonly snapshot. > > Agreed, this would eg. need to toggle RO/RW status when needed, but this > does not sound very clean.IIRC the RO flags is mandatory for the send/receive; this basically means that we wouldn''t be able to use a recursive snapshot with send/receive.> >> Implementing the atomic recursive snapshot in the kernel, is out of my >> possibility; anyway basically this means that the filesystem is frozen >> until all the snapshot are done, which requires a finite time. In case >> of a high number of subvolumes this could be a problem. > > High number of subvolumes to snapshot atomically will always be > problematic and a lazy userspace-based recursive snapshot might be > actually better regarding the impact on the rest of the system, but > without guaranteed atomicity. > > But, I don''t want to kill the whole idea just because there''s some > scenario that''s possible but hard to handle. > > david >-- gpg @keyserver.linux.it: Goffredo Baroncelli (kreijackATinwind.it> Key fingerprint BBF5 1610 0B64 DAC6 5F7D 17B2 0EDA 9B37 8B82 E0B5 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html