Author: pjd
Date: Sun Sep 23 20:12:10 2012
New Revision: 240870
URL: http://svn.freebsd.org/changeset/base/240870

Log:
  It is possible to recursively destroy snapshots even if the snapshot
  doesn't exist on a dataset we are starting from. For example if we
  have the following configuration:
  
        tank
        tank/foo
        tank/foo@snap
        tank/bar
        tank/bar@snap
  
  We can execute:
  
        # zfs destroy -t tank@snap
  
  eventhough tank@snap doesn't exit.
  
  Unfortunately it is not possible to do the same with recursive rename:
  
        # zfs rename -r tank@snap tank@pans
        cannot open 'tank@snap': dataset does not exist
  
  ...until now. This change allows to recursively rename snapshots even if
  snapshot doesn't exist on the starting dataset.
  
  Sponsored by: rsync.net
  MFC after:    2 weeks

Modified:
  head/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c

Modified: head/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
==============================================================================
--- head/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c    Sun Sep 23 19:48:29 
2012        (r240869)
+++ head/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c    Sun Sep 23 20:12:10 
2012        (r240870)
@@ -3081,6 +3081,7 @@ zfs_do_rename(int argc, char **argv)
        int ret = 0;
        int types;
        boolean_t parents = B_FALSE;
+       char *snapshot = NULL;
 
        /* check options */
        while ((c = getopt(argc, argv, "fpru")) != -1) {
@@ -3149,6 +3150,19 @@ zfs_do_rename(int argc, char **argv)
        else
                types = ZFS_TYPE_DATASET;
 
+       if (flags.recurse) {
+               /*
+                * When we do recursive rename we are fine when the given
+                * snapshot for the given dataset doesn't exist - it can
+                * still exists below.
+                */
+
+               snapshot = strchr(argv[0], '@');
+               assert(snapshot != NULL);
+               *snapshot = '\0';
+               snapshot++;
+       }
+
        if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL)
                return (1);
 
@@ -3159,7 +3173,7 @@ zfs_do_rename(int argc, char **argv)
                return (1);
        }
 
-       ret = (zfs_rename(zhp, argv[1], flags) != 0);
+       ret = (zfs_rename(zhp, snapshot, argv[1], flags) != 0);
 
        zfs_close(zhp);
        return (ret);

Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h    Sun Sep 23 
19:48:29 2012        (r240869)
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs.h    Sun Sep 23 
20:12:10 2012        (r240870)
@@ -571,7 +571,8 @@ typedef struct renameflags {
        int forceunmount : 1;
 } renameflags_t;
 
-extern int zfs_rename(zfs_handle_t *, const char *, renameflags_t flags);
+extern int zfs_rename(zfs_handle_t *, const char *, const char *,
+    renameflags_t flags);
 
 typedef struct sendflags {
        /* print informational messages (ie, -v was specified) */

Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c    Sun Sep 
23 19:48:29 2012        (r240869)
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c    Sun Sep 
23 20:12:10 2012        (r240870)
@@ -611,6 +611,22 @@ zfs_open(libzfs_handle_t *hdl, const cha
                return (NULL);
        }
 
+       if (zhp == NULL) {
+               char *at = strchr(path, '@');
+
+               if (at != NULL)
+                       *at = '\0';
+               errno = 0;
+               if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
+                       (void) zfs_standard_error(hdl, errno, errbuf);
+                       return (NULL);
+               }
+               if (at != NULL)
+                       *at = '@';
+               (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
+               zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
+       }
+
        if (!(types & zhp->zfs_type)) {
                (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
                zfs_close(zhp);
@@ -3614,7 +3630,8 @@ zfs_rollback(zfs_handle_t *zhp, zfs_hand
  * Renames the given dataset.
  */
 int
-zfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags)
+zfs_rename(zfs_handle_t *zhp, const char *source, const char *target,
+    renameflags_t flags)
 {
        int ret;
        zfs_cmd_t zc = { 0 };
@@ -3634,6 +3651,18 @@ zfs_rename(zfs_handle_t *zhp, const char
        (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
            "cannot rename to '%s'"), target);
 
+       if (source != NULL) {
+               /*
+                * This is recursive snapshots rename, put snapshot name
+                * (that might not exist) into zfs_name.
+                */
+               assert(flags.recurse);
+
+               (void) strlcat(zhp->zfs_name, "@", sizeof(zhp->zfs_name));
+               (void) strlcat(zhp->zfs_name, source, sizeof(zhp->zfs_name));
+               zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
+       }
+
        /*
         * Make sure the target name is valid
         */

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c   Sun Sep 
23 19:48:29 2012        (r240869)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c   Sun Sep 
23 20:12:10 2012        (r240870)
@@ -2520,6 +2520,7 @@ struct renamesnaparg {
        char failed[MAXPATHLEN];
        char *oldsnap;
        char *newsnap;
+       int error;
 };
 
 static int
@@ -2557,6 +2558,9 @@ dsl_snapshot_rename_one(const char *name
        dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check,
            dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0);
 
+       /* First successful rename clears the error. */
+       ra->error = 0;
+
        return (0);
 }
 
@@ -2585,14 +2589,16 @@ dsl_recursive_rename(char *oldname, cons
        ra->oldsnap = strchr(oldname, '@') + 1;
        ra->newsnap = strchr(newname, '@') + 1;
        *ra->failed = '\0';
+       ra->error = ENOENT;
 
        err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra,
            DS_FIND_CHILDREN);
        kmem_free(fsname, len);
+       if (err == 0)
+               err = ra->error;
 
-       if (err == 0) {
+       if (err == 0)
                err = dsl_sync_task_group_wait(ra->dstg);
-       }
 
        for (dst = list_head(&ra->dstg->dstg_tasks); dst;
            dst = list_next(&ra->dstg->dstg_tasks, dst)) {

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c     Sun Sep 
23 19:48:29 2012        (r240869)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c     Sun Sep 
23 20:12:10 2012        (r240870)
@@ -766,7 +766,26 @@ zfs_secpolicy_rename_perms(const char *f
 static int
 zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr)
 {
-       return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr));
+       char *at = NULL;
+       int error;
+
+       if ((zc->zc_cookie & 1) != 0) {
+               /*
+                * This is recursive rename, so the starting snapshot might
+                * not exist. Check file system or volume permission instead.
+                */
+               at = strchr(zc->zc_name, '@');
+               if (at == NULL)
+                       return (EINVAL);
+               *at = '\0';
+       }
+
+       error = zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr);
+
+       if (at != NULL)
+               *at = '@';
+
+       return (error);
 }
 
 static int
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to