diff options
11 files changed, 91 insertions, 15 deletions
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c index 84b9300..8f222a9 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_changelist.c @@ -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; diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c index 381f5ed..bdd48b1 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c @@ -3489,6 +3489,7 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive) 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 *target, boolean_t recursive) } } 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 *target, boolean_t recursive) (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) { /* diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h index 9d1ecb7..db4aca7 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_impl.h @@ -158,7 +158,13 @@ int zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp, * 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; 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 |