Changeset View
Changeset View
Standalone View
Standalone View
cddl/contrib/opensolaris/lib/libzfs/common/libzfs_sendrecv.c
Show All 22 Lines | |||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. | * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. | ||||
* Copyright (c) 2011, 2015 by Delphix. All rights reserved. | * Copyright (c) 2011, 2015 by Delphix. All rights reserved. | ||||
* Copyright (c) 2012, Joyent, Inc. All rights reserved. | * Copyright (c) 2012, Joyent, Inc. All rights reserved. | ||||
* Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved. | * Copyright (c) 2012 Pawel Jakub Dawidek. All rights reserved. | ||||
* Copyright (c) 2013 Steven Hartland. All rights reserved. | * Copyright (c) 2013 Steven Hartland. All rights reserved. | ||||
* Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. | * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. | ||||
* Copyright (c) 2014 Integros [integros.com] | * Copyright (c) 2014 Integros [integros.com] | ||||
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> | * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> | ||||
* Copyright (c) 2019, Intel Corporation. All rights reserved. | |||||
*/ | */ | ||||
#include <assert.h> | #include <assert.h> | ||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <libintl.h> | #include <libintl.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
▲ Show 20 Lines • Show All 565 Lines • ▼ Show 20 Lines | typedef struct send_data { | ||||
nvlist_t *fss; | nvlist_t *fss; | ||||
nvlist_t *snapprops; | nvlist_t *snapprops; | ||||
/* send-receive configuration, does not change during traversal */ | /* send-receive configuration, does not change during traversal */ | ||||
const char *fsname; | const char *fsname; | ||||
const char *fromsnap; | const char *fromsnap; | ||||
const char *tosnap; | const char *tosnap; | ||||
boolean_t recursive; | boolean_t recursive; | ||||
boolean_t force; | |||||
boolean_t verbose; | boolean_t verbose; | ||||
/* | /* | ||||
* The header nvlist is of the following format: | * The header nvlist is of the following format: | ||||
* { | * { | ||||
* "tosnap" -> string | * "tosnap" -> string | ||||
* "fromsnap" -> string (if incremental) | * "fromsnap" -> string (if incremental) | ||||
* "fss" -> { | * "fss" -> { | ||||
▲ Show 20 Lines • Show All 188 Lines • ▼ Show 20 Lines | send_iterate_fs(zfs_handle_t *zhp, void *arg) | ||||
* perform two additional checks: | * perform two additional checks: | ||||
* | * | ||||
* - skip sending the current dataset if it was created later than | * - skip sending the current dataset if it was created later than | ||||
* the parent tosnap | * the parent tosnap | ||||
* - return error if the current dataset was created earlier than | * - return error if the current dataset was created earlier than | ||||
* the parent tosnap | * the parent tosnap | ||||
*/ | */ | ||||
if (sd->tosnap != NULL && tosnap_txg == 0) { | if (sd->tosnap != NULL && tosnap_txg == 0) { | ||||
if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) { | if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg || | ||||
sd->recursive && sd->force) { | |||||
if (sd->verbose) { | if (sd->verbose) { | ||||
(void) fprintf(stderr, dgettext(TEXT_DOMAIN, | (void) fprintf(stderr, dgettext(TEXT_DOMAIN, | ||||
"skipping dataset %s: snapshot %s does " | "skipping dataset %s: snapshot %s does " | ||||
"not exist\n"), zhp->zfs_name, sd->tosnap); | "not exist\n"), zhp->zfs_name, sd->tosnap); | ||||
} | } | ||||
} else { | } else { | ||||
(void) fprintf(stderr, dgettext(TEXT_DOMAIN, | (void) fprintf(stderr, dgettext(TEXT_DOMAIN, | ||||
"cannot send %s@%s%s: snapshot %s@%s does not " | "cannot send %s@%s%s: snapshot %s@%s does not " | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | out: | ||||
sd->tosnap_txg = tosnap_txg_save; | sd->tosnap_txg = tosnap_txg_save; | ||||
zfs_close(zhp); | zfs_close(zhp); | ||||
return (rv); | return (rv); | ||||
} | } | ||||
static int | static int | ||||
gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap, | gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap, | ||||
const char *tosnap, boolean_t recursive, boolean_t verbose, | const char *tosnap, boolean_t recursive, boolean_t force, | ||||
nvlist_t **nvlp, avl_tree_t **avlp) | boolean_t verbose, nvlist_t **nvlp, avl_tree_t **avlp) | ||||
{ | { | ||||
zfs_handle_t *zhp; | zfs_handle_t *zhp; | ||||
send_data_t sd = { 0 }; | send_data_t sd = { 0 }; | ||||
int error; | int error; | ||||
zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); | zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); | ||||
if (zhp == NULL) | if (zhp == NULL) | ||||
return (EZFS_BADTYPE); | return (EZFS_BADTYPE); | ||||
VERIFY(0 == nvlist_alloc(&sd.fss, NV_UNIQUE_NAME, 0)); | VERIFY(0 == nvlist_alloc(&sd.fss, NV_UNIQUE_NAME, 0)); | ||||
sd.fsname = fsname; | sd.fsname = fsname; | ||||
sd.fromsnap = fromsnap; | sd.fromsnap = fromsnap; | ||||
sd.tosnap = tosnap; | sd.tosnap = tosnap; | ||||
sd.recursive = recursive; | sd.recursive = recursive; | ||||
sd.force = force; | |||||
sd.verbose = verbose; | sd.verbose = verbose; | ||||
if ((error = send_iterate_fs(zhp, &sd)) != 0) { | if ((error = send_iterate_fs(zhp, &sd)) != 0) { | ||||
nvlist_free(sd.fss); | nvlist_free(sd.fss); | ||||
if (avlp != NULL) | if (avlp != NULL) | ||||
*avlp = NULL; | *avlp = NULL; | ||||
*nvlp = NULL; | *nvlp = NULL; | ||||
return (error); | return (error); | ||||
Show All 15 Lines | |||||
typedef struct send_dump_data { | typedef struct send_dump_data { | ||||
/* these are all just the short snapname (the part after the @) */ | /* these are all just the short snapname (the part after the @) */ | ||||
const char *fromsnap; | const char *fromsnap; | ||||
const char *tosnap; | const char *tosnap; | ||||
char prevsnap[ZFS_MAX_DATASET_NAME_LEN]; | char prevsnap[ZFS_MAX_DATASET_NAME_LEN]; | ||||
uint64_t prevsnap_obj; | uint64_t prevsnap_obj; | ||||
boolean_t seenfrom, seento, replicate, doall, fromorigin; | boolean_t seenfrom, seento, replicate, doall, fromorigin; | ||||
boolean_t verbose, dryrun, parsable, progress, embed_data, std_out; | boolean_t verbose, dryrun, parsable, progress, embed_data, std_out; | ||||
boolean_t large_block, compress; | boolean_t large_block, compress, force; | ||||
int outfd; | int outfd; | ||||
boolean_t err; | boolean_t err; | ||||
nvlist_t *fss; | nvlist_t *fss; | ||||
nvlist_t *snapholds; | nvlist_t *snapholds; | ||||
avl_tree_t *fsavl; | avl_tree_t *fsavl; | ||||
snapfilter_cb_t *filter_cb; | snapfilter_cb_t *filter_cb; | ||||
void *filter_cb_arg; | void *filter_cb_arg; | ||||
nvlist_t *debugnv; | nvlist_t *debugnv; | ||||
▲ Show 20 Lines • Show All 869 Lines • ▼ Show 20 Lines | if (flags->replicate || flags->props) { | ||||
} | } | ||||
VERIFY(0 == nvlist_add_string(hdrnv, "tosnap", tosnap)); | VERIFY(0 == nvlist_add_string(hdrnv, "tosnap", tosnap)); | ||||
if (!flags->replicate) { | if (!flags->replicate) { | ||||
VERIFY(0 == nvlist_add_boolean(hdrnv, | VERIFY(0 == nvlist_add_boolean(hdrnv, | ||||
"not_recursive")); | "not_recursive")); | ||||
} | } | ||||
err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name, | err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name, | ||||
fromsnap, tosnap, flags->replicate, flags->verbose, | fromsnap, tosnap, flags->replicate, flags->force, | ||||
&fss, &fsavl); | flags->verbose, &fss, &fsavl); | ||||
if (err) | if (err) | ||||
goto err_out; | goto err_out; | ||||
VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss)); | VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss)); | ||||
err = nvlist_pack(hdrnv, &packbuf, &buflen, | err = nvlist_pack(hdrnv, &packbuf, &buflen, | ||||
NV_ENCODE_XDR, 0); | NV_ENCODE_XDR, 0); | ||||
if (debugnvp) | if (debugnvp) | ||||
*debugnvp = hdrnv; | *debugnvp = hdrnv; | ||||
else | else | ||||
Show All 37 Lines | zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, | ||||
/* dump each stream */ | /* dump each stream */ | ||||
sdd.fromsnap = fromsnap; | sdd.fromsnap = fromsnap; | ||||
sdd.tosnap = tosnap; | sdd.tosnap = tosnap; | ||||
if (tid != 0) | if (tid != 0) | ||||
sdd.outfd = pipefd[0]; | sdd.outfd = pipefd[0]; | ||||
else | else | ||||
sdd.outfd = outfd; | sdd.outfd = outfd; | ||||
sdd.replicate = flags->replicate; | sdd.replicate = flags->replicate; | ||||
sdd.force = flags->force; | |||||
sdd.doall = flags->doall; | sdd.doall = flags->doall; | ||||
sdd.fromorigin = flags->fromorigin; | sdd.fromorigin = flags->fromorigin; | ||||
sdd.fss = fss; | sdd.fss = fss; | ||||
sdd.fsavl = fsavl; | sdd.fsavl = fsavl; | ||||
sdd.verbose = flags->verbose; | sdd.verbose = flags->verbose; | ||||
sdd.parsable = flags->parsable; | sdd.parsable = flags->parsable; | ||||
sdd.progress = flags->progress; | sdd.progress = flags->progress; | ||||
sdd.dryrun = flags->dryrun; | sdd.dryrun = flags->dryrun; | ||||
▲ Show 20 Lines • Show All 540 Lines • ▼ Show 20 Lines | if (flags->dryrun) | ||||
return (0); | return (0); | ||||
again: | again: | ||||
needagain = progress = B_FALSE; | needagain = progress = B_FALSE; | ||||
VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0)); | VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0)); | ||||
if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL, | if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL, | ||||
recursive, B_FALSE, &local_nv, &local_avl)) != 0) | recursive, B_FALSE, B_FALSE, &local_nv, &local_avl)) != 0) | ||||
return (error); | return (error); | ||||
/* | /* | ||||
* Process deletes and renames | * Process deletes and renames | ||||
*/ | */ | ||||
for (fselem = nvlist_next_nvpair(local_nv, NULL); | for (fselem = nvlist_next_nvpair(local_nv, NULL); | ||||
fselem; fselem = nextfselem) { | fselem; fselem = nextfselem) { | ||||
nvlist_t *nvfs, *snaps; | nvlist_t *nvfs, *snaps; | ||||
▲ Show 20 Lines • Show All 1,053 Lines • ▼ Show 20 Lines | if (err && (ioctl_errno == ENOENT || ioctl_errno == EEXIST)) { | ||||
/* | /* | ||||
* XXX Do this faster by just iterating over snaps in | * XXX Do this faster by just iterating over snaps in | ||||
* this fs. Also if zc_value does not exist, we will | * this fs. Also if zc_value does not exist, we will | ||||
* get a strange "does not exist" error message. | * get a strange "does not exist" error message. | ||||
*/ | */ | ||||
*cp = '\0'; | *cp = '\0'; | ||||
if (gather_nvlist(hdl, zc.zc_value, NULL, NULL, B_FALSE, | if (gather_nvlist(hdl, zc.zc_value, NULL, NULL, B_FALSE, | ||||
B_FALSE, &local_nv, &local_avl) == 0) { | B_FALSE, B_FALSE, &local_nv, &local_avl) == 0) { | ||||
*cp = '@'; | *cp = '@'; | ||||
fs = fsavl_find(local_avl, drrb->drr_toguid, NULL); | fs = fsavl_find(local_avl, drrb->drr_toguid, NULL); | ||||
fsavl_destroy(local_avl); | fsavl_destroy(local_avl); | ||||
nvlist_free(local_nv); | nvlist_free(local_nv); | ||||
if (fs != NULL) { | if (fs != NULL) { | ||||
if (flags->verbose) { | if (flags->verbose) { | ||||
(void) printf("snap %s already exists; " | (void) printf("snap %s already exists; " | ||||
▲ Show 20 Lines • Show All 298 Lines • Show Last 20 Lines |