diff options
Diffstat (limited to 'sys/contrib')
6 files changed, 142 insertions, 20 deletions
diff --git a/sys/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c b/sys/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c index af06c31..7d4689f 100644 --- a/sys/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c +++ b/sys/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/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h b/sys/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h index f534015..8c2a1fd 100644 --- a/sys/contrib/opensolaris/uts/common/fs/zfs/sys/dmu.h +++ b/sys/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/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h b/sys/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h index 8929dbc..8cfc1dc 100644 --- a/sys/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_dataset.h +++ b/sys/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/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h b/sys/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h index d28729b..61a0a9e 100644 --- a/sys/contrib/opensolaris/uts/common/fs/zfs/sys/zfs_ioctl.h +++ b/sys/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/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c b/sys/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c index c759962..ff5c15b 100644 --- a/sys/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c +++ b/sys/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/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c b/sys/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c index aac1bb1..80af684 100644 --- a/sys/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c +++ b/sys/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 |