svn commit: r226676 - in head: cddl/contrib/opensolaris/lib/libzfs/common sys/cddl/contrib/opensolaris/uts/common/fs/zfs sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys

Pawel Jakub Dawidek pjd at FreeBSD.org
Mon Oct 24 00:38:10 UTC 2011


Author: pjd
Date: Mon Oct 24 00:38:09 2011
New Revision: 226676
URL: http://svn.freebsd.org/changeset/base/226676

Log:
  Allow to rename file systems without remounting if it is possible.
  It is possible for file systems with 'mountpoint' preperty set to 'legacy'
  or 'none' - we don't have to change mount directory for them.
  Currently such file systems are unmounted on rename and not even mounted back.
  
  This introduces layering violation, as we need to update 'f_mntfromname'
  field in statfs structure related to mountpoint (for the dataset we are
  renaming and all its children).
  
  In my opinion it is worth it, as it allow to update FreeBSD in even cleaner
  way - in ZFS-only configuration root file system is ZFS file system with
  'mountpoint' property set to 'legacy'. If root dataset is named system/rootfs,
  we can snapshot it (system/rootfs at upgrade), clone it (system/oldrootfs),
  update FreeBSD and if it doesn't boot we can boot back from system/oldrootfs
  and rename it back to system/rootfs while it is mounted as /. Before it was
  not possible, because unmounting / was not possible.
  
  MFC after:	2 weeks

Modified:
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
  head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dir.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c

Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c	Sun Oct 23 23:04:39 2011	(r226675)
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c	Mon Oct 24 00:38:09 2011	(r226676)
@@ -122,6 +122,10 @@ changelist_prefix(prop_changelist_t *clp
 			 */
 			switch (clp->cl_prop) {
 			case ZFS_PROP_MOUNTPOINT:
+				if (clp->cl_waslegacy &&
+				    (clp->cl_gflags & CL_GATHER_KEEP_LEGACY)) {
+					break;
+				}
 				if (zfs_unmount(cn->cn_handle, NULL,
 				    clp->cl_mflags) != 0) {
 					ret = -1;

Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c	Sun Oct 23 23:04:39 2011	(r226675)
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c	Mon Oct 24 00:38:09 2011	(r226676)
@@ -3489,6 +3489,7 @@ zfs_rename(zfs_handle_t *zhp, const char
 	zfs_handle_t *zhrp = NULL;
 	char *parentname = NULL;
 	char parent[ZFS_MAXNAMELEN];
+	char property[ZFS_MAXPROPLEN];
 	libzfs_handle_t *hdl = zhp->zfs_hdl;
 	char errbuf[1024];
 
@@ -3592,8 +3593,10 @@ zfs_rename(zfs_handle_t *zhp, const char
 		}
 
 	} else {
-		if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0)) == NULL)
+		if ((cl = changelist_gather(zhp, ZFS_PROP_NAME,
+		    CL_GATHER_KEEP_LEGACY, 0)) == NULL) {
 			return (-1);
+		}
 
 		if (changelist_haszonedchild(cl)) {
 			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -3615,7 +3618,13 @@ zfs_rename(zfs_handle_t *zhp, const char
 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 	(void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
 
-	zc.zc_cookie = recursive;
+	zc.zc_cookie = recursive ? 1 : 0;
+	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, property, sizeof (property),
+	    NULL, NULL, 0, B_FALSE) == 0 &&
+	    (strcmp(property, "legacy") == 0 ||
+	     strcmp(property, "none") == 0)) {
+		zc.zc_cookie |= 2;
+	}
 
 	if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) {
 		/*

Modified: head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h	Sun Oct 23 23:04:39 2011	(r226675)
+++ head/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h	Mon Oct 24 00:38:09 2011	(r226676)
@@ -158,7 +158,13 @@ int zprop_expand_list(libzfs_handle_t *h
  * on each change node regardless of whether or not it is currently
  * mounted.
  */
-#define	CL_GATHER_MOUNT_ALWAYS	1
+#define	CL_GATHER_MOUNT_ALWAYS	0x01
+/*
+ * Use this changelist_gather() flag to prevent unmounting of legacy
+ * file systems. Useful when renaming legacy file systems, where there is
+ * no need to unmount them.
+ */
+#define	CL_GATHER_KEEP_LEGACY	0x02
 
 typedef struct prop_changelist prop_changelist_t;
 

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 Oct 23 23:04:39 2011	(r226675)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c	Mon Oct 24 00:38:09 2011	(r226676)
@@ -2461,7 +2461,7 @@ dsl_valid_rename(const char *oldname, vo
 
 #pragma weak dmu_objset_rename = dsl_dataset_rename
 int
-dsl_dataset_rename(char *oldname, const char *newname, boolean_t recursive)
+dsl_dataset_rename(char *oldname, const char *newname, int flags)
 {
 	dsl_dir_t *dd;
 	dsl_dataset_t *ds;
@@ -2481,7 +2481,7 @@ dsl_dataset_rename(char *oldname, const 
 			    &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
 
 		if (err == 0)
-			err = dsl_dir_rename(dd, newname);
+			err = dsl_dir_rename(dd, newname, flags);
 		dsl_dir_close(dd, FTAG);
 		return (err);
 	}
@@ -2502,7 +2502,7 @@ dsl_dataset_rename(char *oldname, const 
 	if (strncmp(oldname, newname, tail - newname) != 0)
 		return (EXDEV);
 
-	if (recursive) {
+	if (flags & ZFS_RENAME_RECURSIVE) {
 		err = dsl_recursive_rename(oldname, newname);
 	} else {
 		err = dsl_dataset_hold(oldname, FTAG, &ds);

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c	Sun Oct 23 23:04:39 2011	(r226675)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c	Mon Oct 24 00:38:09 2011	(r226676)
@@ -37,6 +37,7 @@
 #include <sys/arc.h>
 #include <sys/sunddi.h>
 #include <sys/zvol.h>
+#include <sys/zfs_vfsops.h>
 #include "zfs_namecheck.h"
 
 static uint64_t dsl_dir_space_towrite(dsl_dir_t *dd);
@@ -1245,6 +1246,7 @@ would_change(dsl_dir_t *dd, int64_t delt
 struct renamearg {
 	dsl_dir_t *newparent;
 	const char *mynewname;
+	boolean_t islegacy;
 };
 
 static int
@@ -1263,9 +1265,13 @@ dsl_dir_rename_check(void *arg1, void *a
 	 * stats), but any that are present in open context will likely
 	 * be gone by syncing context, so only fail from syncing
 	 * context.
+	 * Don't check if we are renaming dataset with mountpoint set to
+	 * "legacy" or "none".
 	 */
-	if (dmu_tx_is_syncing(tx) && dmu_buf_refcount(dd->dd_dbuf) > 1)
+	if (!ra->islegacy && dmu_tx_is_syncing(tx) &&
+	    dmu_buf_refcount(dd->dd_dbuf) > 1) {
 		return (EBUSY);
+	}
 
 	/* check for existing name */
 	err = zap_lookup(mos, ra->newparent->dd_phys->dd_child_dir_zapobj,
@@ -1302,7 +1308,7 @@ dsl_dir_rename_sync(void *arg1, void *ar
 	objset_t *mos = dp->dp_meta_objset;
 	int err;
 
-	ASSERT(dmu_buf_refcount(dd->dd_dbuf) <= 2);
+	ASSERT(ra->islegacy || dmu_buf_refcount(dd->dd_dbuf) <= 2);
 
 	if (ra->newparent != dd->dd_parent) {
 		dsl_dir_diduse_space(dd->dd_parent, DD_USED_CHILD,
@@ -1345,6 +1351,7 @@ dsl_dir_rename_sync(void *arg1, void *ar
 	ASSERT3U(err, ==, 0);
 	dsl_dir_name(dd, newname);
 #ifdef _KERNEL
+	zfsvfs_update_fromname(oldname, newname);
 	zvol_rename_minors(oldname, newname);
 #endif
 
@@ -1353,7 +1360,7 @@ dsl_dir_rename_sync(void *arg1, void *ar
 }
 
 int
-dsl_dir_rename(dsl_dir_t *dd, const char *newname)
+dsl_dir_rename(dsl_dir_t *dd, const char *newname, int flags)
 {
 	struct renamearg ra;
 	int err;
@@ -1375,6 +1382,8 @@ dsl_dir_rename(dsl_dir_t *dd, const char
 		goto out;
 	}
 
+	ra.islegacy = !!(flags & ZFS_RENAME_IS_LEGACY);
+
 	err = dsl_sync_task_do(dd->dd_pool,
 	    dsl_dir_rename_check, dsl_dir_rename_sync, dd, &ra, 3);
 

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h	Sun Oct 23 23:04:39 2011	(r226675)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h	Mon Oct 24 00:38:09 2011	(r226676)
@@ -178,6 +178,12 @@ struct dsl_ds_holdarg {
 	char failed[MAXPATHLEN];
 };
 
+/*
+ * Flags for dsl_dataset_rename().
+ */
+#define	ZFS_RENAME_RECURSIVE	0x01
+#define	ZFS_RENAME_IS_LEGACY	0x02
+
 #define	dsl_dataset_is_snapshot(ds) \
 	((ds)->ds_phys->ds_num_children != 0)
 
@@ -211,7 +217,7 @@ dsl_syncfunc_t dsl_dataset_destroy_sync;
 dsl_checkfunc_t dsl_dataset_snapshot_check;
 dsl_syncfunc_t dsl_dataset_snapshot_sync;
 dsl_syncfunc_t dsl_dataset_user_hold_sync;
-int dsl_dataset_rename(char *name, const char *newname, boolean_t recursive);
+int dsl_dataset_rename(char *name, const char *newname, int flags);
 int dsl_dataset_promote(const char *name, char *conflsnap);
 int dsl_dataset_clone_swap(dsl_dataset_t *clone, dsl_dataset_t *origin_head,
     boolean_t force);

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dir.h
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dir.h	Sun Oct 23 23:04:39 2011	(r226675)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dir.h	Mon Oct 24 00:38:09 2011	(r226676)
@@ -131,7 +131,7 @@ int dsl_dir_set_quota(const char *ddname
     uint64_t quota);
 int dsl_dir_set_reservation(const char *ddname, zprop_source_t source,
     uint64_t reservation);
-int dsl_dir_rename(dsl_dir_t *dd, const char *newname);
+int dsl_dir_rename(dsl_dir_t *dd, const char *newname, int flags);
 int dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd, uint64_t space);
 int dsl_dir_set_reservation_check(void *arg1, void *arg2, dmu_tx_t *tx);
 boolean_t dsl_dir_is_clone(dsl_dir_t *dd);

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h	Sun Oct 23 23:04:39 2011	(r226675)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h	Mon Oct 24 00:38:09 2011	(r226676)
@@ -153,6 +153,10 @@ extern void zfsvfs_free(zfsvfs_t *zfsvfs
 extern int zfs_check_global_label(const char *dsname, const char *hexsl);
 extern int zfs_vnode_lock(vnode_t *vp, int flags);
 
+#ifdef _KERNEL
+extern void zfsvfs_update_fromname(const char *oldname, const char *newname);
+#endif
+
 #ifdef	__cplusplus
 }
 #endif

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c	Sun Oct 23 23:04:39 2011	(r226675)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c	Mon Oct 24 00:38:09 2011	(r226676)
@@ -785,7 +785,7 @@ zfsctl_snapdir_rename(vnode_t *sdvp, cha
 		return (ENOENT);
 	}
 
-	err = dmu_objset_rename(from, to, B_FALSE);
+	err = dmu_objset_rename(from, to, 0);
 	if (err == 0)
 		zfsctl_rename_snap(sdp, sep, tnm);
 

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 Oct 23 23:04:39 2011	(r226675)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c	Mon Oct 24 00:38:09 2011	(r226676)
@@ -3261,7 +3261,12 @@ out:
 static int
 zfs_ioc_rename(zfs_cmd_t *zc)
 {
-	boolean_t recursive = zc->zc_cookie & 1;
+	int flags = 0;
+
+	if (zc->zc_cookie & 1)
+		flags |= ZFS_RENAME_RECURSIVE;
+	if (zc->zc_cookie & 2)
+		flags |= ZFS_RENAME_IS_LEGACY;
 
 	zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
 	if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
@@ -3273,13 +3278,14 @@ zfs_ioc_rename(zfs_cmd_t *zc)
 	 * in which case the dataset code figures out which snapshots
 	 * to unmount.
 	 */
-	if (!recursive && strchr(zc->zc_name, '@') != NULL &&
+	if (!(flags & ZFS_RENAME_RECURSIVE) &&
+	    strchr(zc->zc_name, '@') != NULL &&
 	    zc->zc_objset_type == DMU_OST_ZFS) {
 		int err = zfs_unmount_snap(zc->zc_name, NULL);
 		if (err)
 			return (err);
 	}
-	return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive));
+	return (dmu_objset_rename(zc->zc_name, zc->zc_value, flags));
 }
 
 static int

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c	Sun Oct 23 23:04:39 2011	(r226675)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c	Mon Oct 24 00:38:09 2011	(r226676)
@@ -2416,3 +2416,35 @@ zfs_get_zplprop(objset_t *os, zfs_prop_t
 	}
 	return (error);
 }
+
+#ifdef _KERNEL
+void
+zfsvfs_update_fromname(const char *oldname, const char *newname)
+{
+	char tmpbuf[MAXPATHLEN];
+	struct mount *mp;
+	char *fromname;
+	size_t oldlen;
+
+	oldlen = strlen(oldname);
+
+	mtx_lock(&mountlist_mtx);
+	TAILQ_FOREACH(mp, &mountlist, mnt_list) {
+		fromname = mp->mnt_stat.f_mntfromname;
+		if (strcmp(fromname, oldname) == 0) {
+			(void)strlcpy(fromname, newname,
+			    sizeof(mp->mnt_stat.f_mntfromname));
+			continue;
+		}
+		if (strncmp(fromname, oldname, oldlen) == 0 &&
+		    fromname[oldlen] == '/') {
+			(void)snprintf(tmpbuf, sizeof(tmpbuf), "%s%s",
+			    newname, fromname + oldlen);
+			(void)strlcpy(fromname, tmpbuf,
+			    sizeof(mp->mnt_stat.f_mntfromname));
+			continue;
+		}
+	}
+	mtx_unlock(&mountlist_mtx);
+}
+#endif


More information about the svn-src-head mailing list