Skip to content

Commit

Permalink
Merge branch 'illumos-2605'
Browse files Browse the repository at this point in the history
Adds support for resuming interrupted zfs send streams and include
all related send/recv bug fixes from upstream OpenZFS.

Unlike the upstream implementation this branch does not change
the existing ioctl interface.  Instead a new ZFS_IOC_RECV_NEW ioctl
was added to support resuming zfs send streams.  This was done by
applying the original upstream patch and then reverting the ioctl
changes in a follow up patch.  For this reason there are a handful
on commits between the relevant patches on this branch which are
not interoperable.  This was done to make it easier to extract
the new ZFS_IOC_RECV_NEW and submit it upstream.

Signed-off-by: Brian Behlendorf <[email protected]>
Closes #4742
  • Loading branch information
behlendorf committed Jun 29, 2016
2 parents 669cf0a + 0dab2e8 commit 5c27b29
Show file tree
Hide file tree
Showing 71 changed files with 2,627 additions and 970 deletions.
5 changes: 2 additions & 3 deletions cmd/zdb/zdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@
#include <sys/ddt.h>
#include <sys/zfeature.h>
#include <zfs_comutil.h>
#undef ZFS_MAXNAMELEN
#include <libzfs.h>

#define ZDB_COMPRESS_NAME(idx) ((idx) < ZIO_COMPRESS_FUNCTIONS ? \
Expand Down Expand Up @@ -2005,7 +2004,7 @@ dump_dir(objset_t *os)
uint64_t refdbytes, usedobjs, scratch;
char numbuf[32];
char blkbuf[BP_SPRINTF_LEN + 20];
char osname[MAXNAMELEN];
char osname[ZFS_MAX_DATASET_NAME_LEN];
char *type = "UNKNOWN";
int verbosity = dump_opt['d'];
int print_header = 1;
Expand Down Expand Up @@ -3553,7 +3552,7 @@ find_zpool(char **target, nvlist_t **configp, int dirc, char **dirv)
nvlist_t *match = NULL;
char *name = NULL;
char *sepp = NULL;
char sep = 0;
char sep = '\0';
int count = 0;
importargs_t args = { 0 };

Expand Down
148 changes: 117 additions & 31 deletions cmd/zfs/zfs_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,11 @@ get_usage(zfs_help_t idx)
case HELP_PROMOTE:
return (gettext("\tpromote <clone-filesystem>\n"));
case HELP_RECEIVE:
return (gettext("\treceive [-vnFu] <filesystem|volume|"
return (gettext("\treceive [-vnsFu] <filesystem|volume|"
"snapshot>\n"
"\treceive [-vnFu] [-o origin=<snapshot>] [-d | -e] "
"<filesystem>\n"));
"\treceive [-vnsFu] [-o origin=<snapshot>] [-d | -e] "
"<filesystem>\n"
"\treceive -A <filesystem|volume>\n"));
case HELP_RENAME:
return (gettext("\trename [-f] <filesystem|volume|snapshot> "
"<filesystem|volume|snapshot>\n"
Expand All @@ -263,7 +264,8 @@ get_usage(zfs_help_t idx)
return (gettext("\tsend [-DnPpRvLe] [-[iI] snapshot] "
"<snapshot>\n"
"\tsend [-Le] [-i snapshot|bookmark] "
"<filesystem|volume|snapshot>\n"));
"<filesystem|volume|snapshot>\n"
"\tsend [-nvPe] -t <receive_resume_token>\n"));
case HELP_SET:
return (gettext("\tset <property=value> ... "
"<filesystem|volume|snapshot> ...\n"));
Expand Down Expand Up @@ -1481,7 +1483,7 @@ get_callback(zfs_handle_t *zhp, void *data)
char buf[ZFS_MAXPROPLEN];
char rbuf[ZFS_MAXPROPLEN];
zprop_source_t sourcetype;
char source[ZFS_MAXNAMELEN];
char source[ZFS_MAX_DATASET_NAME_LEN];
zprop_get_cbdata_t *cbp = data;
nvlist_t *user_props = zfs_get_user_props(zhp);
zprop_list_t *pl = cbp->cb_proplist;
Expand Down Expand Up @@ -1961,7 +1963,7 @@ typedef struct upgrade_cbdata {
uint64_t cb_version;
boolean_t cb_newer;
boolean_t cb_foundone;
char cb_lastfs[ZFS_MAXNAMELEN];
char cb_lastfs[ZFS_MAX_DATASET_NAME_LEN];
} upgrade_cbdata_t;

static int
Expand Down Expand Up @@ -2410,7 +2412,7 @@ userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
if (domain != NULL && domain[0] != '\0') {
#ifdef HAVE_IDMAP
/* SMB */
char sid[ZFS_MAXNAMELEN + 32];
char sid[MAXNAMELEN + 32];
uid_t id;
uint64_t classes;
int err;
Expand Down Expand Up @@ -2544,7 +2546,7 @@ print_us_node(boolean_t scripted, boolean_t parsable, int *fields, int types,
size_t *width, us_node_t *node)
{
nvlist_t *nvl = node->usn_nvl;
char valstr[ZFS_MAXNAMELEN];
char valstr[MAXNAMELEN];
boolean_t first = B_TRUE;
int cfield = 0;
int field;
Expand Down Expand Up @@ -3415,7 +3417,7 @@ zfs_do_rollback(int argc, char **argv)
boolean_t force = B_FALSE;
rollback_cbdata_t cb = { 0 };
zfs_handle_t *zhp, *snap;
char parentname[ZFS_MAXNAMELEN];
char parentname[ZFS_MAX_DATASET_NAME_LEN];
char *delim;

/* check options */
Expand Down Expand Up @@ -3707,6 +3709,7 @@ zfs_do_send(int argc, char **argv)
{
char *fromname = NULL;
char *toname = NULL;
char *resume_token = NULL;
char *cp;
zfs_handle_t *zhp;
sendflags_t flags = { 0 };
Expand All @@ -3715,7 +3718,7 @@ zfs_do_send(int argc, char **argv)
boolean_t extraverbose = B_FALSE;

/* check options */
while ((c = getopt(argc, argv, ":i:I:RDpvnPLe")) != -1) {
while ((c = getopt(argc, argv, ":i:I:RDpvnPLet:")) != -1) {
switch (c) {
case 'i':
if (fromname)
Expand Down Expand Up @@ -3756,6 +3759,9 @@ zfs_do_send(int argc, char **argv)
case 'e':
flags.embed_data = B_TRUE;
break;
case 't':
resume_token = optarg;
break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
Expand All @@ -3771,14 +3777,28 @@ zfs_do_send(int argc, char **argv)
argc -= optind;
argv += optind;

/* check number of arguments */
if (argc < 1) {
(void) fprintf(stderr, gettext("missing snapshot argument\n"));
usage(B_FALSE);
}
if (argc > 1) {
(void) fprintf(stderr, gettext("too many arguments\n"));
usage(B_FALSE);
if (resume_token != NULL) {
if (fromname != NULL || flags.replicate || flags.props ||
flags.dedup) {
(void) fprintf(stderr,
gettext("invalid flags combined with -t\n"));
usage(B_FALSE);
}
if (argc != 0) {
(void) fprintf(stderr, gettext("no additional "
"arguments are permitted with -t\n"));
usage(B_FALSE);
}
} else {
if (argc < 1) {
(void) fprintf(stderr,
gettext("missing snapshot argument\n"));
usage(B_FALSE);
}
if (argc > 1) {
(void) fprintf(stderr, gettext("too many arguments\n"));
usage(B_FALSE);
}
}

if (!flags.dryrun && isatty(STDOUT_FILENO)) {
Expand All @@ -3788,12 +3808,17 @@ zfs_do_send(int argc, char **argv)
return (1);
}

if (resume_token != NULL) {
return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
resume_token));
}

/*
* Special case sending a filesystem, or from a bookmark.
*/
if (strchr(argv[0], '@') == NULL ||
(fromname && strchr(fromname, '#') != NULL)) {
char frombuf[ZFS_MAXNAMELEN];
char frombuf[ZFS_MAX_DATASET_NAME_LEN];
enum lzc_send_flags lzc_flags = 0;

if (flags.replicate || flags.doall || flags.props ||
Expand Down Expand Up @@ -3845,7 +3870,7 @@ zfs_do_send(int argc, char **argv)
* case if they specify the origin.
*/
if (fromname && (cp = strchr(fromname, '@')) != NULL) {
char origin[ZFS_MAXNAMELEN];
char origin[ZFS_MAX_DATASET_NAME_LEN];
zprop_source_t src;

(void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
Expand Down Expand Up @@ -3893,23 +3918,23 @@ zfs_do_send(int argc, char **argv)
}

/*
* zfs receive [-vnFu] [-d | -e] <fs@snap>
*
* Restore a backup stream from stdin.
*/
static int
zfs_do_receive(int argc, char **argv)
{
int c, err;
recvflags_t flags = { 0 };
boolean_t abort_resumable = B_FALSE;

nvlist_t *props;
nvpair_t *nvp = NULL;

if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
nomem();

/* check options */
while ((c = getopt(argc, argv, ":o:denuvF")) != -1) {
while ((c = getopt(argc, argv, ":o:denuvFsA")) != -1) {
switch (c) {
case 'o':
if (parseprop(props, optarg) != 0)
Expand All @@ -3931,9 +3956,15 @@ zfs_do_receive(int argc, char **argv)
case 'v':
flags.verbose = B_TRUE;
break;
case 's':
flags.resumable = B_TRUE;
break;
case 'F':
flags.force = B_TRUE;
break;
case 'A':
abort_resumable = B_TRUE;
break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
Expand Down Expand Up @@ -3966,14 +3997,51 @@ zfs_do_receive(int argc, char **argv)
}
}

if (abort_resumable) {
if (flags.isprefix || flags.istail || flags.dryrun ||
flags.resumable || flags.nomount) {
(void) fprintf(stderr, gettext("invalid option"));
usage(B_FALSE);
}

char namebuf[ZFS_MAX_DATASET_NAME_LEN];
(void) snprintf(namebuf, sizeof (namebuf),
"%s/%%recv", argv[0]);

if (zfs_dataset_exists(g_zfs, namebuf,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) {
zfs_handle_t *zhp = zfs_open(g_zfs,
namebuf, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
if (zhp == NULL)
return (1);
err = zfs_destroy(zhp, B_FALSE);
} else {
zfs_handle_t *zhp = zfs_open(g_zfs,
argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
if (zhp == NULL)
usage(B_FALSE);
if (!zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) ||
zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
NULL, 0, NULL, NULL, 0, B_TRUE) == -1) {
(void) fprintf(stderr,
gettext("'%s' does not have any "
"resumable receive state to abort\n"),
argv[0]);
return (1);
}
err = zfs_destroy(zhp, B_FALSE);
}

return (err != 0);
}

if (isatty(STDIN_FILENO)) {
(void) fprintf(stderr,
gettext("Error: Backup stream can not be read "
"from a terminal.\n"
"You must redirect standard input.\n"));
return (1);
}

err = zfs_receive(g_zfs, argv[0], props, &flags, STDIN_FILENO, NULL);

return (err != 0);
Expand Down Expand Up @@ -4792,7 +4860,7 @@ store_allow_perm(zfs_deleg_who_type_t type, boolean_t local, boolean_t descend,
{
int i;
char ld[2] = { '\0', '\0' };
char who_buf[ZFS_MAXNAMELEN+32];
char who_buf[MAXNAMELEN + 32];
char base_type = ZFS_DELEG_WHO_UNKNOWN;
char set_type = ZFS_DELEG_WHO_UNKNOWN;
nvlist_t *base_nvl = NULL;
Expand Down Expand Up @@ -5156,7 +5224,7 @@ static void
print_fs_perms(fs_perm_set_t *fspset)
{
fs_perm_node_t *node = NULL;
char buf[ZFS_MAXNAMELEN+32];
char buf[MAXNAMELEN + 32];
const char *dsname = buf;

for (node = uu_list_first(fspset->fsps_list); node != NULL;
Expand All @@ -5165,7 +5233,7 @@ print_fs_perms(fs_perm_set_t *fspset)
uu_avl_t *uge_avl = node->fspn_fsperm.fsp_uge_avl;
int left = 0;

(void) snprintf(buf, ZFS_MAXNAMELEN+32,
(void) snprintf(buf, sizeof (buf),
gettext("---- Permissions on %s "),
node->fspn_fsperm.fsp_name);
(void) printf("%s", dsname);
Expand Down Expand Up @@ -5362,7 +5430,7 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)

for (i = 0; i < argc; ++i) {
zfs_handle_t *zhp;
char parent[ZFS_MAXNAMELEN];
char parent[ZFS_MAX_DATASET_NAME_LEN];
const char *delim;
char *path = argv[i];

Expand Down Expand Up @@ -5490,7 +5558,7 @@ holds_callback(zfs_handle_t *zhp, void *data)
nvlist_t *nvl = NULL;
nvpair_t *nvp = NULL;
const char *zname = zfs_get_name(zhp);
size_t znamelen = strnlen(zname, ZFS_MAXNAMELEN);
size_t znamelen = strlen(zname);

if (cbp->cb_recursive) {
const char *snapname;
Expand All @@ -5511,7 +5579,7 @@ holds_callback(zfs_handle_t *zhp, void *data)

while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
const char *tag = nvpair_name(nvp);
size_t taglen = strnlen(tag, MAXNAMELEN);
size_t taglen = strlen(tag);
if (taglen > cbp->cb_max_taglen)
cbp->cb_max_taglen = taglen;
}
Expand Down Expand Up @@ -5803,6 +5871,24 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
return (0);
}

/*
* If this filesystem is inconsistent and has a receive resume
* token, we can not mount it.
*/
if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
if (!explicit)
return (0);

(void) fprintf(stderr, gettext("cannot %s '%s': "
"Contains partially-completed state from "
"\"zfs receive -r\", which can be resumed with "
"\"zfs send -t\"\n"),
cmdname, zfs_get_name(zhp));
return (1);
}

/*
* At this point, we have verified that the mountpoint and/or
* shareopts are appropriate for auto management. If the
Expand Down Expand Up @@ -6609,7 +6695,7 @@ zfs_do_diff(int argc, char **argv)
static int
zfs_do_bookmark(int argc, char **argv)
{
char snapname[ZFS_MAXNAMELEN];
char snapname[ZFS_MAX_DATASET_NAME_LEN];
zfs_handle_t *zhp;
nvlist_t *nvl;
int ret = 0;
Expand Down
1 change: 0 additions & 1 deletion cmd/zhack/zhack.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
#include <sys/zio_compress.h>
#include <sys/zfeature.h>
#include <sys/dmu_tx.h>
#undef ZFS_MAXNAMELEN
#include <libzfs.h>

extern boolean_t zfeature_checks_disable;
Expand Down
5 changes: 2 additions & 3 deletions cmd/zstreamdump/zstreamdump.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ read_hdr(dmu_replay_record_t *drr, zio_cksum_t *cksum)
(longlong_t)saved_cksum.zc_word[1],
(longlong_t)saved_cksum.zc_word[2],
(longlong_t)saved_cksum.zc_word[3]);
exit(1);
return (0);
}
return (sizeof (*drr));
}
Expand Down Expand Up @@ -347,8 +347,7 @@ main(int argc, char *argv[])
if (verbose)
(void) printf("\n");

if ((DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
DMU_COMPOUNDSTREAM) && drr->drr_payloadlen != 0) {
if (drr->drr_payloadlen != 0) {
nvlist_t *nv;
int sz = drr->drr_payloadlen;

Expand Down
Loading

0 comments on commit 5c27b29

Please sign in to comment.