aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs.813
-rw-r--r--cddl/contrib/opensolaris/cmd/zfs/zfs_main.c17
-rw-r--r--cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c30
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_bookmark.c105
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_bookmark.h1
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c113
6 files changed, 237 insertions, 42 deletions
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
index 84f13273af22..9ede617b01bc 100644
--- a/cddl/contrib/opensolaris/cmd/zfs/zfs.8
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs.8
@@ -105,6 +105,9 @@
.Ar snapshot snapshot
.Nm
.Cm rename
+.Ar bookmark bookmark
+.Nm
+.Cm rename
.Fl u
.Op Fl p
.Ar filesystem filesystem
@@ -2094,6 +2097,16 @@ Recursively rename the snapshots of all descendent datasets. Snapshots are the
only dataset that can be renamed recursively.
.It Xo
.Nm
+.Cm rename
+.Ar bookmark bookmark
+.Xc
+.Pp
+Renames the given bookmark.
+Bookmarks can only be renamed within the parent file system or volume.
+When renaming a bookmark, the parent file system or volume of the bookmark
+does not need to be specified as part of the second argument.
+.It Xo
+.Nm
.Cm list
.Op Fl r Ns | Ns Fl d Ar depth
.Op Fl Hp
diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
index bb5a2a94ccc0..c2f9f9548ca3 100644
--- a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
+++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c
@@ -284,6 +284,7 @@ get_usage(zfs_help_t idx)
"<filesystem|volume|snapshot>\n"
"\trename [-f] -p <filesystem|volume> <filesystem|volume>\n"
"\trename -r <snapshot> <snapshot>\n"
+ "\trename <bookmark> <bookmark>\n"
"\trename -u [-p] <filesystem> <filesystem>"));
case HELP_ROLLBACK:
return (gettext("\trollback [-rRf] <snapshot>\n"));
@@ -3254,6 +3255,7 @@ zfs_do_list(int argc, char **argv)
* zfs rename [-f] <fs | snap | vol> <fs | snap | vol>
* zfs rename [-f] -p <fs | vol> <fs | vol>
* zfs rename -r <snap> <snap>
+ * zfs rename <bmark> <bmark>
* zfs rename -u [-p] <fs> <fs>
*
* Renames the given dataset to another of the same type.
@@ -3270,6 +3272,7 @@ zfs_do_rename(int argc, char **argv)
int ret = 0;
int types;
boolean_t parents = B_FALSE;
+ boolean_t bookmarks = B_FALSE;
char *snapshot = NULL;
/* check options */
@@ -3320,7 +3323,7 @@ zfs_do_rename(int argc, char **argv)
usage(B_FALSE);
}
- if (flags.recurse && strchr(argv[0], '@') == 0) {
+ if (flags.recurse && strchr(argv[0], '@') == NULL) {
(void) fprintf(stderr, gettext("source dataset for recursive "
"rename must be a snapshot\n"));
usage(B_FALSE);
@@ -3332,10 +3335,22 @@ zfs_do_rename(int argc, char **argv)
usage(B_FALSE);
}
+ if (strchr(argv[0], '#') != NULL)
+ bookmarks = B_TRUE;
+
+ if (bookmarks && (flags.nounmount || flags.recurse ||
+ flags.forceunmount || parents)) {
+ (void) fprintf(stderr, gettext("options are not supported "
+ "for renaming bookmarks\n"));
+ usage(B_FALSE);
+ }
+
if (flags.nounmount)
types = ZFS_TYPE_FILESYSTEM;
else if (parents)
types = ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME;
+ else if (bookmarks)
+ types = ZFS_TYPE_BOOKMARK;
else
types = ZFS_TYPE_DATASET;
diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
index 1d344b1f6f71..76a71f39d987 100644
--- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
+++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c
@@ -4291,17 +4291,18 @@ zfs_rename(zfs_handle_t *zhp, const char *source, const char *target,
/*
* Make sure the target name is valid
*/
- if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
- if ((strchr(target, '@') == NULL) ||
- *target == '@') {
+ if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT ||
+ zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
+ const char sep = zhp->zfs_type == ZFS_TYPE_SNAPSHOT ? '@' : '#';
+
+ if ((strchr(target, sep) == NULL) || *target == sep) {
/*
* Snapshot target name is abbreviated,
* reconstruct full dataset name
*/
- (void) strlcpy(parent, zhp->zfs_name,
- sizeof (parent));
- delim = strchr(parent, '@');
- if (strchr(target, '@') == NULL)
+ (void) strlcpy(parent, zhp->zfs_name, sizeof (parent));
+ delim = strchr(parent, sep);
+ if (strchr(target, sep) == NULL)
*(++delim) = '\0';
else
*delim = '\0';
@@ -4311,12 +4312,13 @@ zfs_rename(zfs_handle_t *zhp, const char *source, const char *target,
/*
* Make sure we're renaming within the same dataset.
*/
- delim = strchr(target, '@');
+ delim = strchr(target, sep);
if (strncmp(zhp->zfs_name, target, delim - target)
- != 0 || zhp->zfs_name[delim - target] != '@') {
+ != 0 || zhp->zfs_name[delim - target] != sep) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
- "snapshots must be part of same "
- "dataset"));
+ "%s must be part of same dataset"),
+ zhp->zfs_type == ZFS_TYPE_SNAPSHOT ?
+ "snapshots" : "bookmarks");
return (zfs_error(hdl, EZFS_CROSSTARGET,
errbuf));
}
@@ -4379,7 +4381,6 @@ zfs_rename(zfs_handle_t *zhp, const char *source, const char *target,
flags.nounmount = B_TRUE;
}
if (flags.recurse) {
-
parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
if (parentname == NULL) {
ret = -1;
@@ -4392,7 +4393,8 @@ zfs_rename(zfs_handle_t *zhp, const char *source, const char *target,
ret = -1;
goto error;
}
- } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) {
+ } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT &&
+ zhp->zfs_type != ZFS_TYPE_BOOKMARK) {
if ((cl = changelist_gather(zhp, ZFS_PROP_NAME,
flags.nounmount ? CL_GATHER_DONT_UNMOUNT : 0,
flags.forceunmount ? MS_FORCE : 0)) == NULL) {
@@ -4437,6 +4439,8 @@ zfs_rename(zfs_handle_t *zhp, const char *source, const char *target,
"a child dataset already has a snapshot "
"with the new name"));
(void) zfs_error(hdl, EZFS_EXISTS, errbuf);
+ } else if (errno == EINVAL) {
+ (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
} else {
(void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
}
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_bookmark.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_bookmark.c
index 0a58115341c7..cae6d00ca2ce 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_bookmark.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_bookmark.c
@@ -459,3 +459,108 @@ dsl_bookmark_destroy(nvlist_t *bmarks, nvlist_t *errors)
fnvlist_free(dbda.dbda_success);
return (rv);
}
+
+typedef struct dsl_bookmark_rename_arg {
+ const char *dbra_fsname;
+ const char *dbra_oldname;
+ const char *dbra_newname;
+} dsl_bookmark_rename_arg_t;
+
+static int
+dsl_bookmark_rename_check(void *arg, dmu_tx_t *tx)
+{
+ dsl_bookmark_rename_arg_t *dbra = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ dsl_dataset_t *ds;
+ zfs_bookmark_phys_t bmark_phys;
+ int error;
+
+ if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_BOOKMARKS))
+ return (SET_ERROR(ENOTSUP));
+
+ /* Check validity and the full length of the new bookmark name. */
+ if (zfs_component_namecheck(dbra->dbra_newname, NULL, NULL))
+ return (SET_ERROR(EINVAL));
+ if (strlen(dbra->dbra_fsname) + strlen(dbra->dbra_newname) + 1 >=
+ ZFS_MAX_DATASET_NAME_LEN)
+ return (SET_ERROR(ENAMETOOLONG));
+
+ error = dsl_dataset_hold(dp, dbra->dbra_fsname, FTAG, &ds);
+ if (error != 0)
+ return (error);
+ if (ds->ds_is_snapshot) {
+ dsl_dataset_rele(ds, FTAG);
+ return (SET_ERROR(EINVAL));
+ }
+ error = dsl_dataset_bmark_lookup(ds, dbra->dbra_oldname, &bmark_phys);
+ if (error != 0) {
+ dsl_dataset_rele(ds, FTAG);
+ return (error);
+ }
+
+ error = dsl_dataset_bmark_lookup(ds, dbra->dbra_newname, &bmark_phys);
+ dsl_dataset_rele(ds, FTAG);
+ if (error == 0)
+ return (SET_ERROR(EEXIST));
+ if (error != ESRCH)
+ return (error);
+ return (0);
+}
+
+static void
+dsl_bookmark_rename_sync(void *arg, dmu_tx_t *tx)
+{
+ zfs_bookmark_phys_t bmark_phys;
+ dsl_bookmark_rename_arg_t *dbra = arg;
+ dsl_pool_t *dp = dmu_tx_pool(tx);
+ objset_t *mos;
+ dsl_dataset_t *ds;
+ uint64_t bmark_zapobj;
+ uint64_t int_size, num_ints;
+ matchtype_t mt = 0;
+ int error;
+
+ ASSERT(spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_BOOKMARKS));
+ VERIFY0(dsl_dataset_hold(dp, dbra->dbra_fsname, FTAG, &ds));
+
+ mos = ds->ds_dir->dd_pool->dp_meta_objset;
+ bmark_zapobj = ds->ds_bookmarks;
+
+ if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
+ mt = MT_NORMALIZE;
+
+ VERIFY0(zap_length(mos, bmark_zapobj, dbra->dbra_oldname,
+ &int_size, &num_ints));
+ ASSERT3U(int_size, ==, sizeof (uint64_t));
+ VERIFY0(zap_lookup_norm(mos, bmark_zapobj, dbra->dbra_oldname, int_size,
+ num_ints, &bmark_phys, mt, NULL, 0, NULL));
+ VERIFY0(zap_remove_norm(mos, bmark_zapobj, dbra->dbra_oldname, mt, tx));
+
+ VERIFY0(zap_add(mos, bmark_zapobj, dbra->dbra_newname, int_size,
+ num_ints, &bmark_phys, tx));
+
+ spa_history_log_internal_ds(ds, "rename bookmark", tx,
+ "#%s -> #%s creation_txg=%llu",
+ dbra->dbra_oldname, dbra->dbra_newname,
+ (longlong_t)bmark_phys.zbm_creation_txg);
+
+ dsl_dataset_rele(ds, FTAG);
+}
+
+/*
+ * The bookmarks must all be in the same pool.
+ */
+int
+dsl_bookmark_rename(const char *fsname, const char *oldbmark,
+ const char *newbmark)
+{
+ dsl_bookmark_rename_arg_t dbra;
+
+ dbra.dbra_fsname = fsname;
+ dbra.dbra_oldname = oldbmark;
+ dbra.dbra_newname = newbmark;
+
+ return (dsl_sync_task(fsname, dsl_bookmark_rename_check,
+ dsl_bookmark_rename_sync, &dbra, 1, ZFS_SPACE_CHECK_NORMAL));
+}
+
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_bookmark.h b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_bookmark.h
index 3591986d7bd7..e4d9ec2be033 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_bookmark.h
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/dsl_bookmark.h
@@ -41,6 +41,7 @@ int dsl_bookmark_create(nvlist_t *, nvlist_t *);
int dsl_get_bookmarks(const char *, nvlist_t *, nvlist_t *);
int dsl_get_bookmarks_impl(dsl_dataset_t *, nvlist_t *, nvlist_t *);
int dsl_bookmark_destroy(nvlist_t *, nvlist_t *);
+int dsl_bookmark_rename(const char *fs, const char *from, const char *to);
int dsl_bookmark_lookup(struct dsl_pool *, const char *,
struct dsl_dataset *, zfs_bookmark_phys_t *);
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 575dd6904917..a7ff11d1488f 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
@@ -224,7 +224,8 @@ typedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *);
typedef enum {
NO_NAME,
POOL_NAME,
- DATASET_NAME
+ DATASET_NAME,
+ ENTITY_NAME
} zfs_ioc_namecheck_t;
typedef enum {
@@ -922,8 +923,21 @@ static int
zfs_secpolicy_rename(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
char *at = NULL;
+ char *pound;
int error;
+ if ((pound = strchr(zc->zc_name, '#')) != NULL) {
+ *pound = '\0';
+ error = zfs_secpolicy_write_perms(zc->zc_name,
+ ZFS_DELEG_PERM_RENAME, cr);
+ if (error == 0) {
+ error = zfs_secpolicy_write_perms(zc->zc_name,
+ ZFS_DELEG_PERM_BOOKMARK, cr);
+ }
+ *pound = '#';
+ return (error);
+ }
+
if ((zc->zc_cookie & 1) != 0) {
/*
* This is recursive rename, so the starting snapshot might
@@ -4020,8 +4034,8 @@ recursive_unmount(const char *fsname, void *arg)
/*
* inputs:
- * zc_name old name of dataset
- * zc_value new name of dataset
+ * zc_name old name of dataset or bookmark
+ * zc_value new name of dataset or bookmark
* zc_cookie recursive flag (only valid for snapshots)
*
* outputs: none
@@ -4032,7 +4046,7 @@ zfs_ioc_rename(zfs_cmd_t *zc)
objset_t *os;
dmu_objset_type_t ost;
boolean_t recursive = zc->zc_cookie & 1;
- char *at;
+ char *pos, *pos2;
boolean_t allow_mounted = B_TRUE;
int err;
@@ -4040,9 +4054,34 @@ zfs_ioc_rename(zfs_cmd_t *zc)
allow_mounted = (zc->zc_cookie & 2) != 0;
#endif
- /* "zfs rename" from and to ...%recv datasets should both fail */
zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
+
+ pos = strchr(zc->zc_name, '#');
+ if (pos != NULL) {
+ /* Bookmarks must be in same fs. */
+ pos2 = strchr(zc->zc_value, '#');
+ if (pos2 == NULL)
+ return (SET_ERROR(EINVAL));
+
+ /* Recursive flag is not supported yet. */
+ if (recursive)
+ return (SET_ERROR(ENOTSUP));
+
+ *pos = '\0';
+ *pos2 = '\0';
+ if (strcmp(zc->zc_name, zc->zc_value) == 0) {
+ err = dsl_bookmark_rename(zc->zc_name,
+ pos + 1, pos2 + 1);
+ } else {
+ err = SET_ERROR(EXDEV);
+ }
+ *pos = '#';
+ *pos2 = '#';
+ return (err);
+ }
+
+ /* "zfs rename" from and to ...%recv datasets should both fail */
if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0 ||
dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
strchr(zc->zc_name, '%') || strchr(zc->zc_value, '%'))
@@ -4054,28 +4093,30 @@ zfs_ioc_rename(zfs_cmd_t *zc)
ost = dmu_objset_type(os);
dmu_objset_rele(os, FTAG);
- at = strchr(zc->zc_name, '@');
- if (at != NULL) {
- /* snaps must be in same fs */
- int error;
-
- if (strncmp(zc->zc_name, zc->zc_value, at - zc->zc_name + 1))
- return (SET_ERROR(EXDEV));
- *at = '\0';
- if (ost == DMU_OST_ZFS && !allow_mounted) {
- error = dmu_objset_find(zc->zc_name,
- recursive_unmount, at + 1,
- recursive ? DS_FIND_CHILDREN : 0);
- if (error != 0) {
- *at = '@';
- return (error);
+ pos = strchr(zc->zc_name, '@');
+ if (pos != NULL) {
+ /* Snapshots must be in same fs. */
+ pos2 = strchr(zc->zc_value, '@');
+ if (pos2 == NULL)
+ return (SET_ERROR(EINVAL));
+ *pos = '\0';
+ *pos2 = '\0';
+ if (strcmp(zc->zc_name, zc->zc_value) != 0) {
+ err = SET_ERROR(EXDEV);
+ } else {
+ if (ost == DMU_OST_ZFS && !allow_mounted) {
+ err = dmu_objset_find(zc->zc_name,
+ recursive_unmount, pos + 1,
+ recursive ? DS_FIND_CHILDREN : 0);
+ }
+ if (err == 0) {
+ err = dsl_dataset_rename_snapshot(zc->zc_name,
+ pos + 1, pos2 + 1, recursive);
}
}
- error = dsl_dataset_rename_snapshot(zc->zc_name,
- at + 1, strchr(zc->zc_value, '@') + 1, recursive);
- *at = '@';
-
- return (error);
+ *pos = '@';
+ *pos2 = '@';
+ return (err);
} else {
#ifdef illumos
if (ost == DMU_OST_ZVOL)
@@ -6352,8 +6393,6 @@ zfs_ioctl_init(void)
zfs_secpolicy_none);
zfs_ioctl_register_dataset_modify(ZFS_IOC_DESTROY, zfs_ioc_destroy,
zfs_secpolicy_destroy);
- zfs_ioctl_register_dataset_modify(ZFS_IOC_RENAME, zfs_ioc_rename,
- zfs_secpolicy_rename);
zfs_ioctl_register_dataset_modify(ZFS_IOC_RECV, zfs_ioc_recv,
zfs_secpolicy_recv);
zfs_ioctl_register_dataset_modify(ZFS_IOC_PROMOTE, zfs_ioc_promote,
@@ -6363,6 +6402,14 @@ zfs_ioctl_init(void)
zfs_ioctl_register_dataset_modify(ZFS_IOC_SET_FSACL, zfs_ioc_set_fsacl,
zfs_secpolicy_set_fsacl);
+ /*
+ * Not using zfs_ioctl_register_dataset_modify as DATASET_NAME check
+ * won't allow a bookmark name.
+ */
+ zfs_ioctl_register_legacy(ZFS_IOC_RENAME, zfs_ioc_rename,
+ zfs_secpolicy_rename, ENTITY_NAME, B_TRUE,
+ POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY);
+
zfs_ioctl_register_dataset_nolog(ZFS_IOC_SHARE, zfs_ioc_share,
zfs_secpolicy_share, POOL_CHECK_NONE);
zfs_ioctl_register_dataset_nolog(ZFS_IOC_SMB_ACL, zfs_ioc_smb_acl,
@@ -6392,7 +6439,8 @@ pool_status_check(const char *name, zfs_ioc_namecheck_t type,
spa_t *spa;
int error;
- ASSERT(type == POOL_NAME || type == DATASET_NAME);
+ ASSERT(type == POOL_NAME || type == DATASET_NAME ||
+ type == ENTITY_NAME);
if (check & POOL_CHECK_NONE)
return (0);
@@ -6725,6 +6773,15 @@ zfsdev_ioctl(struct cdev *dev, u_long zcmd, caddr_t arg, int flag,
vec->zvec_namecheck, vec->zvec_pool_check);
break;
+ case ENTITY_NAME:
+ if (entity_namecheck(zc->zc_name, NULL, NULL) != 0) {
+ error = SET_ERROR(EINVAL);
+ } else {
+ error = pool_status_check(zc->zc_name,
+ vec->zvec_namecheck, vec->zvec_pool_check);
+ }
+ break;
+
case NO_NAME:
break;
}