Skip to content

Commit 47dfff3

Browse files
ahrensbehlendorf
authored andcommitted
OpenZFS 2605, 6980, 6902
2605 want to resume interrupted zfs send Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: Richard Elling <Richard.Elling@RichardElling.com> Reviewed by: Xin Li <delphij@freebsd.org> Reviewed by: Arne Jansen <sensille@gmx.net> Approved by: Dan McDonald <danmcd@omniti.com> Ported-by: kernelOfTruth <kerneloftruth@gmail.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> OpenZFS-issue: https://www.illumos.org/issues/2605 OpenZFS-commit: openzfs/openzfs@9c3fd12 6980 6902 causes zfs send to break due to 32-bit/64-bit struct mismatch Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Approved by: Robert Mustacchi <rm@joyent.com> Ported by: Brian Behlendorf <behlendorf1@llnl.gov> OpenZFS-issue: https://www.illumos.org/issues/6980 OpenZFS-commit: openzfs/openzfs@ea4a67f Porting notes: - All rsend and snapshop tests enabled and updated for Linux. - Fix misuse of input argument in traverse_visitbp(). - Fix ISO C90 warnings and errors. - Fix gcc 'missing braces around initializer' in 'struct send_thread_arg to_arg =' warning. - Replace 4 argument fletcher_4_native() with 3 argument version, this change was made in OpenZFS 4185 which has not been ported. - Part of the sections for 'zfs receive' and 'zfs send' was rewritten and reordered to approximate upstream. - Fix mktree xattr creation, 'user.' prefix required. - Minor fixes to newly enabled test cases - Long holds for volumes allowed during receive for minor registration.
1 parent 669cf0a commit 47dfff3

40 files changed

+1483
-337
lines changed

cmd/zfs/zfs_main.c

+103-17
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,11 @@ get_usage(zfs_help_t idx)
248248
case HELP_PROMOTE:
249249
return (gettext("\tpromote <clone-filesystem>\n"));
250250
case HELP_RECEIVE:
251-
return (gettext("\treceive [-vnFu] <filesystem|volume|"
251+
return (gettext("\treceive [-vnsFu] <filesystem|volume|"
252252
"snapshot>\n"
253-
"\treceive [-vnFu] [-o origin=<snapshot>] [-d | -e] "
254-
"<filesystem>\n"));
253+
"\treceive [-vnsFu] [-o origin=<snapshot>] [-d | -e] "
254+
"<filesystem>\n"
255+
"\treceive -A <filesystem|volume>\n"));
255256
case HELP_RENAME:
256257
return (gettext("\trename [-f] <filesystem|volume|snapshot> "
257258
"<filesystem|volume|snapshot>\n"
@@ -263,7 +264,8 @@ get_usage(zfs_help_t idx)
263264
return (gettext("\tsend [-DnPpRvLe] [-[iI] snapshot] "
264265
"<snapshot>\n"
265266
"\tsend [-Le] [-i snapshot|bookmark] "
266-
"<filesystem|volume|snapshot>\n"));
267+
"<filesystem|volume|snapshot>\n"
268+
"\tsend [-nvPe] -t <receive_resume_token>\n"));
267269
case HELP_SET:
268270
return (gettext("\tset <property=value> ... "
269271
"<filesystem|volume|snapshot> ...\n"));
@@ -3707,6 +3709,7 @@ zfs_do_send(int argc, char **argv)
37073709
{
37083710
char *fromname = NULL;
37093711
char *toname = NULL;
3712+
char *resume_token = NULL;
37103713
char *cp;
37113714
zfs_handle_t *zhp;
37123715
sendflags_t flags = { 0 };
@@ -3715,7 +3718,7 @@ zfs_do_send(int argc, char **argv)
37153718
boolean_t extraverbose = B_FALSE;
37163719

37173720
/* check options */
3718-
while ((c = getopt(argc, argv, ":i:I:RDpvnPLe")) != -1) {
3721+
while ((c = getopt(argc, argv, ":i:I:RDpvnPLet:")) != -1) {
37193722
switch (c) {
37203723
case 'i':
37213724
if (fromname)
@@ -3756,6 +3759,9 @@ zfs_do_send(int argc, char **argv)
37563759
case 'e':
37573760
flags.embed_data = B_TRUE;
37583761
break;
3762+
case 't':
3763+
resume_token = optarg;
3764+
break;
37593765
case ':':
37603766
(void) fprintf(stderr, gettext("missing argument for "
37613767
"'%c' option\n"), optopt);
@@ -3771,14 +3777,28 @@ zfs_do_send(int argc, char **argv)
37713777
argc -= optind;
37723778
argv += optind;
37733779

3774-
/* check number of arguments */
3775-
if (argc < 1) {
3776-
(void) fprintf(stderr, gettext("missing snapshot argument\n"));
3777-
usage(B_FALSE);
3778-
}
3779-
if (argc > 1) {
3780-
(void) fprintf(stderr, gettext("too many arguments\n"));
3781-
usage(B_FALSE);
3780+
if (resume_token != NULL) {
3781+
if (fromname != NULL || flags.replicate || flags.props ||
3782+
flags.dedup) {
3783+
(void) fprintf(stderr,
3784+
gettext("invalid flags combined with -t\n"));
3785+
usage(B_FALSE);
3786+
}
3787+
if (argc != 0) {
3788+
(void) fprintf(stderr, gettext("no additional "
3789+
"arguments are permitted with -t\n"));
3790+
usage(B_FALSE);
3791+
}
3792+
} else {
3793+
if (argc < 1) {
3794+
(void) fprintf(stderr,
3795+
gettext("missing snapshot argument\n"));
3796+
usage(B_FALSE);
3797+
}
3798+
if (argc > 1) {
3799+
(void) fprintf(stderr, gettext("too many arguments\n"));
3800+
usage(B_FALSE);
3801+
}
37823802
}
37833803

37843804
if (!flags.dryrun && isatty(STDOUT_FILENO)) {
@@ -3788,6 +3808,11 @@ zfs_do_send(int argc, char **argv)
37883808
return (1);
37893809
}
37903810

3811+
if (resume_token != NULL) {
3812+
return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
3813+
resume_token));
3814+
}
3815+
37913816
/*
37923817
* Special case sending a filesystem, or from a bookmark.
37933818
*/
@@ -3893,23 +3918,23 @@ zfs_do_send(int argc, char **argv)
38933918
}
38943919

38953920
/*
3896-
* zfs receive [-vnFu] [-d | -e] <fs@snap>
3897-
*
38983921
* Restore a backup stream from stdin.
38993922
*/
39003923
static int
39013924
zfs_do_receive(int argc, char **argv)
39023925
{
39033926
int c, err;
39043927
recvflags_t flags = { 0 };
3928+
boolean_t abort_resumable = B_FALSE;
3929+
39053930
nvlist_t *props;
39063931
nvpair_t *nvp = NULL;
39073932

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

39113936
/* check options */
3912-
while ((c = getopt(argc, argv, ":o:denuvF")) != -1) {
3937+
while ((c = getopt(argc, argv, ":o:denuvFsA")) != -1) {
39133938
switch (c) {
39143939
case 'o':
39153940
if (parseprop(props, optarg) != 0)
@@ -3931,9 +3956,15 @@ zfs_do_receive(int argc, char **argv)
39313956
case 'v':
39323957
flags.verbose = B_TRUE;
39333958
break;
3959+
case 's':
3960+
flags.resumable = B_TRUE;
3961+
break;
39343962
case 'F':
39353963
flags.force = B_TRUE;
39363964
break;
3965+
case 'A':
3966+
abort_resumable = B_TRUE;
3967+
break;
39373968
case ':':
39383969
(void) fprintf(stderr, gettext("missing argument for "
39393970
"'%c' option\n"), optopt);
@@ -3966,14 +3997,51 @@ zfs_do_receive(int argc, char **argv)
39663997
}
39673998
}
39683999

4000+
if (abort_resumable) {
4001+
if (flags.isprefix || flags.istail || flags.dryrun ||
4002+
flags.resumable || flags.nomount) {
4003+
(void) fprintf(stderr, gettext("invalid option"));
4004+
usage(B_FALSE);
4005+
}
4006+
4007+
char namebuf[ZFS_MAXNAMELEN];
4008+
(void) snprintf(namebuf, sizeof (namebuf),
4009+
"%s/%%recv", argv[0]);
4010+
4011+
if (zfs_dataset_exists(g_zfs, namebuf,
4012+
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) {
4013+
zfs_handle_t *zhp = zfs_open(g_zfs,
4014+
namebuf, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
4015+
if (zhp == NULL)
4016+
return (1);
4017+
err = zfs_destroy(zhp, B_FALSE);
4018+
} else {
4019+
zfs_handle_t *zhp = zfs_open(g_zfs,
4020+
argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
4021+
if (zhp == NULL)
4022+
usage(B_FALSE);
4023+
if (!zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) ||
4024+
zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
4025+
NULL, 0, NULL, NULL, 0, B_TRUE) == -1) {
4026+
(void) fprintf(stderr,
4027+
gettext("'%s' does not have any "
4028+
"resumable receive state to abort\n"),
4029+
argv[0]);
4030+
return (1);
4031+
}
4032+
err = zfs_destroy(zhp, B_FALSE);
4033+
}
4034+
4035+
return (err != 0);
4036+
}
4037+
39694038
if (isatty(STDIN_FILENO)) {
39704039
(void) fprintf(stderr,
39714040
gettext("Error: Backup stream can not be read "
39724041
"from a terminal.\n"
39734042
"You must redirect standard input.\n"));
39744043
return (1);
39754044
}
3976-
39774045
err = zfs_receive(g_zfs, argv[0], props, &flags, STDIN_FILENO, NULL);
39784046

39794047
return (err != 0);
@@ -5803,6 +5871,24 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
58035871
return (0);
58045872
}
58055873

5874+
/*
5875+
* If this filesystem is inconsistent and has a receive resume
5876+
* token, we can not mount it.
5877+
*/
5878+
if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
5879+
zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
5880+
NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
5881+
if (!explicit)
5882+
return (0);
5883+
5884+
(void) fprintf(stderr, gettext("cannot %s '%s': "
5885+
"Contains partially-completed state from "
5886+
"\"zfs receive -r\", which can be resumed with "
5887+
"\"zfs send -t\"\n"),
5888+
cmdname, zfs_get_name(zhp));
5889+
return (1);
5890+
}
5891+
58065892
/*
58075893
* At this point, we have verified that the mountpoint and/or
58085894
* shareopts are appropriate for auto management. If the

cmd/zstreamdump/zstreamdump.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ read_hdr(dmu_replay_record_t *drr, zio_cksum_t *cksum)
127127
(longlong_t)saved_cksum.zc_word[1],
128128
(longlong_t)saved_cksum.zc_word[2],
129129
(longlong_t)saved_cksum.zc_word[3]);
130-
exit(1);
130+
return (0);
131131
}
132132
return (sizeof (*drr));
133133
}
@@ -347,8 +347,7 @@ main(int argc, char *argv[])
347347
if (verbose)
348348
(void) printf("\n");
349349

350-
if ((DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
351-
DMU_COMPOUNDSTREAM) && drr->drr_payloadlen != 0) {
350+
if (drr->drr_payloadlen != 0) {
352351
nvlist_t *nv;
353352
int sz = drr->drr_payloadlen;
354353

config/user-commands.m4

+2-1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_COMMON], [
6767
AC_PATH_TOOL(SHUF, shuf, "")
6868
AC_PATH_TOOL(SLEEP, sleep, "")
6969
AC_PATH_TOOL(SORT, sort, "")
70+
AC_PATH_TOOL(STAT, stat, "")
7071
AC_PATH_TOOL(STRINGS, strings, "")
7172
AC_PATH_TOOL(SU, su, "")
7273
AC_PATH_TOOL(SUM, sum, "")
@@ -75,6 +76,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_COMMON], [
7576
AC_PATH_TOOL(TAR, tar, "")
7677
AC_PATH_TOOL(TOUCH, touch, "")
7778
AC_PATH_TOOL(TR, tr, "")
79+
AC_PATH_TOOL(TRUNCATE, truncate, "")
7880
AC_PATH_TOOL(TRUE, true, "")
7981
AC_PATH_TOOL(UMASK, umask, "")
8082
AC_PATH_TOOL(UMOUNT, umount, "")
@@ -103,7 +105,6 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_LINUX], [
103105
AC_PATH_TOOL(SHARE, exportfs, "")
104106
AC_PATH_TOOL(SWAP, swapon, "")
105107
AC_PATH_TOOL(SWAPADD, swapon, "")
106-
AC_PATH_TOOL(TRUNCATE, truncate, "")
107108
AC_PATH_TOOL(UDEVADM, udevadm, "")
108109
AC_PATH_TOOL(UFSDUMP, dump, "")
109110
AC_PATH_TOOL(UFSRESTORE, restore, "")

include/libzfs.h

+10
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,10 @@ typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
640640
extern int zfs_send(zfs_handle_t *, const char *, const char *,
641641
sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
642642
extern int zfs_send_one(zfs_handle_t *, const char *, int, enum lzc_send_flags);
643+
extern int zfs_send_resume(libzfs_handle_t *, sendflags_t *, int outfd,
644+
const char *);
645+
extern nvlist_t *zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl,
646+
const char *token);
643647

644648
extern int zfs_promote(zfs_handle_t *);
645649
extern int zfs_hold(zfs_handle_t *, const char *, const char *,
@@ -680,6 +684,12 @@ typedef struct recvflags {
680684
/* set "canmount=off" on all modified filesystems */
681685
boolean_t canmountoff;
682686

687+
/*
688+
* Mark the file systems as "resumable" and do not destroy them if the
689+
* receive is interrupted
690+
*/
691+
boolean_t resumable;
692+
683693
/* byteswap flag is used internally; callers need not specify */
684694
boolean_t byteswap;
685695

include/libzfs_core.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*/
2121

2222
/*
23-
* Copyright (c) 2013 by Delphix. All rights reserved.
23+
* Copyright (c) 2012, 2014 by Delphix. All rights reserved.
2424
*/
2525

2626
#ifndef _LIBZFS_CORE_H
@@ -58,7 +58,11 @@ enum lzc_send_flags {
5858
};
5959

6060
int lzc_send(const char *, const char *, int, enum lzc_send_flags);
61+
int lzc_send_resume(const char *, const char *, int,
62+
enum lzc_send_flags, uint64_t, uint64_t);
6163
int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
64+
int lzc_receive_resumable(const char *, nvlist_t *, const char *,
65+
boolean_t, int);
6266
int lzc_send_space(const char *, const char *, uint64_t *);
6367

6468
boolean_t lzc_exists(const char *);

include/sys/dmu_impl.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*/
2525
/*
2626
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
27-
* Copyright (c) 2013 by Delphix. All rights reserved.
27+
* Copyright (c) 2013, 2014 by Delphix. All rights reserved.
2828
*/
2929

3030
#ifndef _SYS_DMU_IMPL_H
@@ -272,6 +272,8 @@ typedef struct dmu_sendarg {
272272
uint64_t dsa_featureflags;
273273
uint64_t dsa_last_data_object;
274274
uint64_t dsa_last_data_offset;
275+
uint64_t dsa_resume_object;
276+
uint64_t dsa_resume_offset;
275277
} dmu_sendarg_t;
276278

277279
void dmu_object_zapify(objset_t *, uint64_t, dmu_object_type_t, dmu_tx_t *);

include/sys/dmu_send.h

+11-5
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@ struct vnode;
3636
struct dsl_dataset;
3737
struct drr_begin;
3838
struct avl_tree;
39+
struct dmu_replay_record;
3940

40-
int dmu_send(const char *tosnap, const char *fromsnap,
41-
boolean_t embedok, boolean_t large_block_ok,
42-
int outfd, struct vnode *vp, offset_t *off);
41+
extern const char *recv_clone_name;
42+
43+
int dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok,
44+
boolean_t large_block_ok, int outfd, uint64_t resumeobj, uint64_t resumeoff,
45+
struct vnode *vp, offset_t *off);
4346
int dmu_send_estimate(struct dsl_dataset *ds, struct dsl_dataset *fromds,
4447
uint64_t *sizep);
4548
int dmu_send_estimate_from_txg(struct dsl_dataset *ds, uint64_t fromtxg,
@@ -50,21 +53,24 @@ int dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
5053

5154
typedef struct dmu_recv_cookie {
5255
struct dsl_dataset *drc_ds;
56+
struct dmu_replay_record *drc_drr_begin;
5357
struct drr_begin *drc_drrb;
5458
const char *drc_tofs;
5559
const char *drc_tosnap;
5660
boolean_t drc_newfs;
5761
boolean_t drc_byteswap;
5862
boolean_t drc_force;
63+
boolean_t drc_resumable;
5964
struct avl_tree *drc_guid_to_ds_map;
6065
zio_cksum_t drc_cksum;
6166
uint64_t drc_newsnapobj;
6267
void *drc_owner;
6368
cred_t *drc_cred;
6469
} dmu_recv_cookie_t;
6570

66-
int dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb,
67-
boolean_t force, char *origin, dmu_recv_cookie_t *drc);
71+
int dmu_recv_begin(char *tofs, char *tosnap,
72+
struct dmu_replay_record *drr_begin,
73+
boolean_t force, boolean_t resumable, char *origin, dmu_recv_cookie_t *drc);
6874
int dmu_recv_stream(dmu_recv_cookie_t *drc, struct vnode *vp, offset_t *voffp,
6975
int cleanup_fd, uint64_t *action_handlep);
7076
int dmu_recv_end(dmu_recv_cookie_t *drc, void *owner);

include/sys/dmu_traverse.h

+2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ typedef int (blkptr_cb_t)(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
5454

5555
int traverse_dataset(struct dsl_dataset *ds,
5656
uint64_t txg_start, int flags, blkptr_cb_t func, void *arg);
57+
int traverse_dataset_resume(struct dsl_dataset *ds, uint64_t txg_start,
58+
zbookmark_phys_t *resume, int flags, blkptr_cb_t func, void *arg);
5759
int traverse_dataset_destroyed(spa_t *spa, blkptr_t *blkptr,
5860
uint64_t txg_start, zbookmark_phys_t *resume, int flags,
5961
blkptr_cb_t func, void *arg);

0 commit comments

Comments
 (0)