mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-25 11:47:43 +03:00
Illumos 4368, 4369.
4369 implement zfs bookmarks 4368 zfs send filesystems from readonly pools Reviewed by: Christopher Siden <christopher.siden@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Approved by: Garrett D'Amore <garrett@damore.org> References: https://www.illumos.org/issues/4369 https://www.illumos.org/issues/4368 https://github.com/illumos/illumos-gate/commit/78f1710 Ported by: Tim Chase <tim@chase2k.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #2530
This commit is contained in:
committed by
Brian Behlendorf
parent
b0bc7a84d9
commit
da536844d5
+191
-35
@@ -180,6 +180,7 @@
|
||||
|
||||
#include <sys/dmu_send.h>
|
||||
#include <sys/dsl_destroy.h>
|
||||
#include <sys/dsl_bookmark.h>
|
||||
#include <sys/dsl_userhold.h>
|
||||
#include <sys/zfeature.h>
|
||||
|
||||
@@ -812,22 +813,9 @@ zfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
|
||||
return (SET_ERROR(EINVAL));
|
||||
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
|
||||
pair = nextpair) {
|
||||
dsl_pool_t *dp;
|
||||
dsl_dataset_t *ds;
|
||||
|
||||
error = dsl_pool_hold(nvpair_name(pair), FTAG, &dp);
|
||||
if (error != 0)
|
||||
break;
|
||||
nextpair = nvlist_next_nvpair(snaps, pair);
|
||||
error = dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds);
|
||||
if (error == 0)
|
||||
dsl_dataset_rele(ds, FTAG);
|
||||
dsl_pool_rele(dp, FTAG);
|
||||
|
||||
if (error == 0) {
|
||||
error = zfs_secpolicy_destroy_perms(nvpair_name(pair),
|
||||
cr);
|
||||
} else if (error == ENOENT) {
|
||||
error = zfs_secpolicy_destroy_perms(nvpair_name(pair), cr);
|
||||
if (error == ENOENT) {
|
||||
/*
|
||||
* Ignore any snapshots that don't exist (we consider
|
||||
* them "already destroyed"). Remove the name from the
|
||||
@@ -986,6 +974,76 @@ zfs_secpolicy_snapshot(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for permission to create each snapshot in the nvlist.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
zfs_secpolicy_bookmark(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
|
||||
{
|
||||
int error = 0;
|
||||
nvpair_t *pair;
|
||||
|
||||
for (pair = nvlist_next_nvpair(innvl, NULL);
|
||||
pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) {
|
||||
char *name = nvpair_name(pair);
|
||||
char *hashp = strchr(name, '#');
|
||||
|
||||
if (hashp == NULL) {
|
||||
error = SET_ERROR(EINVAL);
|
||||
break;
|
||||
}
|
||||
*hashp = '\0';
|
||||
error = zfs_secpolicy_write_perms(name,
|
||||
ZFS_DELEG_PERM_BOOKMARK, cr);
|
||||
*hashp = '#';
|
||||
if (error != 0)
|
||||
break;
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
zfs_secpolicy_destroy_bookmarks(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
|
||||
{
|
||||
nvpair_t *pair, *nextpair;
|
||||
int error = 0;
|
||||
|
||||
for (pair = nvlist_next_nvpair(innvl, NULL); pair != NULL;
|
||||
pair = nextpair) {
|
||||
char *name = nvpair_name(pair);
|
||||
char *hashp = strchr(name, '#');
|
||||
nextpair = nvlist_next_nvpair(innvl, pair);
|
||||
|
||||
if (hashp == NULL) {
|
||||
error = SET_ERROR(EINVAL);
|
||||
break;
|
||||
}
|
||||
|
||||
*hashp = '\0';
|
||||
error = zfs_secpolicy_write_perms(name,
|
||||
ZFS_DELEG_PERM_DESTROY, cr);
|
||||
*hashp = '#';
|
||||
if (error == ENOENT) {
|
||||
/*
|
||||
* Ignore any filesystems that don't exist (we consider
|
||||
* their bookmarks "already destroyed"). Remove
|
||||
* the name from the nvl here in case the filesystem
|
||||
* is created between now and when we try to destroy
|
||||
* the bookmark (in which case we don't want to
|
||||
* destroy it since we haven't checked for permission).
|
||||
*/
|
||||
fnvlist_remove_nvpair(innvl, pair);
|
||||
error = 0;
|
||||
}
|
||||
if (error != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
zfs_secpolicy_log_history(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
|
||||
@@ -2551,7 +2609,6 @@ zfs_check_userprops(const char *fsname, nvlist_t *nvl)
|
||||
|
||||
while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) {
|
||||
const char *propname = nvpair_name(pair);
|
||||
char *valstr;
|
||||
|
||||
if (!zfs_prop_user(propname) ||
|
||||
nvpair_type(pair) != DATA_TYPE_STRING)
|
||||
@@ -2564,8 +2621,7 @@ zfs_check_userprops(const char *fsname, nvlist_t *nvl)
|
||||
if (strlen(propname) >= ZAP_MAXNAMELEN)
|
||||
return (SET_ERROR(ENAMETOOLONG));
|
||||
|
||||
VERIFY(nvpair_value_string(pair, &valstr) == 0);
|
||||
if (strlen(valstr) >= ZAP_MAXVALUELEN)
|
||||
if (strlen(fnvpair_value_string(pair)) >= ZAP_MAXVALUELEN)
|
||||
return (SET_ERROR(E2BIG));
|
||||
}
|
||||
return (0);
|
||||
@@ -3242,7 +3298,8 @@ zfs_ioc_snapshot(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||
* The snap name must contain an @, and the part after it must
|
||||
* contain only valid characters.
|
||||
*/
|
||||
if (cp == NULL || snapshot_namecheck(cp + 1, NULL, NULL) != 0)
|
||||
if (cp == NULL ||
|
||||
zfs_component_namecheck(cp + 1, NULL, NULL) != 0)
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
/*
|
||||
@@ -3396,10 +3453,10 @@ zfs_destroy_unmount_origin(const char *fsname)
|
||||
*
|
||||
* outnvl: snapshot -> error code (int32)
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||
{
|
||||
int error, poollen;
|
||||
nvlist_t *snaps;
|
||||
nvpair_t *pair;
|
||||
boolean_t defer;
|
||||
@@ -3408,27 +3465,112 @@ zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||
return (SET_ERROR(EINVAL));
|
||||
defer = nvlist_exists(innvl, "defer");
|
||||
|
||||
poollen = strlen(poolname);
|
||||
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
|
||||
pair = nvlist_next_nvpair(snaps, pair)) {
|
||||
const char *name = nvpair_name(pair);
|
||||
|
||||
/*
|
||||
* The snap must be in the specified pool.
|
||||
*/
|
||||
if (strncmp(name, poolname, poollen) != 0 ||
|
||||
(name[poollen] != '/' && name[poollen] != '@'))
|
||||
return (SET_ERROR(EXDEV));
|
||||
|
||||
error = zfs_unmount_snap(name);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
(void) zvol_remove_minor(name);
|
||||
(void) zfs_unmount_snap(nvpair_name(pair));
|
||||
(void) zvol_remove_minor(nvpair_name(pair));
|
||||
}
|
||||
|
||||
return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create bookmarks. Bookmark names are of the form <fs>#<bmark>.
|
||||
* All bookmarks must be in the same pool.
|
||||
*
|
||||
* innvl: {
|
||||
* bookmark1 -> snapshot1, bookmark2 -> snapshot2
|
||||
* }
|
||||
*
|
||||
* outnvl: bookmark -> error code (int32)
|
||||
*
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
zfs_ioc_bookmark(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||
{
|
||||
nvpair_t *pair, *pair2;
|
||||
|
||||
for (pair = nvlist_next_nvpair(innvl, NULL);
|
||||
pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) {
|
||||
char *snap_name;
|
||||
|
||||
/*
|
||||
* Verify the snapshot argument.
|
||||
*/
|
||||
if (nvpair_value_string(pair, &snap_name) != 0)
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
|
||||
/* Verify that the keys (bookmarks) are unique */
|
||||
for (pair2 = nvlist_next_nvpair(innvl, pair);
|
||||
pair2 != NULL; pair2 = nvlist_next_nvpair(innvl, pair2)) {
|
||||
if (strcmp(nvpair_name(pair), nvpair_name(pair2)) == 0)
|
||||
return (SET_ERROR(EINVAL));
|
||||
}
|
||||
}
|
||||
|
||||
return (dsl_bookmark_create(innvl, outnvl));
|
||||
}
|
||||
|
||||
/*
|
||||
* innvl: {
|
||||
* property 1, property 2, ...
|
||||
* }
|
||||
*
|
||||
* outnvl: {
|
||||
* bookmark name 1 -> { property 1, property 2, ... },
|
||||
* bookmark name 2 -> { property 1, property 2, ... }
|
||||
* }
|
||||
*
|
||||
*/
|
||||
static int
|
||||
zfs_ioc_get_bookmarks(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
|
||||
{
|
||||
return (dsl_get_bookmarks(fsname, innvl, outnvl));
|
||||
}
|
||||
|
||||
/*
|
||||
* innvl: {
|
||||
* bookmark name 1, bookmark name 2
|
||||
* }
|
||||
*
|
||||
* outnvl: bookmark -> error code (int32)
|
||||
*
|
||||
*/
|
||||
static int
|
||||
zfs_ioc_destroy_bookmarks(const char *poolname, nvlist_t *innvl,
|
||||
nvlist_t *outnvl)
|
||||
{
|
||||
int error, poollen;
|
||||
nvpair_t *pair;
|
||||
|
||||
poollen = strlen(poolname);
|
||||
for (pair = nvlist_next_nvpair(innvl, NULL);
|
||||
pair != NULL; pair = nvlist_next_nvpair(innvl, pair)) {
|
||||
const char *name = nvpair_name(pair);
|
||||
const char *cp = strchr(name, '#');
|
||||
|
||||
/*
|
||||
* The bookmark name must contain an #, and the part after it
|
||||
* must contain only valid characters.
|
||||
*/
|
||||
if (cp == NULL ||
|
||||
zfs_component_namecheck(cp + 1, NULL, NULL) != 0)
|
||||
return (SET_ERROR(EINVAL));
|
||||
|
||||
/*
|
||||
* The bookmark must be in the specified pool.
|
||||
*/
|
||||
if (strncmp(name, poolname, poollen) != 0 ||
|
||||
(name[poollen] != '/' && name[poollen] != '#'))
|
||||
return (SET_ERROR(EXDEV));
|
||||
}
|
||||
|
||||
error = dsl_bookmark_destroy(innvl, outnvl);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* inputs:
|
||||
* zc_name name of dataset to destroy
|
||||
@@ -4097,7 +4239,8 @@ out:
|
||||
* zc_guid if set, estimate size of stream only. zc_cookie is ignored.
|
||||
* output size in zc_objset_type.
|
||||
*
|
||||
* outputs: none
|
||||
* outputs:
|
||||
* zc_objset_type estimated size, if zc_guid is set
|
||||
*/
|
||||
static int
|
||||
zfs_ioc_send(zfs_cmd_t *zc)
|
||||
@@ -5272,6 +5415,19 @@ zfs_ioctl_init(void)
|
||||
zfs_ioc_rollback, zfs_secpolicy_rollback, DATASET_NAME,
|
||||
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_TRUE);
|
||||
|
||||
zfs_ioctl_register("bookmark", ZFS_IOC_BOOKMARK,
|
||||
zfs_ioc_bookmark, zfs_secpolicy_bookmark, POOL_NAME,
|
||||
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
|
||||
|
||||
zfs_ioctl_register("get_bookmarks", ZFS_IOC_GET_BOOKMARKS,
|
||||
zfs_ioc_get_bookmarks, zfs_secpolicy_read, DATASET_NAME,
|
||||
POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE);
|
||||
|
||||
zfs_ioctl_register("destroy_bookmarks", ZFS_IOC_DESTROY_BOOKMARKS,
|
||||
zfs_ioc_destroy_bookmarks, zfs_secpolicy_destroy_bookmarks,
|
||||
POOL_NAME,
|
||||
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
|
||||
|
||||
/* IOCTLS that use the legacy function signature */
|
||||
|
||||
zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze,
|
||||
|
||||
Reference in New Issue
Block a user