mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 10:37:35 +03:00
Implement Redacted Send/Receive
Redacted send/receive allows users to send subsets of their data to a target system. One possible use case for this feature is to not transmit sensitive information to a data warehousing, test/dev, or analytics environment. Another is to save space by not replicating unimportant data within a given dataset, for example in backup tools like zrepl. Redacted send/receive is a three-stage process. First, a clone (or clones) is made of the snapshot to be sent to the target. In this clone (or clones), all unnecessary or unwanted data is removed or modified. This clone is then snapshotted to create the "redaction snapshot" (or snapshots). Second, the new zfs redact command is used to create a redaction bookmark. The redaction bookmark stores the list of blocks in a snapshot that were modified by the redaction snapshot(s). Finally, the redaction bookmark is passed as a parameter to zfs send. When sending to the snapshot that was redacted, the redaction bookmark is used to filter out blocks that contain sensitive or unwanted information, and those blocks are not included in the send stream. When sending from the redaction bookmark, the blocks it contains are considered as candidate blocks in addition to those blocks in the destination snapshot that were modified since the creation_txg of the redaction bookmark. This step is necessary to allow the target to rehydrate data in the case where some blocks are accidentally or unnecessarily modified in the redaction snapshot. The changes to bookmarks to enable fast space estimation involve adding deadlists to bookmarks. There is also logic to manage the life cycles of these deadlists. The new size estimation process operates in cases where previously an accurate estimate could not be provided. In those cases, a send is performed where no data blocks are read, reducing the runtime significantly and providing a byte-accurate size estimate. Reviewed-by: Dan Kimmel <dan.kimmel@delphix.com> Reviewed-by: Matt Ahrens <mahrens@delphix.com> Reviewed-by: Prashanth Sreenivasa <pks@delphix.com> Reviewed-by: John Kennedy <john.kennedy@delphix.com> Reviewed-by: George Wilson <george.wilson@delphix.com> Reviewed-by: Chris Williamson <chris.williamson@delphix.com> Reviewed-by: Pavel Zhakarov <pavel.zakharov@delphix.com> Reviewed-by: Sebastien Roy <sebastien.roy@delphix.com> Reviewed-by: Prakash Surya <prakash.surya@delphix.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Paul Dagnelie <pcd@delphix.com> Closes #7958
This commit is contained in:
committed by
Brian Behlendorf
parent
c1b5801bb5
commit
30af21b025
@@ -22,7 +22,7 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, Joyent, Inc. All rights reserved.
|
||||
* Copyright (c) 2011, 2017 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2011, 2018 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
|
||||
* Copyright (c) 2013 Martin Matuska. All rights reserved.
|
||||
@@ -597,7 +597,6 @@ zfs_bookmark_exists(const char *path)
|
||||
int err;
|
||||
boolean_t rv;
|
||||
|
||||
|
||||
(void) strlcpy(fsname, path, sizeof (fsname));
|
||||
pound = strchr(fsname, '#');
|
||||
if (pound == NULL)
|
||||
@@ -2408,6 +2407,10 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
|
||||
*val = zhp->zfs_dmustats.dds_inconsistent;
|
||||
break;
|
||||
|
||||
case ZFS_PROP_REDACTED:
|
||||
*val = zhp->zfs_dmustats.dds_redacted;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (zfs_prop_get_type(prop)) {
|
||||
case PROP_TYPE_NUMBER:
|
||||
@@ -2620,6 +2623,37 @@ zfs_get_clones_nvl(zfs_handle_t *zhp)
|
||||
return (value);
|
||||
}
|
||||
|
||||
static int
|
||||
get_rsnaps_string(zfs_handle_t *zhp, char *propbuf, size_t proplen)
|
||||
{
|
||||
nvlist_t *value;
|
||||
uint64_t *snaps;
|
||||
uint_t nsnaps;
|
||||
|
||||
if (nvlist_lookup_nvlist(zhp->zfs_props,
|
||||
zfs_prop_to_name(ZFS_PROP_REDACT_SNAPS), &value) != 0)
|
||||
return (-1);
|
||||
if (nvlist_lookup_uint64_array(value, ZPROP_VALUE, &snaps,
|
||||
&nsnaps) != 0)
|
||||
return (-1);
|
||||
if (nsnaps == 0) {
|
||||
/* There's no redaction snapshots; pass a special value back */
|
||||
(void) snprintf(propbuf, proplen, "none");
|
||||
return (0);
|
||||
}
|
||||
propbuf[0] = '\0';
|
||||
for (int i = 0; i < nsnaps; i++) {
|
||||
char buf[128];
|
||||
if (propbuf[0] != '\0')
|
||||
(void) strlcat(propbuf, ",", proplen);
|
||||
(void) snprintf(buf, sizeof (buf), "%llu",
|
||||
(u_longlong_t)snaps[i]);
|
||||
(void) strlcat(propbuf, buf, proplen);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accepts a property and value and checks that the value
|
||||
* matches the one found by the channel program. If they are
|
||||
@@ -2814,6 +2848,11 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
||||
zcp_check(zhp, prop, 0, str);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_REDACT_SNAPS:
|
||||
if (get_rsnaps_string(zhp, propbuf, proplen) != 0)
|
||||
return (-1);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_CLONES:
|
||||
if (get_clones_string(zhp, propbuf, proplen) != 0)
|
||||
return (-1);
|
||||
@@ -3333,6 +3372,9 @@ zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* propname must start with "written@" or "written#".
|
||||
*/
|
||||
int
|
||||
zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
|
||||
uint64_t *propvalue)
|
||||
@@ -3343,8 +3385,10 @@ zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
|
||||
|
||||
(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
|
||||
|
||||
snapname = strchr(propname, '@') + 1;
|
||||
if (strchr(snapname, '@')) {
|
||||
assert(zfs_prop_written(propname));
|
||||
snapname = propname + strlen("written@");
|
||||
if (strchr(snapname, '@') != NULL || strchr(snapname, '#') != NULL) {
|
||||
/* full snapshot or bookmark name specified */
|
||||
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
|
||||
} else {
|
||||
/* snapname is the short name, append it to zhp's fsname */
|
||||
@@ -3355,8 +3399,7 @@ zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
|
||||
cp = strchr(zc.zc_value, '@');
|
||||
if (cp != NULL)
|
||||
*cp = '\0';
|
||||
(void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value));
|
||||
(void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value));
|
||||
(void) strlcat(zc.zc_value, snapname - 1, sizeof (zc.zc_value));
|
||||
}
|
||||
|
||||
err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2015 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2013, 2019 by Delphix. All rights reserved.
|
||||
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2019 Datto Inc.
|
||||
*/
|
||||
@@ -212,10 +212,12 @@ zfs_iter_bookmarks(zfs_handle_t *zhp, zfs_iter_f func, void *data)
|
||||
|
||||
/* Setup the requested properties nvlist. */
|
||||
props = fnvlist_alloc();
|
||||
fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_GUID));
|
||||
fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATETXG));
|
||||
fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATION));
|
||||
fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_IVSET_GUID));
|
||||
for (zfs_prop_t p = 0; p < ZFS_NUM_PROPS; p++) {
|
||||
if (zfs_prop_valid_for_type(p, ZFS_TYPE_BOOKMARK, B_FALSE)) {
|
||||
fnvlist_add_boolean(props, zfs_prop_to_name(p));
|
||||
}
|
||||
}
|
||||
fnvlist_add_boolean(props, "redact_complete");
|
||||
|
||||
if ((err = lzc_get_bookmarks(zhp->zfs_name, props, &bmarks)) != 0)
|
||||
goto out;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
/*
|
||||
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2017 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2014, 2019 by Delphix. All rights reserved.
|
||||
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
|
||||
* Copyright 2017 RackTop Systems.
|
||||
* Copyright (c) 2018 Datto Inc.
|
||||
@@ -306,7 +306,7 @@ zfs_is_mounted(zfs_handle_t *zhp, char **where)
|
||||
*/
|
||||
static boolean_t
|
||||
zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
|
||||
zprop_source_t *source)
|
||||
zprop_source_t *source, int flags)
|
||||
{
|
||||
char sourceloc[MAXNAMELEN];
|
||||
zprop_source_t sourcetype;
|
||||
@@ -329,6 +329,13 @@ zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
|
||||
getzoneid() == GLOBAL_ZONEID)
|
||||
return (B_FALSE);
|
||||
|
||||
if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
|
||||
getzoneid() == GLOBAL_ZONEID)
|
||||
return (B_FALSE);
|
||||
|
||||
if (zfs_prop_get_int(zhp, ZFS_PROP_REDACTED) && !(flags & MS_FORCE))
|
||||
return (B_FALSE);
|
||||
|
||||
if (source)
|
||||
*source = sourcetype;
|
||||
|
||||
@@ -495,8 +502,10 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
|
||||
if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
|
||||
(void) strlcat(mntopts, "," MNTOPT_RO, sizeof (mntopts));
|
||||
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL,
|
||||
flags)) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append default mount options which apply to the mount point.
|
||||
@@ -868,7 +877,7 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
|
||||
zprop_source_t sourcetype;
|
||||
int ret;
|
||||
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL, 0))
|
||||
return (0);
|
||||
|
||||
for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
|
||||
@@ -1135,8 +1144,7 @@ remove_mountpoint(zfs_handle_t *zhp)
|
||||
char mountpoint[ZFS_MAXPROPLEN];
|
||||
zprop_source_t source;
|
||||
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
|
||||
&source))
|
||||
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), &source, 0))
|
||||
return;
|
||||
|
||||
if (source == ZPROP_SRC_DEFAULT ||
|
||||
|
||||
+757
-154
File diff suppressed because it is too large
Load Diff
@@ -468,6 +468,7 @@ zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
|
||||
case EREMOTEIO:
|
||||
zfs_verror(hdl, EZFS_ACTIVE_POOL, fmt, ap);
|
||||
break;
|
||||
case ZFS_ERR_UNKNOWN_SEND_STREAM_FEATURE:
|
||||
case ZFS_ERR_IOC_CMD_UNAVAIL:
|
||||
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "the loaded zfs "
|
||||
"module does not support this operation. A reboot may "
|
||||
|
||||
@@ -632,12 +632,42 @@ int
|
||||
lzc_send(const char *snapname, const char *from, int fd,
|
||||
enum lzc_send_flags flags)
|
||||
{
|
||||
return (lzc_send_resume(snapname, from, fd, flags, 0, 0));
|
||||
return (lzc_send_resume_redacted(snapname, from, fd, flags, 0, 0,
|
||||
NULL));
|
||||
}
|
||||
|
||||
int
|
||||
lzc_send_redacted(const char *snapname, const char *from, int fd,
|
||||
enum lzc_send_flags flags, const char *redactbook)
|
||||
{
|
||||
return (lzc_send_resume_redacted(snapname, from, fd, flags, 0, 0,
|
||||
redactbook));
|
||||
}
|
||||
|
||||
int
|
||||
lzc_send_resume(const char *snapname, const char *from, int fd,
|
||||
enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff)
|
||||
{
|
||||
return (lzc_send_resume_redacted(snapname, from, fd, flags, resumeobj,
|
||||
resumeoff, NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* snapname: The name of the "tosnap", or the snapshot whose contents we are
|
||||
* sending.
|
||||
* from: The name of the "fromsnap", or the incremental source.
|
||||
* fd: File descriptor to write the stream to.
|
||||
* flags: flags that determine features to be used by the stream.
|
||||
* resumeobj: Object to resume from, for resuming send
|
||||
* resumeoff: Offset to resume from, for resuming send.
|
||||
* redactnv: nvlist of string -> boolean(ignored) containing the names of all
|
||||
* the snapshots that we should redact with respect to.
|
||||
* redactbook: Name of the redaction bookmark to create.
|
||||
*/
|
||||
int
|
||||
lzc_send_resume_redacted(const char *snapname, const char *from, int fd,
|
||||
enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff,
|
||||
const char *redactbook)
|
||||
{
|
||||
nvlist_t *args;
|
||||
int err;
|
||||
@@ -658,6 +688,9 @@ lzc_send_resume(const char *snapname, const char *from, int fd,
|
||||
fnvlist_add_uint64(args, "resume_object", resumeobj);
|
||||
fnvlist_add_uint64(args, "resume_offset", resumeoff);
|
||||
}
|
||||
if (redactbook != NULL)
|
||||
fnvlist_add_string(args, "redactbook", redactbook);
|
||||
|
||||
err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);
|
||||
nvlist_free(args);
|
||||
return (err);
|
||||
@@ -676,11 +709,13 @@ lzc_send_resume(const char *snapname, const char *from, int fd,
|
||||
* are traversed, looking for blocks with a birth time since the creation TXG of
|
||||
* the snapshot this bookmark was created from. This will result in
|
||||
* significantly more I/O and be less efficient than a send space estimation on
|
||||
* an equivalent snapshot.
|
||||
* an equivalent snapshot. This process is also used if redact_snaps is
|
||||
* non-null.
|
||||
*/
|
||||
int
|
||||
lzc_send_space(const char *snapname, const char *from,
|
||||
enum lzc_send_flags flags, uint64_t *spacep)
|
||||
lzc_send_space_resume_redacted(const char *snapname, const char *from,
|
||||
enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff,
|
||||
uint64_t resume_bytes, const char *redactbook, int fd, uint64_t *spacep)
|
||||
{
|
||||
nvlist_t *args;
|
||||
nvlist_t *result;
|
||||
@@ -697,6 +732,16 @@ lzc_send_space(const char *snapname, const char *from,
|
||||
fnvlist_add_boolean(args, "compressok");
|
||||
if (flags & LZC_SEND_FLAG_RAW)
|
||||
fnvlist_add_boolean(args, "rawok");
|
||||
if (resumeobj != 0 || resumeoff != 0) {
|
||||
fnvlist_add_uint64(args, "resume_object", resumeobj);
|
||||
fnvlist_add_uint64(args, "resume_offset", resumeoff);
|
||||
fnvlist_add_uint64(args, "bytes", resume_bytes);
|
||||
}
|
||||
if (redactbook != NULL)
|
||||
fnvlist_add_string(args, "redactbook", redactbook);
|
||||
if (fd != -1)
|
||||
fnvlist_add_int32(args, "fd", fd);
|
||||
|
||||
err = lzc_ioctl(ZFS_IOC_SEND_SPACE, snapname, args, &result);
|
||||
nvlist_free(args);
|
||||
if (err == 0)
|
||||
@@ -705,6 +750,14 @@ lzc_send_space(const char *snapname, const char *from,
|
||||
return (err);
|
||||
}
|
||||
|
||||
int
|
||||
lzc_send_space(const char *snapname, const char *from,
|
||||
enum lzc_send_flags flags, uint64_t *spacep)
|
||||
{
|
||||
return (lzc_send_space_resume_redacted(snapname, from, flags, 0, 0, 0,
|
||||
NULL, -1, spacep));
|
||||
}
|
||||
|
||||
static int
|
||||
recv_read(int fd, void *buf, int ilen)
|
||||
{
|
||||
@@ -744,6 +797,7 @@ recv_impl(const char *snapname, nvlist_t *recvdprops, nvlist_t *localprops,
|
||||
char fsname[MAXPATHLEN];
|
||||
char *atp;
|
||||
int error;
|
||||
boolean_t payload = B_FALSE;
|
||||
|
||||
ASSERT3S(g_refcount, >, 0);
|
||||
VERIFY3S(g_fd, !=, -1);
|
||||
@@ -774,13 +828,13 @@ recv_impl(const char *snapname, nvlist_t *recvdprops, nvlist_t *localprops,
|
||||
return (error);
|
||||
} else {
|
||||
drr = *begin_record;
|
||||
payload = (begin_record->drr_payloadlen != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Raw receives, resumable receives, and receives that include a
|
||||
* wrapping key all use the new interface.
|
||||
* All recives with a payload should use the new interface.
|
||||
*/
|
||||
if (resumable || raw || wkeydata != NULL) {
|
||||
if (resumable || raw || wkeydata != NULL || payload) {
|
||||
nvlist_t *outnvl = NULL;
|
||||
nvlist_t *innvl = fnvlist_alloc();
|
||||
|
||||
@@ -1118,19 +1172,33 @@ lzc_bookmark(nvlist_t *bookmarks, nvlist_t **errlist)
|
||||
* parameter is an nvlist of property names (with no values) that will be
|
||||
* returned for each bookmark.
|
||||
*
|
||||
* The following are valid properties on bookmarks, all of which are numbers
|
||||
* (represented as uint64 in the nvlist)
|
||||
* The following are valid properties on bookmarks, most of which are numbers
|
||||
* (represented as uint64 in the nvlist), except redact_snaps, which is a
|
||||
* uint64 array, and redact_complete, which is a boolean
|
||||
*
|
||||
* "guid" - globally unique identifier of the snapshot it refers to
|
||||
* "createtxg" - txg when the snapshot it refers to was created
|
||||
* "creation" - timestamp when the snapshot it refers to was created
|
||||
* "ivsetguid" - IVset guid for identifying encrypted snapshots
|
||||
* "redact_snaps" - list of guids of the redaction snapshots for the specified
|
||||
* bookmark. If the bookmark is not a redaction bookmark, the nvlist will
|
||||
* not contain an entry for this value. If it is redacted with respect to
|
||||
* no snapshots, it will contain value -> NULL uint64 array
|
||||
* "redact_complete" - boolean value; true if the redaction bookmark is
|
||||
* complete, false otherwise.
|
||||
*
|
||||
* The format of the returned nvlist as follows:
|
||||
* <short name of bookmark> -> {
|
||||
* <name of property> -> {
|
||||
* "value" -> uint64
|
||||
* }
|
||||
* ...
|
||||
* "redact_snaps" -> {
|
||||
* "value" -> uint64 array
|
||||
* }
|
||||
* "redact_complete" -> {
|
||||
* "value" -> boolean value
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
int
|
||||
@@ -1139,6 +1207,33 @@ lzc_get_bookmarks(const char *fsname, nvlist_t *props, nvlist_t **bmarks)
|
||||
return (lzc_ioctl(ZFS_IOC_GET_BOOKMARKS, fsname, props, bmarks));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get bookmark properties.
|
||||
*
|
||||
* Given a bookmark's full name, retrieve all properties for the bookmark.
|
||||
*
|
||||
* The format of the returned property list is as follows:
|
||||
* {
|
||||
* <name of property> -> {
|
||||
* "value" -> uint64
|
||||
* }
|
||||
* ...
|
||||
* "redact_snaps" -> {
|
||||
* "value" -> uint64 array
|
||||
* }
|
||||
*/
|
||||
int
|
||||
lzc_get_bookmark_props(const char *bookmark, nvlist_t **props)
|
||||
{
|
||||
int error;
|
||||
|
||||
nvlist_t *innvl = fnvlist_alloc();
|
||||
error = lzc_ioctl(ZFS_IOC_GET_BOOKMARK_PROPS, bookmark, innvl, props);
|
||||
fnvlist_free(innvl);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys bookmarks.
|
||||
*
|
||||
@@ -1479,3 +1574,18 @@ lzc_trim(const char *poolname, pool_trim_func_t cmd_type, uint64_t rate,
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a redaction bookmark named bookname by redacting snapshot with respect
|
||||
* to all the snapshots in snapnv.
|
||||
*/
|
||||
int
|
||||
lzc_redact(const char *snapshot, const char *bookname, nvlist_t *snapnv)
|
||||
{
|
||||
nvlist_t *args = fnvlist_alloc();
|
||||
fnvlist_add_string(args, "bookname", bookname);
|
||||
fnvlist_add_nvlist(args, "snapnv", snapnv);
|
||||
int error = lzc_ioctl(ZFS_IOC_REDACT, snapshot, args, NULL);
|
||||
fnvlist_free(args);
|
||||
return (error);
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ KERNEL_C = \
|
||||
dmu_object.c \
|
||||
dmu_objset.c \
|
||||
dmu_recv.c \
|
||||
dmu_redact.c \
|
||||
dmu_send.c \
|
||||
dmu_traverse.c \
|
||||
dmu_tx.c \
|
||||
@@ -86,6 +87,7 @@ KERNEL_C = \
|
||||
metaslab.c \
|
||||
mmp.c \
|
||||
multilist.c \
|
||||
objlist.c \
|
||||
pathname.c \
|
||||
range_tree.c \
|
||||
refcount.c \
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2016 Actifio, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user