OpenZFS 9630 - add lzc_rename and lzc_destroy to libzfs_core

Porting Notes:
* Additional changes to recv_rename_impl() were required due to
  encryption code not being merged in OpenZFS yet.
* libzfs_core python bindings (pyzfs) were updated to fully support
  both lzc_rename() and lzc_destroy()

Authored by: Andriy Gapon <avg@FreeBSD.org>
Reviewed by: Andy Stormont <astormont@racktopsystems.com>
Reviewed by: Matt Ahrens <matt@delphix.com>
Reviewed by: Serapheim Dimitropoulos <serapheim.dimitro@delphix.com>
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Approved by: Dan McDonald <danmcd@joyent.com>
Ported-by: loli10K <ezomori.nozomu@gmail.com>

OpenZFS-issue: https://www.illumos.org/issues/9630
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/049ba63
Closes #8207
This commit is contained in:
Andriy Gapon 2018-06-28 00:37:54 +03:00 committed by Brian Behlendorf
parent eff7d78f8a
commit dc1c630b8a
8 changed files with 81 additions and 51 deletions

View File

@ -1605,7 +1605,6 @@ def lzc_pool_checkpoint_discard(name):
errors.lzc_pool_checkpoint_discard_translate_error(ret, name) errors.lzc_pool_checkpoint_discard_translate_error(ret, name)
@_uncommitted()
def lzc_rename(source, target): def lzc_rename(source, target):
''' '''
Rename the ZFS dataset. Rename the ZFS dataset.
@ -1621,12 +1620,11 @@ def lzc_rename(source, target):
:raises FilesystemExists: if the target already exists. :raises FilesystemExists: if the target already exists.
:raises PoolsDiffer: if the source and target belong to different pools. :raises PoolsDiffer: if the source and target belong to different pools.
''' '''
ret = _lib.lzc_rename(source, target, _ffi.NULL, _ffi.NULL) ret = _lib.lzc_rename(source, target)
errors.lzc_rename_translate_error(ret, source, target) errors.lzc_rename_translate_error(ret, source, target)
@_uncommitted() def lzc_destroy(name):
def lzc_destroy_one(name):
''' '''
Destroy the ZFS dataset. Destroy the ZFS dataset.
@ -1635,16 +1633,10 @@ def lzc_destroy_one(name):
:raises NameTooLong: if the dataset name is too long. :raises NameTooLong: if the dataset name is too long.
:raises FilesystemNotFound: if the dataset does not exist. :raises FilesystemNotFound: if the dataset does not exist.
''' '''
ret = _lib.lzc_destroy_one(name, _ffi.NULL) ret = _lib.lzc_destroy(name)
errors.lzc_destroy_translate_error(ret, name) errors.lzc_destroy_translate_error(ret, name)
# As the extended API is not committed yet, the names of the new interfaces
# are not settled down yet.
# lzc_destroy() might make more sense as we do not have lzc_create_one().
lzc_destroy = lzc_destroy_one
@_uncommitted() @_uncommitted()
def lzc_inherit(name, prop): def lzc_inherit(name, prop):
''' '''

View File

@ -129,9 +129,9 @@ CDEF = """
int lzc_remap(const char *); int lzc_remap(const char *);
int lzc_pool_checkpoint(const char *); int lzc_pool_checkpoint(const char *);
int lzc_pool_checkpoint_discard(const char *); int lzc_pool_checkpoint_discard(const char *);
int lzc_rename(const char *, const char *);
int lzc_destroy(const char *fsname);
int lzc_rename(const char *, const char *, nvlist_t *, char **);
int lzc_destroy_one(const char *fsname, nvlist_t *);
int lzc_inherit(const char *fsname, const char *name, nvlist_t *); int lzc_inherit(const char *fsname, const char *name, nvlist_t *);
int lzc_set_props(const char *, nvlist_t *, nvlist_t *, nvlist_t *); int lzc_set_props(const char *, nvlist_t *, nvlist_t *, nvlist_t *);
int lzc_list (const char *, nvlist_t *); int lzc_list (const char *, nvlist_t *);

View File

@ -102,6 +102,9 @@ boolean_t lzc_exists(const char *);
int lzc_rollback(const char *, char *, int); int lzc_rollback(const char *, char *, int);
int lzc_rollback_to(const char *, const char *); int lzc_rollback_to(const char *, const char *);
int lzc_rename(const char *, const char *);
int lzc_destroy(const char *);
int lzc_channel_program(const char *, const char *, uint64_t, int lzc_channel_program(const char *, const char *, uint64_t,
uint64_t, nvlist_t *, nvlist_t **); uint64_t, nvlist_t *, nvlist_t **);
int lzc_channel_program_nosync(const char *, const char *, uint64_t, int lzc_channel_program_nosync(const char *, const char *, uint64_t,

View File

@ -3856,32 +3856,34 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
int int
zfs_destroy(zfs_handle_t *zhp, boolean_t defer) zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
{ {
zfs_cmd_t zc = {"\0"}; int error;
if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT && defer)
return (EINVAL);
if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) { if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
nvlist_t *nv = fnvlist_alloc(); nvlist_t *nv = fnvlist_alloc();
fnvlist_add_boolean(nv, zhp->zfs_name); fnvlist_add_boolean(nv, zhp->zfs_name);
int error = lzc_destroy_bookmarks(nv, NULL); error = lzc_destroy_bookmarks(nv, NULL);
fnvlist_free(nv); fnvlist_free(nv);
if (error != 0) { if (error != 0) {
return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, return (zfs_standard_error_fmt(zhp->zfs_hdl, error,
dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
zhp->zfs_name)); zhp->zfs_name));
} }
return (0); return (0);
} }
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name)); if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
nvlist_t *nv = fnvlist_alloc();
if (ZFS_IS_VOLUME(zhp)) { fnvlist_add_boolean(nv, zhp->zfs_name);
zc.zc_objset_type = DMU_OST_ZVOL; error = lzc_destroy_snaps(nv, defer, NULL);
fnvlist_free(nv);
} else { } else {
zc.zc_objset_type = DMU_OST_ZFS; error = lzc_destroy(zhp->zfs_name);
} }
zc.zc_defer_destroy = defer; if (error != 0 && error != ENOENT) {
if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 &&
errno != ENOENT) {
return (zfs_standard_error_fmt(zhp->zfs_hdl, errno, return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
dgettext(TEXT_DOMAIN, "cannot destroy '%s'"), dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
zhp->zfs_name)); zhp->zfs_name));

View File

@ -2294,7 +2294,7 @@ recv_open_grand_origin(zfs_handle_t *zhp)
} }
static int static int
recv_rename_impl(zfs_handle_t *zhp, zfs_cmd_t *zc) recv_rename_impl(zfs_handle_t *zhp, const char *name, const char *newname)
{ {
int err; int err;
zfs_handle_t *ozhp = NULL; zfs_handle_t *ozhp = NULL;
@ -2304,7 +2304,7 @@ recv_rename_impl(zfs_handle_t *zhp, zfs_cmd_t *zc)
* attempted to rename the dataset outside of its encryption root. * attempted to rename the dataset outside of its encryption root.
* Force the dataset to become an encryption root and try again. * Force the dataset to become an encryption root and try again.
*/ */
err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc); err = lzc_rename(name, newname);
if (err == EACCES) { if (err == EACCES) {
ozhp = recv_open_grand_origin(zhp); ozhp = recv_open_grand_origin(zhp);
if (ozhp == NULL) { if (ozhp == NULL) {
@ -2317,7 +2317,7 @@ recv_rename_impl(zfs_handle_t *zhp, zfs_cmd_t *zc)
if (err != 0) if (err != 0)
goto out; goto out;
err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_RENAME, &zc); err = lzc_rename(name, newname);
} }
out: out:
@ -2331,7 +2331,6 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
int baselen, char *newname, recvflags_t *flags) int baselen, char *newname, recvflags_t *flags)
{ {
static int seq; static int seq;
zfs_cmd_t zc = {"\0"};
int err; int err;
prop_changelist_t *clp = NULL; prop_changelist_t *clp = NULL;
zfs_handle_t *zhp = NULL; zfs_handle_t *zhp = NULL;
@ -2351,19 +2350,13 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
if (err) if (err)
goto out; goto out;
zc.zc_objset_type = DMU_OST_ZFS;
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
if (tryname) { if (tryname) {
(void) strcpy(newname, tryname); (void) strcpy(newname, tryname);
(void) strlcpy(zc.zc_value, tryname, sizeof (zc.zc_value));
if (flags->verbose) { if (flags->verbose) {
(void) printf("attempting rename %s to %s\n", (void) printf("attempting rename %s to %s\n",
zc.zc_name, zc.zc_value); name, newname);
} }
err = recv_rename_impl(zhp, &zc); err = recv_rename_impl(zhp, name, newname);
if (err == 0) if (err == 0)
changelist_rename(clp, name, tryname); changelist_rename(clp, name, tryname);
} else { } else {
@ -2375,13 +2368,12 @@ recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
(void) snprintf(newname, ZFS_MAX_DATASET_NAME_LEN, (void) snprintf(newname, ZFS_MAX_DATASET_NAME_LEN,
"%.*srecv-%u-%u", baselen, name, getpid(), seq); "%.*srecv-%u-%u", baselen, name, getpid(), seq);
(void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value));
if (flags->verbose) { if (flags->verbose) {
(void) printf("failed - trying rename %s to %s\n", (void) printf("failed - trying rename %s to %s\n",
zc.zc_name, zc.zc_value); name, newname);
} }
err = recv_rename_impl(zhp, &zc); err = recv_rename_impl(zhp, name, newname);
if (err == 0) if (err == 0)
changelist_rename(clp, name, newname); changelist_rename(clp, name, newname);
if (err && flags->verbose) { if (err && flags->verbose) {
@ -2461,7 +2453,6 @@ static int
recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen, recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
char *newname, recvflags_t *flags) char *newname, recvflags_t *flags)
{ {
zfs_cmd_t zc = {"\0"};
int err = 0; int err = 0;
prop_changelist_t *clp; prop_changelist_t *clp;
zfs_handle_t *zhp; zfs_handle_t *zhp;
@ -2484,17 +2475,20 @@ recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
if (err) if (err)
return (err); return (err);
zc.zc_objset_type = DMU_OST_ZFS;
zc.zc_defer_destroy = defer;
(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
if (flags->verbose) if (flags->verbose)
(void) printf("attempting destroy %s\n", zc.zc_name); (void) printf("attempting destroy %s\n", name);
err = ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc); if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
nvlist_t *nv = fnvlist_alloc();
fnvlist_add_boolean(nv, name);
err = lzc_destroy_snaps(nv, defer, NULL);
fnvlist_free(nv);
} else {
err = lzc_destroy(name);
}
if (err == 0) { if (err == 0) {
if (flags->verbose) if (flags->verbose)
(void) printf("success\n"); (void) printf("success\n");
changelist_remove(clp, zc.zc_name); changelist_remove(clp, name);
} }
(void) changelist_postfix(clp); (void) changelist_postfix(clp);

View File

@ -316,6 +316,30 @@ lzc_remap(const char *fsname)
return (error); return (error);
} }
int
lzc_rename(const char *source, const char *target)
{
zfs_cmd_t zc = { "\0" };
int error;
ASSERT3S(g_refcount, >, 0);
VERIFY3S(g_fd, !=, -1);
(void) strlcpy(zc.zc_name, source, sizeof (zc.zc_name));
(void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
error = ioctl(g_fd, ZFS_IOC_RENAME, &zc);
if (error != 0)
error = errno;
return (error);
}
int
lzc_destroy(const char *fsname)
{
int error;
nvlist_t *args = fnvlist_alloc();
error = lzc_ioctl(ZFS_IOC_DESTROY, fsname, args, NULL);
nvlist_free(args);
return (error);
}
/* /*
* Creates snapshots. * Creates snapshots.
* *

View File

@ -3785,7 +3785,6 @@ zfs_ioc_pool_discard_checkpoint(const char *poolname, nvlist_t *innvl,
/* /*
* inputs: * inputs:
* zc_name name of dataset to destroy * zc_name name of dataset to destroy
* zc_objset_type type of objset
* zc_defer_destroy mark for deferred destroy * zc_defer_destroy mark for deferred destroy
* *
* outputs: none * outputs: none
@ -3793,9 +3792,17 @@ zfs_ioc_pool_discard_checkpoint(const char *poolname, nvlist_t *innvl,
static int static int
zfs_ioc_destroy(zfs_cmd_t *zc) zfs_ioc_destroy(zfs_cmd_t *zc)
{ {
objset_t *os;
dmu_objset_type_t ost;
int err; int err;
if (zc->zc_objset_type == DMU_OST_ZFS) err = dmu_objset_hold(zc->zc_name, FTAG, &os);
if (err != 0)
return (err);
ost = dmu_objset_type(os);
dmu_objset_rele(os, FTAG);
if (ost == DMU_OST_ZFS)
zfs_unmount_snap(zc->zc_name); zfs_unmount_snap(zc->zc_name);
if (strchr(zc->zc_name, '@')) { if (strchr(zc->zc_name, '@')) {
@ -3917,8 +3924,11 @@ recursive_unmount(const char *fsname, void *arg)
static int static int
zfs_ioc_rename(zfs_cmd_t *zc) zfs_ioc_rename(zfs_cmd_t *zc)
{ {
objset_t *os;
dmu_objset_type_t ost;
boolean_t recursive = zc->zc_cookie & 1; boolean_t recursive = zc->zc_cookie & 1;
char *at; char *at;
int err;
/* "zfs rename" from and to ...%recv datasets should both fail */ /* "zfs rename" from and to ...%recv datasets should both fail */
zc->zc_name[sizeof (zc->zc_name) - 1] = '\0'; zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
@ -3928,6 +3938,12 @@ zfs_ioc_rename(zfs_cmd_t *zc)
strchr(zc->zc_name, '%') || strchr(zc->zc_value, '%')) strchr(zc->zc_name, '%') || strchr(zc->zc_value, '%'))
return (SET_ERROR(EINVAL)); return (SET_ERROR(EINVAL));
err = dmu_objset_hold(zc->zc_name, FTAG, &os);
if (err != 0)
return (err);
ost = dmu_objset_type(os);
dmu_objset_rele(os, FTAG);
at = strchr(zc->zc_name, '@'); at = strchr(zc->zc_name, '@');
if (at != NULL) { if (at != NULL) {
/* snaps must be in same fs */ /* snaps must be in same fs */
@ -3936,7 +3952,7 @@ zfs_ioc_rename(zfs_cmd_t *zc)
if (strncmp(zc->zc_name, zc->zc_value, at - zc->zc_name + 1)) if (strncmp(zc->zc_name, zc->zc_value, at - zc->zc_name + 1))
return (SET_ERROR(EXDEV)); return (SET_ERROR(EXDEV));
*at = '\0'; *at = '\0';
if (zc->zc_objset_type == DMU_OST_ZFS) { if (ost == DMU_OST_ZFS) {
error = dmu_objset_find(zc->zc_name, error = dmu_objset_find(zc->zc_name,
recursive_unmount, at + 1, recursive_unmount, at + 1,
recursive ? DS_FIND_CHILDREN : 0); recursive ? DS_FIND_CHILDREN : 0);

View File

@ -650,7 +650,6 @@ zfs_destroy(const char *dataset)
(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name)); (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
zc.zc_name[sizeof (zc.zc_name) - 1] = '\0'; zc.zc_name[sizeof (zc.zc_name) - 1] = '\0';
zc.zc_objset_type = DMU_OST_ZFS;
err = ioctl(zfs_fd, ZFS_IOC_DESTROY, &zc); err = ioctl(zfs_fd, ZFS_IOC_DESTROY, &zc);
return (err == 0 ? 0 : errno); return (err == 0 ? 0 : errno);