It is possible to recursively destroy snapshots even if the snapshot

doesn't exist on a dataset we are starting from. For example if we
have the following configuration:

	tank
	tank/foo
	tank/foo@snap
	tank/bar
	tank/bar@snap

We can execute:

	# zfs destroy -t tank@snap

eventhough tank@snap doesn't exit.

Unfortunately it is not possible to do the same with recursive rename:

	# zfs rename -r tank@snap tank@pans
	cannot open 'tank@snap': dataset does not exist

...until now. This change allows to recursively rename snapshots even if
snapshot doesn't exist on the starting dataset.

Sponsored by:	rsync.net
MFC after:	2 weeks
This commit is contained in:
Pawel Jakub Dawidek 2012-09-23 20:12:10 +00:00
parent c2257f93ba
commit c622f88dd2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=240870
5 changed files with 75 additions and 6 deletions

View File

@ -3081,6 +3081,7 @@ zfs_do_rename(int argc, char **argv)
int ret = 0;
int types;
boolean_t parents = B_FALSE;
char *snapshot = NULL;
/* check options */
while ((c = getopt(argc, argv, "fpru")) != -1) {
@ -3149,6 +3150,19 @@ zfs_do_rename(int argc, char **argv)
else
types = ZFS_TYPE_DATASET;
if (flags.recurse) {
/*
* When we do recursive rename we are fine when the given
* snapshot for the given dataset doesn't exist - it can
* still exists below.
*/
snapshot = strchr(argv[0], '@');
assert(snapshot != NULL);
*snapshot = '\0';
snapshot++;
}
if ((zhp = zfs_open(g_zfs, argv[0], types)) == NULL)
return (1);
@ -3159,7 +3173,7 @@ zfs_do_rename(int argc, char **argv)
return (1);
}
ret = (zfs_rename(zhp, argv[1], flags) != 0);
ret = (zfs_rename(zhp, snapshot, argv[1], flags) != 0);
zfs_close(zhp);
return (ret);

View File

@ -571,7 +571,8 @@ typedef struct renameflags {
int forceunmount : 1;
} renameflags_t;
extern int zfs_rename(zfs_handle_t *, const char *, renameflags_t flags);
extern int zfs_rename(zfs_handle_t *, const char *, const char *,
renameflags_t flags);
typedef struct sendflags {
/* print informational messages (ie, -v was specified) */

View File

@ -611,6 +611,22 @@ zfs_open(libzfs_handle_t *hdl, const char *path, int types)
return (NULL);
}
if (zhp == NULL) {
char *at = strchr(path, '@');
if (at != NULL)
*at = '\0';
errno = 0;
if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
(void) zfs_standard_error(hdl, errno, errbuf);
return (NULL);
}
if (at != NULL)
*at = '@';
(void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
}
if (!(types & zhp->zfs_type)) {
(void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
zfs_close(zhp);
@ -3614,7 +3630,8 @@ zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
* Renames the given dataset.
*/
int
zfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags)
zfs_rename(zfs_handle_t *zhp, const char *source, const char *target,
renameflags_t flags)
{
int ret;
zfs_cmd_t zc = { 0 };
@ -3634,6 +3651,18 @@ zfs_rename(zfs_handle_t *zhp, const char *target, renameflags_t flags)
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot rename to '%s'"), target);
if (source != NULL) {
/*
* This is recursive snapshots rename, put snapshot name
* (that might not exist) into zfs_name.
*/
assert(flags.recurse);
(void) strlcat(zhp->zfs_name, "@", sizeof(zhp->zfs_name));
(void) strlcat(zhp->zfs_name, source, sizeof(zhp->zfs_name));
zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
}
/*
* Make sure the target name is valid
*/

View File

@ -2520,6 +2520,7 @@ struct renamesnaparg {
char failed[MAXPATHLEN];
char *oldsnap;
char *newsnap;
int error;
};
static int
@ -2557,6 +2558,9 @@ dsl_snapshot_rename_one(const char *name, void *arg)
dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check,
dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0);
/* First successful rename clears the error. */
ra->error = 0;
return (0);
}
@ -2585,14 +2589,16 @@ dsl_recursive_rename(char *oldname, const char *newname)
ra->oldsnap = strchr(oldname, '@') + 1;
ra->newsnap = strchr(newname, '@') + 1;
*ra->failed = '\0';
ra->error = ENOENT;
err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra,
DS_FIND_CHILDREN);
kmem_free(fsname, len);
if (err == 0)
err = ra->error;
if (err == 0) {
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)) {

View File

@ -766,7 +766,26 @@ zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
static int
zfs_secpolicy_rename(zfs_cmd_t *zc, cred_t *cr)
{
return (zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr));
char *at = NULL;
int error;
if ((zc->zc_cookie & 1) != 0) {
/*
* This is recursive rename, so the starting snapshot might
* not exist. Check file system or volume permission instead.
*/
at = strchr(zc->zc_name, '@');
if (at == NULL)
return (EINVAL);
*at = '\0';
}
error = zfs_secpolicy_rename_perms(zc->zc_name, zc->zc_value, cr);
if (at != NULL)
*at = '@';
return (error);
}
static int