Merge branch 'illumos-2605'

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 <behlendorf1@llnl.gov>
Closes #4742
This commit is contained in:
Brian Behlendorf 2016-06-29 11:26:30 -07:00
commit 5c27b29605
71 changed files with 2632 additions and 975 deletions

View File

@ -60,7 +60,6 @@
#include <sys/ddt.h> #include <sys/ddt.h>
#include <sys/zfeature.h> #include <sys/zfeature.h>
#include <zfs_comutil.h> #include <zfs_comutil.h>
#undef ZFS_MAXNAMELEN
#include <libzfs.h> #include <libzfs.h>
#define ZDB_COMPRESS_NAME(idx) ((idx) < ZIO_COMPRESS_FUNCTIONS ? \ #define ZDB_COMPRESS_NAME(idx) ((idx) < ZIO_COMPRESS_FUNCTIONS ? \
@ -2005,7 +2004,7 @@ dump_dir(objset_t *os)
uint64_t refdbytes, usedobjs, scratch; uint64_t refdbytes, usedobjs, scratch;
char numbuf[32]; char numbuf[32];
char blkbuf[BP_SPRINTF_LEN + 20]; char blkbuf[BP_SPRINTF_LEN + 20];
char osname[MAXNAMELEN]; char osname[ZFS_MAX_DATASET_NAME_LEN];
char *type = "UNKNOWN"; char *type = "UNKNOWN";
int verbosity = dump_opt['d']; int verbosity = dump_opt['d'];
int print_header = 1; int print_header = 1;
@ -3553,7 +3552,7 @@ find_zpool(char **target, nvlist_t **configp, int dirc, char **dirv)
nvlist_t *match = NULL; nvlist_t *match = NULL;
char *name = NULL; char *name = NULL;
char *sepp = NULL; char *sepp = NULL;
char sep = 0; char sep = '\0';
int count = 0; int count = 0;
importargs_t args = { 0 }; importargs_t args = { 0 };

View File

@ -248,10 +248,11 @@ get_usage(zfs_help_t idx)
case HELP_PROMOTE: case HELP_PROMOTE:
return (gettext("\tpromote <clone-filesystem>\n")); return (gettext("\tpromote <clone-filesystem>\n"));
case HELP_RECEIVE: case HELP_RECEIVE:
return (gettext("\treceive [-vnFu] <filesystem|volume|" return (gettext("\treceive [-vnsFu] <filesystem|volume|"
"snapshot>\n" "snapshot>\n"
"\treceive [-vnFu] [-o origin=<snapshot>] [-d | -e] " "\treceive [-vnsFu] [-o origin=<snapshot>] [-d | -e] "
"<filesystem>\n")); "<filesystem>\n"
"\treceive -A <filesystem|volume>\n"));
case HELP_RENAME: case HELP_RENAME:
return (gettext("\trename [-f] <filesystem|volume|snapshot> " return (gettext("\trename [-f] <filesystem|volume|snapshot> "
"<filesystem|volume|snapshot>\n" "<filesystem|volume|snapshot>\n"
@ -263,7 +264,8 @@ get_usage(zfs_help_t idx)
return (gettext("\tsend [-DnPpRvLe] [-[iI] snapshot] " return (gettext("\tsend [-DnPpRvLe] [-[iI] snapshot] "
"<snapshot>\n" "<snapshot>\n"
"\tsend [-Le] [-i snapshot|bookmark] " "\tsend [-Le] [-i snapshot|bookmark] "
"<filesystem|volume|snapshot>\n")); "<filesystem|volume|snapshot>\n"
"\tsend [-nvPe] -t <receive_resume_token>\n"));
case HELP_SET: case HELP_SET:
return (gettext("\tset <property=value> ... " return (gettext("\tset <property=value> ... "
"<filesystem|volume|snapshot> ...\n")); "<filesystem|volume|snapshot> ...\n"));
@ -1481,7 +1483,7 @@ get_callback(zfs_handle_t *zhp, void *data)
char buf[ZFS_MAXPROPLEN]; char buf[ZFS_MAXPROPLEN];
char rbuf[ZFS_MAXPROPLEN]; char rbuf[ZFS_MAXPROPLEN];
zprop_source_t sourcetype; zprop_source_t sourcetype;
char source[ZFS_MAXNAMELEN]; char source[ZFS_MAX_DATASET_NAME_LEN];
zprop_get_cbdata_t *cbp = data; zprop_get_cbdata_t *cbp = data;
nvlist_t *user_props = zfs_get_user_props(zhp); nvlist_t *user_props = zfs_get_user_props(zhp);
zprop_list_t *pl = cbp->cb_proplist; zprop_list_t *pl = cbp->cb_proplist;
@ -1961,7 +1963,7 @@ typedef struct upgrade_cbdata {
uint64_t cb_version; uint64_t cb_version;
boolean_t cb_newer; boolean_t cb_newer;
boolean_t cb_foundone; boolean_t cb_foundone;
char cb_lastfs[ZFS_MAXNAMELEN]; char cb_lastfs[ZFS_MAX_DATASET_NAME_LEN];
} upgrade_cbdata_t; } upgrade_cbdata_t;
static int static int
@ -2410,7 +2412,7 @@ userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
if (domain != NULL && domain[0] != '\0') { if (domain != NULL && domain[0] != '\0') {
#ifdef HAVE_IDMAP #ifdef HAVE_IDMAP
/* SMB */ /* SMB */
char sid[ZFS_MAXNAMELEN + 32]; char sid[MAXNAMELEN + 32];
uid_t id; uid_t id;
uint64_t classes; uint64_t classes;
int err; int err;
@ -2544,7 +2546,7 @@ print_us_node(boolean_t scripted, boolean_t parsable, int *fields, int types,
size_t *width, us_node_t *node) size_t *width, us_node_t *node)
{ {
nvlist_t *nvl = node->usn_nvl; nvlist_t *nvl = node->usn_nvl;
char valstr[ZFS_MAXNAMELEN]; char valstr[MAXNAMELEN];
boolean_t first = B_TRUE; boolean_t first = B_TRUE;
int cfield = 0; int cfield = 0;
int field; int field;
@ -3415,7 +3417,7 @@ zfs_do_rollback(int argc, char **argv)
boolean_t force = B_FALSE; boolean_t force = B_FALSE;
rollback_cbdata_t cb = { 0 }; rollback_cbdata_t cb = { 0 };
zfs_handle_t *zhp, *snap; zfs_handle_t *zhp, *snap;
char parentname[ZFS_MAXNAMELEN]; char parentname[ZFS_MAX_DATASET_NAME_LEN];
char *delim; char *delim;
/* check options */ /* check options */
@ -3707,6 +3709,7 @@ zfs_do_send(int argc, char **argv)
{ {
char *fromname = NULL; char *fromname = NULL;
char *toname = NULL; char *toname = NULL;
char *resume_token = NULL;
char *cp; char *cp;
zfs_handle_t *zhp; zfs_handle_t *zhp;
sendflags_t flags = { 0 }; sendflags_t flags = { 0 };
@ -3715,7 +3718,7 @@ zfs_do_send(int argc, char **argv)
boolean_t extraverbose = B_FALSE; boolean_t extraverbose = B_FALSE;
/* check options */ /* check options */
while ((c = getopt(argc, argv, ":i:I:RDpvnPLe")) != -1) { while ((c = getopt(argc, argv, ":i:I:RDpvnPLet:")) != -1) {
switch (c) { switch (c) {
case 'i': case 'i':
if (fromname) if (fromname)
@ -3756,6 +3759,9 @@ zfs_do_send(int argc, char **argv)
case 'e': case 'e':
flags.embed_data = B_TRUE; flags.embed_data = B_TRUE;
break; break;
case 't':
resume_token = optarg;
break;
case ':': case ':':
(void) fprintf(stderr, gettext("missing argument for " (void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt); "'%c' option\n"), optopt);
@ -3771,14 +3777,28 @@ zfs_do_send(int argc, char **argv)
argc -= optind; argc -= optind;
argv += optind; argv += optind;
/* check number of arguments */ if (resume_token != NULL) {
if (argc < 1) { if (fromname != NULL || flags.replicate || flags.props ||
(void) fprintf(stderr, gettext("missing snapshot argument\n")); flags.dedup) {
usage(B_FALSE); (void) fprintf(stderr,
} gettext("invalid flags combined with -t\n"));
if (argc > 1) { usage(B_FALSE);
(void) fprintf(stderr, gettext("too many arguments\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)) { if (!flags.dryrun && isatty(STDOUT_FILENO)) {
@ -3788,12 +3808,17 @@ zfs_do_send(int argc, char **argv)
return (1); 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. * Special case sending a filesystem, or from a bookmark.
*/ */
if (strchr(argv[0], '@') == NULL || if (strchr(argv[0], '@') == NULL ||
(fromname && strchr(fromname, '#') != NULL)) { (fromname && strchr(fromname, '#') != NULL)) {
char frombuf[ZFS_MAXNAMELEN]; char frombuf[ZFS_MAX_DATASET_NAME_LEN];
enum lzc_send_flags lzc_flags = 0; enum lzc_send_flags lzc_flags = 0;
if (flags.replicate || flags.doall || flags.props || if (flags.replicate || flags.doall || flags.props ||
@ -3845,7 +3870,7 @@ zfs_do_send(int argc, char **argv)
* case if they specify the origin. * case if they specify the origin.
*/ */
if (fromname && (cp = strchr(fromname, '@')) != NULL) { if (fromname && (cp = strchr(fromname, '@')) != NULL) {
char origin[ZFS_MAXNAMELEN]; char origin[ZFS_MAX_DATASET_NAME_LEN];
zprop_source_t src; zprop_source_t src;
(void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN, (void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
@ -3893,8 +3918,6 @@ zfs_do_send(int argc, char **argv)
} }
/* /*
* zfs receive [-vnFu] [-d | -e] <fs@snap>
*
* Restore a backup stream from stdin. * Restore a backup stream from stdin.
*/ */
static int static int
@ -3902,6 +3925,8 @@ zfs_do_receive(int argc, char **argv)
{ {
int c, err; int c, err;
recvflags_t flags = { 0 }; recvflags_t flags = { 0 };
boolean_t abort_resumable = B_FALSE;
nvlist_t *props; nvlist_t *props;
nvpair_t *nvp = NULL; nvpair_t *nvp = NULL;
@ -3909,7 +3934,7 @@ zfs_do_receive(int argc, char **argv)
nomem(); nomem();
/* check options */ /* check options */
while ((c = getopt(argc, argv, ":o:denuvF")) != -1) { while ((c = getopt(argc, argv, ":o:denuvFsA")) != -1) {
switch (c) { switch (c) {
case 'o': case 'o':
if (parseprop(props, optarg) != 0) if (parseprop(props, optarg) != 0)
@ -3931,9 +3956,15 @@ zfs_do_receive(int argc, char **argv)
case 'v': case 'v':
flags.verbose = B_TRUE; flags.verbose = B_TRUE;
break; break;
case 's':
flags.resumable = B_TRUE;
break;
case 'F': case 'F':
flags.force = B_TRUE; flags.force = B_TRUE;
break; break;
case 'A':
abort_resumable = B_TRUE;
break;
case ':': case ':':
(void) fprintf(stderr, gettext("missing argument for " (void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt); "'%c' option\n"), optopt);
@ -3966,6 +3997,44 @@ 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)) { if (isatty(STDIN_FILENO)) {
(void) fprintf(stderr, (void) fprintf(stderr,
gettext("Error: Backup stream can not be read " gettext("Error: Backup stream can not be read "
@ -3973,7 +4042,6 @@ zfs_do_receive(int argc, char **argv)
"You must redirect standard input.\n")); "You must redirect standard input.\n"));
return (1); return (1);
} }
err = zfs_receive(g_zfs, argv[0], props, &flags, STDIN_FILENO, NULL); err = zfs_receive(g_zfs, argv[0], props, &flags, STDIN_FILENO, NULL);
return (err != 0); return (err != 0);
@ -4792,7 +4860,7 @@ store_allow_perm(zfs_deleg_who_type_t type, boolean_t local, boolean_t descend,
{ {
int i; int i;
char ld[2] = { '\0', '\0' }; char ld[2] = { '\0', '\0' };
char who_buf[ZFS_MAXNAMELEN+32]; char who_buf[MAXNAMELEN + 32];
char base_type = ZFS_DELEG_WHO_UNKNOWN; char base_type = ZFS_DELEG_WHO_UNKNOWN;
char set_type = ZFS_DELEG_WHO_UNKNOWN; char set_type = ZFS_DELEG_WHO_UNKNOWN;
nvlist_t *base_nvl = NULL; nvlist_t *base_nvl = NULL;
@ -5156,7 +5224,7 @@ static void
print_fs_perms(fs_perm_set_t *fspset) print_fs_perms(fs_perm_set_t *fspset)
{ {
fs_perm_node_t *node = NULL; fs_perm_node_t *node = NULL;
char buf[ZFS_MAXNAMELEN+32]; char buf[MAXNAMELEN + 32];
const char *dsname = buf; const char *dsname = buf;
for (node = uu_list_first(fspset->fsps_list); node != NULL; for (node = uu_list_first(fspset->fsps_list); node != NULL;
@ -5165,7 +5233,7 @@ print_fs_perms(fs_perm_set_t *fspset)
uu_avl_t *uge_avl = node->fspn_fsperm.fsp_uge_avl; uu_avl_t *uge_avl = node->fspn_fsperm.fsp_uge_avl;
int left = 0; int left = 0;
(void) snprintf(buf, ZFS_MAXNAMELEN+32, (void) snprintf(buf, sizeof (buf),
gettext("---- Permissions on %s "), gettext("---- Permissions on %s "),
node->fspn_fsperm.fsp_name); node->fspn_fsperm.fsp_name);
(void) printf("%s", dsname); (void) printf("%s", dsname);
@ -5362,7 +5430,7 @@ zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
for (i = 0; i < argc; ++i) { for (i = 0; i < argc; ++i) {
zfs_handle_t *zhp; zfs_handle_t *zhp;
char parent[ZFS_MAXNAMELEN]; char parent[ZFS_MAX_DATASET_NAME_LEN];
const char *delim; const char *delim;
char *path = argv[i]; char *path = argv[i];
@ -5490,7 +5558,7 @@ holds_callback(zfs_handle_t *zhp, void *data)
nvlist_t *nvl = NULL; nvlist_t *nvl = NULL;
nvpair_t *nvp = NULL; nvpair_t *nvp = NULL;
const char *zname = zfs_get_name(zhp); const char *zname = zfs_get_name(zhp);
size_t znamelen = strnlen(zname, ZFS_MAXNAMELEN); size_t znamelen = strlen(zname);
if (cbp->cb_recursive) { if (cbp->cb_recursive) {
const char *snapname; const char *snapname;
@ -5511,7 +5579,7 @@ holds_callback(zfs_handle_t *zhp, void *data)
while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
const char *tag = nvpair_name(nvp); const char *tag = nvpair_name(nvp);
size_t taglen = strnlen(tag, MAXNAMELEN); size_t taglen = strlen(tag);
if (taglen > cbp->cb_max_taglen) if (taglen > cbp->cb_max_taglen)
cbp->cb_max_taglen = taglen; cbp->cb_max_taglen = taglen;
} }
@ -5803,6 +5871,24 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
return (0); 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 * At this point, we have verified that the mountpoint and/or
* shareopts are appropriate for auto management. If the * shareopts are appropriate for auto management. If the
@ -6609,7 +6695,7 @@ zfs_do_diff(int argc, char **argv)
static int static int
zfs_do_bookmark(int argc, char **argv) zfs_do_bookmark(int argc, char **argv)
{ {
char snapname[ZFS_MAXNAMELEN]; char snapname[ZFS_MAX_DATASET_NAME_LEN];
zfs_handle_t *zhp; zfs_handle_t *zhp;
nvlist_t *nvl; nvlist_t *nvl;
int ret = 0; int ret = 0;

View File

@ -48,7 +48,6 @@
#include <sys/zio_compress.h> #include <sys/zio_compress.h>
#include <sys/zfeature.h> #include <sys/zfeature.h>
#include <sys/dmu_tx.h> #include <sys/dmu_tx.h>
#undef ZFS_MAXNAMELEN
#include <libzfs.h> #include <libzfs.h>
extern boolean_t zfeature_checks_disable; extern boolean_t zfeature_checks_disable;

View File

@ -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[1],
(longlong_t)saved_cksum.zc_word[2], (longlong_t)saved_cksum.zc_word[2],
(longlong_t)saved_cksum.zc_word[3]); (longlong_t)saved_cksum.zc_word[3]);
exit(1); return (0);
} }
return (sizeof (*drr)); return (sizeof (*drr));
} }
@ -347,8 +347,7 @@ main(int argc, char *argv[])
if (verbose) if (verbose)
(void) printf("\n"); (void) printf("\n");
if ((DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == if (drr->drr_payloadlen != 0) {
DMU_COMPOUNDSTREAM) && drr->drr_payloadlen != 0) {
nvlist_t *nv; nvlist_t *nv;
int sz = drr->drr_payloadlen; int sz = drr->drr_payloadlen;

View File

@ -145,8 +145,8 @@ typedef struct ztest_shared_hdr {
static ztest_shared_hdr_t *ztest_shared_hdr; static ztest_shared_hdr_t *ztest_shared_hdr;
typedef struct ztest_shared_opts { typedef struct ztest_shared_opts {
char zo_pool[MAXNAMELEN]; char zo_pool[ZFS_MAX_DATASET_NAME_LEN];
char zo_dir[MAXNAMELEN]; char zo_dir[ZFS_MAX_DATASET_NAME_LEN];
char zo_alt_ztest[MAXNAMELEN]; char zo_alt_ztest[MAXNAMELEN];
char zo_alt_libpath[MAXNAMELEN]; char zo_alt_libpath[MAXNAMELEN];
uint64_t zo_vdevs; uint64_t zo_vdevs;
@ -262,7 +262,7 @@ typedef struct ztest_od {
uint64_t od_crdnodesize; uint64_t od_crdnodesize;
uint64_t od_gen; uint64_t od_gen;
uint64_t od_crgen; uint64_t od_crgen;
char od_name[MAXNAMELEN]; char od_name[ZFS_MAX_DATASET_NAME_LEN];
} ztest_od_t; } ztest_od_t;
/* /*
@ -274,7 +274,7 @@ typedef struct ztest_ds {
rwlock_t zd_zilog_lock; rwlock_t zd_zilog_lock;
zilog_t *zd_zilog; zilog_t *zd_zilog;
ztest_od_t *zd_od; /* debugging aid */ ztest_od_t *zd_od; /* debugging aid */
char zd_name[MAXNAMELEN]; char zd_name[ZFS_MAX_DATASET_NAME_LEN];
kmutex_t zd_dirobj_lock; kmutex_t zd_dirobj_lock;
rll_t zd_object_lock[ZTEST_OBJECT_LOCKS]; rll_t zd_object_lock[ZTEST_OBJECT_LOCKS];
zll_t zd_range_lock[ZTEST_RANGE_LOCKS]; zll_t zd_range_lock[ZTEST_RANGE_LOCKS];
@ -3504,7 +3504,7 @@ ztest_objset_destroy_cb(const char *name, void *arg)
static boolean_t static boolean_t
ztest_snapshot_create(char *osname, uint64_t id) ztest_snapshot_create(char *osname, uint64_t id)
{ {
char snapname[MAXNAMELEN]; char snapname[ZFS_MAX_DATASET_NAME_LEN];
int error; int error;
(void) snprintf(snapname, sizeof (snapname), "%llu", (u_longlong_t)id); (void) snprintf(snapname, sizeof (snapname), "%llu", (u_longlong_t)id);
@ -3524,10 +3524,10 @@ ztest_snapshot_create(char *osname, uint64_t id)
static boolean_t static boolean_t
ztest_snapshot_destroy(char *osname, uint64_t id) ztest_snapshot_destroy(char *osname, uint64_t id)
{ {
char snapname[MAXNAMELEN]; char snapname[ZFS_MAX_DATASET_NAME_LEN];
int error; int error;
(void) snprintf(snapname, MAXNAMELEN, "%s@%llu", osname, (void) snprintf(snapname, sizeof (snapname), "%s@%llu", osname,
(u_longlong_t)id); (u_longlong_t)id);
error = dsl_destroy_snapshot(snapname, B_FALSE); error = dsl_destroy_snapshot(snapname, B_FALSE);
@ -3544,16 +3544,15 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
int iters; int iters;
int error; int error;
objset_t *os, *os2; objset_t *os, *os2;
char *name; char name[ZFS_MAX_DATASET_NAME_LEN];
zilog_t *zilog; zilog_t *zilog;
int i; int i;
zdtmp = umem_alloc(sizeof (ztest_ds_t), UMEM_NOFAIL); zdtmp = umem_alloc(sizeof (ztest_ds_t), UMEM_NOFAIL);
name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL);
(void) rw_rdlock(&ztest_name_lock); (void) rw_rdlock(&ztest_name_lock);
(void) snprintf(name, MAXNAMELEN, "%s/temp_%llu", (void) snprintf(name, sizeof (name), "%s/temp_%llu",
ztest_opts.zo_pool, (u_longlong_t)id); ztest_opts.zo_pool, (u_longlong_t)id);
/* /*
@ -3639,7 +3638,6 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
out: out:
(void) rw_unlock(&ztest_name_lock); (void) rw_unlock(&ztest_name_lock);
umem_free(name, MAXNAMELEN);
umem_free(zdtmp, sizeof (ztest_ds_t)); umem_free(zdtmp, sizeof (ztest_ds_t));
} }
@ -3668,22 +3666,22 @@ ztest_dsl_dataset_cleanup(char *osname, uint64_t id)
char *snap3name; char *snap3name;
int error; int error;
snap1name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL); snap1name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
clone1name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL); clone1name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
snap2name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL); snap2name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
clone2name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL); clone2name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
snap3name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL); snap3name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
(void) snprintf(snap1name, MAXNAMELEN, "%s@s1_%llu", (void) snprintf(snap1name, ZFS_MAX_DATASET_NAME_LEN,
osname, (u_longlong_t)id); "%s@s1_%llu", osname, (u_longlong_t)id);
(void) snprintf(clone1name, MAXNAMELEN, "%s/c1_%llu", (void) snprintf(clone1name, ZFS_MAX_DATASET_NAME_LEN,
osname, (u_longlong_t)id); "%s/c1_%llu", osname, (u_longlong_t)id);
(void) snprintf(snap2name, MAXNAMELEN, "%s@s2_%llu", (void) snprintf(snap2name, ZFS_MAX_DATASET_NAME_LEN,
clone1name, (u_longlong_t)id); "%s@s2_%llu", clone1name, (u_longlong_t)id);
(void) snprintf(clone2name, MAXNAMELEN, "%s/c2_%llu", (void) snprintf(clone2name, ZFS_MAX_DATASET_NAME_LEN,
osname, (u_longlong_t)id); "%s/c2_%llu", osname, (u_longlong_t)id);
(void) snprintf(snap3name, MAXNAMELEN, "%s@s3_%llu", (void) snprintf(snap3name, ZFS_MAX_DATASET_NAME_LEN,
clone1name, (u_longlong_t)id); "%s@s3_%llu", clone1name, (u_longlong_t)id);
error = dsl_destroy_head(clone2name); error = dsl_destroy_head(clone2name);
if (error && error != ENOENT) if (error && error != ENOENT)
@ -3701,11 +3699,11 @@ ztest_dsl_dataset_cleanup(char *osname, uint64_t id)
if (error && error != ENOENT) if (error && error != ENOENT)
fatal(0, "dsl_destroy_snapshot(%s) = %d", snap1name, error); fatal(0, "dsl_destroy_snapshot(%s) = %d", snap1name, error);
umem_free(snap1name, MAXNAMELEN); umem_free(snap1name, ZFS_MAX_DATASET_NAME_LEN);
umem_free(clone1name, MAXNAMELEN); umem_free(clone1name, ZFS_MAX_DATASET_NAME_LEN);
umem_free(snap2name, MAXNAMELEN); umem_free(snap2name, ZFS_MAX_DATASET_NAME_LEN);
umem_free(clone2name, MAXNAMELEN); umem_free(clone2name, ZFS_MAX_DATASET_NAME_LEN);
umem_free(snap3name, MAXNAMELEN); umem_free(snap3name, ZFS_MAX_DATASET_NAME_LEN);
} }
/* /*
@ -3723,26 +3721,26 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
char *osname = zd->zd_name; char *osname = zd->zd_name;
int error; int error;
snap1name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL); snap1name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
clone1name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL); clone1name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
snap2name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL); snap2name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
clone2name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL); clone2name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
snap3name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL); snap3name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
(void) rw_rdlock(&ztest_name_lock); (void) rw_rdlock(&ztest_name_lock);
ztest_dsl_dataset_cleanup(osname, id); ztest_dsl_dataset_cleanup(osname, id);
(void) snprintf(snap1name, MAXNAMELEN, "%s@s1_%llu", (void) snprintf(snap1name, ZFS_MAX_DATASET_NAME_LEN,
osname, (u_longlong_t)id); "%s@s1_%llu", osname, (u_longlong_t)id);
(void) snprintf(clone1name, MAXNAMELEN, "%s/c1_%llu", (void) snprintf(clone1name, ZFS_MAX_DATASET_NAME_LEN,
osname, (u_longlong_t)id); "%s/c1_%llu", osname, (u_longlong_t)id);
(void) snprintf(snap2name, MAXNAMELEN, "%s@s2_%llu", (void) snprintf(snap2name, ZFS_MAX_DATASET_NAME_LEN,
clone1name, (u_longlong_t)id); "%s@s2_%llu", clone1name, (u_longlong_t)id);
(void) snprintf(clone2name, MAXNAMELEN, "%s/c2_%llu", (void) snprintf(clone2name, ZFS_MAX_DATASET_NAME_LEN,
osname, (u_longlong_t)id); "%s/c2_%llu", osname, (u_longlong_t)id);
(void) snprintf(snap3name, MAXNAMELEN, "%s@s3_%llu", (void) snprintf(snap3name, ZFS_MAX_DATASET_NAME_LEN,
clone1name, (u_longlong_t)id); "%s@s3_%llu", clone1name, (u_longlong_t)id);
error = dmu_objset_snapshot_one(osname, strchr(snap1name, '@') + 1); error = dmu_objset_snapshot_one(osname, strchr(snap1name, '@') + 1);
if (error && error != EEXIST) { if (error && error != EEXIST) {
@ -3808,11 +3806,11 @@ out:
(void) rw_unlock(&ztest_name_lock); (void) rw_unlock(&ztest_name_lock);
umem_free(snap1name, MAXNAMELEN); umem_free(snap1name, ZFS_MAX_DATASET_NAME_LEN);
umem_free(clone1name, MAXNAMELEN); umem_free(clone1name, ZFS_MAX_DATASET_NAME_LEN);
umem_free(snap2name, MAXNAMELEN); umem_free(snap2name, ZFS_MAX_DATASET_NAME_LEN);
umem_free(clone2name, MAXNAMELEN); umem_free(clone2name, ZFS_MAX_DATASET_NAME_LEN);
umem_free(snap3name, MAXNAMELEN); umem_free(snap3name, ZFS_MAX_DATASET_NAME_LEN);
} }
#undef OD_ARRAY_SIZE #undef OD_ARRAY_SIZE
@ -4622,7 +4620,7 @@ ztest_fzap(ztest_ds_t *zd, uint64_t id)
* 2050 entries we should see ptrtbl growth and leaf-block split. * 2050 entries we should see ptrtbl growth and leaf-block split.
*/ */
for (i = 0; i < 2050; i++) { for (i = 0; i < 2050; i++) {
char name[MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
uint64_t value = i; uint64_t value = i;
dmu_tx_t *tx; dmu_tx_t *tx;
int error; int error;
@ -5077,7 +5075,7 @@ ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
char fullname[100]; char fullname[100];
char clonename[100]; char clonename[100];
char tag[100]; char tag[100];
char osname[MAXNAMELEN]; char osname[ZFS_MAX_DATASET_NAME_LEN];
nvlist_t *holds; nvlist_t *holds;
(void) rw_rdlock(&ztest_name_lock); (void) rw_rdlock(&ztest_name_lock);
@ -5964,13 +5962,13 @@ ztest_thread(void *arg)
static void static void
ztest_dataset_name(char *dsname, char *pool, int d) ztest_dataset_name(char *dsname, char *pool, int d)
{ {
(void) snprintf(dsname, MAXNAMELEN, "%s/ds_%d", pool, d); (void) snprintf(dsname, ZFS_MAX_DATASET_NAME_LEN, "%s/ds_%d", pool, d);
} }
static void static void
ztest_dataset_destroy(int d) ztest_dataset_destroy(int d)
{ {
char name[MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
int t; int t;
ztest_dataset_name(name, ztest_opts.zo_pool, d); ztest_dataset_name(name, ztest_opts.zo_pool, d);
@ -6019,7 +6017,7 @@ ztest_dataset_open(int d)
uint64_t committed_seq = ZTEST_GET_SHARED_DS(d)->zd_seq; uint64_t committed_seq = ZTEST_GET_SHARED_DS(d)->zd_seq;
objset_t *os; objset_t *os;
zilog_t *zilog; zilog_t *zilog;
char name[MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
int error; int error;
ztest_dataset_name(name, ztest_opts.zo_pool, d); ztest_dataset_name(name, ztest_opts.zo_pool, d);
@ -6256,8 +6254,8 @@ ztest_run(ztest_shared_t *zs)
* different name. * different name.
*/ */
if (ztest_random(2) == 0) { if (ztest_random(2) == 0) {
char name[MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
(void) snprintf(name, MAXNAMELEN, "%s_import", (void) snprintf(name, sizeof (name), "%s_import",
ztest_opts.zo_pool); ztest_opts.zo_pool);
ztest_spa_import_export(ztest_opts.zo_pool, name); ztest_spa_import_export(ztest_opts.zo_pool, name);
ztest_spa_import_export(name, ztest_opts.zo_pool); ztest_spa_import_export(name, ztest_opts.zo_pool);
@ -6834,7 +6832,7 @@ main(int argc, char **argv)
if (spa_open(ztest_opts.zo_pool, &spa, FTAG) == 0) { if (spa_open(ztest_opts.zo_pool, &spa, FTAG) == 0) {
spa_close(spa, FTAG); spa_close(spa, FTAG);
} else { } else {
char tmpname[MAXNAMELEN]; char tmpname[ZFS_MAX_DATASET_NAME_LEN];
kernel_fini(); kernel_fini();
kernel_init(FREAD | FWRITE); kernel_init(FREAD | FWRITE);
(void) snprintf(tmpname, sizeof (tmpname), "%s_tmp", (void) snprintf(tmpname, sizeof (tmpname), "%s_tmp",

View File

@ -39,14 +39,14 @@ static int
ioctl_get_msg(char *var, int fd) ioctl_get_msg(char *var, int fd)
{ {
int error = 0; int error = 0;
char msg[ZFS_MAXNAMELEN]; char msg[ZFS_MAX_DATASET_NAME_LEN];
error = ioctl(fd, BLKZNAME, msg); error = ioctl(fd, BLKZNAME, msg);
if (error < 0) { if (error < 0) {
return (error); return (error);
} }
snprintf(var, ZFS_MAXNAMELEN, "%s", msg); snprintf(var, ZFS_MAX_DATASET_NAME_LEN, "%s", msg);
return (error); return (error);
} }
@ -54,7 +54,8 @@ int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int fd, error = 0; int fd, error = 0;
char zvol_name[ZFS_MAXNAMELEN], zvol_name_part[ZFS_MAXNAMELEN]; char zvol_name[ZFS_MAX_DATASET_NAME_LEN];
char zvol_name_part[ZFS_MAX_DATASET_NAME_LEN];
char *dev_name; char *dev_name;
struct stat64 statbuf; struct stat64 statbuf;
int dev_minor, dev_part; int dev_minor, dev_part;
@ -87,10 +88,11 @@ main(int argc, char **argv)
return (errno); return (errno);
} }
if (dev_part > 0) if (dev_part > 0)
snprintf(zvol_name_part, ZFS_MAXNAMELEN, "%s-part%d", zvol_name, snprintf(zvol_name_part, ZFS_MAX_DATASET_NAME_LEN,
dev_part); "%s-part%d", zvol_name, dev_part);
else else
snprintf(zvol_name_part, ZFS_MAXNAMELEN, "%s", zvol_name); snprintf(zvol_name_part, ZFS_MAX_DATASET_NAME_LEN,
"%s", zvol_name);
for (i = 0; i < strlen(zvol_name_part); i++) { for (i = 0; i < strlen(zvol_name_part); i++) {
if (isblank(zvol_name_part[i])) if (isblank(zvol_name_part[i]))

View File

@ -1,21 +0,0 @@
dnl #
dnl # 2.6.27 API change,
dnl # kobject KOBJ_NAME_LEN static limit removed. All users of this
dnl # constant were removed prior to 2.6.27, but to be on the safe
dnl # side this check ensures the constant is undefined.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_KOBJ_NAME_LEN], [
AC_MSG_CHECKING([whether kernel defines KOBJ_NAME_LEN])
ZFS_LINUX_TRY_COMPILE([
#include <linux/kobject.h>
],[
int val __attribute__ ((unused));
val = KOBJ_NAME_LEN;
],[
AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_KOBJ_NAME_LEN, 1,
[kernel defines KOBJ_NAME_LEN])
],[
AC_MSG_RESULT([no])
])
])

View File

@ -11,7 +11,6 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
ZFS_AC_KERNEL_BDEV_BLOCK_DEVICE_OPERATIONS ZFS_AC_KERNEL_BDEV_BLOCK_DEVICE_OPERATIONS
ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
ZFS_AC_KERNEL_TYPE_FMODE_T ZFS_AC_KERNEL_TYPE_FMODE_T
ZFS_AC_KERNEL_KOBJ_NAME_LEN
ZFS_AC_KERNEL_3ARG_BLKDEV_GET ZFS_AC_KERNEL_3ARG_BLKDEV_GET
ZFS_AC_KERNEL_BLKDEV_GET_BY_PATH ZFS_AC_KERNEL_BLKDEV_GET_BY_PATH
ZFS_AC_KERNEL_OPEN_BDEV_EXCLUSIVE ZFS_AC_KERNEL_OPEN_BDEV_EXCLUSIVE

View File

@ -67,6 +67,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_COMMON], [
AC_PATH_TOOL(SHUF, shuf, "") AC_PATH_TOOL(SHUF, shuf, "")
AC_PATH_TOOL(SLEEP, sleep, "") AC_PATH_TOOL(SLEEP, sleep, "")
AC_PATH_TOOL(SORT, sort, "") AC_PATH_TOOL(SORT, sort, "")
AC_PATH_TOOL(STAT, stat, "")
AC_PATH_TOOL(STRINGS, strings, "") AC_PATH_TOOL(STRINGS, strings, "")
AC_PATH_TOOL(SU, su, "") AC_PATH_TOOL(SU, su, "")
AC_PATH_TOOL(SUM, sum, "") AC_PATH_TOOL(SUM, sum, "")
@ -75,6 +76,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_COMMON], [
AC_PATH_TOOL(TAR, tar, "") AC_PATH_TOOL(TAR, tar, "")
AC_PATH_TOOL(TOUCH, touch, "") AC_PATH_TOOL(TOUCH, touch, "")
AC_PATH_TOOL(TR, tr, "") AC_PATH_TOOL(TR, tr, "")
AC_PATH_TOOL(TRUNCATE, truncate, "")
AC_PATH_TOOL(TRUE, true, "") AC_PATH_TOOL(TRUE, true, "")
AC_PATH_TOOL(UMASK, umask, "") AC_PATH_TOOL(UMASK, umask, "")
AC_PATH_TOOL(UMOUNT, umount, "") AC_PATH_TOOL(UMOUNT, umount, "")
@ -103,7 +105,6 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_LINUX], [
AC_PATH_TOOL(SHARE, exportfs, "") AC_PATH_TOOL(SHARE, exportfs, "")
AC_PATH_TOOL(SWAP, swapon, "") AC_PATH_TOOL(SWAP, swapon, "")
AC_PATH_TOOL(SWAPADD, swapon, "") AC_PATH_TOOL(SWAPADD, swapon, "")
AC_PATH_TOOL(TRUNCATE, truncate, "")
AC_PATH_TOOL(UDEVADM, udevadm, "") AC_PATH_TOOL(UDEVADM, udevadm, "")
AC_PATH_TOOL(UFSDUMP, dump, "") AC_PATH_TOOL(UFSDUMP, dump, "")
AC_PATH_TOOL(UFSRESTORE, restore, "") AC_PATH_TOOL(UFSRESTORE, restore, "")

View File

@ -49,8 +49,6 @@ extern "C" {
/* /*
* Miscellaneous ZFS constants * Miscellaneous ZFS constants
*/ */
#define ZFS_MAXNAMELEN MAXNAMELEN
#define ZPOOL_MAXNAMELEN MAXNAMELEN
#define ZFS_MAXPROPLEN MAXPATHLEN #define ZFS_MAXPROPLEN MAXPATHLEN
#define ZPOOL_MAXPROPLEN MAXPATHLEN #define ZPOOL_MAXPROPLEN MAXPATHLEN
@ -640,6 +638,10 @@ typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
extern int zfs_send(zfs_handle_t *, const char *, const char *, extern int zfs_send(zfs_handle_t *, const char *, const char *,
sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **); sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
extern int zfs_send_one(zfs_handle_t *, const char *, int, enum lzc_send_flags); extern int zfs_send_one(zfs_handle_t *, const char *, int, enum lzc_send_flags);
extern int zfs_send_resume(libzfs_handle_t *, sendflags_t *, int outfd,
const char *);
extern nvlist_t *zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl,
const char *token);
extern int zfs_promote(zfs_handle_t *); extern int zfs_promote(zfs_handle_t *);
extern int zfs_hold(zfs_handle_t *, const char *, const char *, extern int zfs_hold(zfs_handle_t *, const char *, const char *,
@ -680,6 +682,12 @@ typedef struct recvflags {
/* set "canmount=off" on all modified filesystems */ /* set "canmount=off" on all modified filesystems */
boolean_t canmountoff; boolean_t canmountoff;
/*
* Mark the file systems as "resumable" and do not destroy them if the
* receive is interrupted
*/
boolean_t resumable;
/* byteswap flag is used internally; callers need not specify */ /* byteswap flag is used internally; callers need not specify */
boolean_t byteswap; boolean_t byteswap;

View File

@ -20,7 +20,7 @@
*/ */
/* /*
* Copyright (c) 2013 by Delphix. All rights reserved. * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
*/ */
#ifndef _LIBZFS_CORE_H #ifndef _LIBZFS_CORE_H
@ -58,9 +58,21 @@ enum lzc_send_flags {
}; };
int lzc_send(const char *, const char *, int, enum lzc_send_flags); int lzc_send(const char *, const char *, int, enum lzc_send_flags);
int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int); int lzc_send_resume(const char *, const char *, int,
enum lzc_send_flags, uint64_t, uint64_t);
int lzc_send_space(const char *, const char *, uint64_t *); int lzc_send_space(const char *, const char *, uint64_t *);
struct dmu_replay_record;
int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
int lzc_receive_resumable(const char *, nvlist_t *, const char *,
boolean_t, int);
int lzc_receive_with_header(const char *, nvlist_t *, const char *, boolean_t,
boolean_t, int, const struct dmu_replay_record *);
int lzc_receive_one(const char *, nvlist_t *, const char *, boolean_t,
boolean_t, int, const struct dmu_replay_record *, int, uint64_t *,
uint64_t *, uint64_t *, nvlist_t **);
boolean_t lzc_exists(const char *); boolean_t lzc_exists(const char *);
int lzc_rollback(const char *, char *, int); int lzc_rollback(const char *, char *, int);

View File

@ -21,17 +21,17 @@
/* /*
* 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) 2013 by Delphix. All rights reserved. * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
*/ */
#ifndef _LIBZFS_IMPL_H #ifndef _LIBZFS_IMPL_H
#define _LIBZFS_IMPL_H #define _LIBZFS_IMPL_H
#include <sys/dmu.h>
#include <sys/fs/zfs.h> #include <sys/fs/zfs.h>
#include <sys/zfs_ioctl.h>
#include <sys/spa.h> #include <sys/spa.h>
#include <sys/nvpair.h> #include <sys/nvpair.h>
#include <sys/dmu.h>
#include <sys/zfs_ioctl.h>
#include <libuutil.h> #include <libuutil.h>
#include <libzfs.h> #include <libzfs.h>
@ -85,7 +85,7 @@ struct libzfs_handle {
struct zfs_handle { struct zfs_handle {
libzfs_handle_t *zfs_hdl; libzfs_handle_t *zfs_hdl;
zpool_handle_t *zpool_hdl; zpool_handle_t *zpool_hdl;
char zfs_name[ZFS_MAXNAMELEN]; char zfs_name[ZFS_MAX_DATASET_NAME_LEN];
zfs_type_t zfs_type; /* type including snapshot */ zfs_type_t zfs_type; /* type including snapshot */
zfs_type_t zfs_head_type; /* type excluding snapshot */ zfs_type_t zfs_head_type; /* type excluding snapshot */
dmu_objset_stats_t zfs_dmustats; dmu_objset_stats_t zfs_dmustats;
@ -106,7 +106,7 @@ struct zfs_handle {
struct zpool_handle { struct zpool_handle {
libzfs_handle_t *zpool_hdl; libzfs_handle_t *zpool_hdl;
zpool_handle_t *zpool_next; zpool_handle_t *zpool_next;
char zpool_name[ZPOOL_MAXNAMELEN]; char zpool_name[ZFS_MAX_DATASET_NAME_LEN];
int zpool_state; int zpool_state;
size_t zpool_config_size; size_t zpool_config_size;
nvlist_t *zpool_config; nvlist_t *zpool_config;

View File

@ -816,7 +816,7 @@ typedef struct dmu_objset_stats {
dmu_objset_type_t dds_type; dmu_objset_type_t dds_type;
uint8_t dds_is_snapshot; uint8_t dds_is_snapshot;
uint8_t dds_inconsistent; uint8_t dds_inconsistent;
char dds_origin[MAXNAMELEN]; char dds_origin[ZFS_MAX_DATASET_NAME_LEN];
} dmu_objset_stats_t; } dmu_objset_stats_t;
/* /*

View File

@ -24,7 +24,7 @@
*/ */
/* /*
* Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved. * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
*/ */
#ifndef _SYS_DMU_IMPL_H #ifndef _SYS_DMU_IMPL_H
@ -268,10 +268,11 @@ typedef struct dmu_sendarg {
uint64_t dsa_toguid; uint64_t dsa_toguid;
int dsa_err; int dsa_err;
dmu_pendop_t dsa_pending_op; dmu_pendop_t dsa_pending_op;
boolean_t dsa_incremental;
uint64_t dsa_featureflags; uint64_t dsa_featureflags;
uint64_t dsa_last_data_object; uint64_t dsa_last_data_object;
uint64_t dsa_last_data_offset; uint64_t dsa_last_data_offset;
uint64_t dsa_resume_object;
uint64_t dsa_resume_offset;
} dmu_sendarg_t; } dmu_sendarg_t;
void dmu_object_zapify(objset_t *, uint64_t, dmu_object_type_t, dmu_tx_t *); void dmu_object_zapify(objset_t *, uint64_t, dmu_object_type_t, dmu_tx_t *);

View File

@ -36,10 +36,13 @@ struct vnode;
struct dsl_dataset; struct dsl_dataset;
struct drr_begin; struct drr_begin;
struct avl_tree; struct avl_tree;
struct dmu_replay_record;
int dmu_send(const char *tosnap, const char *fromsnap, extern const char *recv_clone_name;
boolean_t embedok, boolean_t large_block_ok,
int outfd, struct vnode *vp, offset_t *off); int dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok,
boolean_t large_block_ok, int outfd, uint64_t resumeobj, uint64_t resumeoff,
struct vnode *vp, offset_t *off);
int dmu_send_estimate(struct dsl_dataset *ds, struct dsl_dataset *fromds, int dmu_send_estimate(struct dsl_dataset *ds, struct dsl_dataset *fromds,
uint64_t *sizep); uint64_t *sizep);
int dmu_send_estimate_from_txg(struct dsl_dataset *ds, uint64_t fromtxg, int dmu_send_estimate_from_txg(struct dsl_dataset *ds, uint64_t fromtxg,
@ -50,12 +53,14 @@ int dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
typedef struct dmu_recv_cookie { typedef struct dmu_recv_cookie {
struct dsl_dataset *drc_ds; struct dsl_dataset *drc_ds;
struct dmu_replay_record *drc_drr_begin;
struct drr_begin *drc_drrb; struct drr_begin *drc_drrb;
const char *drc_tofs; const char *drc_tofs;
const char *drc_tosnap; const char *drc_tosnap;
boolean_t drc_newfs; boolean_t drc_newfs;
boolean_t drc_byteswap; boolean_t drc_byteswap;
boolean_t drc_force; boolean_t drc_force;
boolean_t drc_resumable;
struct avl_tree *drc_guid_to_ds_map; struct avl_tree *drc_guid_to_ds_map;
zio_cksum_t drc_cksum; zio_cksum_t drc_cksum;
uint64_t drc_newsnapobj; uint64_t drc_newsnapobj;
@ -63,8 +68,9 @@ typedef struct dmu_recv_cookie {
cred_t *drc_cred; cred_t *drc_cred;
} dmu_recv_cookie_t; } dmu_recv_cookie_t;
int dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb, int dmu_recv_begin(char *tofs, char *tosnap,
boolean_t force, char *origin, dmu_recv_cookie_t *drc); struct dmu_replay_record *drr_begin,
boolean_t force, boolean_t resumable, char *origin, dmu_recv_cookie_t *drc);
int dmu_recv_stream(dmu_recv_cookie_t *drc, struct vnode *vp, offset_t *voffp, int dmu_recv_stream(dmu_recv_cookie_t *drc, struct vnode *vp, offset_t *voffp,
int cleanup_fd, uint64_t *action_handlep); int cleanup_fd, uint64_t *action_handlep);
int dmu_recv_end(dmu_recv_cookie_t *drc, void *owner); int dmu_recv_end(dmu_recv_cookie_t *drc, void *owner);

View File

@ -54,6 +54,8 @@ typedef int (blkptr_cb_t)(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
int traverse_dataset(struct dsl_dataset *ds, int traverse_dataset(struct dsl_dataset *ds,
uint64_t txg_start, int flags, blkptr_cb_t func, void *arg); uint64_t txg_start, int flags, blkptr_cb_t func, void *arg);
int traverse_dataset_resume(struct dsl_dataset *ds, uint64_t txg_start,
zbookmark_phys_t *resume, int flags, blkptr_cb_t func, void *arg);
int traverse_dataset_destroyed(spa_t *spa, blkptr_t *blkptr, int traverse_dataset_destroyed(spa_t *spa, blkptr_t *blkptr,
uint64_t txg_start, zbookmark_phys_t *resume, int flags, uint64_t txg_start, zbookmark_phys_t *resume, int flags,
blkptr_cb_t func, void *arg); blkptr_cb_t func, void *arg);

View File

@ -98,6 +98,18 @@ struct dsl_pool;
*/ */
#define DS_FIELD_LARGE_DNODE "org.zfsonlinux:large_dnode" #define DS_FIELD_LARGE_DNODE "org.zfsonlinux:large_dnode"
/*
* These fields are set on datasets that are in the middle of a resumable
* receive, and allow the sender to resume the send if it is interrupted.
*/
#define DS_FIELD_RESUME_FROMGUID "com.delphix:resume_fromguid"
#define DS_FIELD_RESUME_TONAME "com.delphix:resume_toname"
#define DS_FIELD_RESUME_TOGUID "com.delphix:resume_toguid"
#define DS_FIELD_RESUME_OBJECT "com.delphix:resume_object"
#define DS_FIELD_RESUME_OFFSET "com.delphix:resume_offset"
#define DS_FIELD_RESUME_BYTES "com.delphix:resume_bytes"
#define DS_FIELD_RESUME_EMBEDOK "com.delphix:resume_embedok"
/* /*
* DS_FLAG_CI_DATASET is set if the dataset contains a file system whose * DS_FLAG_CI_DATASET is set if the dataset contains a file system whose
* name lookups should be performed case-insensitively. * name lookups should be performed case-insensitively.
@ -191,6 +203,14 @@ typedef struct dsl_dataset {
kmutex_t ds_sendstream_lock; kmutex_t ds_sendstream_lock;
list_t ds_sendstreams; list_t ds_sendstreams;
/*
* When in the middle of a resumable receive, tracks how much
* progress we have made.
*/
uint64_t ds_resume_object[TXG_SIZE];
uint64_t ds_resume_offset[TXG_SIZE];
uint64_t ds_resume_bytes[TXG_SIZE];
/* Protected by our dsl_dir's dd_lock */ /* Protected by our dsl_dir's dd_lock */
list_t ds_prop_cbs; list_t ds_prop_cbs;
@ -207,7 +227,7 @@ typedef struct dsl_dataset {
uint8_t ds_feature_activation_needed[SPA_FEATURES]; uint8_t ds_feature_activation_needed[SPA_FEATURES];
/* Protected by ds_lock; keep at end of struct for better locality */ /* Protected by ds_lock; keep at end of struct for better locality */
char ds_snapname[MAXNAMELEN]; char ds_snapname[ZFS_MAX_DATASET_NAME_LEN];
} dsl_dataset_t; } dsl_dataset_t;
static inline dsl_dataset_phys_t * static inline dsl_dataset_phys_t *
@ -242,6 +262,8 @@ int dsl_dataset_own_obj(struct dsl_pool *dp, uint64_t dsobj,
void dsl_dataset_disown(dsl_dataset_t *ds, void *tag); void dsl_dataset_disown(dsl_dataset_t *ds, void *tag);
void dsl_dataset_name(dsl_dataset_t *ds, char *name); void dsl_dataset_name(dsl_dataset_t *ds, char *name);
boolean_t dsl_dataset_tryown(dsl_dataset_t *ds, void *tag); boolean_t dsl_dataset_tryown(dsl_dataset_t *ds, void *tag);
int dsl_dataset_namelen(dsl_dataset_t *ds);
boolean_t dsl_dataset_has_owner(dsl_dataset_t *ds);
uint64_t dsl_dataset_create_sync(dsl_dir_t *pds, const char *lastname, uint64_t dsl_dataset_create_sync(dsl_dir_t *pds, const char *lastname,
dsl_dataset_t *origin, uint64_t flags, cred_t *, dmu_tx_t *); dsl_dataset_t *origin, uint64_t flags, cred_t *, dmu_tx_t *);
uint64_t dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, uint64_t dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
@ -322,6 +344,8 @@ int dsl_dataset_snap_remove(dsl_dataset_t *ds, const char *name, dmu_tx_t *tx,
void dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds, void dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds,
zprop_source_t source, uint64_t value, dmu_tx_t *tx); zprop_source_t source, uint64_t value, dmu_tx_t *tx);
void dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx); void dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx);
boolean_t dsl_dataset_is_zapified(dsl_dataset_t *ds);
boolean_t dsl_dataset_has_resume_receive_state(dsl_dataset_t *ds);
int dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result); int dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result);
void dsl_dataset_deactivate_feature(uint64_t dsobj, void dsl_dataset_deactivate_feature(uint64_t dsobj,
@ -330,10 +354,10 @@ void dsl_dataset_deactivate_feature(uint64_t dsobj,
#ifdef ZFS_DEBUG #ifdef ZFS_DEBUG
#define dprintf_ds(ds, fmt, ...) do { \ #define dprintf_ds(ds, fmt, ...) do { \
if (zfs_flags & ZFS_DEBUG_DPRINTF) { \ if (zfs_flags & ZFS_DEBUG_DPRINTF) { \
char *__ds_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); \ char *__ds_name = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP); \
dsl_dataset_name(ds, __ds_name); \ dsl_dataset_name(ds, __ds_name); \
dprintf("ds=%s " fmt, __ds_name, __VA_ARGS__); \ dprintf("ds=%s " fmt, __ds_name, __VA_ARGS__); \
kmem_free(__ds_name, MAXNAMELEN); \ kmem_free(__ds_name, ZFS_MAX_DATASET_NAME_LEN); \
} \ } \
_NOTE(CONSTCOND) } while (0) _NOTE(CONSTCOND) } while (0)
#else #else

View File

@ -112,7 +112,7 @@ struct dsl_dir {
int64_t dd_space_towrite[TXG_SIZE]; int64_t dd_space_towrite[TXG_SIZE];
/* protected by dd_lock; keep at end of struct for better locality */ /* protected by dd_lock; keep at end of struct for better locality */
char dd_myname[MAXNAMELEN]; char dd_myname[ZFS_MAX_DATASET_NAME_LEN];
}; };
static inline dsl_dir_phys_t * static inline dsl_dir_phys_t *
@ -176,11 +176,10 @@ boolean_t dsl_dir_is_zapified(dsl_dir_t *dd);
#ifdef ZFS_DEBUG #ifdef ZFS_DEBUG
#define dprintf_dd(dd, fmt, ...) do { \ #define dprintf_dd(dd, fmt, ...) do { \
if (zfs_flags & ZFS_DEBUG_DPRINTF) { \ if (zfs_flags & ZFS_DEBUG_DPRINTF) { \
char *__ds_name = kmem_alloc(MAXNAMELEN + strlen(MOS_DIR_NAME) + 1, \ char *__ds_name = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP); \
KM_SLEEP); \
dsl_dir_name(dd, __ds_name); \ dsl_dir_name(dd, __ds_name); \
dprintf("dd=%s " fmt, __ds_name, __VA_ARGS__); \ dprintf("dd=%s " fmt, __ds_name, __VA_ARGS__); \
kmem_free(__ds_name, MAXNAMELEN + strlen(MOS_DIR_NAME) + 1); \ kmem_free(__ds_name, ZFS_MAX_DATASET_NAME_LEN); \
} \ } \
_NOTE(CONSTCOND) } while (0) _NOTE(CONSTCOND) } while (0)
#else #else

View File

@ -67,9 +67,13 @@ typedef enum dmu_objset_type {
#define ZFS_TYPE_DATASET \ #define ZFS_TYPE_DATASET \
(ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME | ZFS_TYPE_SNAPSHOT) (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME | ZFS_TYPE_SNAPSHOT)
/*
* All of these include the terminating NUL byte.
*/
#define ZAP_MAXNAMELEN 256 #define ZAP_MAXNAMELEN 256
#define ZAP_MAXVALUELEN (1024 * 8) #define ZAP_MAXVALUELEN (1024 * 8)
#define ZAP_OLDMAXVALUELEN 1024 #define ZAP_OLDMAXVALUELEN 1024
#define ZFS_MAX_DATASET_NAME_LEN 256
/* /*
* Dataset properties are identified by these constants and must be added to * Dataset properties are identified by these constants and must be added to
@ -158,6 +162,7 @@ typedef enum {
ZFS_PROP_REDUNDANT_METADATA, ZFS_PROP_REDUNDANT_METADATA,
ZFS_PROP_OVERLAY, ZFS_PROP_OVERLAY,
ZFS_PROP_PREV_SNAP, ZFS_PROP_PREV_SNAP,
ZFS_PROP_RECEIVE_RESUME_TOKEN,
ZFS_NUM_PROPS ZFS_NUM_PROPS
} zfs_prop_t; } zfs_prop_t;
@ -231,6 +236,7 @@ typedef enum {
#define ZPROP_SOURCE_VAL_RECVD "$recvd" #define ZPROP_SOURCE_VAL_RECVD "$recvd"
#define ZPROP_N_MORE_ERRORS "N_MORE_ERRORS" #define ZPROP_N_MORE_ERRORS "N_MORE_ERRORS"
/* /*
* Dataset flag implemented as a special entry in the props zap object * Dataset flag implemented as a special entry in the props zap object
* indicating that the dataset has received properties on or after * indicating that the dataset has received properties on or after
@ -922,7 +928,7 @@ typedef struct ddt_histogram {
*/ */
typedef enum zfs_ioc { typedef enum zfs_ioc {
/* /*
* Illumos - 70/128 numbers reserved. * Illumos - 71/128 numbers reserved.
*/ */
ZFS_IOC_FIRST = ('Z' << 8), ZFS_IOC_FIRST = ('Z' << 8),
ZFS_IOC = ZFS_IOC_FIRST, ZFS_IOC = ZFS_IOC_FIRST,
@ -996,6 +1002,7 @@ typedef enum zfs_ioc {
ZFS_IOC_BOOKMARK, ZFS_IOC_BOOKMARK,
ZFS_IOC_GET_BOOKMARKS, ZFS_IOC_GET_BOOKMARKS,
ZFS_IOC_DESTROY_BOOKMARKS, ZFS_IOC_DESTROY_BOOKMARKS,
ZFS_IOC_RECV_NEW,
/* /*
* Linux - 3/64 numbers reserved. * Linux - 3/64 numbers reserved.
@ -1016,7 +1023,7 @@ typedef enum zfs_ioc {
/* /*
* zvol ioctl to get dataset name * zvol ioctl to get dataset name
*/ */
#define BLKZNAME _IOR(0x12, 125, char[ZFS_MAXNAMELEN]) #define BLKZNAME _IOR(0x12, 125, char[ZFS_MAX_DATASET_NAME_LEN])
/* /*
* Internal SPA load state. Used by FMA diagnosis engine. * Internal SPA load state. Used by FMA diagnosis engine.

View File

@ -126,7 +126,7 @@ struct spa {
/* /*
* Fields protected by spa_namespace_lock. * Fields protected by spa_namespace_lock.
*/ */
char spa_name[MAXNAMELEN]; /* pool name */ char spa_name[ZFS_MAX_DATASET_NAME_LEN]; /* pool name */
char *spa_comment; /* comment */ char *spa_comment; /* comment */
avl_node_t spa_avl; /* node in spa_namespace_avl */ avl_node_t spa_avl; /* node in spa_namespace_avl */
nvlist_t *spa_config; /* last synced config */ nvlist_t *spa_config; /* last synced config */

View File

@ -363,7 +363,7 @@ typedef struct {
boolean_t za_normalization_conflict; boolean_t za_normalization_conflict;
uint64_t za_num_integers; uint64_t za_num_integers;
uint64_t za_first_integer; /* no sign extension for <8byte ints */ uint64_t za_first_integer; /* no sign extension for <8byte ints */
char za_name[MAXNAMELEN]; char za_name[ZAP_MAXNAMELEN];
} zap_attribute_t; } zap_attribute_t;
/* /*

View File

@ -20,7 +20,8 @@
*/ */
/* /*
* 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) 2012, 2014 by Delphix. All rights reserved. * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright 2016 RackTop Systems.
*/ */
#ifndef _SYS_ZFS_IOCTL_H #ifndef _SYS_ZFS_IOCTL_H
@ -90,16 +91,16 @@ typedef enum drr_headertype {
* Feature flags for zfs send streams (flags in drr_versioninfo) * Feature flags for zfs send streams (flags in drr_versioninfo)
*/ */
#define DMU_BACKUP_FEATURE_DEDUP (1<<0) #define DMU_BACKUP_FEATURE_DEDUP (1 << 0)
#define DMU_BACKUP_FEATURE_DEDUPPROPS (1<<1) #define DMU_BACKUP_FEATURE_DEDUPPROPS (1 << 1)
#define DMU_BACKUP_FEATURE_SA_SPILL (1<<2) #define DMU_BACKUP_FEATURE_SA_SPILL (1 << 2)
/* flags #3 - #15 are reserved for incompatible closed-source implementations */ /* flags #3 - #15 are reserved for incompatible closed-source implementations */
#define DMU_BACKUP_FEATURE_EMBED_DATA (1<<16) #define DMU_BACKUP_FEATURE_EMBED_DATA (1 << 16)
#define DMU_BACKUP_FEATURE_EMBED_DATA_LZ4 (1<<17) #define DMU_BACKUP_FEATURE_EMBED_DATA_LZ4 (1 << 17)
/* flag #18 is reserved for a Delphix feature */ /* flag #18 is reserved for a Delphix feature */
#define DMU_BACKUP_FEATURE_LARGE_BLOCKS (1<<19) #define DMU_BACKUP_FEATURE_LARGE_BLOCKS (1 << 19)
/* flag #20 is reserved for resumable streams */ #define DMU_BACKUP_FEATURE_RESUMING (1 << 20)
#define DMU_BACKUP_FEATURE_LARGE_DNODE (1<<21) #define DMU_BACKUP_FEATURE_LARGE_DNODE (1 << 21)
/* /*
* Mask of all supported backup features * Mask of all supported backup features
@ -107,11 +108,16 @@ typedef enum drr_headertype {
#define DMU_BACKUP_FEATURE_MASK (DMU_BACKUP_FEATURE_DEDUP | \ #define DMU_BACKUP_FEATURE_MASK (DMU_BACKUP_FEATURE_DEDUP | \
DMU_BACKUP_FEATURE_DEDUPPROPS | DMU_BACKUP_FEATURE_SA_SPILL | \ DMU_BACKUP_FEATURE_DEDUPPROPS | DMU_BACKUP_FEATURE_SA_SPILL | \
DMU_BACKUP_FEATURE_EMBED_DATA | DMU_BACKUP_FEATURE_EMBED_DATA_LZ4 | \ DMU_BACKUP_FEATURE_EMBED_DATA | DMU_BACKUP_FEATURE_EMBED_DATA_LZ4 | \
DMU_BACKUP_FEATURE_LARGE_BLOCKS | DMU_BACKUP_FEATURE_LARGE_DNODE) DMU_BACKUP_FEATURE_RESUMING | DMU_BACKUP_FEATURE_LARGE_BLOCKS | \
DMU_BACKUP_FEATURE_LARGE_DNODE)
/* Are all features in the given flag word currently supported? */ /* Are all features in the given flag word currently supported? */
#define DMU_STREAM_SUPPORTED(x) (!((x) & ~DMU_BACKUP_FEATURE_MASK)) #define DMU_STREAM_SUPPORTED(x) (!((x) & ~DMU_BACKUP_FEATURE_MASK))
typedef enum dmu_send_resume_token_version {
ZFS_SEND_RESUME_TOKEN_VERSION = 1
} dmu_send_resume_token_version_t;
/* /*
* The drr_versioninfo field of the dmu_replay_record has the * The drr_versioninfo field of the dmu_replay_record has the
* following layout: * following layout:
@ -131,8 +137,22 @@ typedef enum drr_headertype {
#define DMU_BACKUP_MAGIC 0x2F5bacbacULL #define DMU_BACKUP_MAGIC 0x2F5bacbacULL
/*
* Send stream flags. Bits 24-31 are reserved for vendor-specific
* implementations and should not be used.
*/
#define DRR_FLAG_CLONE (1<<0) #define DRR_FLAG_CLONE (1<<0)
#define DRR_FLAG_CI_DATA (1<<1) #define DRR_FLAG_CI_DATA (1<<1)
/*
* This send stream, if it is a full send, includes the FREE and FREEOBJECT
* records that are created by the sending process. This means that the send
* stream can be received as a clone, even though it is not an incremental.
* This is not implemented as a feature flag, because the receiving side does
* not need to have implemented it to receive this stream; it is fully backwards
* compatible. We need a flag, though, because full send streams without it
* cannot necessarily be received as a clone correctly.
*/
#define DRR_FLAG_FREERECORDS (1<<2)
/* /*
* flags in the drr_checksumflags field in the DRR_WRITE and * flags in the drr_checksumflags field in the DRR_WRITE and
@ -335,6 +355,12 @@ typedef enum zfs_case {
ZFS_CASE_MIXED ZFS_CASE_MIXED
} zfs_case_t; } zfs_case_t;
/*
* Note: this struct must have the same layout in 32-bit and 64-bit, so
* that 32-bit processes (like /sbin/zfs) can pass it to the 64-bit
* kernel. Therefore, we add padding to it so that no "hidden" padding
* is automatically added on 64-bit (but not on 32-bit).
*/
typedef struct zfs_cmd { typedef struct zfs_cmd {
char zc_name[MAXPATHLEN]; /* name of pool or dataset */ char zc_name[MAXPATHLEN]; /* name of pool or dataset */
uint64_t zc_nvlist_src; /* really (char *) */ uint64_t zc_nvlist_src; /* really (char *) */

View File

@ -20,7 +20,7 @@
*/ */
/* /*
* 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) 2012 by Delphix. All rights reserved. * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
*/ */
#ifndef _SYS_FS_ZFS_ZNODE_H #ifndef _SYS_FS_ZFS_ZNODE_H
@ -138,17 +138,6 @@ extern "C" {
#define ZFS_SHARES_DIR "SHARES" #define ZFS_SHARES_DIR "SHARES"
#define ZFS_SA_ATTRS "SA_ATTRS" #define ZFS_SA_ATTRS "SA_ATTRS"
/*
* Path component length
*
* The generic fs code uses MAXNAMELEN to represent
* what the largest component length is. Unfortunately,
* this length includes the terminating NULL. ZFS needs
* to tell the users via pathconf() and statvfs() what the
* true maximum length of a component is, excluding the NULL.
*/
#define ZFS_MAXNAMELEN (MAXNAMELEN - 1)
/* /*
* Convert mode bits (zp_mode) to BSD-style DT_* values for storing in * Convert mode bits (zp_mode) to BSD-style DT_* values for storing in
* the directory entries. On Linux systems this value is already * the directory entries. On Linux systems this value is already

View File

@ -32,6 +32,8 @@
#define ZVOL_OBJ 1ULL #define ZVOL_OBJ 1ULL
#define ZVOL_ZAP_OBJ 2ULL #define ZVOL_ZAP_OBJ 2ULL
extern void *zvol_tag;
extern void zvol_create_minors(spa_t *spa, const char *name, boolean_t async); extern void zvol_create_minors(spa_t *spa, const char *name, boolean_t async);
extern void zvol_remove_minors(spa_t *spa, const char *name, boolean_t async); extern void zvol_remove_minors(spa_t *spa, const char *name, boolean_t async);
extern void zvol_rename_minors(spa_t *spa, const char *oldname, extern void zvol_rename_minors(spa_t *spa, const char *oldname,

View File

@ -24,6 +24,7 @@
* Use is subject to license terms. * Use is subject to license terms.
* *
* Portions Copyright 2007 Ramprakash Jelari * Portions Copyright 2007 Ramprakash Jelari
* Copyright (c) 2014, 2015 by Delphix. All rights reserved.
*/ */
#include <libintl.h> #include <libintl.h>
@ -287,7 +288,7 @@ void
changelist_rename(prop_changelist_t *clp, const char *src, const char *dst) changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
{ {
prop_changenode_t *cn; prop_changenode_t *cn;
char newname[ZFS_MAXNAMELEN]; char newname[ZFS_MAX_DATASET_NAME_LEN];
for (cn = uu_list_first(clp->cl_list); cn != NULL; for (cn = uu_list_first(clp->cl_list); cn != NULL;
cn = uu_list_next(clp->cl_list, cn)) { cn = uu_list_next(clp->cl_list, cn)) {

View File

@ -551,7 +551,7 @@ zfs_bookmark_exists(const char *path)
{ {
nvlist_t *bmarks; nvlist_t *bmarks;
nvlist_t *props; nvlist_t *props;
char fsname[ZFS_MAXNAMELEN]; char fsname[ZFS_MAX_DATASET_NAME_LEN];
char *bmark_name; char *bmark_name;
char *pound; char *pound;
int err; int err;
@ -1865,22 +1865,21 @@ getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
return (value); return (value);
} }
static char * static const char *
getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source) getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
{ {
nvlist_t *nv; nvlist_t *nv;
char *value; const char *value;
*source = NULL; *source = NULL;
if (nvlist_lookup_nvlist(zhp->zfs_props, if (nvlist_lookup_nvlist(zhp->zfs_props,
zfs_prop_to_name(prop), &nv) == 0) { zfs_prop_to_name(prop), &nv) == 0) {
verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0); value = fnvlist_lookup_string(nv, ZPROP_VALUE);
(void) nvlist_lookup_string(nv, ZPROP_SOURCE, source); (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
} else { } else {
verify(!zhp->zfs_props_table || verify(!zhp->zfs_props_table ||
zhp->zfs_props_table[prop] == B_TRUE); zhp->zfs_props_table[prop] == B_TRUE);
if ((value = (char *)zfs_prop_default_string(prop)) == NULL) value = zfs_prop_default_string(prop);
value = "";
*source = ""; *source = "";
} }
@ -2202,7 +2201,7 @@ struct get_clones_arg {
uint64_t numclones; uint64_t numclones;
nvlist_t *value; nvlist_t *value;
const char *origin; const char *origin;
char buf[ZFS_MAXNAMELEN]; char buf[ZFS_MAX_DATASET_NAME_LEN];
}; };
int int
@ -2257,7 +2256,7 @@ zfs_get_clones_nvl(zfs_handle_t *zhp)
if (gca.numclones != 0) { if (gca.numclones != 0) {
zfs_handle_t *root; zfs_handle_t *root;
char pool[ZFS_MAXNAMELEN]; char pool[ZFS_MAX_DATASET_NAME_LEN];
char *cp = pool; char *cp = pool;
/* get the pool name */ /* get the pool name */
@ -2301,7 +2300,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
{ {
char *source = NULL; char *source = NULL;
uint64_t val; uint64_t val;
char *str; const char *str;
const char *strval; const char *strval;
boolean_t received = zfs_is_recvd_props_mode(zhp); boolean_t received = zfs_is_recvd_props_mode(zhp);
@ -2407,14 +2406,10 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
break; break;
case ZFS_PROP_ORIGIN: case ZFS_PROP_ORIGIN:
(void) strlcpy(propbuf, getprop_string(zhp, prop, &source), str = getprop_string(zhp, prop, &source);
proplen); if (str == NULL)
/*
* If there is no parent at all, return failure to indicate that
* it doesn't apply to this dataset.
*/
if (propbuf[0] == '\0')
return (-1); return (-1);
(void) strlcpy(propbuf, str, proplen);
break; break;
case ZFS_PROP_CLONES: case ZFS_PROP_CLONES:
@ -2596,8 +2591,10 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
break; break;
case PROP_TYPE_STRING: case PROP_TYPE_STRING:
(void) strlcpy(propbuf, str = getprop_string(zhp, prop, &source);
getprop_string(zhp, prop, &source), proplen); if (str == NULL)
return (-1);
(void) strlcpy(propbuf, str, proplen);
break; break;
case PROP_TYPE_INDEX: case PROP_TYPE_INDEX:
@ -3004,7 +3001,7 @@ check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
boolean_t accept_ancestor, int *prefixlen) boolean_t accept_ancestor, int *prefixlen)
{ {
zfs_cmd_t zc = {"\0"}; zfs_cmd_t zc = {"\0"};
char parent[ZFS_MAXNAMELEN]; char parent[ZFS_MAX_DATASET_NAME_LEN];
char *slash; char *slash;
zfs_handle_t *zhp; zfs_handle_t *zhp;
char errbuf[1024]; char errbuf[1024];
@ -3243,7 +3240,7 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
ost = DMU_OST_ZFS; ost = DMU_OST_ZFS;
/* open zpool handle for prop validation */ /* open zpool handle for prop validation */
char pool_path[MAXNAMELEN]; char pool_path[ZFS_MAX_DATASET_NAME_LEN];
(void) strlcpy(pool_path, path, sizeof (pool_path)); (void) strlcpy(pool_path, path, sizeof (pool_path));
/* truncate pool_path at first slash */ /* truncate pool_path at first slash */
@ -3312,7 +3309,7 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
/* check for failure */ /* check for failure */
if (ret != 0) { if (ret != 0) {
char parent[ZFS_MAXNAMELEN]; char parent[ZFS_MAX_DATASET_NAME_LEN];
(void) parent_name(path, parent, sizeof (parent)); (void) parent_name(path, parent, sizeof (parent));
switch (errno) { switch (errno) {
@ -3402,7 +3399,7 @@ static int
zfs_check_snap_cb(zfs_handle_t *zhp, void *arg) zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
{ {
struct destroydata *dd = arg; struct destroydata *dd = arg;
char name[ZFS_MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
int rv = 0; int rv = 0;
(void) snprintf(name, sizeof (name), (void) snprintf(name, sizeof (name),
@ -3493,7 +3490,7 @@ zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
int int
zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props) zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
{ {
char parent[ZFS_MAXNAMELEN]; char parent[ZFS_MAX_DATASET_NAME_LEN];
int ret; int ret;
char errbuf[1024]; char errbuf[1024];
libzfs_handle_t *hdl = zhp->zfs_hdl; libzfs_handle_t *hdl = zhp->zfs_hdl;
@ -3623,7 +3620,7 @@ static int
zfs_snapshot_cb(zfs_handle_t *zhp, void *arg) zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
{ {
snapdata_t *sd = arg; snapdata_t *sd = arg;
char name[ZFS_MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
int rv = 0; int rv = 0;
if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) { if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) {
@ -3672,7 +3669,7 @@ zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
* get pool handle for prop validation. assumes all snaps are in the * get pool handle for prop validation. assumes all snaps are in the
* same pool, as does lzc_snapshot (below). * same pool, as does lzc_snapshot (below).
*/ */
char pool[MAXNAMELEN]; char pool[ZFS_MAX_DATASET_NAME_LEN];
elem = nvlist_next_nvpair(snaps, NULL); elem = nvlist_next_nvpair(snaps, NULL);
(void) strlcpy(pool, nvpair_name(elem), sizeof (pool)); (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
pool[strcspn(pool, "/@")] = '\0'; pool[strcspn(pool, "/@")] = '\0';
@ -3726,7 +3723,7 @@ zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
{ {
int ret; int ret;
snapdata_t sd = { 0 }; snapdata_t sd = { 0 };
char fsname[ZFS_MAXNAMELEN]; char fsname[ZFS_MAX_DATASET_NAME_LEN];
char *cp; char *cp;
zfs_handle_t *zhp; zfs_handle_t *zhp;
char errbuf[1024]; char errbuf[1024];
@ -3905,7 +3902,7 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
prop_changelist_t *cl = NULL; prop_changelist_t *cl = NULL;
zfs_handle_t *zhrp = NULL; zfs_handle_t *zhrp = NULL;
char *parentname = NULL; char *parentname = NULL;
char parent[ZFS_MAXNAMELEN]; char parent[ZFS_MAX_DATASET_NAME_LEN];
libzfs_handle_t *hdl = zhp->zfs_hdl; libzfs_handle_t *hdl = zhp->zfs_hdl;
char errbuf[1024]; char errbuf[1024];
@ -4325,7 +4322,7 @@ zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
zc.zc_nvlist_dst_size = sizeof (buf); zc.zc_nvlist_dst_size = sizeof (buf);
if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) { if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) {
char errbuf[ZFS_MAXNAMELEN + 32]; char errbuf[1024];
(void) snprintf(errbuf, sizeof (errbuf), (void) snprintf(errbuf, sizeof (errbuf),
dgettext(TEXT_DOMAIN, dgettext(TEXT_DOMAIN,
@ -4359,7 +4356,7 @@ static int
zfs_hold_one(zfs_handle_t *zhp, void *arg) zfs_hold_one(zfs_handle_t *zhp, void *arg)
{ {
struct holdarg *ha = arg; struct holdarg *ha = arg;
char name[ZFS_MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
int rv = 0; int rv = 0;
(void) snprintf(name, sizeof (name), (void) snprintf(name, sizeof (name),
@ -4478,7 +4475,7 @@ static int
zfs_release_one(zfs_handle_t *zhp, void *arg) zfs_release_one(zfs_handle_t *zhp, void *arg)
{ {
struct holdarg *ha = arg; struct holdarg *ha = arg;
char name[ZFS_MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
int rv = 0; int rv = 0;
nvlist_t *existing_holds; nvlist_t *existing_holds;
@ -4607,7 +4604,7 @@ tryagain:
zc.zc_nvlist_dst_size = nvsz; zc.zc_nvlist_dst_size = nvsz;
zc.zc_nvlist_dst = (uintptr_t)nvbuf; zc.zc_nvlist_dst = (uintptr_t)nvbuf;
(void) strlcpy(zc.zc_name, zhp->zfs_name, ZFS_MAXNAMELEN); (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) { if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
(void) snprintf(errbuf, sizeof (errbuf), (void) snprintf(errbuf, sizeof (errbuf),

View File

@ -22,6 +22,7 @@
/* /*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2015 by Delphix. All rights reserved.
* Copyright 2016 Joyent, Inc. * Copyright 2016 Joyent, Inc.
*/ */
@ -604,7 +605,7 @@ get_snapshot_names(differ_info_t *di, const char *fromsnap,
* not the same dataset name, might be okay if * not the same dataset name, might be okay if
* tosnap is a clone of a fromsnap descendant. * tosnap is a clone of a fromsnap descendant.
*/ */
char origin[ZFS_MAXNAMELEN]; char origin[ZFS_MAX_DATASET_NAME_LEN];
zprop_source_t src; zprop_source_t src;
zfs_handle_t *zhp; zfs_handle_t *zhp;

View File

@ -197,7 +197,7 @@ zfs_iter_bookmarks(zfs_handle_t *zhp, zfs_iter_f func, void *data)
for (pair = nvlist_next_nvpair(bmarks, NULL); for (pair = nvlist_next_nvpair(bmarks, NULL);
pair != NULL; pair = nvlist_next_nvpair(bmarks, pair)) { pair != NULL; pair = nvlist_next_nvpair(bmarks, pair)) {
char name[ZFS_MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
char *bmark_name; char *bmark_name;
nvlist_t *bmark_props; nvlist_t *bmark_props;
@ -384,7 +384,7 @@ zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
* exists. * exists.
*/ */
if (ssa.ssa_last[0] != '\0') { if (ssa.ssa_last[0] != '\0') {
char snapname[ZFS_MAXNAMELEN]; char snapname[ZFS_MAX_DATASET_NAME_LEN];
(void) snprintf(snapname, sizeof (snapname), (void) snprintf(snapname, sizeof (snapname),
"%s@%s", zfs_get_name(fs_zhp), "%s@%s", zfs_get_name(fs_zhp),
ssa.ssa_last); ssa.ssa_last);
@ -404,7 +404,7 @@ zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
ret = ENOENT; ret = ENOENT;
} }
} else { } else {
char snapname[ZFS_MAXNAMELEN]; char snapname[ZFS_MAX_DATASET_NAME_LEN];
zfs_handle_t *snap_zhp; zfs_handle_t *snap_zhp;
(void) snprintf(snapname, sizeof (snapname), "%s@%s", (void) snprintf(snapname, sizeof (snapname), "%s@%s",
zfs_get_name(fs_zhp), comma_separated); zfs_get_name(fs_zhp), comma_separated);

View File

@ -230,7 +230,7 @@ static boolean_t
zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen, zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
zprop_source_t *source) zprop_source_t *source)
{ {
char sourceloc[ZFS_MAXNAMELEN]; char sourceloc[MAXNAMELEN];
zprop_source_t sourcetype; zprop_source_t sourcetype;
if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type, if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type,
@ -1051,6 +1051,17 @@ mount_cb(zfs_handle_t *zhp, void *data)
return (0); 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) {
zfs_close(zhp);
return (0);
}
libzfs_add_handle(cbp, zhp); libzfs_add_handle(cbp, zhp);
if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) { if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
zfs_close(zhp); zfs_close(zhp);

View File

@ -441,7 +441,7 @@ pool_uses_efi(nvlist_t *config)
boolean_t boolean_t
zpool_is_bootable(zpool_handle_t *zhp) zpool_is_bootable(zpool_handle_t *zhp)
{ {
char bootfs[ZPOOL_MAXNAMELEN]; char bootfs[ZFS_MAX_DATASET_NAME_LEN];
return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs, return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-", sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
@ -1907,7 +1907,12 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
"one or more devices are already in use\n")); "one or more devices are already in use\n"));
(void) zfs_error(hdl, EZFS_BADDEV, desc); (void) zfs_error(hdl, EZFS_BADDEV, desc);
break; break;
case ENAMETOOLONG:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"new name of at least one dataset is longer than "
"the maximum allowable length"));
(void) zfs_error(hdl, EZFS_NAMETOOLONG, desc);
break;
default: default:
(void) zpool_standard_error(hdl, error, desc); (void) zpool_standard_error(hdl, error, desc);
zpool_explain_recover(hdl, zpool_explain_recover(hdl,
@ -4006,7 +4011,7 @@ zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
zfs_cmd_t zc = {"\0"}; zfs_cmd_t zc = {"\0"};
boolean_t mounted = B_FALSE; boolean_t mounted = B_FALSE;
char *mntpnt = NULL; char *mntpnt = NULL;
char dsname[MAXNAMELEN]; char dsname[ZFS_MAX_DATASET_NAME_LEN];
if (dsobj == 0) { if (dsobj == 0) {
/* special case for the MOS */ /* special case for the MOS */

File diff suppressed because it is too large Load Diff

View File

@ -217,7 +217,7 @@ lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist)
nvpair_t *elem; nvpair_t *elem;
nvlist_t *args; nvlist_t *args;
int error; int error;
char pool[MAXNAMELEN]; char pool[ZFS_MAX_DATASET_NAME_LEN];
*errlist = NULL; *errlist = NULL;
@ -269,7 +269,7 @@ lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist)
nvpair_t *elem; nvpair_t *elem;
nvlist_t *args; nvlist_t *args;
int error; int error;
char pool[MAXNAMELEN]; char pool[ZFS_MAX_DATASET_NAME_LEN];
/* determine the pool name */ /* determine the pool name */
elem = nvlist_next_nvpair(snaps, NULL); elem = nvlist_next_nvpair(snaps, NULL);
@ -296,7 +296,7 @@ lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
nvlist_t *args; nvlist_t *args;
nvlist_t *result; nvlist_t *result;
int err; int err;
char fs[MAXNAMELEN]; char fs[ZFS_MAX_DATASET_NAME_LEN];
char *atp; char *atp;
/* determine the fs name */ /* determine the fs name */
@ -361,7 +361,7 @@ lzc_exists(const char *dataset)
int int
lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist) lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist)
{ {
char pool[MAXNAMELEN]; char pool[ZFS_MAX_DATASET_NAME_LEN];
nvlist_t *args; nvlist_t *args;
nvpair_t *elem; nvpair_t *elem;
int error; int error;
@ -408,7 +408,7 @@ lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist)
int int
lzc_release(nvlist_t *holds, nvlist_t **errlist) lzc_release(nvlist_t *holds, nvlist_t **errlist)
{ {
char pool[MAXNAMELEN]; char pool[ZFS_MAX_DATASET_NAME_LEN];
nvpair_t *elem; nvpair_t *elem;
/* determine the pool name */ /* determine the pool name */
@ -467,6 +467,13 @@ lzc_get_holds(const char *snapname, nvlist_t **holdsp)
int int
lzc_send(const char *snapname, const char *from, int fd, lzc_send(const char *snapname, const char *from, int fd,
enum lzc_send_flags flags) enum lzc_send_flags flags)
{
return (lzc_send_resume(snapname, from, fd, flags, 0, 0));
}
int
lzc_send_resume(const char *snapname, const char *from, int fd,
enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff)
{ {
nvlist_t *args; nvlist_t *args;
int err; int err;
@ -479,6 +486,10 @@ lzc_send(const char *snapname, const char *from, int fd,
fnvlist_add_boolean(args, "largeblockok"); fnvlist_add_boolean(args, "largeblockok");
if (flags & LZC_SEND_FLAG_EMBED_DATA) if (flags & LZC_SEND_FLAG_EMBED_DATA)
fnvlist_add_boolean(args, "embedok"); fnvlist_add_boolean(args, "embedok");
if (resumeobj != 0 || resumeoff != 0) {
fnvlist_add_uint64(args, "resume_object", resumeobj);
fnvlist_add_uint64(args, "resume_offset", resumeoff);
}
err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL); err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);
nvlist_free(args); nvlist_free(args);
return (err); return (err);
@ -536,9 +547,174 @@ recv_read(int fd, void *buf, int ilen)
return (0); return (0);
} }
/*
* Linux adds ZFS_IOC_RECV_NEW for resumable streams and preserves the legacy
* ZFS_IOC_RECV user/kernel interface. The new interface supports all stream
* options but is currently only used for resumable streams. This way updated
* user space utilities will interoperate with older kernel modules.
*
* Non-Linux OpenZFS platforms have opted to modify the legacy interface.
*/
static int
recv_impl(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, boolean_t resumable, int input_fd,
const dmu_replay_record_t *begin_record, int cleanup_fd,
uint64_t *read_bytes, uint64_t *errflags, uint64_t *action_handle,
nvlist_t **errors)
{
dmu_replay_record_t drr;
char fsname[MAXPATHLEN];
char *atp;
int error;
/* Set 'fsname' to the name of containing filesystem */
(void) strlcpy(fsname, snapname, sizeof (fsname));
atp = strchr(fsname, '@');
if (atp == NULL)
return (EINVAL);
*atp = '\0';
/* If the fs does not exist, try its parent. */
if (!lzc_exists(fsname)) {
char *slashp = strrchr(fsname, '/');
if (slashp == NULL)
return (ENOENT);
*slashp = '\0';
}
/*
* The begin_record is normally a non-byteswapped BEGIN record.
* For resumable streams it may be set to any non-byteswapped
* dmu_replay_record_t.
*/
if (begin_record == NULL) {
error = recv_read(input_fd, &drr, sizeof (drr));
if (error != 0)
return (error);
} else {
drr = *begin_record;
}
if (resumable) {
nvlist_t *outnvl = NULL;
nvlist_t *innvl = fnvlist_alloc();
fnvlist_add_string(innvl, "snapname", snapname);
if (props != NULL)
fnvlist_add_nvlist(innvl, "props", props);
if (origin != NULL && strlen(origin))
fnvlist_add_string(innvl, "origin", origin);
fnvlist_add_byte_array(innvl, "begin_record",
(uchar_t *) &drr, sizeof (drr));
fnvlist_add_int32(innvl, "input_fd", input_fd);
if (force)
fnvlist_add_boolean(innvl, "force");
if (resumable)
fnvlist_add_boolean(innvl, "resumable");
if (cleanup_fd >= 0)
fnvlist_add_int32(innvl, "cleanup_fd", cleanup_fd);
if (action_handle != NULL)
fnvlist_add_uint64(innvl, "action_handle",
*action_handle);
error = lzc_ioctl(ZFS_IOC_RECV_NEW, fsname, innvl, &outnvl);
if (error == 0 && read_bytes != NULL)
error = nvlist_lookup_uint64(outnvl, "read_bytes",
read_bytes);
if (error == 0 && errflags != NULL)
error = nvlist_lookup_uint64(outnvl, "error_flags",
errflags);
if (error == 0 && action_handle != NULL)
error = nvlist_lookup_uint64(outnvl, "action_handle",
action_handle);
if (error == 0 && errors != NULL) {
nvlist_t *nvl;
error = nvlist_lookup_nvlist(outnvl, "errors", &nvl);
if (error == 0)
*errors = fnvlist_dup(nvl);
}
fnvlist_free(innvl);
fnvlist_free(outnvl);
} else {
zfs_cmd_t zc = {"\0"};
char *packed = NULL;
size_t size;
ASSERT3S(g_refcount, >, 0);
(void) strlcpy(zc.zc_name, fsname, sizeof (zc.zc_value));
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
if (props != NULL) {
packed = fnvlist_pack(props, &size);
zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
zc.zc_nvlist_src_size = size;
}
if (origin != NULL)
(void) strlcpy(zc.zc_string, origin,
sizeof (zc.zc_string));
ASSERT3S(drr.drr_type, ==, DRR_BEGIN);
zc.zc_begin_record = drr.drr_u.drr_begin;
zc.zc_guid = force;
zc.zc_cookie = input_fd;
zc.zc_cleanup_fd = -1;
zc.zc_action_handle = 0;
if (cleanup_fd >= 0)
zc.zc_cleanup_fd = cleanup_fd;
if (action_handle != NULL)
zc.zc_action_handle = *action_handle;
zc.zc_nvlist_dst_size = 128 * 1024;
zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
malloc(zc.zc_nvlist_dst_size);
error = ioctl(g_fd, ZFS_IOC_RECV, &zc);
if (error != 0) {
error = errno;
} else {
if (read_bytes != NULL)
*read_bytes = zc.zc_cookie;
if (errflags != NULL)
*errflags = zc.zc_obj;
if (action_handle != NULL)
*action_handle = zc.zc_action_handle;
if (errors != NULL)
VERIFY0(nvlist_unpack(
(void *)(uintptr_t)zc.zc_nvlist_dst,
zc.zc_nvlist_dst_size, errors, KM_SLEEP));
}
if (packed != NULL)
fnvlist_pack_free(packed, size);
free((void *)(uintptr_t)zc.zc_nvlist_dst);
}
return (error);
}
/* /*
* The simplest receive case: receive from the specified fd, creating the * The simplest receive case: receive from the specified fd, creating the
* specified snapshot. Apply the specified properties a "received" properties * specified snapshot. Apply the specified properties as "received" properties
* (which can be overridden by locally-set properties). If the stream is a * (which can be overridden by locally-set properties). If the stream is a
* clone, its origin snapshot must be specified by 'origin'. The 'force' * clone, its origin snapshot must be specified by 'origin'. The 'force'
* flag will cause the target filesystem to be rolled back or destroyed if * flag will cause the target filesystem to be rolled back or destroyed if
@ -553,73 +729,75 @@ int
lzc_receive(const char *snapname, nvlist_t *props, const char *origin, lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, int fd) boolean_t force, int fd)
{ {
/* return (recv_impl(snapname, props, origin, force, B_FALSE, fd,
* The receive ioctl is still legacy, so we need to construct our own NULL, -1, NULL, NULL, NULL, NULL));
* zfs_cmd_t rather than using zfsc_ioctl(). }
*/
zfs_cmd_t zc = {"\0"};
char *atp;
char *packed = NULL;
size_t size;
dmu_replay_record_t drr;
int error;
ASSERT3S(g_refcount, >, 0); /*
* Like lzc_receive, but if the receive fails due to premature stream
* termination, the intermediate state will be preserved on disk. In this
* case, ECKSUM will be returned. The receive may subsequently be resumed
* with a resuming send stream generated by lzc_send_resume().
*/
int
lzc_receive_resumable(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, int fd)
{
return (recv_impl(snapname, props, origin, force, B_TRUE, fd,
NULL, -1, NULL, NULL, NULL, NULL));
}
/* zc_name is name of containing filesystem */ /*
(void) strlcpy(zc.zc_name, snapname, sizeof (zc.zc_name)); * Like lzc_receive, but allows the caller to read the begin record and then to
atp = strchr(zc.zc_name, '@'); * pass it in. That could be useful if the caller wants to derive, for example,
if (atp == NULL) * the snapname or the origin parameters based on the information contained in
* the begin record.
* The begin record must be in its original form as read from the stream,
* in other words, it should not be byteswapped.
*
* The 'resumable' parameter allows to obtain the same behavior as with
* lzc_receive_resumable.
*/
int
lzc_receive_with_header(const char *snapname, nvlist_t *props,
const char *origin, boolean_t force, boolean_t resumable, int fd,
const dmu_replay_record_t *begin_record)
{
if (begin_record == NULL)
return (EINVAL); return (EINVAL);
*atp = '\0'; return (recv_impl(snapname, props, origin, force, resumable, fd,
begin_record, -1, NULL, NULL, NULL, NULL));
}
/* if the fs does not exist, try its parent. */ /*
if (!lzc_exists(zc.zc_name)) { * Like lzc_receive, but allows the caller to pass all supported arguments
char *slashp = strrchr(zc.zc_name, '/'); * and retrieve all values returned. The only additional input parameter
if (slashp == NULL) * is 'cleanup_fd' which is used to set a cleanup-on-exit file descriptor.
return (ENOENT); *
*slashp = '\0'; * The following parameters all provide return values. Several may be set
* in the failure case and will contain additional information.
} *
* The 'read_bytes' value will be set to the total number of bytes read.
/* zc_value is full name of the snapshot to create */ *
(void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value)); * The 'errflags' value will contain zprop_errflags_t flags which are
* used to describe any failures.
if (props != NULL) { *
/* zc_nvlist_src is props to set */ * The 'action_handle' is used to pass the handle for this guid/ds mapping.
packed = fnvlist_pack(props, &size); * It should be set to zero on first call and will contain an updated handle
zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed; * on success, it should be passed in subsequent calls.
zc.zc_nvlist_src_size = size; *
} * The 'errors' nvlist contains an entry for each unapplied received
* property. Callers are responsible for freeing this nvlist.
/* zc_string is name of clone origin (if DRR_FLAG_CLONE) */ */
if (origin != NULL) int lzc_receive_one(const char *snapname, nvlist_t *props,
(void) strlcpy(zc.zc_string, origin, sizeof (zc.zc_string)); const char *origin, boolean_t force, boolean_t resumable, int input_fd,
const dmu_replay_record_t *begin_record, int cleanup_fd,
/* zc_begin_record is non-byteswapped BEGIN record */ uint64_t *read_bytes, uint64_t *errflags, uint64_t *action_handle,
error = recv_read(fd, &drr, sizeof (drr)); nvlist_t **errors)
if (error != 0) {
goto out; return (recv_impl(snapname, props, origin, force, resumable,
zc.zc_begin_record = drr.drr_u.drr_begin; input_fd, begin_record, cleanup_fd, read_bytes, errflags,
action_handle, errors));
/* zc_cookie is fd to read from */
zc.zc_cookie = fd;
/* zc guid is force flag */
zc.zc_guid = force;
/* zc_cleanup_fd is unused */
zc.zc_cleanup_fd = -1;
error = ioctl(g_fd, ZFS_IOC_RECV, &zc);
if (error != 0)
error = errno;
out:
if (packed != NULL)
fnvlist_pack_free(packed, size);
free((void*)(uintptr_t)zc.zc_nvlist_dst);
return (error);
} }
/* /*
@ -664,7 +842,7 @@ lzc_bookmark(nvlist_t *bookmarks, nvlist_t **errlist)
{ {
nvpair_t *elem; nvpair_t *elem;
int error; int error;
char pool[MAXNAMELEN]; char pool[ZFS_MAX_DATASET_NAME_LEN];
/* determine the pool name */ /* determine the pool name */
elem = nvlist_next_nvpair(bookmarks, NULL); elem = nvlist_next_nvpair(bookmarks, NULL);
@ -726,7 +904,7 @@ lzc_destroy_bookmarks(nvlist_t *bmarks, nvlist_t **errlist)
{ {
nvpair_t *elem; nvpair_t *elem;
int error; int error;
char pool[MAXNAMELEN]; char pool[ZFS_MAX_DATASET_NAME_LEN];
/* determine the pool name */ /* determine the pool name */
elem = nvlist_next_nvpair(bmarks, NULL); elem = nvlist_next_nvpair(bmarks, NULL);

View File

@ -1408,6 +1408,8 @@ spl_fstrans_check(void)
return (0); return (0);
} }
void *zvol_tag = "zvol_tag";
void void
zvol_create_minors(spa_t *spa, const char *name, boolean_t async) zvol_create_minors(spa_t *spa, const char *name, boolean_t async)
{ {

View File

@ -22,7 +22,7 @@
.\" .\"
.\" Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. .\" Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright 2011 Joshua M. Clulow <josh@sysmgr.org> .\" Copyright 2011 Joshua M. Clulow <josh@sysmgr.org>
.\" Copyright (c) 2011, 2014 by Delphix. All rights reserved. .\" Copyright (c) 2011, 2015 by Delphix. All rights reserved.
.\" Copyright (c) 2014, Joyent, Inc. All rights reserved. .\" Copyright (c) 2014, Joyent, Inc. All rights reserved.
.\" Copyright 2012 Nexenta Systems, Inc. All Rights Reserved. .\" Copyright 2012 Nexenta Systems, Inc. All Rights Reserved.
.\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved. .\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
@ -180,17 +180,27 @@ zfs \- configures ZFS file systems
.LP .LP
.nf .nf
\fBzfs\fR \fBsend\fR [\fB-eL\fR] [\fB-i \fIsnapshot\fR|\fIbookmark\fR]\fR \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR \fBzfs\fR \fBsend\fR [\fB-Le\fR] [\fB-i \fIsnapshot\fR|\fIbookmark\fR]\fR \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR
.fi .fi
.LP .LP
.nf .nf
\fBzfs\fR \fBreceive\fR [\fB-vnFu\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR \fBzfs\fR \fBsend\fR [\fB-Penv\fR] \fB-t\fR \fIreceive_resume_token\fR
.fi .fi
.LP .LP
.nf .nf
\fBzfs\fR \fBreceive\fR [\fB-vnFu\fR] [\fB-d\fR|\fB-e\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR \fBzfs\fR \fBreceive\fR [\fB-Fnsuv\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR
.fi
.LP
.nf
\fBzfs\fR \fBreceive\fR [\fB-Fnsuv\fR] [\fB-d\fR|\fB-e\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR
.fi
.LP
.nf
\fBzfs\fR \fBreceive\fR \fB-A\fR \fIfilesystem\fR|\fIvolume\fR
.fi .fi
.LP .LP
@ -532,6 +542,17 @@ For cloned file systems or volumes, the snapshot from which the clone was create
.sp .sp
.ne 2 .ne 2
.na .na
\fB\fBreceive_resume_token\fR\fR
.ad
.sp .6
.RS 4n
For filesystems or volumes which have saved partially-completed state from \fBzfs receive -s\fR , this opaque token can be provided to \fBzfs send -t\fR to resume and complete the \fBzfs receive\fR.
.RE
.sp
.ne 2
.mk
.na
\fB\fBreferenced\fR\fR \fB\fBreferenced\fR\fR
.ad .ad
.sp .6 .sp .6
@ -2799,7 +2820,7 @@ The format of the stream is committed. You will be able to receive your streams
.sp .sp
.ne 2 .ne 2
.na .na
\fBzfs send\fR [\fB-eL\fR] [\fB-i\fR \fIsnapshot\fR|\fIbookmark\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR \fBzfs send\fR [\fB-Le\fR] [\fB-i\fR \fIsnapshot\fR|\fIbookmark\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR
.ad .ad
.sp .6 .sp .6
.RS 4n .RS 4n
@ -2809,24 +2830,6 @@ the pool must be read-only, or the filesystem must not be mounted. When the
stream generated from a filesystem or volume is received, the default snapshot stream generated from a filesystem or volume is received, the default snapshot
name will be "--head--". name will be "--head--".
.sp
.ne 2
.na
\fB-i\fR \fIsnapshot\fR|\fIbookmark\fR
.ad
.sp .6
.RS 4n
Generate an incremental send stream. The incremental source must be an earlier
snapshot in the destination's history. It will commonly be an earlier
snapshot in the destination's filesystem, in which case it can be
specified as the last component of the name (the \fB#\fR or \fB@\fR character
and following).
.sp
If the incremental target is a clone, the incremental source can
be the origin snapshot, or an earlier snapshot in the origin's filesystem,
or the origin's origin, etc.
.RE
.sp .sp
.ne 2 .ne 2
.na .na
@ -2859,15 +2862,39 @@ then the receiving system must have that feature enabled as well. See
\fBembedded_data\fR feature. \fBembedded_data\fR feature.
.RE .RE
.sp
.ne 2
.na
\fB-i\fR \fIsnapshot\fR|\fIbookmark\fR
.ad
.sp .6
.RS 4n
Generate an incremental send stream. The incremental source must be an earlier snapshot in the destination's history. It will commonly be an earlier snapshot in the destination's filesystem, in which case it can be specified as the last component of the name (the \fB#\fR or \fB@\fR character and following).
.sp
If the incremental target is a clone, the incremental source can be the origin snapshot, or an earlier snapshot in the origin's filesystem, or the origin's origin, etc.
.RE
.RE .RE
.sp .sp
.ne 2 .ne 2
.na .na
\fB\fBzfs receive\fR [\fB-vnFu\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR\fR \fB\fBzfs send\fR [\fB-Penv\fR] \fB-t\fR \fIreceive_resume_token\fR\fR
.ad
.sp .6
.RS 4n
Creates a send stream which resumes an interrupted receive. The \fIreceive_resume_token\fR is the value of this property on the filesystem or volume that was being received into. See the documentation for \fBzfs receive -s\fR for more details.
.RE
.RE
.sp
.ne 2
.na
\fB\fBzfs receive\fR [\fB-Fnsuv\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR\fR
.ad .ad
.br .br
.na .na
\fB\fBzfs receive\fR [\fB-vnFu\fR] [\fB-d\fR|\fB-e\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR\fR \fB\fBzfs receive\fR [\fB-Fnsuv\fR] [\fB-d\fR|\fB-e\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR\fR
.ad .ad
.sp .6 .sp .6
.RS 4n .RS 4n
@ -2885,21 +2912,36 @@ The \fB-d\fR and \fB-e\fR options cause the file system name of the target snaps
.sp .sp
.ne 2 .ne 2
.na .na
\fB\fB-d\fR\fR \fB\fB-F\fR\fR
.ad .ad
.sp .6 .sp .6
.RS 4n .RS 4n
Discard the first element of the sent snapshot's file system name, using the remaining elements to determine the name of the target file system for the new snapshot as described in the paragraph above. Force a rollback of the file system to the most recent snapshot before performing the receive operation. If receiving an incremental replication stream (for example, one generated by \fBzfs send -R -[iI]\fR), destroy snapshots and file systems that do not exist on the sending side.
.RE
.sp
.ne 2
.mk
.na
\fB\fB-n\fR\fR
.ad
.sp .6
.RS 4n
Do not actually receive the stream. This can be useful in conjunction with the \fB-v\fR option to verify the name the receive operation would use.
.RE .RE
.sp .sp
.ne 2 .ne 2
.na .na
\fB\fB-e\fR\fR \fB\fB-s\fR\fR
.ad .ad
.sp .6 .sp .6
.RS 4n .RS 4n
Discard all but the last element of the sent snapshot's file system name, using that element to determine the name of the target file system for the new snapshot as described in the paragraph above. If the receive is interrupted, save the partially received state, rather than deleting it. Interruption may be due to premature termination of the stream (e.g. due to network failure or failure of the remote system if the stream is being read over a network connection), a checksum error in the stream, termination of the \fBzfs receive\fR process, or unclean shutdown of the system.
.sp
The receive can be resumed with a stream generated by \fBzfs send -t\fR token, where the \fItoken\fR is the value of the \fBreceive_resume_token\fR property of the filesystem or volume which is received into.
.sp
To use this flag, the storage pool must have the \fBextensible_dataset\fR feature enabled. See \fBzpool-features\fR(5) for details on ZFS feature flags.
.RE .RE
.sp .sp
@ -2925,11 +2967,21 @@ Print verbose information about the stream and the time required to perform the
.sp .sp
.ne 2 .ne 2
.na .na
\fB\fB-n\fR\fR \fB\fB-d\fR\fR
.ad .ad
.sp .6 .sp .6
.RS 4n .RS 4n
Do not actually receive the stream. This can be useful in conjunction with the \fB-v\fR option to verify the name the receive operation would use. Discard the first element of the sent snapshot's file system name, using the remaining elements to determine the name of the target file system for the new snapshot as described in the paragraph above.
.RE
.sp
.ne 2
.na
\fB\fB-e\fR\fR
.ad
.sp .6
.RS 4n
Discard all but the last element of the sent snapshot's file system name, using that element to determine the name of the target file system for the new snapshot as described in the paragraph above.
.RE .RE
.sp .sp
@ -2939,18 +2991,24 @@ Do not actually receive the stream. This can be useful in conjunction with the \
.ad .ad
.sp .6 .sp .6
.RS 4n .RS 4n
Forces the stream to be received as a clone of the given snapshot. This is only valid if the stream is an incremental stream whose source is the same as the provided origin. Forces the stream to be received as a clone of the given snapshot.
If the stream is a full send stream, this will create the filesystem
described by the stream as a clone of the specified snapshot. Which
snapshot was specified will not affect the success or failure of the
receive, as long as the snapshot does exist. If the stream is an
incremental send stream, all the normal verification will be performed.
.RE
.RE .RE
.sp .sp
.ne 2 .ne 2
.na .na
\fB\fB-F\fR\fR \fB\fBzfs receive\fR [\fB-A\fR] \fIfilesystem\fR|\fIvolume\fR
.ad .ad
.sp .6 .sp .6
.RS 4n .RS 4n
Force a rollback of the file system to the most recent snapshot before performing the receive operation. If receiving an incremental replication stream (for example, one generated by \fBzfs send -R -[iI]\fR), destroy snapshots and file systems that do not exist on the sending side. Abort an interrupted \fBzfs receive \fB-s\fR\fR, deleting its saved partially received state.
.RE
.RE .RE

View File

@ -334,7 +334,12 @@ fletcher_4_impl_get(void)
void void
fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp) fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
{ {
const fletcher_4_ops_t *ops = fletcher_4_impl_get(); const fletcher_4_ops_t *ops;
if (IS_P2ALIGNED(size, 4 * sizeof (uint32_t)))
ops = fletcher_4_impl_get();
else
ops = &fletcher_4_scalar_ops;
ops->init(zcp); ops->init(zcp);
ops->compute(buf, size, zcp); ops->compute(buf, size, zcp);
@ -345,7 +350,12 @@ fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
void void
fletcher_4_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp) fletcher_4_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
{ {
const fletcher_4_ops_t *ops = fletcher_4_impl_get(); const fletcher_4_ops_t *ops;
if (IS_P2ALIGNED(size, 4 * sizeof (uint32_t)))
ops = fletcher_4_impl_get();
else
ops = &fletcher_4_scalar_ops;
ops->init(zcp); ops->init(zcp);
ops->compute_byteswap(buf, size, zcp); ops->compute_byteswap(buf, size, zcp);

View File

@ -69,7 +69,7 @@ zfs_component_namecheck(const char *path, namecheck_err_t *why, char *what)
{ {
const char *loc; const char *loc;
if (strlen(path) >= MAXNAMELEN) { if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
if (why) if (why)
*why = NAME_ERR_TOOLONG; *why = NAME_ERR_TOOLONG;
return (-1); return (-1);
@ -140,27 +140,8 @@ dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
/* /*
* Make sure the name is not too long. * Make sure the name is not too long.
*
* ZFS_MAXNAMELEN is the maximum dataset length used in the userland
* which is the same as MAXNAMELEN used in the kernel.
* If ZFS_MAXNAMELEN value is changed, make sure to cleanup all
* places using MAXNAMELEN.
*
* When HAVE_KOBJ_NAME_LEN is defined the maximum safe kobject name
* length is 20 bytes. This 20 bytes is broken down as follows to
* provide a maximum safe <pool>/<dataset>[@snapshot] length of only
* 18 bytes. To ensure bytes are left for <dataset>[@snapshot] the
* <pool> portition is futher limited to 9 bytes. For 2.6.27 and
* newer kernels this limit is set to MAXNAMELEN.
*
* <pool>/<dataset> + <partition> + <newline>
* (18) + (1) + (1)
*/ */
#ifdef HAVE_KOBJ_NAME_LEN if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
if (strlen(path) > 18) {
#else
if (strlen(path) >= MAXNAMELEN) {
#endif /* HAVE_KOBJ_NAME_LEN */
if (why) if (why)
*why = NAME_ERR_TOOLONG; *why = NAME_ERR_TOOLONG;
return (-1); return (-1);
@ -289,7 +270,7 @@ mountpoint_namecheck(const char *path, namecheck_err_t *why)
while (*end != '/' && *end != '\0') while (*end != '/' && *end != '\0')
end++; end++;
if (end - start >= MAXNAMELEN) { if (end - start >= ZFS_MAX_DATASET_NAME_LEN) {
if (why) if (why)
*why = NAME_ERR_TOOLONG; *why = NAME_ERR_TOOLONG;
return (-1); return (-1);
@ -314,27 +295,8 @@ pool_namecheck(const char *pool, namecheck_err_t *why, char *what)
/* /*
* Make sure the name is not too long. * Make sure the name is not too long.
*
* ZPOOL_MAXNAMELEN is the maximum pool length used in the userland
* which is the same as MAXNAMELEN used in the kernel.
* If ZPOOL_MAXNAMELEN value is changed, make sure to cleanup all
* places using MAXNAMELEN.
*
* When HAVE_KOBJ_NAME_LEN is defined the maximum safe kobject name
* length is 20 bytes. This 20 bytes is broken down as follows to
* provide a maximum safe <pool>/<dataset>[@snapshot] length of only
* 18 bytes. To ensure bytes are left for <dataset>[@snapshot] the
* <pool> portition is futher limited to 8 bytes. For 2.6.27 and
* newer kernels this limit is set to MAXNAMELEN.
*
* <pool>/<dataset> + <partition> + <newline>
* (18) + (1) + (1)
*/ */
#ifdef HAVE_KOBJ_NAME_LEN if (strlen(pool) >= ZFS_MAX_DATASET_NAME_LEN) {
if (strlen(pool) > 8) {
#else
if (strlen(pool) >= MAXNAMELEN) {
#endif /* HAVE_KOBJ_NAME_LEN */
if (why) if (why)
*why = NAME_ERR_TOOLONG; *why = NAME_ERR_TOOLONG;
return (-1); return (-1);

View File

@ -375,6 +375,10 @@ zfs_prop_init(void)
zprop_register_string(ZFS_PROP_SELINUX_ROOTCONTEXT, "rootcontext", zprop_register_string(ZFS_PROP_SELINUX_ROOTCONTEXT, "rootcontext",
"none", PROP_DEFAULT, ZFS_TYPE_DATASET, "<selinux rootcontext>", "none", PROP_DEFAULT, ZFS_TYPE_DATASET, "<selinux rootcontext>",
"ROOTCONTEXT"); "ROOTCONTEXT");
zprop_register_string(ZFS_PROP_RECEIVE_RESUME_TOKEN,
"receive_resume_token",
NULL, PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
"<string token>", "RESUMETOK");
/* readonly number properties */ /* readonly number properties */
zprop_register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY, zprop_register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY,

View File

@ -405,6 +405,17 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
* checksum/compression/copies. * checksum/compression/copies.
*/ */
if (ds != NULL) { if (ds != NULL) {
boolean_t needlock = B_FALSE;
/*
* Note: it's valid to open the objset if the dataset is
* long-held, in which case the pool_config lock will not
* be held.
*/
if (!dsl_pool_config_held(dmu_objset_pool(os))) {
needlock = B_TRUE;
dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
}
err = dsl_prop_register(ds, err = dsl_prop_register(ds,
zfs_prop_to_name(ZFS_PROP_PRIMARYCACHE), zfs_prop_to_name(ZFS_PROP_PRIMARYCACHE),
primary_cache_changed_cb, os); primary_cache_changed_cb, os);
@ -461,6 +472,8 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
dnodesize_changed_cb, os); dnodesize_changed_cb, os);
} }
} }
if (needlock)
dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
if (err != 0) { if (err != 0) {
VERIFY(arc_buf_remove_ref(os->os_phys_buf, VERIFY(arc_buf_remove_ref(os->os_phys_buf,
&os->os_phys_buf)); &os->os_phys_buf));
@ -520,6 +533,13 @@ dmu_objset_from_ds(dsl_dataset_t *ds, objset_t **osp)
{ {
int err = 0; int err = 0;
/*
* We shouldn't be doing anything with dsl_dataset_t's unless the
* pool_config lock is held, or the dataset is long-held.
*/
ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool) ||
dsl_dataset_long_held(ds));
mutex_enter(&ds->ds_opening_lock); mutex_enter(&ds->ds_opening_lock);
if (ds->ds_objset == NULL) { if (ds->ds_objset == NULL) {
objset_t *os; objset_t *os;
@ -651,7 +671,7 @@ dmu_objset_refresh_ownership(objset_t *os, void *tag)
{ {
dsl_pool_t *dp; dsl_pool_t *dp;
dsl_dataset_t *ds, *newds; dsl_dataset_t *ds, *newds;
char name[MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
ds = os->os_dsl_dataset; ds = os->os_dsl_dataset;
VERIFY3P(ds, !=, NULL); VERIFY3P(ds, !=, NULL);
@ -875,6 +895,9 @@ dmu_objset_create_check(void *arg, dmu_tx_t *tx)
if (strchr(doca->doca_name, '@') != NULL) if (strchr(doca->doca_name, '@') != NULL)
return (SET_ERROR(EINVAL)); return (SET_ERROR(EINVAL));
if (strlen(doca->doca_name) >= ZFS_MAX_DATASET_NAME_LEN)
return (SET_ERROR(ENAMETOOLONG));
error = dsl_dir_hold(dp, doca->doca_name, FTAG, &pdd, &tail); error = dsl_dir_hold(dp, doca->doca_name, FTAG, &pdd, &tail);
if (error != 0) if (error != 0)
return (error); return (error);
@ -961,6 +984,9 @@ dmu_objset_clone_check(void *arg, dmu_tx_t *tx)
if (strchr(doca->doca_clone, '@') != NULL) if (strchr(doca->doca_clone, '@') != NULL)
return (SET_ERROR(EINVAL)); return (SET_ERROR(EINVAL));
if (strlen(doca->doca_clone) >= ZFS_MAX_DATASET_NAME_LEN)
return (SET_ERROR(ENAMETOOLONG));
error = dsl_dir_hold(dp, doca->doca_clone, FTAG, &pdd, &tail); error = dsl_dir_hold(dp, doca->doca_clone, FTAG, &pdd, &tail);
if (error != 0) if (error != 0)
return (error); return (error);
@ -1000,7 +1026,7 @@ dmu_objset_clone_sync(void *arg, dmu_tx_t *tx)
const char *tail; const char *tail;
dsl_dataset_t *origin, *ds; dsl_dataset_t *origin, *ds;
uint64_t obj; uint64_t obj;
char namebuf[MAXNAMELEN]; char namebuf[ZFS_MAX_DATASET_NAME_LEN];
VERIFY0(dsl_dir_hold(dp, doca->doca_clone, FTAG, &pdd, &tail)); VERIFY0(dsl_dir_hold(dp, doca->doca_clone, FTAG, &pdd, &tail));
VERIFY0(dsl_dataset_hold(dp, doca->doca_origin, FTAG, &origin)); VERIFY0(dsl_dataset_hold(dp, doca->doca_origin, FTAG, &origin));
@ -2027,7 +2053,7 @@ dmu_objset_get_user(objset_t *os)
/* /*
* Determine name of filesystem, given name of snapshot. * Determine name of filesystem, given name of snapshot.
* buf must be at least MAXNAMELEN bytes * buf must be at least ZFS_MAX_DATASET_NAME_LEN bytes
*/ */
int int
dmu_fsname(const char *snapname, char *buf) dmu_fsname(const char *snapname, char *buf)
@ -2035,7 +2061,7 @@ dmu_fsname(const char *snapname, char *buf)
char *atp = strchr(snapname, '@'); char *atp = strchr(snapname, '@');
if (atp == NULL) if (atp == NULL)
return (SET_ERROR(EINVAL)); return (SET_ERROR(EINVAL));
if (atp - snapname >= MAXNAMELEN) if (atp - snapname >= ZFS_MAX_DATASET_NAME_LEN)
return (SET_ERROR(ENAMETOOLONG)); return (SET_ERROR(ENAMETOOLONG));
(void) strlcpy(buf, snapname, atp - snapname + 1); (void) strlcpy(buf, snapname, atp - snapname + 1);
return (0); return (0);

File diff suppressed because it is too large Load Diff

View File

@ -47,6 +47,7 @@ typedef struct prefetch_data {
int pd_flags; int pd_flags;
boolean_t pd_cancel; boolean_t pd_cancel;
boolean_t pd_exited; boolean_t pd_exited;
zbookmark_phys_t pd_resume;
} prefetch_data_t; } prefetch_data_t;
typedef struct traverse_data { typedef struct traverse_data {
@ -323,30 +324,29 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
uint32_t flags = ARC_FLAG_WAIT; uint32_t flags = ARC_FLAG_WAIT;
int32_t i; int32_t i;
int32_t epb = BP_GET_LSIZE(bp) >> DNODE_SHIFT; int32_t epb = BP_GET_LSIZE(bp) >> DNODE_SHIFT;
dnode_phys_t *cdnp; dnode_phys_t *child_dnp;
err = arc_read(NULL, td->td_spa, bp, arc_getbuf_func, &buf, err = arc_read(NULL, td->td_spa, bp, arc_getbuf_func, &buf,
ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb); ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
if (err != 0) if (err != 0)
goto post; goto post;
cdnp = buf->b_data; child_dnp = buf->b_data;
for (i = 0; i < epb; i += cdnp[i].dn_extra_slots + 1) { for (i = 0; i < epb; i += child_dnp[i].dn_extra_slots + 1) {
prefetch_dnode_metadata(td, &cdnp[i], zb->zb_objset, prefetch_dnode_metadata(td, &child_dnp[i],
zb->zb_blkid * epb + i); zb->zb_objset, zb->zb_blkid * epb + i);
} }
/* recursively visitbp() blocks below this */ /* recursively visitbp() blocks below this */
for (i = 0; i < epb; i += cdnp[i].dn_extra_slots + 1) { for (i = 0; i < epb; i += child_dnp[i].dn_extra_slots + 1) {
err = traverse_dnode(td, &cdnp[i], zb->zb_objset, err = traverse_dnode(td, &child_dnp[i],
zb->zb_blkid * epb + i); zb->zb_objset, zb->zb_blkid * epb + i);
if (err != 0) if (err != 0)
break; break;
} }
} else if (BP_GET_TYPE(bp) == DMU_OT_OBJSET) { } else if (BP_GET_TYPE(bp) == DMU_OT_OBJSET) {
arc_flags_t flags = ARC_FLAG_WAIT; arc_flags_t flags = ARC_FLAG_WAIT;
objset_phys_t *osp; objset_phys_t *osp;
dnode_phys_t *mdnp, *gdnp, *udnp;
err = arc_read(NULL, td->td_spa, bp, arc_getbuf_func, &buf, err = arc_read(NULL, td->td_spa, bp, arc_getbuf_func, &buf,
ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb); ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
@ -354,11 +354,7 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
goto post; goto post;
osp = buf->b_data; osp = buf->b_data;
mdnp = &osp->os_meta_dnode; prefetch_dnode_metadata(td, &osp->os_meta_dnode, zb->zb_objset,
gdnp = &osp->os_groupused_dnode;
udnp = &osp->os_userused_dnode;
prefetch_dnode_metadata(td, mdnp, zb->zb_objset,
DMU_META_DNODE_OBJECT); DMU_META_DNODE_OBJECT);
/* /*
* See the block comment above for the goal of this variable. * See the block comment above for the goal of this variable.
@ -370,21 +366,21 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
td->td_realloc_possible = B_FALSE; td->td_realloc_possible = B_FALSE;
if (arc_buf_size(buf) >= sizeof (objset_phys_t)) { if (arc_buf_size(buf) >= sizeof (objset_phys_t)) {
prefetch_dnode_metadata(td, gdnp, zb->zb_objset, prefetch_dnode_metadata(td, &osp->os_groupused_dnode,
DMU_GROUPUSED_OBJECT); zb->zb_objset, DMU_GROUPUSED_OBJECT);
prefetch_dnode_metadata(td, udnp, zb->zb_objset, prefetch_dnode_metadata(td, &osp->os_userused_dnode,
DMU_USERUSED_OBJECT); zb->zb_objset, DMU_USERUSED_OBJECT);
} }
err = traverse_dnode(td, mdnp, zb->zb_objset, err = traverse_dnode(td, &osp->os_meta_dnode, zb->zb_objset,
DMU_META_DNODE_OBJECT); DMU_META_DNODE_OBJECT);
if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) { if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) {
err = traverse_dnode(td, gdnp, zb->zb_objset, err = traverse_dnode(td, &osp->os_groupused_dnode,
DMU_GROUPUSED_OBJECT); zb->zb_objset, DMU_GROUPUSED_OBJECT);
} }
if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) { if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) {
err = traverse_dnode(td, udnp, zb->zb_objset, err = traverse_dnode(td, &osp->os_userused_dnode,
DMU_USERUSED_OBJECT); zb->zb_objset, DMU_USERUSED_OBJECT);
} }
} }
@ -416,9 +412,15 @@ post:
* Set the bookmark to the first level-0 block that we need * Set the bookmark to the first level-0 block that we need
* to visit. This way, the resuming code does not need to * to visit. This way, the resuming code does not need to
* deal with resuming from indirect blocks. * deal with resuming from indirect blocks.
*
* Note, if zb_level <= 0, dnp may be NULL, so we don't want
* to dereference it.
*/ */
td->td_resume->zb_blkid = zb->zb_blkid << td->td_resume->zb_blkid = zb->zb_blkid;
(zb->zb_level * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT)); if (zb->zb_level > 0) {
td->td_resume->zb_blkid <<= zb->zb_level *
(dnp->dn_indblkshift - SPA_BLKPTRSHIFT);
}
td->td_paused = B_TRUE; td->td_paused = B_TRUE;
} }
@ -450,6 +452,10 @@ traverse_dnode(traverse_data_t *td, const dnode_phys_t *dnp,
int j, err = 0; int j, err = 0;
zbookmark_phys_t czb; zbookmark_phys_t czb;
if (object != DMU_META_DNODE_OBJECT && td->td_resume != NULL &&
object < td->td_resume->zb_object)
return (0);
if (td->td_flags & TRAVERSE_PRE) { if (td->td_flags & TRAVERSE_PRE) {
SET_BOOKMARK(&czb, objset, object, ZB_DNODE_LEVEL, SET_BOOKMARK(&czb, objset, object, ZB_DNODE_LEVEL,
ZB_DNODE_BLKID); ZB_DNODE_BLKID);
@ -527,6 +533,7 @@ traverse_prefetch_thread(void *arg)
td.td_func = traverse_prefetcher; td.td_func = traverse_prefetcher;
td.td_arg = td_main->td_pfd; td.td_arg = td_main->td_pfd;
td.td_pfd = NULL; td.td_pfd = NULL;
td.td_resume = &td_main->td_pfd->pd_resume;
SET_BOOKMARK(&czb, td.td_objset, SET_BOOKMARK(&czb, td.td_objset,
ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID); ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
@ -556,12 +563,6 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
ASSERT(ds == NULL || objset == ds->ds_object); ASSERT(ds == NULL || objset == ds->ds_object);
ASSERT(!(flags & TRAVERSE_PRE) || !(flags & TRAVERSE_POST)); ASSERT(!(flags & TRAVERSE_PRE) || !(flags & TRAVERSE_POST));
/*
* The data prefetching mechanism (the prefetch thread) is incompatible
* with resuming from a bookmark.
*/
ASSERT(resume == NULL || !(flags & TRAVERSE_PREFETCH_DATA));
td = kmem_alloc(sizeof (traverse_data_t), KM_SLEEP); td = kmem_alloc(sizeof (traverse_data_t), KM_SLEEP);
pd = kmem_zalloc(sizeof (prefetch_data_t), KM_SLEEP); pd = kmem_zalloc(sizeof (prefetch_data_t), KM_SLEEP);
czb = kmem_alloc(sizeof (zbookmark_phys_t), KM_SLEEP); czb = kmem_alloc(sizeof (zbookmark_phys_t), KM_SLEEP);
@ -586,6 +587,8 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
} }
pd->pd_flags = flags; pd->pd_flags = flags;
if (resume != NULL)
pd->pd_resume = *resume;
mutex_init(&pd->pd_mtx, NULL, MUTEX_DEFAULT, NULL); mutex_init(&pd->pd_mtx, NULL, MUTEX_DEFAULT, NULL);
cv_init(&pd->pd_cv, NULL, CV_DEFAULT, NULL); cv_init(&pd->pd_cv, NULL, CV_DEFAULT, NULL);
@ -638,11 +641,19 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
* in syncing context). * in syncing context).
*/ */
int int
traverse_dataset(dsl_dataset_t *ds, uint64_t txg_start, int flags, traverse_dataset_resume(dsl_dataset_t *ds, uint64_t txg_start,
blkptr_cb_t func, void *arg) zbookmark_phys_t *resume,
int flags, blkptr_cb_t func, void *arg)
{ {
return (traverse_impl(ds->ds_dir->dd_pool->dp_spa, ds, ds->ds_object, return (traverse_impl(ds->ds_dir->dd_pool->dp_spa, ds, ds->ds_object,
&dsl_dataset_phys(ds)->ds_bp, txg_start, NULL, flags, func, arg)); &dsl_dataset_phys(ds)->ds_bp, txg_start, resume, flags, func, arg));
}
int
traverse_dataset(dsl_dataset_t *ds, uint64_t txg_start,
int flags, blkptr_cb_t func, void *arg)
{
return (traverse_dataset_resume(ds, txg_start, NULL, flags, func, arg));
} }
int int
@ -675,7 +686,7 @@ traverse_pool(spa_t *spa, uint64_t txg_start, int flags,
/* visit each dataset */ /* visit each dataset */
for (obj = 1; err == 0; for (obj = 1; err == 0;
err = dmu_object_next(mos, &obj, FALSE, txg_start)) { err = dmu_object_next(mos, &obj, B_FALSE, txg_start)) {
dmu_object_info_t doi; dmu_object_info_t doi;
err = dmu_object_info(mos, obj, &doi); err = dmu_object_info(mos, obj, &doi);

View File

@ -34,10 +34,10 @@ static int
dsl_bookmark_hold_ds(dsl_pool_t *dp, const char *fullname, dsl_bookmark_hold_ds(dsl_pool_t *dp, const char *fullname,
dsl_dataset_t **dsp, void *tag, char **shortnamep) dsl_dataset_t **dsp, void *tag, char **shortnamep)
{ {
char buf[MAXNAMELEN]; char buf[ZFS_MAX_DATASET_NAME_LEN];
char *hashp; char *hashp;
if (strlen(fullname) >= MAXNAMELEN) if (strlen(fullname) >= ZFS_MAX_DATASET_NAME_LEN)
return (SET_ERROR(ENAMETOOLONG)); return (SET_ERROR(ENAMETOOLONG));
hashp = strchr(fullname, '#'); hashp = strchr(fullname, '#');
if (hashp == NULL) if (hashp == NULL)

View File

@ -25,6 +25,7 @@
* Copyright (c) 2014 RackTop Systems. * Copyright (c) 2014 RackTop Systems.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved. * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
* Copyright (c) 2016 Actifio, Inc. All rights reserved. * Copyright (c) 2016 Actifio, Inc. All rights reserved.
* Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
*/ */
#include <sys/dmu_objset.h> #include <sys/dmu_objset.h>
@ -52,6 +53,9 @@
#include <sys/dsl_userhold.h> #include <sys/dsl_userhold.h>
#include <sys/dsl_bookmark.h> #include <sys/dsl_bookmark.h>
#include <sys/policy.h> #include <sys/policy.h>
#include <sys/dmu_send.h>
#include <sys/zio_compress.h>
#include <zfs_fletcher.h>
/* /*
* The SPA supports block sizes up to 16MB. However, very large blocks * The SPA supports block sizes up to 16MB. However, very large blocks
@ -75,6 +79,8 @@ int zfs_max_recordsize = 1 * 1024 * 1024;
extern inline dsl_dataset_phys_t *dsl_dataset_phys(dsl_dataset_t *ds); extern inline dsl_dataset_phys_t *dsl_dataset_phys(dsl_dataset_t *ds);
extern int spa_asize_inflation;
/* /*
* Figure out how much of this delta should be propogated to the dsl_dir * Figure out how much of this delta should be propogated to the dsl_dir
* layer. If there's a refreservation, that space has already been * layer. If there's a refreservation, that space has already been
@ -664,22 +670,38 @@ dsl_dataset_name(dsl_dataset_t *ds, char *name)
dsl_dir_name(ds->ds_dir, name); dsl_dir_name(ds->ds_dir, name);
VERIFY0(dsl_dataset_get_snapname(ds)); VERIFY0(dsl_dataset_get_snapname(ds));
if (ds->ds_snapname[0]) { if (ds->ds_snapname[0]) {
(void) strcat(name, "@"); VERIFY3U(strlcat(name, "@", ZFS_MAX_DATASET_NAME_LEN),
<, ZFS_MAX_DATASET_NAME_LEN);
/* /*
* We use a "recursive" mutex so that we * We use a "recursive" mutex so that we
* can call dprintf_ds() with ds_lock held. * can call dprintf_ds() with ds_lock held.
*/ */
if (!MUTEX_HELD(&ds->ds_lock)) { if (!MUTEX_HELD(&ds->ds_lock)) {
mutex_enter(&ds->ds_lock); mutex_enter(&ds->ds_lock);
(void) strcat(name, ds->ds_snapname); VERIFY3U(strlcat(name, ds->ds_snapname,
ZFS_MAX_DATASET_NAME_LEN), <,
ZFS_MAX_DATASET_NAME_LEN);
mutex_exit(&ds->ds_lock); mutex_exit(&ds->ds_lock);
} else { } else {
(void) strcat(name, ds->ds_snapname); VERIFY3U(strlcat(name, ds->ds_snapname,
ZFS_MAX_DATASET_NAME_LEN), <,
ZFS_MAX_DATASET_NAME_LEN);
} }
} }
} }
} }
int
dsl_dataset_namelen(dsl_dataset_t *ds)
{
int len;
VERIFY0(dsl_dataset_get_snapname(ds));
mutex_enter(&ds->ds_lock);
len = dsl_dir_namelen(ds->ds_dir) + 1 + strlen(ds->ds_snapname);
mutex_exit(&ds->ds_lock);
return (len);
}
void void
dsl_dataset_rele(dsl_dataset_t *ds, void *tag) dsl_dataset_rele(dsl_dataset_t *ds, void *tag)
{ {
@ -704,6 +726,7 @@ dsl_dataset_tryown(dsl_dataset_t *ds, void *tag)
{ {
boolean_t gotit = FALSE; boolean_t gotit = FALSE;
ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
mutex_enter(&ds->ds_lock); mutex_enter(&ds->ds_lock);
if (ds->ds_owner == NULL && !DS_IS_INCONSISTENT(ds)) { if (ds->ds_owner == NULL && !DS_IS_INCONSISTENT(ds)) {
ds->ds_owner = tag; ds->ds_owner = tag;
@ -714,6 +737,16 @@ dsl_dataset_tryown(dsl_dataset_t *ds, void *tag)
return (gotit); return (gotit);
} }
boolean_t
dsl_dataset_has_owner(dsl_dataset_t *ds)
{
boolean_t rv;
mutex_enter(&ds->ds_lock);
rv = (ds->ds_owner != NULL);
mutex_exit(&ds->ds_lock);
return (rv);
}
static void static void
dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, dmu_tx_t *tx) dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, dmu_tx_t *tx)
{ {
@ -1238,10 +1271,10 @@ dsl_dataset_snapshot_check(void *arg, dmu_tx_t *tx)
int error = 0; int error = 0;
dsl_dataset_t *ds; dsl_dataset_t *ds;
char *name, *atp; char *name, *atp;
char dsname[MAXNAMELEN]; char dsname[ZFS_MAX_DATASET_NAME_LEN];
name = nvpair_name(pair); name = nvpair_name(pair);
if (strlen(name) >= MAXNAMELEN) if (strlen(name) >= ZFS_MAX_DATASET_NAME_LEN)
error = SET_ERROR(ENAMETOOLONG); error = SET_ERROR(ENAMETOOLONG);
if (error == 0) { if (error == 0) {
atp = strchr(name, '@'); atp = strchr(name, '@');
@ -1414,7 +1447,7 @@ dsl_dataset_snapshot_sync(void *arg, dmu_tx_t *tx)
pair != NULL; pair = nvlist_next_nvpair(ddsa->ddsa_snaps, pair)) { pair != NULL; pair = nvlist_next_nvpair(ddsa->ddsa_snaps, pair)) {
dsl_dataset_t *ds; dsl_dataset_t *ds;
char *name, *atp; char *name, *atp;
char dsname[MAXNAMELEN]; char dsname[ZFS_MAX_DATASET_NAME_LEN];
name = nvpair_name(pair); name = nvpair_name(pair);
atp = strchr(name, '@'); atp = strchr(name, '@');
@ -1461,7 +1494,7 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
suspended = fnvlist_alloc(); suspended = fnvlist_alloc();
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
pair = nvlist_next_nvpair(snaps, pair)) { pair = nvlist_next_nvpair(snaps, pair)) {
char fsname[MAXNAMELEN]; char fsname[ZFS_MAX_DATASET_NAME_LEN];
char *snapname = nvpair_name(pair); char *snapname = nvpair_name(pair);
char *atp; char *atp;
void *cookie; void *cookie;
@ -1615,6 +1648,21 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
dmu_buf_will_dirty(ds->ds_dbuf, tx); dmu_buf_will_dirty(ds->ds_dbuf, tx);
dsl_dataset_phys(ds)->ds_fsid_guid = ds->ds_fsid_guid; dsl_dataset_phys(ds)->ds_fsid_guid = ds->ds_fsid_guid;
if (ds->ds_resume_bytes[tx->tx_txg & TXG_MASK] != 0) {
VERIFY0(zap_update(tx->tx_pool->dp_meta_objset,
ds->ds_object, DS_FIELD_RESUME_OBJECT, 8, 1,
&ds->ds_resume_object[tx->tx_txg & TXG_MASK], tx));
VERIFY0(zap_update(tx->tx_pool->dp_meta_objset,
ds->ds_object, DS_FIELD_RESUME_OFFSET, 8, 1,
&ds->ds_resume_offset[tx->tx_txg & TXG_MASK], tx));
VERIFY0(zap_update(tx->tx_pool->dp_meta_objset,
ds->ds_object, DS_FIELD_RESUME_BYTES, 8, 1,
&ds->ds_resume_bytes[tx->tx_txg & TXG_MASK], tx));
ds->ds_resume_object[tx->tx_txg & TXG_MASK] = 0;
ds->ds_resume_offset[tx->tx_txg & TXG_MASK] = 0;
ds->ds_resume_bytes[tx->tx_txg & TXG_MASK] = 0;
}
dmu_objset_sync(ds->ds_objset, zio, tx); dmu_objset_sync(ds->ds_objset, zio, tx);
for (f = 0; f < SPA_FEATURES; f++) { for (f = 0; f < SPA_FEATURES; f++) {
@ -1655,7 +1703,7 @@ get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
zap_cursor_retrieve(&zc, &za) == 0; zap_cursor_retrieve(&zc, &za) == 0;
zap_cursor_advance(&zc)) { zap_cursor_advance(&zc)) {
dsl_dataset_t *clone; dsl_dataset_t *clone;
char buf[ZFS_MAXNAMELEN]; char buf[ZFS_MAX_DATASET_NAME_LEN];
VERIFY0(dsl_dataset_hold_obj(ds->ds_dir->dd_pool, VERIFY0(dsl_dataset_hold_obj(ds->ds_dir->dd_pool,
za.za_first_integer, FTAG, &clone)); za.za_first_integer, FTAG, &clone));
dsl_dir_name(clone->ds_dir, buf); dsl_dir_name(clone->ds_dir, buf);
@ -1670,6 +1718,78 @@ fail:
nvlist_free(propval); nvlist_free(propval);
} }
static void
get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv)
{
dsl_pool_t *dp = ds->ds_dir->dd_pool;
if (dsl_dataset_has_resume_receive_state(ds)) {
char *str;
void *packed;
uint8_t *compressed;
uint64_t val;
nvlist_t *token_nv = fnvlist_alloc();
size_t packed_size, compressed_size;
zio_cksum_t cksum;
char *propval;
char buf[MAXNAMELEN];
int i;
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
DS_FIELD_RESUME_FROMGUID, sizeof (val), 1, &val) == 0) {
fnvlist_add_uint64(token_nv, "fromguid", val);
}
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
DS_FIELD_RESUME_OBJECT, sizeof (val), 1, &val) == 0) {
fnvlist_add_uint64(token_nv, "object", val);
}
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
DS_FIELD_RESUME_OFFSET, sizeof (val), 1, &val) == 0) {
fnvlist_add_uint64(token_nv, "offset", val);
}
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
DS_FIELD_RESUME_BYTES, sizeof (val), 1, &val) == 0) {
fnvlist_add_uint64(token_nv, "bytes", val);
}
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
DS_FIELD_RESUME_TOGUID, sizeof (val), 1, &val) == 0) {
fnvlist_add_uint64(token_nv, "toguid", val);
}
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
DS_FIELD_RESUME_TONAME, 1, sizeof (buf), buf) == 0) {
fnvlist_add_string(token_nv, "toname", buf);
}
if (zap_contains(dp->dp_meta_objset, ds->ds_object,
DS_FIELD_RESUME_EMBEDOK) == 0) {
fnvlist_add_boolean(token_nv, "embedok");
}
packed = fnvlist_pack(token_nv, &packed_size);
fnvlist_free(token_nv);
compressed = kmem_alloc(packed_size, KM_SLEEP);
compressed_size = gzip_compress(packed, compressed,
packed_size, packed_size, 6);
fletcher_4_native(compressed, compressed_size, &cksum);
str = kmem_alloc(compressed_size * 2 + 1, KM_SLEEP);
for (i = 0; i < compressed_size; i++) {
(void) sprintf(str + i * 2, "%02x", compressed[i]);
}
str[compressed_size * 2] = '\0';
propval = kmem_asprintf("%u-%llx-%llx-%s",
ZFS_SEND_RESUME_TOKEN_VERSION,
(longlong_t)cksum.zc_word[0],
(longlong_t)packed_size, str);
dsl_prop_nvlist_add_string(nv,
ZFS_PROP_RECEIVE_RESUME_TOKEN, propval);
kmem_free(packed, packed_size);
kmem_free(str, compressed_size * 2 + 1);
kmem_free(compressed, packed_size);
strfree(propval);
}
}
void void
dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
{ {
@ -1693,7 +1813,7 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
get_clones_stat(ds, nv); get_clones_stat(ds, nv);
} else { } else {
if (ds->ds_prev != NULL && ds->ds_prev != dp->dp_origin_snap) { if (ds->ds_prev != NULL && ds->ds_prev != dp->dp_origin_snap) {
char buf[MAXNAMELEN]; char buf[ZFS_MAX_DATASET_NAME_LEN];
dsl_dataset_name(ds->ds_prev, buf); dsl_dataset_name(ds->ds_prev, buf);
dsl_prop_nvlist_add_string(nv, ZFS_PROP_PREV_SNAP, buf); dsl_prop_nvlist_add_string(nv, ZFS_PROP_PREV_SNAP, buf);
} }
@ -1743,6 +1863,32 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
} }
} }
if (!dsl_dataset_is_snapshot(ds)) {
/* 6 extra bytes for /%recv */
char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
dsl_dataset_t *recv_ds;
/*
* A failed "newfs" (e.g. full) resumable receive leaves
* the stats set on this dataset. Check here for the prop.
*/
get_receive_resume_stats(ds, nv);
/*
* A failed incremental resumable receive leaves the
* stats set on our child named "%recv". Check the child
* for the prop.
*/
dsl_dataset_name(ds, recvname);
if (strlcat(recvname, "/", sizeof (recvname)) <
sizeof (recvname) &&
strlcat(recvname, recv_clone_name, sizeof (recvname)) <
sizeof (recvname) &&
dsl_dataset_hold(dp, recvname, FTAG, &recv_ds) == 0) {
get_receive_resume_stats(recv_ds, nv);
dsl_dataset_rele(recv_ds, FTAG);
}
}
} }
void void
@ -1863,7 +2009,7 @@ dsl_dataset_rename_snapshot_check_impl(dsl_pool_t *dp,
/* dataset name + 1 for the "@" + the new snapshot name must fit */ /* dataset name + 1 for the "@" + the new snapshot name must fit */
if (dsl_dir_namelen(hds->ds_dir) + 1 + if (dsl_dir_namelen(hds->ds_dir) + 1 +
strlen(ddrsa->ddrsa_newsnapname) >= MAXNAMELEN) strlen(ddrsa->ddrsa_newsnapname) >= ZFS_MAX_DATASET_NAME_LEN)
error = SET_ERROR(ENAMETOOLONG); error = SET_ERROR(ENAMETOOLONG);
return (error); return (error);
@ -1970,7 +2116,8 @@ dsl_dataset_rename_snapshot(const char *fsname,
* only one long hold on the dataset. We're not allowed to change anything here * only one long hold on the dataset. We're not allowed to change anything here
* so we don't permanently release the long hold or regular hold here. We want * so we don't permanently release the long hold or regular hold here. We want
* to do this only when syncing to avoid the dataset unexpectedly going away * to do this only when syncing to avoid the dataset unexpectedly going away
* when we release the long hold. * when we release the long hold. Allow a long hold to exist for volumes, this
* may occur when asynchronously registering the minor with the kernel.
*/ */
static int static int
dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx) dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx)
@ -1985,7 +2132,7 @@ dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx)
dsl_dataset_long_rele(ds, owner); dsl_dataset_long_rele(ds, owner);
} }
held = dsl_dataset_long_held(ds); held = (dsl_dataset_long_held(ds) && (ds->ds_owner != zvol_tag));
if (owner != NULL) if (owner != NULL)
dsl_dataset_long_hold(ds, owner); dsl_dataset_long_hold(ds, owner);
@ -2095,7 +2242,7 @@ dsl_dataset_rollback_sync(void *arg, dmu_tx_t *tx)
dsl_pool_t *dp = dmu_tx_pool(tx); dsl_pool_t *dp = dmu_tx_pool(tx);
dsl_dataset_t *ds, *clone; dsl_dataset_t *ds, *clone;
uint64_t cloneobj; uint64_t cloneobj;
char namebuf[ZFS_MAXNAMELEN]; char namebuf[ZFS_MAX_DATASET_NAME_LEN];
VERIFY0(dsl_dataset_hold(dp, ddra->ddra_fsname, FTAG, &ds)); VERIFY0(dsl_dataset_hold(dp, ddra->ddra_fsname, FTAG, &ds));
@ -2648,7 +2795,7 @@ promote_rele(dsl_dataset_promote_arg_t *ddpa, void *tag)
* Promote a clone. * Promote a clone.
* *
* If it fails due to a conflicting snapshot name, "conflsnap" will be filled * If it fails due to a conflicting snapshot name, "conflsnap" will be filled
* in with the name. (It must be at least MAXNAMELEN bytes long.) * in with the name. (It must be at least ZFS_MAX_DATASET_NAME_LEN bytes long.)
*/ */
int int
dsl_dataset_promote(const char *name, char *conflsnap) dsl_dataset_promote(const char *name, char *conflsnap)
@ -2685,6 +2832,11 @@ int
dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone, dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
dsl_dataset_t *origin_head, boolean_t force, void *owner, dmu_tx_t *tx) dsl_dataset_t *origin_head, boolean_t force, void *owner, dmu_tx_t *tx)
{ {
/*
* "slack" factor for received datasets with refquota set on them.
* See the bottom of this function for details on its use.
*/
uint64_t refquota_slack = DMU_MAX_ACCESS * spa_asize_inflation;
int64_t unused_refres_delta; int64_t unused_refres_delta;
/* they should both be heads */ /* they should both be heads */
@ -2727,10 +2879,22 @@ dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
dsl_dir_space_available(origin_head->ds_dir, NULL, 0, TRUE)) dsl_dir_space_available(origin_head->ds_dir, NULL, 0, TRUE))
return (SET_ERROR(ENOSPC)); return (SET_ERROR(ENOSPC));
/* clone can't be over the head's refquota */ /*
* The clone can't be too much over the head's refquota.
*
* To ensure that the entire refquota can be used, we allow one
* transaction to exceed the the refquota. Therefore, this check
* needs to also allow for the space referenced to be more than the
* refquota. The maximum amount of space that one transaction can use
* on disk is DMU_MAX_ACCESS * spa_asize_inflation. Allowing this
* overage ensures that we are able to receive a filesystem that
* exceeds the refquota on the source system.
*
* So that overage is the refquota_slack we use below.
*/
if (origin_head->ds_quota != 0 && if (origin_head->ds_quota != 0 &&
dsl_dataset_phys(clone)->ds_referenced_bytes > dsl_dataset_phys(clone)->ds_referenced_bytes >
origin_head->ds_quota) origin_head->ds_quota + refquota_slack)
return (SET_ERROR(EDQUOT)); return (SET_ERROR(EDQUOT));
return (0); return (0);
@ -2745,8 +2909,13 @@ dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
int64_t unused_refres_delta; int64_t unused_refres_delta;
ASSERT(clone->ds_reserved == 0); ASSERT(clone->ds_reserved == 0);
/*
* NOTE: On DEBUG kernels there could be a race between this and
* the check function if spa_asize_inflation is adjusted...
*/
ASSERT(origin_head->ds_quota == 0 || ASSERT(origin_head->ds_quota == 0 ||
dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota); dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota +
DMU_MAX_ACCESS * spa_asize_inflation);
ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev); ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
/* /*
@ -3391,6 +3560,23 @@ dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx)
dmu_object_zapify(mos, ds->ds_object, DMU_OT_DSL_DATASET, tx); dmu_object_zapify(mos, ds->ds_object, DMU_OT_DSL_DATASET, tx);
} }
boolean_t
dsl_dataset_is_zapified(dsl_dataset_t *ds)
{
dmu_object_info_t doi;
dmu_object_info_from_db(ds->ds_dbuf, &doi);
return (doi.doi_type == DMU_OTN_ZAP_METADATA);
}
boolean_t
dsl_dataset_has_resume_receive_state(dsl_dataset_t *ds)
{
return (dsl_dataset_is_zapified(ds) &&
zap_contains(ds->ds_dir->dd_pool->dp_meta_objset,
ds->ds_object, DS_FIELD_RESUME_TOGUID) == 0);
}
#if defined(_KERNEL) && defined(HAVE_SPL) #if defined(_KERNEL) && defined(HAVE_SPL)
#if defined(_LP64) #if defined(_LP64)
module_param(zfs_max_recordsize, int, 0644); module_param(zfs_max_recordsize, int, 0644);

View File

@ -20,7 +20,7 @@
*/ */
/* /*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2014 by Delphix. All rights reserved. * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
*/ */
/* /*
@ -330,7 +330,7 @@ dsl_deleg_get(const char *ddname, nvlist_t **nvp)
za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
basezc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP); basezc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
baseza = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); baseza = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
source = kmem_alloc(MAXNAMELEN + strlen(MOS_DIR_NAME) + 1, KM_SLEEP); source = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
for (dd = startdd; dd != NULL; dd = dd->dd_parent) { for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
@ -370,7 +370,7 @@ dsl_deleg_get(const char *ddname, nvlist_t **nvp)
nvlist_free(sp_nvp); nvlist_free(sp_nvp);
} }
kmem_free(source, MAXNAMELEN + strlen(MOS_DIR_NAME) + 1); kmem_free(source, ZFS_MAX_DATASET_NAME_LEN);
kmem_free(baseza, sizeof (zap_attribute_t)); kmem_free(baseza, sizeof (zap_attribute_t));
kmem_free(basezc, sizeof (zap_cursor_t)); kmem_free(basezc, sizeof (zap_cursor_t));
kmem_free(za, sizeof (zap_attribute_t)); kmem_free(za, sizeof (zap_attribute_t));

View File

@ -978,9 +978,17 @@ dsl_destroy_inconsistent(const char *dsname, void *arg)
objset_t *os; objset_t *os;
if (dmu_objset_hold(dsname, FTAG, &os) == 0) { if (dmu_objset_hold(dsname, FTAG, &os) == 0) {
boolean_t inconsistent = DS_IS_INCONSISTENT(dmu_objset_ds(os)); boolean_t need_destroy = DS_IS_INCONSISTENT(dmu_objset_ds(os));
/*
* If the dataset is inconsistent because a resumable receive
* has failed, then do not destroy it.
*/
if (dsl_dataset_has_resume_receive_state(dmu_objset_ds(os)))
need_destroy = B_FALSE;
dmu_objset_rele(os, FTAG); dmu_objset_rele(os, FTAG);
if (inconsistent) if (need_destroy)
(void) dsl_destroy_head(dsname); (void) dsl_destroy_head(dsname);
} }
return (0); return (0);

View File

@ -299,13 +299,14 @@ dsl_dir_async_rele(dsl_dir_t *dd, void *tag)
dmu_buf_rele(dd->dd_dbuf, tag); dmu_buf_rele(dd->dd_dbuf, tag);
} }
/* buf must be long enough (MAXNAMELEN + strlen(MOS_DIR_NAME) + 1 should do) */ /* buf must be at least ZFS_MAX_DATASET_NAME_LEN bytes */
void void
dsl_dir_name(dsl_dir_t *dd, char *buf) dsl_dir_name(dsl_dir_t *dd, char *buf)
{ {
if (dd->dd_parent) { if (dd->dd_parent) {
dsl_dir_name(dd->dd_parent, buf); dsl_dir_name(dd->dd_parent, buf);
(void) strcat(buf, "/"); VERIFY3U(strlcat(buf, "/", ZFS_MAX_DATASET_NAME_LEN), <,
ZFS_MAX_DATASET_NAME_LEN);
} else { } else {
buf[0] = '\0'; buf[0] = '\0';
} }
@ -315,10 +316,12 @@ dsl_dir_name(dsl_dir_t *dd, char *buf)
* dprintf_dd() with dd_lock held * dprintf_dd() with dd_lock held
*/ */
mutex_enter(&dd->dd_lock); mutex_enter(&dd->dd_lock);
(void) strcat(buf, dd->dd_myname); VERIFY3U(strlcat(buf, dd->dd_myname, ZFS_MAX_DATASET_NAME_LEN),
<, ZFS_MAX_DATASET_NAME_LEN);
mutex_exit(&dd->dd_lock); mutex_exit(&dd->dd_lock);
} else { } else {
(void) strcat(buf, dd->dd_myname); VERIFY3U(strlcat(buf, dd->dd_myname, ZFS_MAX_DATASET_NAME_LEN),
<, ZFS_MAX_DATASET_NAME_LEN);
} }
} }
@ -367,12 +370,12 @@ getcomponent(const char *path, char *component, const char **nextp)
if (p != NULL && if (p != NULL &&
(p[0] != '@' || strpbrk(path+1, "/@") || p[1] == '\0')) (p[0] != '@' || strpbrk(path+1, "/@") || p[1] == '\0'))
return (SET_ERROR(EINVAL)); return (SET_ERROR(EINVAL));
if (strlen(path) >= MAXNAMELEN) if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN)
return (SET_ERROR(ENAMETOOLONG)); return (SET_ERROR(ENAMETOOLONG));
(void) strcpy(component, path); (void) strcpy(component, path);
p = NULL; p = NULL;
} else if (p[0] == '/') { } else if (p[0] == '/') {
if (p - path >= MAXNAMELEN) if (p - path >= ZFS_MAX_DATASET_NAME_LEN)
return (SET_ERROR(ENAMETOOLONG)); return (SET_ERROR(ENAMETOOLONG));
(void) strncpy(component, path, p - path); (void) strncpy(component, path, p - path);
component[p - path] = '\0'; component[p - path] = '\0';
@ -384,7 +387,7 @@ getcomponent(const char *path, char *component, const char **nextp)
*/ */
if (strchr(path, '/')) if (strchr(path, '/'))
return (SET_ERROR(EINVAL)); return (SET_ERROR(EINVAL));
if (p - path >= MAXNAMELEN) if (p - path >= ZFS_MAX_DATASET_NAME_LEN)
return (SET_ERROR(ENAMETOOLONG)); return (SET_ERROR(ENAMETOOLONG));
(void) strncpy(component, path, p - path); (void) strncpy(component, path, p - path);
component[p - path] = '\0'; component[p - path] = '\0';
@ -412,7 +415,7 @@ dsl_dir_hold(dsl_pool_t *dp, const char *name, void *tag,
dsl_dir_t *dd; dsl_dir_t *dd;
uint64_t ddobj; uint64_t ddobj;
buf = kmem_alloc(MAXNAMELEN, KM_SLEEP); buf = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
err = getcomponent(name, buf, &next); err = getcomponent(name, buf, &next);
if (err != 0) if (err != 0)
goto error; goto error;
@ -479,7 +482,7 @@ dsl_dir_hold(dsl_pool_t *dp, const char *name, void *tag,
*tailp = next; *tailp = next;
*ddp = dd; *ddp = dd;
error: error:
kmem_free(buf, MAXNAMELEN); kmem_free(buf, ZFS_MAX_DATASET_NAME_LEN);
return (err); return (err);
} }
@ -974,7 +977,7 @@ dsl_dir_stats(dsl_dir_t *dd, nvlist_t *nv)
if (dsl_dir_is_clone(dd)) { if (dsl_dir_is_clone(dd)) {
dsl_dataset_t *ds; dsl_dataset_t *ds;
char buf[MAXNAMELEN]; char buf[ZFS_MAX_DATASET_NAME_LEN];
VERIFY0(dsl_dataset_hold_obj(dd->dd_pool, VERIFY0(dsl_dataset_hold_obj(dd->dd_pool,
dsl_dir_phys(dd)->dd_origin_obj, FTAG, &ds)); dsl_dir_phys(dd)->dd_origin_obj, FTAG, &ds));
@ -1691,11 +1694,11 @@ static int
dsl_valid_rename(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg) dsl_valid_rename(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
{ {
int *deltap = arg; int *deltap = arg;
char namebuf[MAXNAMELEN]; char namebuf[ZFS_MAX_DATASET_NAME_LEN];
dsl_dataset_name(ds, namebuf); dsl_dataset_name(ds, namebuf);
if (strlen(namebuf) + *deltap >= MAXNAMELEN) if (strlen(namebuf) + *deltap >= ZFS_MAX_DATASET_NAME_LEN)
return (SET_ERROR(ENAMETOOLONG)); return (SET_ERROR(ENAMETOOLONG));
return (0); return (0);
} }

View File

@ -20,7 +20,7 @@
*/ */
/* /*
* 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) 2012, 2014 by Delphix. All rights reserved. * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright (c) 2013 Martin Matuska. All rights reserved. * Copyright (c) 2013 Martin Matuska. All rights reserved.
* Copyright 2015, Joyent, Inc. * Copyright 2015, Joyent, Inc.
*/ */
@ -1095,7 +1095,7 @@ dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
dsl_pool_t *dp = dd->dd_pool; dsl_pool_t *dp = dd->dd_pool;
objset_t *mos = dp->dp_meta_objset; objset_t *mos = dp->dp_meta_objset;
int err = 0; int err = 0;
char setpoint[MAXNAMELEN]; char setpoint[ZFS_MAX_DATASET_NAME_LEN];
VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);

View File

@ -1115,7 +1115,7 @@ dsl_scan_visitds(dsl_scan_t *scn, uint64_t dsobj, dmu_tx_t *tx)
* rootbp's birth time is < cur_min_txg. Then we will * rootbp's birth time is < cur_min_txg. Then we will
* add the next snapshots/clones to the work queue. * add the next snapshots/clones to the work queue.
*/ */
char *dsname = kmem_alloc(MAXNAMELEN, KM_SLEEP); char *dsname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
dsl_dataset_name(ds, dsname); dsl_dataset_name(ds, dsname);
zfs_dbgmsg("scanning dataset %llu (%s) is unnecessary because " zfs_dbgmsg("scanning dataset %llu (%s) is unnecessary because "
"cur_min_txg (%llu) >= max_txg (%llu)", "cur_min_txg (%llu) >= max_txg (%llu)",
@ -1146,7 +1146,7 @@ dsl_scan_visitds(dsl_scan_t *scn, uint64_t dsobj, dmu_tx_t *tx)
dmu_buf_will_dirty(ds->ds_dbuf, tx); dmu_buf_will_dirty(ds->ds_dbuf, tx);
dsl_scan_visit_rootbp(scn, ds, &dsl_dataset_phys(ds)->ds_bp, tx); dsl_scan_visit_rootbp(scn, ds, &dsl_dataset_phys(ds)->ds_bp, tx);
dsname = kmem_alloc(ZFS_MAXNAMELEN, KM_SLEEP); dsname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
dsl_dataset_name(ds, dsname); dsl_dataset_name(ds, dsname);
zfs_dbgmsg("scanned dataset %llu (%s) with min=%llu max=%llu; " zfs_dbgmsg("scanned dataset %llu (%s) with min=%llu max=%llu; "
"pausing=%u", "pausing=%u",
@ -1154,7 +1154,7 @@ dsl_scan_visitds(dsl_scan_t *scn, uint64_t dsobj, dmu_tx_t *tx)
(longlong_t)scn->scn_phys.scn_cur_min_txg, (longlong_t)scn->scn_phys.scn_cur_min_txg,
(longlong_t)scn->scn_phys.scn_cur_max_txg, (longlong_t)scn->scn_phys.scn_cur_max_txg,
(int)scn->scn_pausing); (int)scn->scn_pausing);
kmem_free(dsname, ZFS_MAXNAMELEN); kmem_free(dsname, ZFS_MAX_DATASET_NAME_LEN);
if (scn->scn_pausing) if (scn->scn_pausing)
goto out; goto out;

View File

@ -20,7 +20,7 @@
*/ */
/* /*
* 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) 2012, 2014 by Delphix. All rights reserved. * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved. * Copyright (c) 2013 Steven Hartland. All rights reserved.
*/ */
@ -181,7 +181,7 @@ dsl_dataset_user_hold_sync_one_impl(nvlist_t *tmpholds, dsl_dataset_t *ds,
} }
typedef struct zfs_hold_cleanup_arg { typedef struct zfs_hold_cleanup_arg {
char zhca_spaname[MAXNAMELEN]; char zhca_spaname[ZFS_MAX_DATASET_NAME_LEN];
uint64_t zhca_spa_load_guid; uint64_t zhca_spa_load_guid;
nvlist_t *zhca_holds; nvlist_t *zhca_holds;
} zfs_hold_cleanup_arg_t; } zfs_hold_cleanup_arg_t;
@ -580,7 +580,7 @@ dsl_dataset_user_release_impl(nvlist_t *holds, nvlist_t *errlist,
error = dsl_dataset_hold_obj_string(tmpdp, error = dsl_dataset_hold_obj_string(tmpdp,
nvpair_name(pair), FTAG, &ds); nvpair_name(pair), FTAG, &ds);
if (error == 0) { if (error == 0) {
char name[MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
dsl_dataset_name(ds, name); dsl_dataset_name(ds, name);
dsl_pool_config_exit(tmpdp, FTAG); dsl_pool_config_exit(tmpdp, FTAG);
dsl_dataset_rele(ds, FTAG); dsl_dataset_rele(ds, FTAG);

View File

@ -361,8 +361,7 @@ spa_prop_get(spa_t *spa, nvlist_t **nvp)
break; break;
} }
strval = kmem_alloc( strval = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN,
MAXNAMELEN + strlen(MOS_DIR_NAME) + 1,
KM_SLEEP); KM_SLEEP);
dsl_dataset_name(ds, strval); dsl_dataset_name(ds, strval);
dsl_dataset_rele(ds, FTAG); dsl_dataset_rele(ds, FTAG);
@ -375,8 +374,7 @@ spa_prop_get(spa_t *spa, nvlist_t **nvp)
spa_prop_add_list(*nvp, prop, strval, intval, src); spa_prop_add_list(*nvp, prop, strval, intval, src);
if (strval != NULL) if (strval != NULL)
kmem_free(strval, kmem_free(strval, ZFS_MAX_DATASET_NAME_LEN);
MAXNAMELEN + strlen(MOS_DIR_NAME) + 1);
break; break;
@ -2018,6 +2016,16 @@ spa_load_verify_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
return (0); return (0);
} }
/* ARGSUSED */
int
verify_dataset_name_len(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
{
if (dsl_dataset_namelen(ds) >= ZFS_MAX_DATASET_NAME_LEN)
return (SET_ERROR(ENAMETOOLONG));
return (0);
}
static int static int
spa_load_verify(spa_t *spa) spa_load_verify(spa_t *spa)
{ {
@ -2032,6 +2040,14 @@ spa_load_verify(spa_t *spa)
if (policy.zrp_request & ZPOOL_NEVER_REWIND) if (policy.zrp_request & ZPOOL_NEVER_REWIND)
return (0); return (0);
dsl_pool_config_enter(spa->spa_dsl_pool, FTAG);
error = dmu_objset_find_dp(spa->spa_dsl_pool,
spa->spa_dsl_pool->dp_root_dir_obj, verify_dataset_name_len, NULL,
DS_FIND_CHILDREN);
dsl_pool_config_exit(spa->spa_dsl_pool, FTAG);
if (error != 0)
return (error);
rio = zio_root(spa, NULL, &sle, rio = zio_root(spa, NULL, &sle,
ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE); ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE);

View File

@ -21,7 +21,7 @@
/* /*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2014 by Delphix. All rights reserved. * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
*/ */
#include <sys/spa.h> #include <sys/spa.h>
@ -493,7 +493,7 @@ spa_history_log_internal_ds(dsl_dataset_t *ds, const char *operation,
dmu_tx_t *tx, const char *fmt, ...) dmu_tx_t *tx, const char *fmt, ...)
{ {
va_list adx; va_list adx;
char namebuf[MAXNAMELEN]; char namebuf[ZFS_MAX_DATASET_NAME_LEN];
nvlist_t *nvl = fnvlist_alloc(); nvlist_t *nvl = fnvlist_alloc();
ASSERT(tx != NULL); ASSERT(tx != NULL);
@ -512,7 +512,7 @@ spa_history_log_internal_dd(dsl_dir_t *dd, const char *operation,
dmu_tx_t *tx, const char *fmt, ...) dmu_tx_t *tx, const char *fmt, ...)
{ {
va_list adx; va_list adx;
char namebuf[MAXNAMELEN]; char namebuf[ZFS_MAX_DATASET_NAME_LEN];
nvlist_t *nvl = fnvlist_alloc(); nvlist_t *nvl = fnvlist_alloc();
ASSERT(tx != NULL); ASSERT(tx != NULL);

View File

@ -749,12 +749,13 @@ zfsctl_snapshot_path_objset(zfs_sb_t *zsb, uint64_t objsetid,
return (ENOENT); return (ENOENT);
cookie = spl_fstrans_mark(); cookie = spl_fstrans_mark();
snapname = kmem_alloc(MAXNAMELEN, KM_SLEEP); snapname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
while (error == 0) { while (error == 0) {
dsl_pool_config_enter(dmu_objset_pool(os), FTAG); dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
error = dmu_snapshot_list_next(zsb->z_os, MAXNAMELEN, error = dmu_snapshot_list_next(zsb->z_os,
snapname, &id, &pos, &case_conflict); ZFS_MAX_DATASET_NAME_LEN, snapname, &id, &pos,
&case_conflict);
dsl_pool_config_exit(dmu_objset_pool(os), FTAG); dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
if (error) if (error)
goto out; goto out;
@ -767,7 +768,7 @@ zfsctl_snapshot_path_objset(zfs_sb_t *zsb, uint64_t objsetid,
snprintf(full_path, path_len - 1, "%s/.zfs/snapshot/%s", snprintf(full_path, path_len - 1, "%s/.zfs/snapshot/%s",
zsb->z_mntopts->z_mntpoint, snapname); zsb->z_mntopts->z_mntpoint, snapname);
out: out:
kmem_free(snapname, MAXNAMELEN); kmem_free(snapname, ZFS_MAX_DATASET_NAME_LEN);
spl_fstrans_unmark(cookie); spl_fstrans_unmark(cookie);
return (error); return (error);
@ -854,14 +855,14 @@ zfsctl_snapdir_rename(struct inode *sdip, char *snm,
ZFS_ENTER(zsb); ZFS_ENTER(zsb);
to = kmem_alloc(MAXNAMELEN, KM_SLEEP); to = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
from = kmem_alloc(MAXNAMELEN, KM_SLEEP); from = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
real = kmem_alloc(MAXNAMELEN, KM_SLEEP); real = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
fsname = kmem_alloc(MAXNAMELEN, KM_SLEEP); fsname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
if (zsb->z_case == ZFS_CASE_INSENSITIVE) { if (zsb->z_case == ZFS_CASE_INSENSITIVE) {
error = dmu_snapshot_realname(zsb->z_os, snm, real, error = dmu_snapshot_realname(zsb->z_os, snm, real,
MAXNAMELEN, NULL); ZFS_MAX_DATASET_NAME_LEN, NULL);
if (error == 0) { if (error == 0) {
snm = real; snm = real;
} else if (error != ENOTSUP) { } else if (error != ENOTSUP) {
@ -871,9 +872,11 @@ zfsctl_snapdir_rename(struct inode *sdip, char *snm,
dmu_objset_name(zsb->z_os, fsname); dmu_objset_name(zsb->z_os, fsname);
error = zfsctl_snapshot_name(ITOZSB(sdip), snm, MAXNAMELEN, from); error = zfsctl_snapshot_name(ITOZSB(sdip), snm,
ZFS_MAX_DATASET_NAME_LEN, from);
if (error == 0) if (error == 0)
error = zfsctl_snapshot_name(ITOZSB(tdip), tnm, MAXNAMELEN, to); error = zfsctl_snapshot_name(ITOZSB(tdip), tnm,
ZFS_MAX_DATASET_NAME_LEN, to);
if (error == 0) if (error == 0)
error = zfs_secpolicy_rename_perms(from, to, cr); error = zfs_secpolicy_rename_perms(from, to, cr);
if (error != 0) if (error != 0)
@ -903,10 +906,10 @@ zfsctl_snapdir_rename(struct inode *sdip, char *snm,
rw_exit(&zfs_snapshot_lock); rw_exit(&zfs_snapshot_lock);
out: out:
kmem_free(from, MAXNAMELEN); kmem_free(from, ZFS_MAX_DATASET_NAME_LEN);
kmem_free(to, MAXNAMELEN); kmem_free(to, ZFS_MAX_DATASET_NAME_LEN);
kmem_free(real, MAXNAMELEN); kmem_free(real, ZFS_MAX_DATASET_NAME_LEN);
kmem_free(fsname, MAXNAMELEN); kmem_free(fsname, ZFS_MAX_DATASET_NAME_LEN);
ZFS_EXIT(zsb); ZFS_EXIT(zsb);
@ -929,12 +932,12 @@ zfsctl_snapdir_remove(struct inode *dip, char *name, cred_t *cr, int flags)
ZFS_ENTER(zsb); ZFS_ENTER(zsb);
snapname = kmem_alloc(MAXNAMELEN, KM_SLEEP); snapname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
real = kmem_alloc(MAXNAMELEN, KM_SLEEP); real = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
if (zsb->z_case == ZFS_CASE_INSENSITIVE) { if (zsb->z_case == ZFS_CASE_INSENSITIVE) {
error = dmu_snapshot_realname(zsb->z_os, name, real, error = dmu_snapshot_realname(zsb->z_os, name, real,
MAXNAMELEN, NULL); ZFS_MAX_DATASET_NAME_LEN, NULL);
if (error == 0) { if (error == 0) {
name = real; name = real;
} else if (error != ENOTSUP) { } else if (error != ENOTSUP) {
@ -942,7 +945,8 @@ zfsctl_snapdir_remove(struct inode *dip, char *name, cred_t *cr, int flags)
} }
} }
error = zfsctl_snapshot_name(ITOZSB(dip), name, MAXNAMELEN, snapname); error = zfsctl_snapshot_name(ITOZSB(dip), name,
ZFS_MAX_DATASET_NAME_LEN, snapname);
if (error == 0) if (error == 0)
error = zfs_secpolicy_destroy_perms(snapname, cr); error = zfs_secpolicy_destroy_perms(snapname, cr);
if (error != 0) if (error != 0)
@ -952,8 +956,8 @@ zfsctl_snapdir_remove(struct inode *dip, char *name, cred_t *cr, int flags)
if ((error == 0) || (error == ENOENT)) if ((error == 0) || (error == ENOENT))
error = dsl_destroy_snapshot(snapname, B_FALSE); error = dsl_destroy_snapshot(snapname, B_FALSE);
out: out:
kmem_free(snapname, MAXNAMELEN); kmem_free(snapname, ZFS_MAX_DATASET_NAME_LEN);
kmem_free(real, MAXNAMELEN); kmem_free(real, ZFS_MAX_DATASET_NAME_LEN);
ZFS_EXIT(zsb); ZFS_EXIT(zsb);
@ -975,7 +979,7 @@ zfsctl_snapdir_mkdir(struct inode *dip, char *dirname, vattr_t *vap,
if (!zfs_admin_snapshot) if (!zfs_admin_snapshot)
return (EACCES); return (EACCES);
dsname = kmem_alloc(MAXNAMELEN, KM_SLEEP); dsname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
if (zfs_component_namecheck(dirname, NULL, NULL) != 0) { if (zfs_component_namecheck(dirname, NULL, NULL) != 0) {
error = SET_ERROR(EILSEQ); error = SET_ERROR(EILSEQ);
@ -997,7 +1001,7 @@ zfsctl_snapdir_mkdir(struct inode *dip, char *dirname, vattr_t *vap,
0, cr, NULL, NULL); 0, cr, NULL, NULL);
} }
out: out:
kmem_free(dsname, MAXNAMELEN); kmem_free(dsname, ZFS_MAX_DATASET_NAME_LEN);
return (error); return (error);
} }
@ -1075,11 +1079,11 @@ zfsctl_snapshot_mount(struct path *path, int flags)
zsb = ITOZSB(ip); zsb = ITOZSB(ip);
ZFS_ENTER(zsb); ZFS_ENTER(zsb);
full_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); full_name = kmem_zalloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
full_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); full_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
error = zfsctl_snapshot_name(zsb, dname(dentry), error = zfsctl_snapshot_name(zsb, dname(dentry),
MAXNAMELEN, full_name); ZFS_MAX_DATASET_NAME_LEN, full_name);
if (error) if (error)
goto error; goto error;
@ -1153,7 +1157,7 @@ zfsctl_snapshot_mount(struct path *path, int flags)
} }
path_put(&spath); path_put(&spath);
error: error:
kmem_free(full_name, MAXNAMELEN); kmem_free(full_name, ZFS_MAX_DATASET_NAME_LEN);
kmem_free(full_path, MAXPATHLEN); kmem_free(full_path, MAXPATHLEN);
ZFS_EXIT(zsb); ZFS_EXIT(zsb);

View File

@ -22,6 +22,7 @@
/* /*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Portions Copyright 2011 Martin Matuska * Portions Copyright 2011 Martin Matuska
* Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
* Portions Copyright 2012 Pawel Jakub Dawidek <pawel@dawidek.net> * Portions Copyright 2012 Pawel Jakub Dawidek <pawel@dawidek.net>
* Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
@ -603,7 +604,7 @@ zfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval,
case ZFS_PROP_SNAPSHOT_LIMIT: case ZFS_PROP_SNAPSHOT_LIMIT:
if (!INGLOBALZONE(curproc)) { if (!INGLOBALZONE(curproc)) {
uint64_t zoned; uint64_t zoned;
char setpoint[MAXNAMELEN]; char setpoint[ZFS_MAX_DATASET_NAME_LEN];
/* /*
* Unprivileged users are allowed to modify the * Unprivileged users are allowed to modify the
* limit on things *under* (ie. contained by) * limit on things *under* (ie. contained by)
@ -845,7 +846,7 @@ zfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
int int
zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
{ {
char parentname[MAXNAMELEN]; char parentname[ZFS_MAX_DATASET_NAME_LEN];
int error; int error;
if ((error = zfs_secpolicy_write_perms(from, if ((error = zfs_secpolicy_write_perms(from,
@ -898,7 +899,7 @@ zfs_secpolicy_promote(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &clone); error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &clone);
if (error == 0) { if (error == 0) {
char parentname[MAXNAMELEN]; char parentname[ZFS_MAX_DATASET_NAME_LEN];
dsl_dataset_t *origin = NULL; dsl_dataset_t *origin = NULL;
dsl_dir_t *dd; dsl_dir_t *dd;
dd = clone->ds_dir; dd = clone->ds_dir;
@ -944,6 +945,13 @@ zfs_secpolicy_recv(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
ZFS_DELEG_PERM_CREATE, cr)); ZFS_DELEG_PERM_CREATE, cr));
} }
/* ARGSUSED */
static int
zfs_secpolicy_recv_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{
return (zfs_secpolicy_recv(zc, innvl, cr));
}
int int
zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
{ {
@ -1068,7 +1076,7 @@ zfs_secpolicy_log_history(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
static int static int
zfs_secpolicy_create_clone(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr) zfs_secpolicy_create_clone(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
{ {
char parentname[MAXNAMELEN]; char parentname[ZFS_MAX_DATASET_NAME_LEN];
int error; int error;
char *origin; char *origin;
@ -1211,7 +1219,7 @@ zfs_secpolicy_hold(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL; for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
pair = nvlist_next_nvpair(holds, pair)) { pair = nvlist_next_nvpair(holds, pair)) {
char fsname[MAXNAMELEN]; char fsname[ZFS_MAX_DATASET_NAME_LEN];
error = dmu_fsname(nvpair_name(pair), fsname); error = dmu_fsname(nvpair_name(pair), fsname);
if (error != 0) if (error != 0)
return (error); return (error);
@ -1232,7 +1240,7 @@ zfs_secpolicy_release(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
for (pair = nvlist_next_nvpair(innvl, NULL); pair != NULL; for (pair = nvlist_next_nvpair(innvl, NULL); pair != NULL;
pair = nvlist_next_nvpair(innvl, pair)) { pair = nvlist_next_nvpair(innvl, pair)) {
char fsname[MAXNAMELEN]; char fsname[ZFS_MAX_DATASET_NAME_LEN];
error = dmu_fsname(nvpair_name(pair), fsname); error = dmu_fsname(nvpair_name(pair), fsname);
if (error != 0) if (error != 0)
return (error); return (error);
@ -2252,7 +2260,8 @@ zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
* A dataset name of maximum length cannot have any snapshots, * A dataset name of maximum length cannot have any snapshots,
* so exit immediately. * so exit immediately.
*/ */
if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) { if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >=
ZFS_MAX_DATASET_NAME_LEN) {
dmu_objset_rele(os, FTAG); dmu_objset_rele(os, FTAG);
return (SET_ERROR(ESRCH)); return (SET_ERROR(ESRCH));
} }
@ -3040,7 +3049,7 @@ zfs_fill_zplprops(const char *dataset, nvlist_t *createprops,
boolean_t fuids_ok, sa_ok; boolean_t fuids_ok, sa_ok;
uint64_t zplver = ZPL_VERSION; uint64_t zplver = ZPL_VERSION;
objset_t *os = NULL; objset_t *os = NULL;
char parentname[MAXNAMELEN]; char parentname[ZFS_MAX_DATASET_NAME_LEN];
char *cp; char *cp;
spa_t *spa; spa_t *spa;
uint64_t spa_vers; uint64_t spa_vers;
@ -3406,7 +3415,7 @@ zfs_destroy_unmount_origin(const char *fsname)
return; return;
ds = dmu_objset_ds(os); ds = dmu_objset_ds(os);
if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev)) { if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev)) {
char originname[MAXNAMELEN]; char originname[ZFS_MAX_DATASET_NAME_LEN];
dsl_dataset_name(ds->ds_prev, originname); dsl_dataset_name(ds->ds_prev, originname);
dmu_objset_rele(os, FTAG); dmu_objset_rele(os, FTAG);
(void) zfs_unmount_snap(originname); (void) zfs_unmount_snap(originname);
@ -3990,77 +3999,93 @@ next:
} }
} }
/*
* Extract properties that cannot be set PRIOR to the receipt of a dataset.
* For example, refquota cannot be set until after the receipt of a dataset,
* because in replication streams, an older/earlier snapshot may exceed the
* refquota. We want to receive the older/earlier snapshot, but setting
* refquota pre-receipt will set the dsl's ACTUAL quota, which will prevent
* the older/earlier snapshot from being received (with EDQUOT).
*
* The ZFS test "zfs_receive_011_pos" demonstrates such a scenario.
*
* libzfs will need to be judicious handling errors encountered by props
* extracted by this function.
*/
static nvlist_t *
extract_delay_props(nvlist_t *props)
{
nvlist_t *delayprops;
nvpair_t *nvp, *tmp;
static const zfs_prop_t delayable[] = { ZFS_PROP_REFQUOTA, 0 };
int i;
VERIFY(nvlist_alloc(&delayprops, NV_UNIQUE_NAME, KM_SLEEP) == 0);
for (nvp = nvlist_next_nvpair(props, NULL); nvp != NULL;
nvp = nvlist_next_nvpair(props, nvp)) {
/*
* strcmp() is safe because zfs_prop_to_name() always returns
* a bounded string.
*/
for (i = 0; delayable[i] != 0; i++) {
if (strcmp(zfs_prop_to_name(delayable[i]),
nvpair_name(nvp)) == 0) {
break;
}
}
if (delayable[i] != 0) {
tmp = nvlist_prev_nvpair(props, nvp);
VERIFY(nvlist_add_nvpair(delayprops, nvp) == 0);
VERIFY(nvlist_remove_nvpair(props, nvp) == 0);
nvp = tmp;
}
}
if (nvlist_empty(delayprops)) {
nvlist_free(delayprops);
delayprops = NULL;
}
return (delayprops);
}
#ifdef DEBUG #ifdef DEBUG
static boolean_t zfs_ioc_recv_inject_err; static boolean_t zfs_ioc_recv_inject_err;
#endif #endif
/* /*
* inputs: * On failure the 'errors' nvlist may be allocated and will contain a
* zc_name name of containing filesystem * descriptions of the failures. It's the callers responsibilty to free.
* zc_nvlist_src{_size} nvlist of properties to apply
* zc_value name of snapshot to create
* zc_string name of clone origin (if DRR_FLAG_CLONE)
* zc_cookie file descriptor to recv from
* zc_begin_record the BEGIN record of the stream (not byteswapped)
* zc_guid force flag
* zc_cleanup_fd cleanup-on-exit file descriptor
* zc_action_handle handle for this guid/ds mapping (or zero on first call)
*
* outputs:
* zc_cookie number of bytes read
* zc_nvlist_dst{_size} error for each unapplied received property
* zc_obj zprop_errflags_t
* zc_action_handle handle for this guid/ds mapping
*/ */
static int static int
zfs_ioc_recv(zfs_cmd_t *zc) zfs_ioc_recv_impl(char *tofs, char *tosnap, char *origin,
nvlist_t *props, boolean_t force, boolean_t resumable, int input_fd,
dmu_replay_record_t *begin_record, int cleanup_fd, uint64_t *read_bytes,
uint64_t *errflags, uint64_t *action_handle, nvlist_t **errors)
{ {
file_t *fp;
dmu_recv_cookie_t drc; dmu_recv_cookie_t drc;
boolean_t force = (boolean_t)zc->zc_guid;
int fd;
int error = 0; int error = 0;
int props_error = 0; int props_error = 0;
nvlist_t *errors;
offset_t off; offset_t off;
nvlist_t *props = NULL; /* sent properties */ nvlist_t *delayprops = NULL; /* sent properties applied post-receive */
nvlist_t *origprops = NULL; /* existing properties */ nvlist_t *origprops = NULL; /* existing properties */
char *origin = NULL;
char *tosnap;
char tofs[ZFS_MAXNAMELEN];
boolean_t first_recvd_props = B_FALSE; boolean_t first_recvd_props = B_FALSE;
file_t *input_fp;
if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 || *errors = NULL;
strchr(zc->zc_value, '@') == NULL || input_fp = getf(input_fd);
strchr(zc->zc_value, '%')) if (input_fp == NULL)
return (SET_ERROR(EINVAL));
(void) strcpy(tofs, zc->zc_value);
tosnap = strchr(tofs, '@');
*tosnap++ = '\0';
if (zc->zc_nvlist_src != 0 &&
(error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
zc->zc_iflags, &props)) != 0)
return (error);
fd = zc->zc_cookie;
fp = getf(fd);
if (fp == NULL) {
nvlist_free(props);
return (SET_ERROR(EBADF)); return (SET_ERROR(EBADF));
}
VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0);
if (zc->zc_string[0])
origin = zc->zc_string;
error = dmu_recv_begin(tofs, tosnap, error = dmu_recv_begin(tofs, tosnap,
&zc->zc_begin_record, force, origin, &drc); begin_record, force, resumable, origin, &drc);
if (error != 0) if (error != 0)
goto out; goto out;
*read_bytes = 0;
*errflags = 0;
*errors = fnvlist_alloc();
/* /*
* Set properties before we receive the stream so that they are applied * Set properties before we receive the stream so that they are applied
* to the new data. Note that we must call dmu_recv_stream() if * to the new data. Note that we must call dmu_recv_stream() if
@ -4090,14 +4115,14 @@ zfs_ioc_recv(zfs_cmd_t *zc)
if (!first_recvd_props) if (!first_recvd_props)
props_reduce(props, origprops); props_reduce(props, origprops);
if (zfs_check_clearable(tofs, origprops, &errlist) != 0) if (zfs_check_clearable(tofs, origprops, &errlist) != 0)
(void) nvlist_merge(errors, errlist, 0); (void) nvlist_merge(*errors, errlist, 0);
nvlist_free(errlist); nvlist_free(errlist);
if (clear_received_props(tofs, origprops, if (clear_received_props(tofs, origprops,
first_recvd_props ? NULL : props) != 0) first_recvd_props ? NULL : props) != 0)
zc->zc_obj |= ZPROP_ERR_NOCLEAR; *errflags |= ZPROP_ERR_NOCLEAR;
} else { } else {
zc->zc_obj |= ZPROP_ERR_NOCLEAR; *errflags |= ZPROP_ERR_NOCLEAR;
} }
} }
@ -4105,24 +4130,15 @@ zfs_ioc_recv(zfs_cmd_t *zc)
props_error = dsl_prop_set_hasrecvd(tofs); props_error = dsl_prop_set_hasrecvd(tofs);
if (props_error == 0) { if (props_error == 0) {
delayprops = extract_delay_props(props);
(void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED, (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
props, errors); props, *errors);
} }
} }
if (zc->zc_nvlist_dst_size != 0 && off = input_fp->f_offset;
(nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 || error = dmu_recv_stream(&drc, input_fp->f_vnode, &off, cleanup_fd,
put_nvlist(zc, errors) != 0)) { action_handle);
/*
* Caller made zc->zc_nvlist_dst less than the minimum expected
* size or supplied an invalid address.
*/
props_error = SET_ERROR(EINVAL);
}
off = fp->f_offset;
error = dmu_recv_stream(&drc, fp->f_vnode, &off, zc->zc_cleanup_fd,
&zc->zc_action_handle);
if (error == 0) { if (error == 0) {
zfs_sb_t *zsb = NULL; zfs_sb_t *zsb = NULL;
@ -4144,11 +4160,32 @@ zfs_ioc_recv(zfs_cmd_t *zc)
} else { } else {
error = dmu_recv_end(&drc, NULL); error = dmu_recv_end(&drc, NULL);
} }
/* Set delayed properties now, after we're done receiving. */
if (delayprops != NULL && error == 0) {
(void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
delayprops, *errors);
}
} }
zc->zc_cookie = off - fp->f_offset; if (delayprops != NULL) {
if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) /*
fp->f_offset = off; * Merge delayed props back in with initial props, in case
* we're DEBUG and zfs_ioc_recv_inject_err is set (which means
* we have to make sure clear_received_props() includes
* the delayed properties).
*
* Since zfs_ioc_recv_inject_err is only in DEBUG kernels,
* using ASSERT() will be just like a VERIFY.
*/
ASSERT(nvlist_merge(props, delayprops, 0) == 0);
nvlist_free(delayprops);
}
*read_bytes = off - input_fp->f_offset;
if (VOP_SEEK(input_fp->f_vnode, input_fp->f_offset, &off, NULL) == 0)
input_fp->f_offset = off;
#ifdef DEBUG #ifdef DEBUG
if (zfs_ioc_recv_inject_err) { if (zfs_ioc_recv_inject_err) {
@ -4167,14 +4204,14 @@ zfs_ioc_recv(zfs_cmd_t *zc)
* Since we may have left a $recvd value on the * Since we may have left a $recvd value on the
* system, we can't clear the $hasrecvd flag. * system, we can't clear the $hasrecvd flag.
*/ */
zc->zc_obj |= ZPROP_ERR_NORESTORE; *errflags |= ZPROP_ERR_NORESTORE;
} else if (first_recvd_props) { } else if (first_recvd_props) {
dsl_prop_unset_hasrecvd(tofs); dsl_prop_unset_hasrecvd(tofs);
} }
if (origprops == NULL && !drc.drc_newfs) { if (origprops == NULL && !drc.drc_newfs) {
/* We failed to stash the original properties. */ /* We failed to stash the original properties. */
zc->zc_obj |= ZPROP_ERR_NORESTORE; *errflags |= ZPROP_ERR_NORESTORE;
} }
/* /*
@ -4191,14 +4228,12 @@ zfs_ioc_recv(zfs_cmd_t *zc)
* We stashed the original properties but failed to * We stashed the original properties but failed to
* restore them. * restore them.
*/ */
zc->zc_obj |= ZPROP_ERR_NORESTORE; *errflags |= ZPROP_ERR_NORESTORE;
} }
} }
out: out:
nvlist_free(props); releasef(input_fd);
nvlist_free(origprops); nvlist_free(origprops);
nvlist_free(errors);
releasef(fd);
if (error == 0) if (error == 0)
error = props_error; error = props_error;
@ -4206,6 +4241,176 @@ out:
return (error); return (error);
} }
/*
* inputs:
* zc_name name of containing filesystem (unused)
* zc_nvlist_src{_size} nvlist of properties to apply
* zc_value name of snapshot to create
* zc_string name of clone origin (if DRR_FLAG_CLONE)
* zc_cookie file descriptor to recv from
* zc_begin_record the BEGIN record of the stream (not byteswapped)
* zc_guid force flag
* zc_cleanup_fd cleanup-on-exit file descriptor
* zc_action_handle handle for this guid/ds mapping (or zero on first call)
*
* outputs:
* zc_cookie number of bytes read
* zc_obj zprop_errflags_t
* zc_action_handle handle for this guid/ds mapping
* zc_nvlist_dst{_size} error for each unapplied received property
*/
static int
zfs_ioc_recv(zfs_cmd_t *zc)
{
dmu_replay_record_t begin_record;
nvlist_t *errors = NULL;
nvlist_t *props = NULL;
char *origin = NULL;
char *tosnap;
char tofs[ZFS_MAX_DATASET_NAME_LEN];
int error = 0;
if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
strchr(zc->zc_value, '@') == NULL ||
strchr(zc->zc_value, '%'))
return (SET_ERROR(EINVAL));
(void) strcpy(tofs, zc->zc_value);
tosnap = strchr(tofs, '@');
*tosnap++ = '\0';
if (zc->zc_nvlist_src != 0 &&
(error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
zc->zc_iflags, &props)) != 0)
return (error);
if (zc->zc_string[0])
origin = zc->zc_string;
begin_record.drr_type = DRR_BEGIN;
begin_record.drr_payloadlen = 0;
begin_record.drr_u.drr_begin = zc->zc_begin_record;
error = zfs_ioc_recv_impl(tofs, tosnap, origin, props, zc->zc_guid,
B_FALSE, zc->zc_cookie, &begin_record, zc->zc_cleanup_fd,
&zc->zc_cookie, &zc->zc_obj, &zc->zc_action_handle, &errors);
nvlist_free(props);
/*
* Now that all props, initial and delayed, are set, report the prop
* errors to the caller.
*/
if (zc->zc_nvlist_dst_size != 0 && errors != NULL &&
(nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 ||
put_nvlist(zc, errors) != 0)) {
/*
* Caller made zc->zc_nvlist_dst less than the minimum expected
* size or supplied an invalid address.
*/
error = SET_ERROR(EINVAL);
}
nvlist_free(errors);
return (error);
}
/*
* innvl: {
* "snapname" -> full name of the snapshot to create
* (optional) "props" -> properties to set (nvlist)
* (optional) "origin" -> name of clone origin (DRR_FLAG_CLONE)
* "begin_record" -> non-byteswapped dmu_replay_record_t
* "input_fd" -> file descriptor to read stream from (int32)
* (optional) "force" -> force flag (value ignored)
* (optional) "resumable" -> resumable flag (value ignored)
* (optional) "cleanup_fd" -> cleanup-on-exit file descriptor
* (optional) "action_handle" -> handle for this guid/ds mapping
* }
*
* outnvl: {
* "read_bytes" -> number of bytes read
* "error_flags" -> zprop_errflags_t
* "action_handle" -> handle for this guid/ds mapping
* "errors" -> error for each unapplied received property (nvlist)
* }
*/
static int
zfs_ioc_recv_new(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
{
dmu_replay_record_t *begin_record;
uint_t begin_record_size;
nvlist_t *errors = NULL;
nvlist_t *props = NULL;
char *snapname = NULL;
char *origin = NULL;
char *tosnap;
char tofs[ZFS_MAX_DATASET_NAME_LEN];
boolean_t force;
boolean_t resumable;
uint64_t action_handle = 0;
uint64_t read_bytes = 0;
uint64_t errflags = 0;
int input_fd = -1;
int cleanup_fd = -1;
int error;
error = nvlist_lookup_string(innvl, "snapname", &snapname);
if (error != 0)
return (SET_ERROR(EINVAL));
if (dataset_namecheck(snapname, NULL, NULL) != 0 ||
strchr(snapname, '@') == NULL ||
strchr(snapname, '%'))
return (SET_ERROR(EINVAL));
(void) strcpy(tofs, snapname);
tosnap = strchr(tofs, '@');
*tosnap++ = '\0';
error = nvlist_lookup_string(innvl, "origin", &origin);
if (error && error != ENOENT)
return (error);
error = nvlist_lookup_byte_array(innvl, "begin_record",
(uchar_t **) &begin_record, &begin_record_size);
if (error != 0 || begin_record_size != sizeof (*begin_record))
return (SET_ERROR(EINVAL));
error = nvlist_lookup_int32(innvl, "input_fd", &input_fd);
if (error != 0)
return (SET_ERROR(EINVAL));
force = nvlist_exists(innvl, "force");
resumable = nvlist_exists(innvl, "resumable");
error = nvlist_lookup_int32(innvl, "cleanup_fd", &cleanup_fd);
if (error && error != ENOENT)
return (error);
error = nvlist_lookup_uint64(innvl, "action_handle", &action_handle);
if (error && error != ENOENT)
return (error);
error = nvlist_lookup_nvlist(innvl, "props", &props);
if (error && error != ENOENT)
return (error);
error = zfs_ioc_recv_impl(tofs, tosnap, origin, props, force,
resumable, input_fd, begin_record, cleanup_fd, &read_bytes,
&errflags, &action_handle, &errors);
fnvlist_add_uint64(outnvl, "read_bytes", read_bytes);
fnvlist_add_uint64(outnvl, "error_flags", errflags);
fnvlist_add_uint64(outnvl, "action_handle", action_handle);
fnvlist_add_nvlist(outnvl, "errors", errors);
nvlist_free(errors);
nvlist_free(props);
return (error);
}
/* /*
* inputs: * inputs:
* zc_name name of snapshot to send * zc_name name of snapshot to send
@ -5182,6 +5387,8 @@ zfs_ioc_space_snaps(const char *lastsnap, nvlist_t *innvl, nvlist_t *outnvl)
* indicates that blocks > 128KB are permitted * indicates that blocks > 128KB are permitted
* (optional) "embedok" -> (value ignored) * (optional) "embedok" -> (value ignored)
* presence indicates DRR_WRITE_EMBEDDED records are permitted * presence indicates DRR_WRITE_EMBEDDED records are permitted
* (optional) "resume_object" and "resume_offset" -> (uint64)
* if present, resume send stream from specified object and offset.
* } * }
* *
* outnvl is unused * outnvl is unused
@ -5197,6 +5404,8 @@ zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
file_t *fp; file_t *fp;
boolean_t largeblockok; boolean_t largeblockok;
boolean_t embedok; boolean_t embedok;
uint64_t resumeobj = 0;
uint64_t resumeoff = 0;
error = nvlist_lookup_int32(innvl, "fd", &fd); error = nvlist_lookup_int32(innvl, "fd", &fd);
if (error != 0) if (error != 0)
@ -5207,12 +5416,15 @@ zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
largeblockok = nvlist_exists(innvl, "largeblockok"); largeblockok = nvlist_exists(innvl, "largeblockok");
embedok = nvlist_exists(innvl, "embedok"); embedok = nvlist_exists(innvl, "embedok");
(void) nvlist_lookup_uint64(innvl, "resume_object", &resumeobj);
(void) nvlist_lookup_uint64(innvl, "resume_offset", &resumeoff);
if ((fp = getf(fd)) == NULL) if ((fp = getf(fd)) == NULL)
return (SET_ERROR(EBADF)); return (SET_ERROR(EBADF));
off = fp->f_offset; off = fp->f_offset;
error = dmu_send(snapname, fromname, embedok, largeblockok, error = dmu_send(snapname, fromname, embedok, largeblockok, fd,
fd, fp->f_vnode, &off); resumeobj, resumeoff, fp->f_vnode, &off);
if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0) if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
fp->f_offset = off; fp->f_offset = off;
@ -5470,6 +5682,10 @@ zfs_ioctl_init(void)
POOL_NAME, POOL_NAME,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE); POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
zfs_ioctl_register("receive", ZFS_IOC_RECV_NEW,
zfs_ioc_recv_new, zfs_secpolicy_recv_new, DATASET_NAME,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
/* IOCTLS that use the legacy function signature */ /* IOCTLS that use the legacy function signature */
zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze, zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze,

View File

@ -1020,7 +1020,7 @@ zfs_statvfs(struct dentry *dentry, struct kstatfs *statp)
statp->f_fsid.val[0] = (uint32_t)fsid; statp->f_fsid.val[0] = (uint32_t)fsid;
statp->f_fsid.val[1] = (uint32_t)(fsid >> 32); statp->f_fsid.val[1] = (uint32_t)(fsid >> 32);
statp->f_type = ZFS_SUPER_MAGIC; statp->f_type = ZFS_SUPER_MAGIC;
statp->f_namelen = ZFS_MAXNAMELEN; statp->f_namelen = MAXNAMELEN - 1;
/* /*
* We have all of 40 characters to stuff a string here. * We have all of 40 characters to stuff a string here.

View File

@ -2080,7 +2080,7 @@ typedef struct zil_replay_arg {
static int static int
zil_replay_error(zilog_t *zilog, lr_t *lr, int error) zil_replay_error(zilog_t *zilog, lr_t *lr, int error)
{ {
char name[MAXNAMELEN]; char name[ZFS_MAX_DATASET_NAME_LEN];
zilog->zl_replaying_seq--; /* didn't actually replay this one */ zilog->zl_replaying_seq--; /* didn't actually replay this one */

View File

@ -50,7 +50,7 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
int zfs_flags = 0; int zfs_flags = 0;
zfs_sb_t *zsb = dentry->d_sb->s_fs_info; zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
if (dlen(dentry) > ZFS_MAXNAMELEN) if (dlen(dentry) > ZFS_MAX_DATASET_NAME_LEN)
return (ERR_PTR(-ENAMETOOLONG)); return (ERR_PTR(-ENAMETOOLONG));
crhold(cr); crhold(cr);

View File

@ -61,7 +61,7 @@ unsigned long zvol_max_discard_blocks = 16384;
static kmutex_t zvol_state_lock; static kmutex_t zvol_state_lock;
static list_t zvol_state_list; static list_t zvol_state_list;
static char *zvol_tag = "zvol_tag"; void *zvol_tag = "zvol_tag";
/* /*
* The in-core state of each volume. * The in-core state of each volume.

View File

@ -146,14 +146,13 @@ tests = ['zfs_promote_001_pos', 'zfs_promote_002_pos', 'zfs_promote_003_pos',
tests = [] tests = []
# DISABLED: # DISABLED:
# zfs_receive_003_pos - needs investigation # zfs_receive_004_neg - Fails for OpenZFS on illumos
# zfs_receive_010_pos - needs investigation # zfs_receive_011_pos - Requires port of OpenZFS 6562
# zfs_receive_011_pos - needs investigation
# zfs_receive_012_pos - needs investigation
[tests/functional/cli_root/zfs_receive] [tests/functional/cli_root/zfs_receive]
tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_005_neg', tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_003_pos',
'zfs_receive_006_pos', 'zfs_receive_007_neg', 'zfs_receive_008_pos', 'zfs_receive_005_neg', 'zfs_receive_006_pos',
'zfs_receive_009_neg'] 'zfs_receive_007_neg', 'zfs_receive_008_pos', 'zfs_receive_009_neg',
'zfs_receive_010_pos', 'zfs_receive_012_pos']
# DISABLED: # DISABLED:
# zfs_rename_002_pos - needs investigation # zfs_rename_002_pos - needs investigation
@ -175,11 +174,10 @@ tests = ['zfs_reservation_001_pos', 'zfs_reservation_002_pos']
[tests/functional/cli_root/zfs_rollback] [tests/functional/cli_root/zfs_rollback]
tests = ['zfs_rollback_003_neg', 'zfs_rollback_004_neg'] tests = ['zfs_rollback_003_neg', 'zfs_rollback_004_neg']
# DISABLED:
# zfs_send_007_pos - needs investigation
[tests/functional/cli_root/zfs_send] [tests/functional/cli_root/zfs_send]
tests = ['zfs_send_001_pos', 'zfs_send_002_pos', 'zfs_send_003_pos', tests = ['zfs_send_001_pos', 'zfs_send_002_pos', 'zfs_send_003_pos',
'zfs_send_004_neg', 'zfs_send_005_pos', 'zfs_send_006_pos'] 'zfs_send_004_neg', 'zfs_send_005_pos', 'zfs_send_006_pos',
'zfs_send_007_pos']
# DISABLED: # DISABLED:
# mountpoint_003_pos - needs investigation # mountpoint_003_pos - needs investigation
@ -207,10 +205,11 @@ tests = ['cache_001_pos', 'cache_002_neg', 'canmount_001_pos',
# DISABLED: # DISABLED:
# zfs_snapshot_008_neg - nested pools # zfs_snapshot_008_neg - nested pools
# zfs_snapshot_009_pos - Fails for OpenZFS on illumos
[tests/functional/cli_root/zfs_snapshot] [tests/functional/cli_root/zfs_snapshot]
tests = ['zfs_snapshot_001_neg', 'zfs_snapshot_002_neg', tests = ['zfs_snapshot_001_neg', 'zfs_snapshot_002_neg',
'zfs_snapshot_003_neg', 'zfs_snapshot_004_neg', 'zfs_snapshot_005_neg', 'zfs_snapshot_003_neg', 'zfs_snapshot_004_neg', 'zfs_snapshot_005_neg',
'zfs_snapshot_006_pos', 'zfs_snapshot_007_neg', 'zfs_snapshot_009_pos'] 'zfs_snapshot_006_pos', 'zfs_snapshot_007_neg']
# DISABLED: # DISABLED:
# zfs_unmount_005_pos - needs investigation # zfs_unmount_005_pos - needs investigation
@ -565,12 +564,17 @@ tests = ['reservation_001_pos', 'reservation_002_pos', 'reservation_003_pos',
#[tests/functional/rootpool] #[tests/functional/rootpool]
#tests = ['rootpool_002_neg', 'rootpool_003_neg', 'rootpool_007_neg'] #tests = ['rootpool_002_neg', 'rootpool_003_neg', 'rootpool_007_neg']
# DISABLED: Hangs on I/O for unclear reason. # DISABLED:
#[tests/functional/rsend] # rsend_008_pos - Fails for OpenZFS on illumos
#tests = ['rsend_002_pos', 'rsend_003_pos', 'rsend_004_pos', # rsend_009_pos - Fails for OpenZFS on illumos
# 'rsend_005_pos', 'rsend_006_pos', 'rsend_007_pos', 'rsend_008_pos', # rsend_020_pos - ASSERTs in dump_record()
# 'rsend_009_pos', 'rsend_010_pos', 'rsend_011_pos', 'rsend_012_pos', [tests/functional/rsend]
# 'rsend_013_pos'] tests = ['rsend_001_pos', 'rsend_002_pos', 'rsend_003_pos', 'rsend_004_pos',
'rsend_005_pos', 'rsend_006_pos', 'rsend_007_pos',
'rsend_010_pos', 'rsend_011_pos', 'rsend_012_pos',
'rsend_013_pos', 'rsend_014_pos',
'rsend_019_pos',
'rsend_021_pos', 'rsend_022_pos', 'rsend_024_pos']
[tests/functional/scrub_mirror] [tests/functional/scrub_mirror]
tests = ['scrub_mirror_001_pos', 'scrub_mirror_002_pos', tests = ['scrub_mirror_001_pos', 'scrub_mirror_002_pos',
@ -586,17 +590,17 @@ tests = ['slog_001_pos', 'slog_002_pos', 'slog_003_pos', 'slog_004_pos',
'slog_009_neg', 'slog_010_neg', 'slog_011_neg'] 'slog_009_neg', 'slog_010_neg', 'slog_011_neg']
# DISABLED: # DISABLED:
# clone_001_pos - nested pools
# rollback_003_pos - Hangs in unmount and spins. # rollback_003_pos - Hangs in unmount and spins.
# snapshot_013_pos - Hangs on I/O for unclear reason. # snapshot_016_pos - Problem with automount
# snapshot_016_pos - .zfs mv/rmdir/mkdir disabled by default. [tests/functional/snapshot]
#[tests/functional/snapshot] tests = ['rollback_001_pos', 'rollback_002_pos',
#tests = ['clone_001_pos', 'rollback_001_pos', 'rollback_002_pos', 'snapshot_001_pos', 'snapshot_002_pos',
# 'snapshot_001_pos', 'snapshot_002_pos', 'snapshot_003_pos', 'snapshot_004_pos', 'snapshot_005_pos',
# 'snapshot_003_pos', 'snapshot_004_pos', 'snapshot_005_pos', 'snapshot_006_pos', 'snapshot_007_pos', 'snapshot_008_pos',
# 'snapshot_006_pos', 'snapshot_007_pos', 'snapshot_008_pos', 'snapshot_009_pos', 'snapshot_010_pos', 'snapshot_011_pos',
# 'snapshot_009_pos', 'snapshot_010_pos', 'snapshot_011_pos', 'snapshot_012_pos', 'snapshot_013_pos', 'snapshot_014_pos',
# 'snapshot_012_pos', 'snapshot_014_pos', 'snapshot_015_pos', 'snapshot_017_pos']
# 'snapshot_015_pos', 'snapshot_017_pos']
[tests/functional/snapused] [tests/functional/snapused]
tests = ['snapused_001_pos', 'snapused_002_pos', 'snapused_003_pos', tests = ['snapused_001_pos', 'snapused_002_pos', 'snapused_003_pos',
'snapused_004_pos', 'snapused_005_pos'] 'snapused_004_pos', 'snapused_005_pos']

View File

@ -172,7 +172,7 @@ crtfile(char *pname)
exit(errno); exit(errno);
} }
if (fsetxattr(fd, "xattr", pbuf, 1024, 0) < 0) { if (fsetxattr(fd, "user.xattr", pbuf, 1024, 0) < 0) {
(void) fprintf(stderr, "fsetxattr(fd, \"xattr\", pbuf, " (void) fprintf(stderr, "fsetxattr(fd, \"xattr\", pbuf, "
"1024, 0) failed.\n[%d]: %s.\n", errno, strerror(errno)); "1024, 0) failed.\n[%d]: %s.\n", errno, strerror(errno));
exit(errno); exit(errno);

View File

@ -85,6 +85,7 @@ export SHARE="@SHARE@"
export SHUF="@SHUF@" export SHUF="@SHUF@"
export SLEEP="@SLEEP@" export SLEEP="@SLEEP@"
export SORT="@SORT@" export SORT="@SORT@"
export STAT="@STAT@"
export STRINGS="@STRINGS@" export STRINGS="@STRINGS@"
export SU="@SU@" export SU="@SU@"
export SUM="@SUM@" export SUM="@SUM@"
@ -97,8 +98,8 @@ export TAIL="@TAIL@"
export TAR="@TAR@" export TAR="@TAR@"
export TOUCH="@TOUCH@" export TOUCH="@TOUCH@"
export TR="@TR@" export TR="@TR@"
export TRUE="@TRUE@"
export TRUNCATE="@TRUNCATE@" export TRUNCATE="@TRUNCATE@"
export TRUE="@TRUE@"
export UDEVADM="@UDEVADM@" export UDEVADM="@UDEVADM@"
export UFSDUMP="@UFSDUMP@" export UFSDUMP="@UFSDUMP@"
export UFSRESTORE="@UFSRESTORE@" export UFSRESTORE="@UFSRESTORE@"

View File

@ -10,4 +10,7 @@ dist_pkgdata_SCRIPTS = \
zfs_receive_006_pos.ksh \ zfs_receive_006_pos.ksh \
zfs_receive_007_neg.ksh \ zfs_receive_007_neg.ksh \
zfs_receive_008_pos.ksh \ zfs_receive_008_pos.ksh \
zfs_receive_009_neg.ksh zfs_receive_009_neg.ksh \
zfs_receive_010_pos.ksh \
zfs_receive_011_pos.ksh \
zfs_receive_012_pos.ksh

View File

@ -61,7 +61,7 @@ test_pool ()
first_object=$(ls -i $mntpnt | awk '{print $1}') first_object=$(ls -i $mntpnt | awk '{print $1}')
log_must $ZFS snapshot $POOL/fs@a log_must $ZFS snapshot $POOL/fs@a
while true; do while true; do
log_must $FIND $mntpnt -delete log_must $FIND $mntpnt/* -delete
sync sync
log_must $MKFILES "$mntpnt/" 4000 log_must $MKFILES "$mntpnt/" 4000
FILE=$(ls -i $mntpnt | awk \ FILE=$(ls -i $mntpnt | awk \

View File

@ -26,7 +26,7 @@
# #
# #
# Copyright (c) 2012 by Delphix. All rights reserved. # Copyright (c) 2012, 2015 by Delphix. All rights reserved.
# #
. $STF_SUITE/include/libtest.shlib . $STF_SUITE/include/libtest.shlib
@ -92,6 +92,8 @@ function cleanup
[[ -d $ALTER_ROOT ]] && \ [[ -d $ALTER_ROOT ]] && \
log_must $RM -rf $ALTER_ROOT log_must $RM -rf $ALTER_ROOT
[[ -e $VDEV_FILE ]] && \
log_must $RM $VDEV_FILE
} }
log_onexit cleanup log_onexit cleanup
@ -159,4 +161,13 @@ while (( i < ${#pools[*]} )); do
((i = i + 1)) ((i = i + 1))
done done
VDEV_FILE=$(mktemp /tmp/tmp.XXXXXX)
log_must $MKFILE -n 128M $VDEV_FILE
log_must $ZPOOL create testpool $VDEV_FILE
log_must $ZFS create testpool/testfs
ID=$($ZPOOL get -Ho value guid testpool)
log_must $ZPOOL export testpool
log_mustnot $ZPOOL import $(echo $ID) $($PRINTF "%*s\n" 250 "" | $TR ' ' 'c')
log_pass "Successfully imported and renamed a ZPOOL" log_pass "Successfully imported and renamed a ZPOOL"

View File

@ -74,9 +74,11 @@ function setup_test_model
if is_global_zone ; then if is_global_zone ; then
log_must $ZFS create -V 16M $pool/vol log_must $ZFS create -V 16M $pool/vol
log_must $ZFS create -V 16M $pool/$FS/vol log_must $ZFS create -V 16M $pool/$FS/vol
block_device_wait
log_must $ZFS snapshot $pool/$FS/vol@vsnap log_must $ZFS snapshot $pool/$FS/vol@vsnap
log_must $ZFS clone $pool/$FS/vol@vsnap $pool/$FS/vclone log_must $ZFS clone $pool/$FS/vol@vsnap $pool/$FS/vclone
block_device_wait
fi fi
log_must snapshot_tree $pool/$FS/fs1/fs2@fsnap log_must snapshot_tree $pool/$FS/fs1/fs2@fsnap
@ -199,10 +201,10 @@ function cmp_ds_prop
typeset dtst1=$1 typeset dtst1=$1
typeset dtst2=$2 typeset dtst2=$2
for item in "type" "origin" "volblocksize" "aclinherit" "aclmode" \ for item in "type" "origin" "volblocksize" "aclinherit" "acltype" \
"atime" "canmount" "checksum" "compression" "copies" "devices" \ "atime" "canmount" "checksum" "compression" "copies" "devices" \
"dnodesize" "exec" "quota" "readonly" "recordsize" "reservation" \ "dnodesize" "exec" "quota" "readonly" "recordsize" "reservation" \
"setuid" "sharenfs" "snapdir" "version" "volsize" "xattr" "zoned" \ "setuid" "snapdir" "version" "volsize" "xattr" "zoned" \
"mountpoint"; "mountpoint";
do do
$ZFS get -H -o property,value,source $item $dtst1 >> \ $ZFS get -H -o property,value,source $item $dtst1 >> \
@ -393,7 +395,7 @@ function mk_files
for ((i=0; i<$nfiles; i=i+1)); do for ((i=0; i<$nfiles; i=i+1)); do
$DD if=/dev/urandom \ $DD if=/dev/urandom \
of=/$fs/file-$maxsize-$((i+$file_id_offset)) \ of=/$fs/file-$maxsize-$((i+$file_id_offset)) \
bs=$(($RANDOM * $RANDOM % $maxsize)) \ bs=$((($RANDOM * $RANDOM % ($maxsize - 1)) + 1)) \
count=1 >/dev/null 2>&1 || log_fail \ count=1 >/dev/null 2>&1 || log_fail \
"Failed to create /$fs/file-$maxsize-$((i+$file_id_offset))" "Failed to create /$fs/file-$maxsize-$((i+$file_id_offset))"
done done
@ -438,7 +440,7 @@ function mess_file
# write the same value that's already there. # write the same value that's already there.
# #
log_must eval "$DD if=/dev/urandom of=$file conv=notrunc " \ log_must eval "$DD if=/dev/urandom of=$file conv=notrunc " \
"bs=1 count=2 oseek=$offset >/dev/null 2>&1" "bs=1 count=2 seek=$offset >/dev/null 2>&1"
else else
log_must $TRUNCATE -s $offset $file log_must $TRUNCATE -s $offset $file
fi fi
@ -523,20 +525,20 @@ function test_fs_setup
mk_files 100 1048576 0 $sendfs & mk_files 100 1048576 0 $sendfs &
mk_files 10 10485760 0 $sendfs & mk_files 10 10485760 0 $sendfs &
mk_files 1 104857600 0 $sendfs & mk_files 1 104857600 0 $sendfs &
log_must $WAIT wait
log_must $ZFS snapshot $sendfs@a log_must $ZFS snapshot $sendfs@a
rm_files 200 256 0 $sendfs & rm_files 200 256 0 $sendfs &
rm_files 200 131072 0 $sendfs & rm_files 200 131072 0 $sendfs &
rm_files 20 1048576 0 $sendfs & rm_files 20 1048576 0 $sendfs &
rm_files 2 10485760 0 $sendfs & rm_files 2 10485760 0 $sendfs &
log_must $WAIT wait
mk_files 400 256 0 $sendfs & mk_files 400 256 0 $sendfs &
mk_files 400 131072 0 $sendfs & mk_files 400 131072 0 $sendfs &
mk_files 40 1048576 0 $sendfs & mk_files 40 1048576 0 $sendfs &
mk_files 4 10485760 0 $sendfs & mk_files 4 10485760 0 $sendfs &
log_must $WAIT wait
log_must $ZFS snapshot $sendfs@b log_must $ZFS snapshot $sendfs@b
log_must eval "$ZFS send -v $sendfs@a >/$sendpool/initial.zsend" log_must eval "$ZFS send -v $sendfs@a >/$sendpool/initial.zsend"

View File

@ -110,9 +110,6 @@ function cleanup
log_must $ZFS inherit $prop $POOL2 log_must $ZFS inherit $prop $POOL2
done done
#if is_shared $POOL; then
# log_must $ZFS set sharenfs=off $POOL
#fi
log_must setup_test_model $POOL log_must setup_test_model $POOL
if [[ -d $TESTDIR ]]; then if [[ -d $TESTDIR ]]; then
@ -131,7 +128,7 @@ for fs in "$POOL" "$POOL/pclone" "$POOL/$FS" "$POOL/$FS/fs1" \
"$POOL/$FS/fs1/fs2" "$POOL/$FS/fs1/fclone" ; do "$POOL/$FS/fs1/fs2" "$POOL/$FS/fs1/fclone" ; do
rand_set_prop $fs aclinherit "discard" "noallow" "secure" "passthrough" rand_set_prop $fs aclinherit "discard" "noallow" "secure" "passthrough"
rand_set_prop $fs checksum "on" "off" "fletcher2" "fletcher4" "sha256" rand_set_prop $fs checksum "on" "off" "fletcher2" "fletcher4" "sha256"
rand_set_prop $fs aclmode "discard" "groupmask" "passthrough" rand_set_prop $fs acltype "off" "noacl" "posixacl"
rand_set_prop $fs atime "on" "off" rand_set_prop $fs atime "on" "off"
rand_set_prop $fs checksum "on" "off" "fletcher2" "fletcher4" "sha256" rand_set_prop $fs checksum "on" "off" "fletcher2" "fletcher4" "sha256"
rand_set_prop $fs compression "on" "off" "lzjb" "gzip" \ rand_set_prop $fs compression "on" "off" "lzjb" "gzip" \
@ -161,7 +158,8 @@ done
# Verify inherited property can be received # Verify inherited property can be received
rand_set_prop $POOL sharenfs "on" "off" "rw" rand_set_prop $POOL redundant_metadata "all" "most"
rand_set_prop $POOL sync "standard" "always" "disabled"
# #
# Duplicate POOL2 for testing # Duplicate POOL2 for testing

View File

@ -46,6 +46,7 @@ log_must cleanup_pool $POOL2
log_must eval "$ZFS send -R $POOL/$FS@final > $BACKDIR/fs-final-R" log_must eval "$ZFS send -R $POOL/$FS@final > $BACKDIR/fs-final-R"
log_must eval "$ZFS receive -d $POOL2 < $BACKDIR/fs-final-R" log_must eval "$ZFS receive -d $POOL2 < $BACKDIR/fs-final-R"
block_device_wait
log_must eval "$ZPOOL export $POOL" log_must eval "$ZPOOL export $POOL"
log_must eval "$ZPOOL import $POOL" log_must eval "$ZPOOL import $POOL"

View File

View File

View File

View File

View File

View File

@ -50,7 +50,7 @@ export FILE_WRITE=${TESTSDIR}/zfs-tests/cmd/file_write/file_write
export LARGEST_FILE=${TESTSDIR}/zfs-tests/cmd/largest_file/largest_file export LARGEST_FILE=${TESTSDIR}/zfs-tests/cmd/largest_file/largest_file
export MKBUSY=${TESTSDIR}/zfs-tests/cmd/mkbusy/mkbusy export MKBUSY=${TESTSDIR}/zfs-tests/cmd/mkbusy/mkbusy
export MKFILE=${TESTSDIR}/zfs-tests/cmd/mkfile/mkfile export MKFILE=${TESTSDIR}/zfs-tests/cmd/mkfile/mkfile
export MKFILES=${TESTSDIR}/zfs-tests/cmd/mkfile/mkfiles export MKFILES=${TESTSDIR}/zfs-tests/cmd/mkfiles/mkfiles
export MKTREE=${TESTSDIR}/zfs-tests/cmd/mktree/mktree export MKTREE=${TESTSDIR}/zfs-tests/cmd/mktree/mktree
export MMAP_EXEC=${TESTSDIR}/zfs-tests/cmd/mmap_exec/mmap_exec export MMAP_EXEC=${TESTSDIR}/zfs-tests/cmd/mmap_exec/mmap_exec
export MMAPWRITE=${TESTSDIR}/zfs-tests/cmd/mmapwrite/mmapwrite export MMAPWRITE=${TESTSDIR}/zfs-tests/cmd/mmapwrite/mmapwrite