Print this page
4986 receiving replication stream fails if any snapshot exceeds refquota
*** 22,31 ****
--- 22,32 ----
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2015 by Delphix. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
*/
#include <assert.h>
#include <ctype.h>
#include <errno.h>
*** 56,66 ****
/* in libzfs_dataset.c */
extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
! uint64_t *);
static int guid_to_name(libzfs_handle_t *, const char *,
uint64_t, boolean_t, char *);
static const zio_cksum_t zero_cksum = { 0 };
--- 57,67 ----
/* in libzfs_dataset.c */
extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
! uint64_t *, const char *);
static int guid_to_name(libzfs_handle_t *, const char *,
uint64_t, boolean_t, char *);
static const zio_cksum_t zero_cksum = { 0 };
*** 2559,2568 ****
--- 2560,2570 ----
char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
{
nvlist_t *stream_nv = NULL;
avl_tree_t *stream_avl = NULL;
char *fromsnap = NULL;
+ char *sendsnap = NULL;
char *cp;
char tofs[ZFS_MAXNAMELEN];
char sendfs[ZFS_MAXNAMELEN];
char errbuf[1024];
dmu_replay_record_t drre;
*** 2707,2718 ****
* specified by 'zfs send') and pass it to each invocation of
* zfs_receive_one().
*/
(void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
ZFS_MAXNAMELEN);
! if ((cp = strchr(sendfs, '@')) != NULL)
*cp = '\0';
/* Finally, receive each contained stream */
do {
/*
* we should figure out if it has a recoverable
--- 2709,2727 ----
* specified by 'zfs send') and pass it to each invocation of
* zfs_receive_one().
*/
(void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
ZFS_MAXNAMELEN);
! if ((cp = strchr(sendfs, '@')) != NULL) {
*cp = '\0';
+ /*
+ * Find the "sendsnap", the final snapshot in a replication
+ * stream, so zfs_receive_one() can set filesystem properties
+ * ONLY when receiving that final snapshot.
+ */
+ sendsnap = (cp + 1);
+ }
/* Finally, receive each contained stream */
do {
/*
* we should figure out if it has a recoverable
*** 2721,2731 ****
* zfs_receive_one() will take care of it (ie,
* recv_skip() and return 0).
*/
error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
! action_handlep);
if (error == ENODATA) {
error = 0;
break;
}
anyerr |= error;
--- 2730,2740 ----
* zfs_receive_one() will take care of it (ie,
* recv_skip() and return 0).
*/
error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
! action_handlep, sendsnap);
if (error == ENODATA) {
error = 0;
break;
}
anyerr |= error;
*** 2885,2897 ****
* Restores a backup of tosnap from the file descriptor specified by infd.
*/
static int
zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
! dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,
avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
! uint64_t *action_handlep)
{
zfs_cmd_t zc = { 0 };
time_t begin_time;
int ioctl_err, ioctl_errno, err;
char *cp;
--- 2894,2906 ----
* Restores a backup of tosnap from the file descriptor specified by infd.
*/
static int
zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
! dmu_replay_record_t *drr_noswap, const char *sendfs,
avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
! uint64_t *action_handlep, const char *finalsnap)
{
zfs_cmd_t zc = { 0 };
time_t begin_time;
int ioctl_err, ioctl_errno, err;
char *cp;
*** 2903,2941 ****
boolean_t stream_wantsnewfs;
uint64_t parent_snapguid = 0;
prop_changelist_t *clp = NULL;
nvlist_t *snapprops_nvlist = NULL;
zprop_errflags_t prop_errflags;
- boolean_t recursive;
begin_time = time(NULL);
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot receive"));
- recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
- ENOENT);
-
if (stream_avl != NULL) {
char *snapname;
nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
&snapname);
nvlist_t *props;
int ret;
(void) nvlist_lookup_uint64(fs, "parentfromsnap",
&parent_snapguid);
err = nvlist_lookup_nvlist(fs, "props", &props);
! if (err)
VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
if (flags->canmountoff) {
VERIFY(0 == nvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
}
ret = zcmd_write_src_nvlist(hdl, &zc, props);
! if (err)
nvlist_free(props);
if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {
VERIFY(0 == nvlist_lookup_nvlist(props,
snapname, &snapprops_nvlist));
--- 2912,2955 ----
boolean_t stream_wantsnewfs;
uint64_t parent_snapguid = 0;
prop_changelist_t *clp = NULL;
nvlist_t *snapprops_nvlist = NULL;
zprop_errflags_t prop_errflags;
begin_time = time(NULL);
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot receive"));
if (stream_avl != NULL) {
char *snapname;
nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
&snapname);
nvlist_t *props;
int ret;
+ boolean_t is_finalsnap;
+ VERIFY(fs != NULL);
(void) nvlist_lookup_uint64(fs, "parentfromsnap",
&parent_snapguid);
+ /*
+ * Can safely use strcmp because at least "snapname" has been
+ * verified.
+ */
+ is_finalsnap = (strcmp(snapname, finalsnap) == 0);
+
+ if (is_finalsnap)
err = nvlist_lookup_nvlist(fs, "props", &props);
! if (!is_finalsnap || err)
VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
if (flags->canmountoff) {
VERIFY(0 == nvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
}
ret = zcmd_write_src_nvlist(hdl, &zc, props);
! if (!is_finalsnap || err)
nvlist_free(props);
if (0 == nvlist_lookup_nvlist(fs, "snapprops", &props)) {
VERIFY(0 == nvlist_lookup_nvlist(props,
snapname, &snapprops_nvlist));
*** 3002,3012 ****
* tack on everything after the fs specified by 'zfs send'.
*/
chopprefix = drrb->drr_toname + strlen(sendfs);
} else {
/* A snapshot was specified as an exact path (no -d or -e). */
! if (recursive) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"cannot specify snapshot name for multi-snapshot "
"stream"));
return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
}
--- 3016,3026 ----
* tack on everything after the fs specified by 'zfs send'.
*/
chopprefix = drrb->drr_toname + strlen(sendfs);
} else {
/* A snapshot was specified as an exact path (no -d or -e). */
! if (flags->recursive) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"cannot specify snapshot name for multi-snapshot "
"stream"));
return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
}
*** 3446,3456 ****
static int
zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
! uint64_t *action_handlep)
{
int err;
dmu_replay_record_t drr, drr_noswap;
struct drr_begin *drrb = &drr.drr_u.drr_begin;
char errbuf[1024];
--- 3460,3470 ----
static int
zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
! uint64_t *action_handlep, const char *finalsnap)
{
int err;
dmu_replay_record_t drr, drr_noswap;
struct drr_begin *drrb = &drr.drr_u.drr_begin;
char errbuf[1024];
*** 3542,3555 ****
(void) strlcpy(nonpackage_sendfs,
drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
*cp = '\0';
sendfs = nonpackage_sendfs;
}
! return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
! &drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,
! cleanup_fd, action_handlep));
} else {
assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
DMU_COMPOUNDSTREAM);
return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
&zcksum, top_zfs, cleanup_fd, action_handlep));
--- 3556,3576 ----
(void) strlcpy(nonpackage_sendfs,
drr.drr_u.drr_begin.drr_toname, ZFS_MAXNAMELEN);
if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
*cp = '\0';
sendfs = nonpackage_sendfs;
+ VERIFY(finalsnap == NULL);
}
! flags->recursive =
! (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
! ENOENT);
! err = zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
! &drr, &drr_noswap, sendfs, stream_avl, top_zfs,
! cleanup_fd, action_handlep, finalsnap);
! /* Clear out internal-only flags. */
! flags->recursive = B_FALSE;
! return (err);
} else {
assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
DMU_COMPOUNDSTREAM);
return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
&zcksum, top_zfs, cleanup_fd, action_handlep));
*** 3580,3590 ****
cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
VERIFY(cleanup_fd >= 0);
err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
! stream_avl, &top_zfs, cleanup_fd, &action_handle);
VERIFY(0 == close(cleanup_fd));
if (err == 0 && !flags->nomount && top_zfs) {
zfs_handle_t *zhp;
--- 3601,3611 ----
cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
VERIFY(cleanup_fd >= 0);
err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
! stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL);
VERIFY(0 == close(cleanup_fd));
if (err == 0 && !flags->nomount && top_zfs) {
zfs_handle_t *zhp;