summaryrefslogtreecommitdiffstats
path: root/sys/cddl
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2007-04-12 23:16:02 +0000
committerpjd <pjd@FreeBSD.org>2007-04-12 23:16:02 +0000
commitf2c622ab52226d52b41c62b45f4f380496fd97c7 (patch)
tree2b414c94764b09e163e6d64fd9693d51fdcd95d6 /sys/cddl
parent52f379b390182080f44d5137bd6a7c9c7ad4f943 (diff)
downloadFreeBSD-src-f2c622ab52226d52b41c62b45f4f380496fd97c7.zip
FreeBSD-src-f2c622ab52226d52b41c62b45f4f380496fd97c7.tar.gz
MFp4: Synchronize with vendor (mostly 'zfs rename -r').
Diffstat (limited to 'sys/cddl')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c141
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h3
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h2
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h1
-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.c13
6 files changed, 142 insertions, 20 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 af06c31..7d4689f 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
@@ -37,6 +37,7 @@
#include <sys/zap.h>
#include <sys/unique.h>
#include <sys/zfs_context.h>
+#include <sys/zfs_ioctl.h>
static dsl_checkfunc_t dsl_dataset_destroy_begin_check;
static dsl_syncfunc_t dsl_dataset_destroy_begin_sync;
@@ -639,7 +640,6 @@ dsl_dataset_create_sync(dsl_dir_t *pdd,
struct destroyarg {
dsl_sync_task_group_t *dstg;
char *snapname;
- void *tag;
char *failed;
};
@@ -655,7 +655,7 @@ dsl_snapshot_destroy_one(char *name, void *arg)
(void) strcat(name, da->snapname);
err = dsl_dataset_open(name,
DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT,
- da->tag, &ds);
+ da->dstg, &ds);
cp = strchr(name, '@');
*cp = '\0';
if (err == ENOENT)
@@ -666,7 +666,7 @@ dsl_snapshot_destroy_one(char *name, void *arg)
}
dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check,
- dsl_dataset_destroy_sync, ds, da->tag, 0);
+ dsl_dataset_destroy_sync, ds, da->dstg, 0);
return (0);
}
@@ -695,7 +695,6 @@ dsl_snapshots_destroy(char *fsname, char *snapname)
return (err);
da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
da.snapname = snapname;
- da.tag = FTAG;
da.failed = fsname;
err = dmu_objset_find(fsname,
@@ -717,7 +716,7 @@ dsl_snapshots_destroy(char *fsname, char *snapname)
* closed the ds
*/
if (err)
- dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG);
+ dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, da.dstg);
}
dsl_sync_task_group_destroy(da.dstg);
@@ -1546,6 +1545,11 @@ dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx)
err = EEXIST;
else if (err == ENOENT)
err = 0;
+
+ /* dataset name + 1 for the "@" + the new snapshot name must fit */
+ if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN)
+ err = ENAMETOOLONG;
+
return (err);
}
@@ -1578,9 +1582,114 @@ dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx)
dsl_dataset_close(hds, DS_MODE_NONE, FTAG);
}
+struct renamearg {
+ dsl_sync_task_group_t *dstg;
+ char failed[MAXPATHLEN];
+ char *oldsnap;
+ char *newsnap;
+};
+
+static int
+dsl_snapshot_rename_one(char *name, void *arg)
+{
+ struct renamearg *ra = arg;
+ dsl_dataset_t *ds = NULL;
+ char *cp;
+ int err;
+
+ cp = name + strlen(name);
+ *cp = '@';
+ (void) strcpy(cp + 1, ra->oldsnap);
+ err = dsl_dataset_open(name, DS_MODE_READONLY | DS_MODE_STANDARD,
+ ra->dstg, &ds);
+ if (err == ENOENT) {
+ *cp = '\0';
+ return (0);
+ }
+ if (err) {
+ (void) strcpy(ra->failed, name);
+ *cp = '\0';
+ dsl_dataset_close(ds, DS_MODE_STANDARD, ra->dstg);
+ return (err);
+ }
+
+#ifdef _KERNEL
+ /* for all filesystems undergoing rename, we'll need to unmount it */
+ (void) zfs_unmount_snap(name, NULL);
+#endif
+
+ *cp = '\0';
+
+ dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check,
+ dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0);
+
+ return (0);
+}
+
+static int
+dsl_recursive_rename(char *oldname, const char *newname)
+{
+ int err;
+ struct renamearg *ra;
+ dsl_sync_task_t *dst;
+ spa_t *spa;
+ char *cp, *fsname = spa_strdup(oldname);
+ int len = strlen(oldname);
+
+ /* truncate the snapshot name to get the fsname */
+ cp = strchr(fsname, '@');
+ *cp = '\0';
+
+ cp = strchr(fsname, '/');
+ if (cp) {
+ *cp = '\0';
+ err = spa_open(fsname, &spa, FTAG);
+ *cp = '/';
+ } else {
+ err = spa_open(fsname, &spa, FTAG);
+ }
+ if (err) {
+ kmem_free(fsname, len + 1);
+ return (err);
+ }
+ ra = kmem_alloc(sizeof (struct renamearg), KM_SLEEP);
+ ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
+
+ ra->oldsnap = strchr(oldname, '@') + 1;
+ ra->newsnap = strchr(newname, '@') + 1;
+ *ra->failed = '\0';
+
+ err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra,
+ DS_FIND_CHILDREN);
+ kmem_free(fsname, len + 1);
+
+ 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)) {
+ dsl_dataset_t *ds = dst->dst_arg1;
+ if (dst->dst_err) {
+ dsl_dir_name(ds->ds_dir, ra->failed);
+ (void) strcat(ra->failed, "@");
+ (void) strcat(ra->failed, ra->newsnap);
+ }
+ dsl_dataset_close(ds, DS_MODE_STANDARD, ra->dstg);
+ }
+
+ (void) strcpy(oldname, ra->failed);
+
+ dsl_sync_task_group_destroy(ra->dstg);
+ kmem_free(ra, sizeof (struct renamearg));
+ spa_close(spa, FTAG);
+ return (err);
+}
+
#pragma weak dmu_objset_rename = dsl_dataset_rename
int
-dsl_dataset_rename(const char *oldname, const char *newname)
+dsl_dataset_rename(char *oldname, const char *newname,
+ boolean_t recursive)
{
dsl_dir_t *dd;
dsl_dataset_t *ds;
@@ -1611,16 +1720,20 @@ dsl_dataset_rename(const char *oldname, const char *newname)
if (strncmp(oldname, newname, tail - newname) != 0)
return (EXDEV);
- err = dsl_dataset_open(oldname,
- DS_MODE_READONLY | DS_MODE_STANDARD, FTAG, &ds);
- if (err)
- return (err);
+ if (recursive) {
+ err = dsl_recursive_rename(oldname, newname);
+ } else {
+ err = dsl_dataset_open(oldname,
+ DS_MODE_READONLY | DS_MODE_STANDARD, FTAG, &ds);
+ if (err)
+ return (err);
- err = dsl_sync_task_do(ds->ds_dir->dd_pool,
- dsl_dataset_snapshot_rename_check,
- dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1);
+ err = dsl_sync_task_do(ds->ds_dir->dd_pool,
+ dsl_dataset_snapshot_rename_check,
+ dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1);
- dsl_dataset_close(ds, DS_MODE_STANDARD, FTAG);
+ dsl_dataset_close(ds, DS_MODE_STANDARD, FTAG);
+ }
return (err);
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h
index f534015..8c2a1fd 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h
@@ -164,7 +164,8 @@ int dmu_objset_destroy(const char *name);
int dmu_snapshots_destroy(char *fsname, char *snapname);
int dmu_objset_rollback(const char *name);
int dmu_objset_snapshot(char *fsname, char *snapname, boolean_t recursive);
-int dmu_objset_rename(const char *name, const char *newname);
+int dmu_objset_rename(const char *name, const char *newname,
+ boolean_t recursive);
int dmu_objset_find(char *name, int func(char *, void *), void *arg,
int flags);
void dmu_objset_byteswap(void *buf, size_t size);
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 8929dbc..8cfc1dc 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
@@ -132,7 +132,7 @@ int dsl_snapshots_destroy(char *fsname, char *snapname);
dsl_checkfunc_t dsl_dataset_snapshot_check;
dsl_syncfunc_t dsl_dataset_snapshot_sync;
int dsl_dataset_rollback(dsl_dataset_t *ds);
-int dsl_dataset_rename(const char *name, const char *newname);
+int dsl_dataset_rename(char *name, const char *newname, boolean_t recursive);
int dsl_dataset_promote(const char *name);
void *dsl_dataset_set_user_ptr(dsl_dataset_t *ds,
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h
index d28729b..61a0a9e 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h
@@ -152,6 +152,7 @@ typedef struct zfs_create_data {
extern int zfs_secpolicy_write(const char *dataset, cred_t *cr);
extern int zfs_busy(void);
+extern int zfs_unmount_snap(char *, void *);
#endif /* _KERNEL */
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 c759962..ff5c15b 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
@@ -590,7 +590,7 @@ zfsctl_snapdir_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm,
return (ENOENT);
}
- err = dmu_objset_rename(from, to);
+ err = dmu_objset_rename(from, to, B_FALSE);
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 aac1bb1..80af684 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
@@ -1354,7 +1354,7 @@ zfs_ioc_snapshot(zfs_cmd_t *zc)
zc->zc_value, zc->zc_cookie));
}
-static int
+int
zfs_unmount_snap(char *name, void *arg)
{
char *snapname = arg;
@@ -1430,18 +1430,25 @@ zfs_ioc_rollback(zfs_cmd_t *zc)
static int
zfs_ioc_rename(zfs_cmd_t *zc)
{
+ int recursive = zc->zc_cookie & 1;
+
zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0)
return (EINVAL);
- if (strchr(zc->zc_name, '@') != NULL &&
+ /*
+ * Unmount snapshot unless we're doing a recursive rename,
+ * in which case the dataset code figures out which snapshots
+ * to unmount.
+ */
+ if (!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));
+ return (dmu_objset_rename(zc->zc_name, zc->zc_value, recursive));
}
static int
OpenPOWER on IntegriCloud