summaryrefslogtreecommitdiffstats
path: root/sys/cddl/contrib/opensolaris/uts/common
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2011-10-24 00:38:09 +0000
committerpjd <pjd@FreeBSD.org>2011-10-24 00:38:09 +0000
commitabdbea665980cd149a350baa8450b4fc59a80b9e (patch)
treedb90d18a179398559a19672e801a29f12acd49a4 /sys/cddl/contrib/opensolaris/uts/common
parent26b45aef71d0af57c82518de4e87288d5c515180 (diff)
downloadFreeBSD-src-abdbea665980cd149a350baa8450b4fc59a80b9e.zip
FreeBSD-src-abdbea665980cd149a350baa8450b4fc59a80b9e.tar.gz
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@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
Diffstat (limited to 'sys/cddl/contrib/opensolaris/uts/common')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c6
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c15
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h8
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dir.h2
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h4
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c2
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c12
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c32
8 files changed, 69 insertions, 12 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
index 498352e..140af06 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c
@@ -2461,7 +2461,7 @@ dsl_valid_rename(const char *oldname, void *arg)
#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 char *newname, boolean_t recursive)
&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 char *newname, boolean_t recursive)
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);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c
index 013e811..bb22dfb 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dir.c
@@ -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 delta, dsl_dir_t *ancestor)
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 *arg2, dmu_tx_t *tx)
* 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 *arg2, dmu_tx_t *tx)
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 *arg2, dmu_tx_t *tx)
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 *arg2, dmu_tx_t *tx)
}
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 *newname)
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);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
index 22733d0..ba2446e 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h
@@ -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);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dir.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dir.h
index 2191635..1ff03f4 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dir.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dir.h
@@ -131,7 +131,7 @@ int dsl_dir_set_quota(const char *ddname, zprop_source_t source,
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);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h
index 0560672..d4ef330 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_vfsops.h
@@ -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
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
index 7372ee7..f7a4fb3 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c
@@ -785,7 +785,7 @@ zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
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);
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
index 17174b2..8fe9287 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
@@ -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
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
index eff9779..2e57eab 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
@@ -2416,3 +2416,35 @@ zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value)
}
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
OpenPOWER on IntegriCloud