297 changes: 289 additions & 8 deletions usr/src/cmd/zfs/zfs_main.c

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions usr/src/cmd/zinject/translate.c
Expand Up @@ -175,7 +175,7 @@ object_from_path(const char *dataset, const char *path, struct stat64 *statbuf,
*/
sync();

err = dmu_objset_own(dataset, DMU_OST_ZFS, B_TRUE, FTAG, &os);
err = dmu_objset_own(dataset, DMU_OST_ZFS, B_TRUE, B_FALSE, FTAG, &os);
if (err != 0) {
(void) fprintf(stderr, "cannot open dataset '%s': %s\n",
dataset, strerror(err));
Expand All @@ -185,7 +185,7 @@ object_from_path(const char *dataset, const char *path, struct stat64 *statbuf,
record->zi_objset = dmu_objset_id(os);
record->zi_object = statbuf->st_ino;

dmu_objset_disown(os, FTAG);
dmu_objset_disown(os, B_FALSE, FTAG);

return (0);
}
Expand Down Expand Up @@ -261,7 +261,7 @@ calculate_range(const char *dataset, err_type_t type, int level, char *range,
* size.
*/
if ((err = dmu_objset_own(dataset, DMU_OST_ANY,
B_TRUE, FTAG, &os)) != 0) {
B_TRUE, B_FALSE, FTAG, &os)) != 0) {
(void) fprintf(stderr, "cannot open dataset '%s': %s\n",
dataset, strerror(err));
goto out;
Expand Down Expand Up @@ -323,7 +323,7 @@ calculate_range(const char *dataset, err_type_t type, int level, char *range,
dnode_rele(dn, FTAG);
}
if (os)
dmu_objset_disown(os, FTAG);
dmu_objset_disown(os, B_FALSE, FTAG);

return (ret);
}
Expand Down
32 changes: 25 additions & 7 deletions usr/src/cmd/zinject/zinject.c
Expand Up @@ -112,9 +112,9 @@
* specified.
*
* The '-e' option takes a string describing the errno to simulate. This must
* be either 'io' or 'checksum'. In most cases this will result in the same
* behavior, but RAID-Z will produce a different set of ereports for this
* situation.
* be one of 'io', 'checksum', or 'decrypt'. In most cases this will result
* in the same behavior, but RAID-Z will produce a different set of ereports
* for this situation.
*
* The '-a', '-u', and '-m' flags toggle internal flush behavior. If '-a' is
* specified, then the ARC cache is flushed appropriately. If '-u' is
Expand Down Expand Up @@ -296,8 +296,9 @@ usage(void)
"\t\tinterperted depending on the '-t' option.\n"
"\n"
"\t\t-q\tQuiet mode. Only print out the handler number added.\n"
"\t\t-e\tInject a specific error. Must be either 'io' or\n"
"\t\t\t'checksum', or 'decompress'. Default is 'io'.\n"
"\t\t-e\tInject a specific error. Must be one of 'io', "
"'checksum',\n"
"\t\t\t'decompress', or decrypt. Default is 'io'.\n"
"\t\t-C\tInject the given error only into specific DVAs. The\n"
"\t\t\tDVAs should be specified as a list of 0-indexed DVAs\n"
"\t\t\tseparated by commas (ex. '0,2').\n"
Expand Down Expand Up @@ -817,6 +818,8 @@ main(int argc, char **argv)
error = EIO;
} else if (strcasecmp(optarg, "checksum") == 0) {
error = ECKSUM;
} else if (strcasecmp(optarg, "decrypt") == 0) {
error = EACCES;
} else if (strcasecmp(optarg, "nxio") == 0) {
error = ENXIO;
} else if (strcasecmp(optarg, "dtl") == 0) {
Expand Down Expand Up @@ -1144,14 +1147,29 @@ main(int argc, char **argv)
(void) fprintf(stderr, "the '-C' option may "
"not be used with logical data errors "
"'decrypt' and 'decompress'\n");
record.zi_dvas = dvas;
}
}

record.zi_cmd = ZINJECT_DATA_FAULT;

if (error == EACCES) {
if (type != TYPE_DATA) {
(void) fprintf(stderr, "decryption errors "
"may only be injected for 'data' types\n");
libzfs_fini(g_zfs);
return (1);
}

record.zi_dvas = dvas;
record.zi_cmd = ZINJECT_DECRYPT_FAULT;
/*
* Internally, ZFS actually uses ECKSUM for decryption
* errors since EACCES is used to indicate the key was
* not found.
*/
error = ECKSUM;
}

record.zi_cmd = ZINJECT_DATA_FAULT;
if (translate_record(type, argv[0], range, level, &record, pool,
dataset) != 0)
return (1);
Expand Down
2 changes: 2 additions & 0 deletions usr/src/cmd/zoneadm/Makefile
Expand Up @@ -38,6 +38,8 @@ POFILES= $(OBJS:%.o=%.po)

LDLIBS += -lzonecfg -lsocket -lgen -lpool -lzfs -luuid -lnvpair -lbrand -ldladm -lsecdb

INCS += -I../../common/zfs

CERRWARN += -_gcc=-Wno-uninitialized

.KEEP_STATE:
Expand Down
168 changes: 158 additions & 10 deletions usr/src/cmd/zpool/zpool_main.c
Expand Up @@ -247,11 +247,13 @@ get_usage(zpool_help_t idx)
return (gettext("\thistory [-il] [<pool>] ...\n"));
case HELP_IMPORT:
return (gettext("\timport [-d dir] [-D]\n"
"\timport [-d dir | -c cachefile] [-F [-n]] [-l] "
"<pool | id>\n"
"\timport [-o mntopts] [-o property=value] ... \n"
"\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
"\t [-d dir | -c cachefile] [-D] [-l] [-f] [-m] [-N] "
"[-R root] [-F [-n]] -a\n"
"\timport [-o mntopts] [-o property=value] ... \n"
"\t [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
"\t [-d dir | -c cachefile] [-D] [-l] [-f] [-m] [-N] "
"[-R root] [-F [-n]] [-t]\n"
"\t [--rewind-to-checkpoint] <pool | id> [newpool]\n"));
case HELP_IOSTAT:
Expand Down Expand Up @@ -292,7 +294,7 @@ get_usage(zpool_help_t idx)
case HELP_SET:
return (gettext("\tset <property=value> <pool> \n"));
case HELP_SPLIT:
return (gettext("\tsplit [-gLnP] [-R altroot] [-o mntopts]\n"
return (gettext("\tsplit [-gLlnP] [-R altroot] [-o mntopts]\n"
"\t [-o property=value] <pool> <newpool> "
"[<device> ...]\n"));
case HELP_REGUID:
Expand Down Expand Up @@ -1955,6 +1957,7 @@ show_import(nvlist_t *config)
char *hostname = "unknown";
nvlist_t *nvroot, *nvinfo;
int reason;
zpool_errata_t errata;
const char *health;
uint_t vsc;
char *comment;
Expand All @@ -1973,7 +1976,7 @@ show_import(nvlist_t *config)
(uint64_t **)&vs, &vsc) == 0);
health = zpool_state_to_name(vs->vs_state, vs->vs_aux);

reason = zpool_import_status(config, &msgid);
reason = zpool_import_status(config, &msgid, &errata);

(void) printf(gettext(" pool: %s\n"), name);
(void) printf(gettext(" id: %llu\n"), (u_longlong_t)guid);
Expand Down Expand Up @@ -2072,6 +2075,11 @@ show_import(nvlist_t *config)
"resilvered.\n"));
break;

case ZPOOL_STATUS_ERRATA:
(void) printf(gettext(" status: Errata #%d detected.\n"),
errata);
break;

default:
/*
* No other status can be seen when importing pools.
Expand All @@ -2093,6 +2101,55 @@ show_import(nvlist_t *config)
(void) printf(gettext(" action: The pool can be "
"imported using its name or numeric "
"identifier and\n\tthe '-f' flag.\n"));
} else if (reason == ZPOOL_STATUS_ERRATA) {
switch (errata) {
case ZPOOL_ERRATA_NONE:
break;

case ZPOOL_ERRATA_ZOL_2094_SCRUB:
(void) printf(gettext(" action: The pool can "
"be imported using its name or numeric "
"identifier,\n\thowever there is a compat"
"ibility issue which should be corrected"
"\n\tby running 'zpool scrub'\n"));
break;

case ZPOOL_ERRATA_ZOL_2094_ASYNC_DESTROY:
(void) printf(gettext(" action: The pool can"
"not be imported with this version of ZFS "
"due to\n\tan active asynchronous destroy. "
"Revert to an earlier version\n\tand "
"allow the destroy to complete before "
"updating.\n"));
break;

case ZPOOL_ERRATA_ZOL_6845_ENCRYPTION:
(void) printf(gettext(" action: Existing "
"encrypted datasets contain an on-disk "
"incompatibility, which\n\tneeds to be "
"corrected. Backup these datasets to new "
"encrypted datasets\n\tand destroy the "
"old ones.\n"));
break;
case ZPOOL_ERRATA_ZOL_8308_ENCRYPTION:
(void) printf(gettext(" action: Any existing "
"encrypted datasets contain an on-disk "
"incompatibility which\n\tmay cause "
"on-disk corruption with 'zfs recv' and "
"which needs to be\n\tcorrected. Enable "
"the bookmark_v2 feature and backup "
"these datasets to new encrypted "
"datasets and\n\tdestroy the old ones. "
"If this pool does not contain any "
"encrypted datasets, simply enable\n\t"
"the bookmark_v2 feature.\n"));
break;
default:
/*
* All errata must contain an action message.
*/
assert(0);
}
} else {
(void) printf(gettext(" action: The pool can be "
"imported using its name or numeric "
Expand Down Expand Up @@ -2235,6 +2292,7 @@ static int
do_import(nvlist_t *config, const char *newname, const char *mntopts,
nvlist_t *props, int flags)
{
int ret = 0;
zpool_handle_t *zhp;
char *name;
uint64_t version;
Expand Down Expand Up @@ -2315,6 +2373,16 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
return (1);

/*
* Loading keys is best effort. We don't want to return immediately
* if it fails but we do want to give the error to the caller.
*/
if (flags & ZFS_IMPORT_LOAD_KEYS) {
ret = zfs_crypto_attempt_load_keys(g_zfs, name);
if (ret != 0)
ret = 1;
}

if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
!(flags & ZFS_IMPORT_ONLY) &&
zpool_enable_datasets(zhp, mntopts, 0) != 0) {
Expand All @@ -2323,7 +2391,7 @@ do_import(nvlist_t *config, const char *newname, const char *mntopts,
}

zpool_close(zhp);
return (0);
return (ret);
}

/*
Expand Down Expand Up @@ -2401,9 +2469,9 @@ zpool_do_checkpoint(int argc, char **argv)

/*
* zpool import [-d dir] [-D]
* import [-o mntopts] [-o prop=value] ... [-R root] [-D]
* import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-l]
* [-d dir | -c cachefile] [-f] -a
* import [-o mntopts] [-o prop=value] ... [-R root] [-D]
* import [-o mntopts] [-o prop=value] ... [-R root] [-D] [-l]
* [-d dir | -c cachefile] [-f] [-n] [-F] [-t]
* <pool | id> [newpool]
*
Expand Down Expand Up @@ -2443,6 +2511,7 @@ zpool_do_checkpoint(int argc, char **argv)
* -a Import all pools found.
*
* -o Set property=value and/or temporary mount options (without '=').
* -l Load encryption keys while importing.
*
* --rewind-to-checkpoint
* Import the pool and revert back to the checkpoint.
Expand Down Expand Up @@ -2487,7 +2556,7 @@ zpool_do_import(int argc, char **argv)
};

/* check options */
while ((c = getopt_long(argc, argv, ":aCc:d:DEfFmnNo:rR:tT:VX",
while ((c = getopt_long(argc, argv, ":aCc:d:DEfFlmnNo:rR:tT:VX",
long_options, NULL)) != -1) {
switch (c) {
case 'a':
Expand Down Expand Up @@ -2518,6 +2587,9 @@ zpool_do_import(int argc, char **argv)
case 'F':
do_rewind = B_TRUE;
break;
case 'l':
flags |= ZFS_IMPORT_LOAD_KEYS;
break;
case 'm':
flags |= ZFS_IMPORT_MISSING_LOG;
break;
Expand Down Expand Up @@ -2591,6 +2663,17 @@ zpool_do_import(int argc, char **argv)
usage(B_FALSE);
}

if ((flags & ZFS_IMPORT_LOAD_KEYS) && (flags & ZFS_IMPORT_ONLY)) {
(void) fprintf(stderr, gettext("-l is incompatible with -N\n"));
usage(B_FALSE);
}

if ((flags & ZFS_IMPORT_LOAD_KEYS) && !do_all && argc == 0) {
(void) fprintf(stderr, gettext("-l is only meaningful during "
"an import\n"));
usage(B_FALSE);
}

if ((dryrun || xtreme_rewind) && !do_rewind) {
(void) fprintf(stderr,
gettext("-n or -X only meaningful with -F\n"));
Expand Down Expand Up @@ -4034,6 +4117,7 @@ zpool_do_detach(int argc, char **argv)
* -o Set property=value, or set mount options.
* -P Display full path for vdev name.
* -R Mount the split-off pool under an alternate root.
* -l Load encryption keys while importing.
*
* Splits the named pool and gives it the new pool name. Devices to be split
* off may be listed, provided that no more than one device is specified
Expand All @@ -4051,6 +4135,7 @@ zpool_do_split(int argc, char **argv)
char *mntopts = NULL;
splitflags_t flags;
int c, ret = 0;
boolean_t loadkeys = B_FALSE;
zpool_handle_t *zhp;
nvlist_t *config, *props = NULL;

Expand All @@ -4059,7 +4144,7 @@ zpool_do_split(int argc, char **argv)
flags.name_flags = 0;

/* check options */
while ((c = getopt(argc, argv, ":gLR:no:P")) != -1) {
while ((c = getopt(argc, argv, ":gLR:lno:P")) != -1) {
switch (c) {
case 'g':
flags.name_flags |= VDEV_NAME_GUID;
Expand All @@ -4076,6 +4161,9 @@ zpool_do_split(int argc, char **argv)
usage(B_FALSE);
}
break;
case 'l':
loadkeys = B_TRUE;
break;
case 'n':
flags.dryrun = B_TRUE;
break;
Expand Down Expand Up @@ -4114,6 +4202,12 @@ zpool_do_split(int argc, char **argv)
usage(B_FALSE);
}

if (!flags.import && loadkeys) {
(void) fprintf(stderr, gettext("loading keys is only "
"valid when importing the pool\n"));
usage(B_FALSE);
}

argc -= optind;
argv += optind;

Expand Down Expand Up @@ -4159,6 +4253,13 @@ zpool_do_split(int argc, char **argv)
*/
if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL)
return (1);

if (loadkeys) {
ret = zfs_crypto_attempt_load_keys(g_zfs, newpool);
if (ret != 0)
ret = 1;
}

if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
zpool_enable_datasets(zhp, mntopts, 0) != 0) {
ret = 1;
Expand Down Expand Up @@ -5203,12 +5304,13 @@ status_callback(zpool_handle_t *zhp, void *data)
nvlist_t *config, *nvroot;
char *msgid;
int reason;
zpool_errata_t errata;
const char *health;
uint_t c;
vdev_stat_t *vs;

config = zpool_get_config(zhp, NULL);
reason = zpool_get_status(zhp, &msgid);
reason = zpool_get_status(zhp, &msgid, &errata);

cbp->cb_count++;

Expand Down Expand Up @@ -5434,6 +5536,52 @@ status_callback(zpool_handle_t *zhp, void *data)
"'zpool clear'.\n"));
break;

case ZPOOL_STATUS_ERRATA:
(void) printf(gettext("status: Errata #%d detected.\n"),
errata);

switch (errata) {
case ZPOOL_ERRATA_NONE:
break;

case ZPOOL_ERRATA_ZOL_2094_SCRUB:
(void) printf(gettext("action: To correct the issue "
"run 'zpool scrub'.\n"));
break;

case ZPOOL_ERRATA_ZOL_6845_ENCRYPTION:
(void) printf(gettext("\tExisting encrypted datasets "
"contain an on-disk incompatibility\n\twhich "
"needs to be corrected.\n"));
(void) printf(gettext("action: To correct the issue "
"backup existing encrypted datasets to new\n\t"
"encrypted datasets and destroy the old ones. "
"'zfs mount -o ro' can\n\tbe used to temporarily "
"mount existing encrypted datasets readonly.\n"));
break;

case ZPOOL_ERRATA_ZOL_8308_ENCRYPTION:
(void) printf(gettext("\tExisting encrypted datasets "
"contain an on-disk incompatibility\n\twhich "
"needs to be corrected.\n"));
(void) printf(gettext("action: To correct the issue "
"enable the bookmark_v2 feature and "
"backup\n\tany existing encrypted datasets to "
"new encrypted datasets and\n\tdestroy the old "
"ones. If this pool does not contain any\n\t"
"encrypted datasets, simply enable the "
"bookmark_v2 feature\n"));
break;

default:
/*
* All errata which allow the pool to be imported
* must contain an action message.
*/
assert(0);
}
break;

default:
/*
* The remaining errors can't actually be generated, yet.
Expand Down
138 changes: 119 additions & 19 deletions usr/src/cmd/zstreamdump/zstreamdump.c
Expand Up @@ -196,12 +196,33 @@ print_block(char *buf, int length)
}
}

/*
* Print an array of bytes to stdout as hexidecimal characters. str must
* have buf_len * 2 + 1 bytes of space.
*/
static void
sprintf_bytes(char *str, uint8_t *buf, uint_t buf_len)
{
int i, n;

for (i = 0; i < buf_len; i++) {
n = sprintf(str, "%02x", buf[i] & 0xff);
str += n;
}

str[0] = '\0';
}

int
main(int argc, char *argv[])
{
char *buf = safe_malloc(SPA_MAXBLOCKSIZE);
uint64_t drr_record_count[DRR_NUMTYPES] = { 0 };
char salt[ZIO_DATA_SALT_LEN * 2 + 1];
char iv[ZIO_DATA_IV_LEN * 2 + 1];
char mac[ZIO_DATA_MAC_LEN * 2 + 1];
uint64_t total_records = 0;
uint64_t payload_size;
dmu_replay_record_t thedrr;
dmu_replay_record_t *drr = &thedrr;
struct drr_begin *drrb = &thedrr.drr_u.drr_begin;
Expand All @@ -213,6 +234,7 @@ main(int argc, char *argv[])
struct drr_free *drrf = &thedrr.drr_u.drr_free;
struct drr_spill *drrs = &thedrr.drr_u.drr_spill;
struct drr_write_embedded *drrwe = &thedrr.drr_u.drr_write_embedded;
struct drr_object_range *drror = &thedrr.drr_u.drr_object_range;
struct drr_checksum *drrc = &thedrr.drr_u.drr_checksum;
char c;
boolean_t verbose = B_FALSE;
Expand Down Expand Up @@ -412,26 +434,37 @@ main(int argc, char *argv[])
drro->drr_blksz = BSWAP_32(drro->drr_blksz);
drro->drr_bonuslen =
BSWAP_32(drro->drr_bonuslen);
drro->drr_raw_bonuslen =
BSWAP_32(drro->drr_raw_bonuslen);
drro->drr_toguid = BSWAP_64(drro->drr_toguid);
}

payload_size = DRR_OBJECT_PAYLOAD_SIZE(drro);

if (verbose) {
(void) printf("OBJECT object = %" PRIu64
" type = %u bonustype = %u blksz = %u"
" bonuslen = %u dn_slots = %u\n",
drro->drr_object,
"type = %u bonustype = %u blksz = %u "
"bonuslen = %u "
"raw_bonuslen = %u flags = %u maxblkid "
"= %llu "
"indblkshift = %u nlevels = %u "
"nblkptr = %u\n",
(u_longlong_t)drro->drr_object,
drro->drr_type,
drro->drr_bonustype,
drro->drr_blksz,
drro->drr_bonuslen,
drro->drr_dn_slots);
drro->drr_raw_bonuslen,
drro->drr_flags,
(u_longlong_t)drro->drr_maxblkid,
drro->drr_indblkshift,
drro->drr_nlevels,
drro->drr_nblkptr);
}
if (drro->drr_bonuslen > 0) {
(void) ssread(buf,
P2ROUNDUP(drro->drr_bonuslen, 8), &zc);
if (dump) {
print_block(buf,
P2ROUNDUP(drro->drr_bonuslen, 8));
}
(void) ssread(buf, payload_size, &zc);
if (dump)
print_block(buf, payload_size);
}
break;

Expand Down Expand Up @@ -465,28 +498,40 @@ main(int argc, char *argv[])
BSWAP_64(drrw->drr_compressed_size);
}

uint64_t payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw);
payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw);

/*
* If this is verbose and/or dump output,
* print info on the modified block
*/
if (verbose) {
sprintf_bytes(salt, drrw->drr_salt,
ZIO_DATA_SALT_LEN);
sprintf_bytes(iv, drrw->drr_iv,
ZIO_DATA_IV_LEN);
sprintf_bytes(mac, drrw->drr_mac,
ZIO_DATA_MAC_LEN);

(void) printf("WRITE object = %llu type = %u "
"checksum type = %u compression type = %u\n"
" offset = %llu logical_size = %llu "
" flags = %u offset = %llu "
"logical_size = %llu "
"compressed_size = %llu "
"payload_size = %llu "
"props = %llx\n",
"payload_size = %llu props = %llx "
"salt = %s iv = %s mac = %s\n",
(u_longlong_t)drrw->drr_object,
drrw->drr_type,
drrw->drr_checksumtype,
drrw->drr_compressiontype,
drrw->drr_flags,
(u_longlong_t)drrw->drr_offset,
(u_longlong_t)drrw->drr_logical_size,
(u_longlong_t)drrw->drr_compressed_size,
(u_longlong_t)payload_size,
(u_longlong_t)drrw->drr_key.ddk_prop);
(u_longlong_t)drrw->drr_key.ddk_prop,
salt,
iv,
mac);
}

/*
Expand Down Expand Up @@ -557,15 +602,40 @@ main(int argc, char *argv[])
if (do_byteswap) {
drrs->drr_object = BSWAP_64(drrs->drr_object);
drrs->drr_length = BSWAP_64(drrs->drr_length);
drrs->drr_compressed_size =
BSWAP_64(drrs->drr_compressed_size);
drrs->drr_type = BSWAP_32(drrs->drr_type);
}

payload_size = DRR_SPILL_PAYLOAD_SIZE(drrs);

if (verbose) {
sprintf_bytes(salt, drrs->drr_salt,
ZIO_DATA_SALT_LEN);
sprintf_bytes(iv, drrs->drr_iv,
ZIO_DATA_IV_LEN);
sprintf_bytes(mac, drrs->drr_mac,
ZIO_DATA_MAC_LEN);

(void) printf("SPILL block for object = %llu "
"length = %llu\n", drrs->drr_object,
drrs->drr_length);
"length = %llu flags = %u "
"compression type = %u "
"compressed_size = %llu "
"payload_size = %llu "
"salt = %s iv = %s mac = %s\n",
(u_longlong_t)drrs->drr_object,
(u_longlong_t)drrs->drr_length,
drrs->drr_flags,
drrs->drr_compressiontype,
(u_longlong_t)drrs->drr_compressed_size,
(u_longlong_t)payload_size,
salt,
iv,
mac);
}
(void) ssread(buf, drrs->drr_length, &zc);
(void) ssread(buf, payload_size, &zc);
if (dump) {
print_block(buf, drrs->drr_length);
print_block(buf, payload_size);
}
break;
case DRR_WRITE_EMBEDDED:
Expand Down Expand Up @@ -600,6 +670,36 @@ main(int argc, char *argv[])
(void) ssread(buf,
P2ROUNDUP(drrwe->drr_psize, 8), &zc);
break;
case DRR_OBJECT_RANGE:
if (do_byteswap) {
drror->drr_firstobj =
BSWAP_64(drror->drr_firstobj);
drror->drr_numslots =
BSWAP_64(drror->drr_numslots);
drror->drr_toguid = BSWAP_64(drror->drr_toguid);
}
if (verbose) {
sprintf_bytes(salt, drror->drr_salt,
ZIO_DATA_SALT_LEN);
sprintf_bytes(iv, drror->drr_iv,
ZIO_DATA_IV_LEN);
sprintf_bytes(mac, drror->drr_mac,
ZIO_DATA_MAC_LEN);

(void) printf("OBJECT_RANGE firstobj = %llu "
"numslots = %llu flags = %u "
"salt = %s iv = %s mac = %s\n",
(u_longlong_t)drror->drr_firstobj,
(u_longlong_t)drror->drr_numslots,
drror->drr_flags,
salt,
iv,
mac);
}
break;
case DRR_NUMTYPES:
/* should never be reached */
exit(1);
}
if (drr->drr_type != DRR_BEGIN && very_verbose) {
(void) printf(" checksum = %llx/%llx/%llx/%llx\n",
Expand Down
172 changes: 134 additions & 38 deletions usr/src/cmd/ztest/ztest.c
Expand Up @@ -212,6 +212,7 @@ extern unsigned long zfs_reconstruct_indirect_damage_fraction;

static ztest_shared_opts_t *ztest_shared_opts;
static ztest_shared_opts_t ztest_opts;
static char *ztest_wkeydata = "abcdefghijklmnopqrstuvwxyz012345";

typedef struct ztest_shared_ds {
uint64_t zd_seq;
Expand Down Expand Up @@ -1213,6 +1214,42 @@ ztest_spa_prop_set_uint64(zpool_prop_t prop, uint64_t value)
return (error);
}

static int
ztest_dmu_objset_own(const char *name, dmu_objset_type_t type,
boolean_t readonly, boolean_t decrypt, void *tag, objset_t **osp)
{
int err;

err = dmu_objset_own(name, type, readonly, decrypt, tag, osp);
if (decrypt && err == EACCES) {
char ddname[ZFS_MAX_DATASET_NAME_LEN];
dsl_crypto_params_t *dcp;
nvlist_t *crypto_args = fnvlist_alloc();
char *cp = NULL;

/* spa_keystore_load_wkey() expects a dsl dir name */
(void) strcpy(ddname, name);
cp = strchr(ddname, '@');
if (cp != NULL)
*cp = '\0';

fnvlist_add_uint8_array(crypto_args, "wkeydata",
(uint8_t *)ztest_wkeydata, WRAPPING_KEY_LEN);
VERIFY0(dsl_crypto_params_create_nvlist(DCP_CMD_NONE, NULL,
crypto_args, &dcp));
err = spa_keystore_load_wkey(ddname, dcp, B_FALSE);
dsl_crypto_params_free(dcp, B_FALSE);
fnvlist_free(crypto_args);

if (err != 0)
return (err);

err = dmu_objset_own(name, type, readonly, decrypt, tag, osp);
}

return (err);
}

static void
ztest_rll_init(rll_t *rll)
{
Expand Down Expand Up @@ -1856,7 +1893,7 @@ ztest_replay_write(void *arg1, void *arg2, boolean_t byteswap)
dmu_write(os, lr->lr_foid, offset, length, data, tx);
} else {
bcopy(data, abuf->b_data, length);
dmu_assign_arcbuf(db, offset, abuf, tx);
dmu_assign_arcbuf_by_dbuf(db, offset, abuf, tx);
}

(void) ztest_log_write(zd, tx, lr);
Expand Down Expand Up @@ -2563,15 +2600,15 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
*/
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 0, 1);
VERIFY3U(ENOENT, ==,
spa_create("ztest_bad_file", nvroot, NULL, NULL));
spa_create("ztest_bad_file", nvroot, NULL, NULL, NULL));
nvlist_free(nvroot);

/*
* Attempt to create using a bad mirror.
*/
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 2, 1);
VERIFY3U(ENOENT, ==,
spa_create("ztest_bad_mirror", nvroot, NULL, NULL));
spa_create("ztest_bad_mirror", nvroot, NULL, NULL, NULL));
nvlist_free(nvroot);

/*
Expand All @@ -2580,7 +2617,8 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
*/
rw_enter(&ztest_name_lock, RW_READER);
nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, NULL, 0, 0, 1);
VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL));
VERIFY3U(EEXIST, ==,
spa_create(zo->zo_pool, nvroot, NULL, NULL, NULL));
nvlist_free(nvroot);
VERIFY3U(0, ==, spa_open(zo->zo_pool, &spa, FTAG));
VERIFY3U(EBUSY, ==, spa_destroy(zo->zo_pool));
Expand Down Expand Up @@ -2691,7 +2729,7 @@ ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
props = fnvlist_alloc();
fnvlist_add_uint64(props,
zpool_prop_to_name(ZPOOL_PROP_VERSION), version);
VERIFY0(spa_create(name, nvroot, props, NULL));
VERIFY0(spa_create(name, nvroot, props, NULL, NULL));
fnvlist_free(nvroot);
fnvlist_free(props);

Expand Down Expand Up @@ -3713,11 +3751,65 @@ ztest_objset_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
static int
ztest_dataset_create(char *dsname)
{
uint64_t zilset = ztest_random(100);
int err = dmu_objset_create(dsname, DMU_OST_OTHER, 0,
int err;
uint64_t rand;
dsl_crypto_params_t *dcp = NULL;

/*
* 50% of the time, we create encrypted datasets
* using a random cipher suite and a hard-coded
* wrapping key.
*/
#ifdef WITHCRYPTO
/*
* Until the crypto framework is compiled in userland, the ztest using
* crypto will not work.
*/
rand = ztest_random(2);
#else
rand = 0;
#endif
if (rand != 0) {
nvlist_t *crypto_args = fnvlist_alloc();
nvlist_t *props = fnvlist_alloc();

/* slight bias towards the default cipher suite */
rand = ztest_random(ZIO_CRYPT_FUNCTIONS);
if (rand < ZIO_CRYPT_AES_128_CCM)
rand = ZIO_CRYPT_ON;

fnvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_ENCRYPTION), rand);
fnvlist_add_uint8_array(crypto_args, "wkeydata",
(uint8_t *)ztest_wkeydata, WRAPPING_KEY_LEN);

/*
* These parameters aren't really used by the kernel. They
* are simply stored so that userspace knows how to load
* the wrapping key.
*/
fnvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_KEYFORMAT), ZFS_KEYFORMAT_RAW);
fnvlist_add_string(props,
zfs_prop_to_name(ZFS_PROP_KEYLOCATION), "prompt");
fnvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), 0ULL);
fnvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), 0ULL);

VERIFY0(dsl_crypto_params_create_nvlist(DCP_CMD_NONE, props,
crypto_args, &dcp));

fnvlist_free(crypto_args);
fnvlist_free(props);
}

err = dmu_objset_create(dsname, DMU_OST_OTHER, 0, dcp,
ztest_objset_create_cb, NULL);
dsl_crypto_params_free(dcp, !!err);

if (err || zilset < 80)
rand = ztest_random(100);
if (err || rand < 80)
return (err);

if (ztest_opts.zo_verbose >= 6)
Expand All @@ -3737,15 +3829,16 @@ ztest_objset_destroy_cb(const char *name, void *arg)
/*
* Verify that the dataset contains a directory object.
*/
VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_TRUE, FTAG, &os));
VERIFY0(ztest_dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
B_TRUE, FTAG, &os));
error = dmu_object_info(os, ZTEST_DIROBJ, &doi);
if (error != ENOENT) {
/* We could have crashed in the middle of destroying it */
ASSERT0(error);
ASSERT3U(doi.doi_type, ==, DMU_OT_ZAP_OTHER);
ASSERT3S(doi.doi_physical_blocks_512, >=, 0);
}
dmu_objset_disown(os, FTAG);
dmu_objset_disown(os, B_TRUE, FTAG);

/*
* Destroy the dataset.
Expand Down Expand Up @@ -3818,11 +3911,12 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
* (invoked from ztest_objset_destroy_cb()) should just throw it away.
*/
if (ztest_random(2) == 0 &&
dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os) == 0) {
ztest_dmu_objset_own(name, DMU_OST_OTHER, B_FALSE,
B_TRUE, FTAG, &os) == 0) {
ztest_zd_init(&zdtmp, NULL, os);
zil_replay(os, &zdtmp, ztest_replay_vector);
ztest_zd_fini(&zdtmp);
dmu_objset_disown(os, FTAG);
dmu_objset_disown(os, B_TRUE, FTAG);
}

/*
Expand All @@ -3836,8 +3930,8 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
/*
* Verify that the destroyed dataset is no longer in the namespace.
*/
VERIFY3U(ENOENT, ==, dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
FTAG, &os));
VERIFY3U(ENOENT, ==, ztest_dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
B_TRUE, FTAG, &os));

/*
* Verify that we can create a new dataset.
Expand All @@ -3852,7 +3946,8 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_objset_create(%s) = %d", name, error);
}

VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os));
VERIFY0(ztest_dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, B_TRUE,
FTAG, &os));

ztest_zd_init(&zdtmp, NULL, os);

Expand All @@ -3876,7 +3971,7 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
* Verify that we cannot create an existing dataset.
*/
VERIFY3U(EEXIST, ==,
dmu_objset_create(name, DMU_OST_OTHER, 0, NULL, NULL));
dmu_objset_create(name, DMU_OST_OTHER, 0, NULL, NULL, NULL));

/*
* Verify that we can hold an objset that is also owned.
Expand All @@ -3887,11 +3982,11 @@ ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
/*
* Verify that we cannot own an objset that is already owned.
*/
VERIFY3U(EBUSY, ==,
dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os2));
VERIFY3U(EBUSY, ==, ztest_dmu_objset_own(name, DMU_OST_OTHER,
B_FALSE, B_TRUE, FTAG, &os2));

zil_close(zilog);
dmu_objset_disown(os, FTAG);
dmu_objset_disown(os, B_TRUE, FTAG);
ztest_zd_fini(&zdtmp);

rw_exit(&ztest_name_lock);
Expand Down Expand Up @@ -4025,19 +4120,20 @@ ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
fatal(0, "dmu_objset_create(%s) = %d", clone2name, error);
}

error = dmu_objset_own(snap2name, DMU_OST_ANY, B_TRUE, FTAG, &os);
error = ztest_dmu_objset_own(snap2name, DMU_OST_ANY, B_TRUE, B_TRUE,
FTAG, &os);
if (error)
fatal(0, "dmu_objset_own(%s) = %d", snap2name, error);
error = dsl_dataset_promote(clone2name, NULL);
if (error == ENOSPC) {
dmu_objset_disown(os, FTAG);
dmu_objset_disown(os, B_TRUE, FTAG);
ztest_record_enospc(FTAG);
goto out;
}
if (error != EBUSY)
fatal(0, "dsl_dataset_promote(%s), %d, not EBUSY", clone2name,
error);
dmu_objset_disown(os, FTAG);
dmu_objset_disown(os, B_TRUE, FTAG);

out:
ztest_dsl_dataset_cleanup(osname, id);
Expand Down Expand Up @@ -4403,7 +4499,7 @@ ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id)
* bigobj, at the tail of the nth chunk
*
* The chunk size is set equal to bigobj block size so that
* dmu_assign_arcbuf() can be tested for object updates.
* dmu_assign_arcbuf_by_dbuf() can be tested for object updates.
*/

/*
Expand Down Expand Up @@ -4463,7 +4559,7 @@ ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id)
/*
* In iteration 5 (i == 5) use arcbufs
* that don't match bigobj blksz to test
* dmu_assign_arcbuf() when it can't directly
* dmu_assign_arcbuf_by_dbuf() when it can't directly
* assign an arcbuf to a dbuf.
*/
for (j = 0; j < s; j++) {
Expand Down Expand Up @@ -4508,8 +4604,8 @@ ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id)

/*
* 50% of the time don't read objects in the 1st iteration to
* test dmu_assign_arcbuf() for the case when there're no
* existing dbufs for the specified offsets.
* test dmu_assign_arcbuf_by_dbuf() for the case when there are
* no existing dbufs for the specified offsets.
*/
if (i != 0 || ztest_random(2) != 0) {
error = dmu_read(os, packobj, packoff,
Expand Down Expand Up @@ -4554,12 +4650,12 @@ ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id)
FTAG, &dbt, DMU_READ_NO_PREFETCH) == 0);
}
if (i != 5 || chunksize < (SPA_MINBLOCKSIZE * 2)) {
dmu_assign_arcbuf(bonus_db, off,
dmu_assign_arcbuf_by_dbuf(bonus_db, off,
bigbuf_arcbufs[j], tx);
} else {
dmu_assign_arcbuf(bonus_db, off,
dmu_assign_arcbuf_by_dbuf(bonus_db, off,
bigbuf_arcbufs[2 * j], tx);
dmu_assign_arcbuf(bonus_db,
dmu_assign_arcbuf_by_dbuf(bonus_db,
off + chunksize / 2,
bigbuf_arcbufs[2 * j + 1], tx);
}
Expand Down Expand Up @@ -6273,7 +6369,8 @@ ztest_dataset_open(int d)
}
ASSERT(error == 0 || error == EEXIST);

VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, zd, &os));
VERIFY0(ztest_dmu_objset_own(name, DMU_OST_OTHER, B_FALSE,
B_TRUE, zd, &os));
rw_exit(&ztest_name_lock);

ztest_zd_init(zd, ZTEST_GET_SHARED_DS(d), os);
Expand Down Expand Up @@ -6314,7 +6411,7 @@ ztest_dataset_close(int d)
ztest_ds_t *zd = &ztest_ds[d];

zil_close(zd->zd_zilog);
dmu_objset_disown(zd->zd_os, zd);
dmu_objset_disown(zd->zd_os, B_TRUE, zd);

ztest_zd_fini(zd);
}
Expand Down Expand Up @@ -6364,13 +6461,13 @@ ztest_run(ztest_shared_t *zs)
ztest_spa = spa;

dmu_objset_stats_t dds;
VERIFY0(dmu_objset_own(ztest_opts.zo_pool,
DMU_OST_ANY, B_TRUE, FTAG, &os));
VERIFY0(ztest_dmu_objset_own(ztest_opts.zo_pool,
DMU_OST_ANY, B_TRUE, B_TRUE, FTAG, &os));
dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
dmu_objset_fast_stat(os, &dds);
dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
zs->zs_guid = dds.dds_guid;
dmu_objset_disown(os, FTAG);
dmu_objset_disown(os, B_TRUE, FTAG);

spa->spa_dedup_ditto = 2 * ZIO_DEDUPDITTO_MIN;

Expand Down Expand Up @@ -6584,10 +6681,9 @@ ztest_freeze(void)
VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
ASSERT(spa_freeze_txg(spa) == UINT64_MAX);
VERIFY3U(0, ==, ztest_dataset_open(0));
ztest_dataset_close(0);

ztest_spa = spa;
txg_wait_synced(spa_get_dsl(spa), 0);
ztest_dataset_close(0);
ztest_reguid(NULL, 0);

spa_close(spa, FTAG);
Expand Down Expand Up @@ -6715,7 +6811,8 @@ ztest_init(ztest_shared_t *zs)
spa_feature_table[i].fi_uname);
VERIFY3U(0, ==, nvlist_add_uint64(props, buf, 0));
}
VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props, NULL));
VERIFY3U(0, ==,
spa_create(ztest_opts.zo_pool, nvroot, props, NULL, NULL));
nvlist_free(nvroot);
nvlist_free(props);

Expand Down Expand Up @@ -6748,7 +6845,6 @@ setup_data_fd(void)
(void) unlink(ztest_name_data);
}


static int
shared_data_size(ztest_shared_hdr_t *hdr)
{
Expand Down
2 changes: 1 addition & 1 deletion usr/src/common/crypto/modes/ccm.c
Expand Up @@ -889,7 +889,7 @@ ccm_init_ctx(ccm_ctx_t *ccm_ctx, char *param, int kmflag,
rv = CRYPTO_MECHANISM_PARAM_INVALID;
goto out;
}
if (!is_encrypt_init) {
if (!is_encrypt_init && ccm_ctx->ccm_data_len != 0) {
/* allocate buffer for storing decrypted plaintext */
#ifdef _KERNEL
ccm_ctx->ccm_pt_buf = kmem_alloc(ccm_ctx->ccm_data_len,
Expand Down
2 changes: 1 addition & 1 deletion usr/src/common/crypto/modes/modes.c
Expand Up @@ -264,7 +264,7 @@ crypto_uio_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd,
offset -= uiop->uio_iov[vec_idx++].iov_len)
;

if (vec_idx == uiop->uio_iovcnt) {
if (vec_idx == uiop->uio_iovcnt && length > 0) {
/*
* The caller specified an offset that is larger than
* the total size of the buffers it provided.
Expand Down
22 changes: 22 additions & 0 deletions usr/src/common/zfs/zfeature_common.c
Expand Up @@ -261,6 +261,18 @@ zpool_feature_init(void)
"Support for blocks larger than 128KB.",
ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);

{
static const spa_feature_t bookmark_v2_deps[] = {
SPA_FEATURE_EXTENSIBLE_DATASET,
SPA_FEATURE_BOOKMARKS,
SPA_FEATURE_NONE
};
zfeature_register(SPA_FEATURE_BOOKMARK_V2,
"com.datto:bookmark_v2", "bookmark_v2",
"Support for larger bookmarks",
ZFEATURE_FLAG_PER_DATASET, bookmark_v2_deps);
}

{
static const spa_feature_t large_dnode_deps[] = {
SPA_FEATURE_EXTENSIBLE_DATASET,
Expand Down Expand Up @@ -324,4 +336,14 @@ zpool_feature_init(void)
"com.datto:resilver_defer", "resilver_defer",
"Support for defering new resilvers when one is already running.",
ZFEATURE_FLAG_READONLY_COMPAT, NULL);

static const spa_feature_t encryption_deps[] = {
SPA_FEATURE_EXTENSIBLE_DATASET,
SPA_FEATURE_BOOKMARK_V2,
SPA_FEATURE_NONE
};
zfeature_register(SPA_FEATURE_ENCRYPTION,
"com.datto:encryption", "encryption",
"Support for dataset level encryption",
ZFEATURE_FLAG_PER_DATASET, encryption_deps);
}
2 changes: 2 additions & 0 deletions usr/src/common/zfs/zfeature_common.h
Expand Up @@ -64,6 +64,8 @@ typedef enum spa_feature {
SPA_FEATURE_SPACEMAP_V2,
SPA_FEATURE_ALLOCATION_CLASSES,
SPA_FEATURE_RESILVER_DEFER,
SPA_FEATURE_ENCRYPTION,
SPA_FEATURE_BOOKMARK_V2,
SPA_FEATURES
} spa_feature_t;

Expand Down
2 changes: 2 additions & 0 deletions usr/src/common/zfs/zfs_deleg.c
Expand Up @@ -66,6 +66,8 @@ zfs_deleg_perm_tab_t zfs_deleg_perm_tab[] = {
{ZFS_DELEG_PERM_GROUPUSED},
{ZFS_DELEG_PERM_HOLD},
{ZFS_DELEG_PERM_RELEASE},
{ZFS_DELEG_PERM_LOAD_KEY},
{ZFS_DELEG_PERM_CHANGE_KEY},
{NULL}
};

Expand Down
2 changes: 2 additions & 0 deletions usr/src/common/zfs/zfs_deleg.h
Expand Up @@ -68,6 +68,8 @@ typedef enum {
ZFS_DELEG_NOTE_DIFF,
ZFS_DELEG_NOTE_BOOKMARK,
ZFS_DELEG_NOTE_REMAP,
ZFS_DELEG_NOTE_LOAD_KEY,
ZFS_DELEG_NOTE_CHANGE_KEY,
ZFS_DELEG_NOTE_NONE
} zfs_deleg_note_t;

Expand Down
100 changes: 97 additions & 3 deletions usr/src/common/zfs/zfs_prop.c
Expand Up @@ -34,6 +34,7 @@
#include <sys/zfs_acl.h>
#include <sys/zfs_ioctl.h>
#include <sys/zfs_znode.h>
#include <sys/dsl_crypt.h>

#include "zfs_prop.h"
#include "zfs_deleg.h"
Expand Down Expand Up @@ -115,6 +116,26 @@ zfs_prop_init(void)
{ NULL }
};

static zprop_index_t crypto_table[] = {
{ "on", ZIO_CRYPT_ON },
{ "off", ZIO_CRYPT_OFF },
{ "aes-128-ccm", ZIO_CRYPT_AES_128_CCM },
{ "aes-192-ccm", ZIO_CRYPT_AES_192_CCM },
{ "aes-256-ccm", ZIO_CRYPT_AES_256_CCM },
{ "aes-128-gcm", ZIO_CRYPT_AES_128_GCM },
{ "aes-192-gcm", ZIO_CRYPT_AES_192_GCM },
{ "aes-256-gcm", ZIO_CRYPT_AES_256_GCM },
{ NULL }
};

static zprop_index_t keyformat_table[] = {
{ "none", ZFS_KEYFORMAT_NONE },
{ "raw", ZFS_KEYFORMAT_RAW },
{ "hex", ZFS_KEYFORMAT_HEX },
{ "passphrase", ZFS_KEYFORMAT_PASSPHRASE },
{ NULL }
};

static zprop_index_t snapdir_table[] = {
{ "hidden", ZFS_SNAPDIR_HIDDEN },
{ "visible", ZFS_SNAPDIR_VISIBLE },
Expand Down Expand Up @@ -183,6 +204,13 @@ zfs_prop_init(void)
{ NULL }
};

static zprop_index_t keystatus_table[] = {
{ "none", ZFS_KEYSTATUS_NONE },
{ "unavailable", ZFS_KEYSTATUS_UNAVAILABLE },
{ "available", ZFS_KEYSTATUS_AVAILABLE },
{ NULL }
};

static zprop_index_t logbias_table[] = {
{ "latency", ZFS_LOGBIAS_LATENCY },
{ "throughput", ZFS_LOGBIAS_THROUGHPUT },
Expand Down Expand Up @@ -316,12 +344,16 @@ zfs_prop_init(void)
PROP_DEFAULT, ZFS_TYPE_FILESYSTEM, "on | off | noauto",
"CANMOUNT", canmount_table);

/* readonly index (boolean) properties */
/* readonly index properties */
zprop_register_index(ZFS_PROP_MOUNTED, "mounted", 0, PROP_READONLY,
ZFS_TYPE_FILESYSTEM, "yes | no", "MOUNTED", boolean_table);
zprop_register_index(ZFS_PROP_DEFER_DESTROY, "defer_destroy", 0,
PROP_READONLY, ZFS_TYPE_SNAPSHOT, "yes | no", "DEFER_DESTROY",
boolean_table);
zprop_register_index(ZFS_PROP_KEYSTATUS, "keystatus",
ZFS_KEYSTATUS_NONE, PROP_READONLY, ZFS_TYPE_DATASET,
"none | unavailable | available",
"KEYSTATUS", keystatus_table);

/* set once index properties */
zprop_register_index(ZFS_PROP_NORMALIZE, "normalization", 0,
Expand All @@ -332,6 +364,15 @@ zfs_prop_init(void)
ZFS_CASE_SENSITIVE, PROP_ONETIME, ZFS_TYPE_FILESYSTEM |
ZFS_TYPE_SNAPSHOT,
"sensitive | insensitive | mixed", "CASE", case_table);
zprop_register_index(ZFS_PROP_KEYFORMAT, "keyformat",
ZFS_KEYFORMAT_NONE, PROP_ONETIME_DEFAULT,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
"none | raw | hex | passphrase", "KEYFORMAT", keyformat_table);
zprop_register_index(ZFS_PROP_ENCRYPTION, "encryption",
ZIO_CRYPT_DEFAULT, PROP_ONETIME, ZFS_TYPE_DATASET,
"on | off | aes-128-ccm | aes-192-ccm | aes-256-ccm | "
"aes-128-gcm | aes-192-gcm | aes-256-gcm", "ENCRYPTION",
crypto_table);

/* set once index (boolean) properties */
zprop_register_index(ZFS_PROP_UTF8ONLY, "utf8only", 0, PROP_ONETIME,
Expand Down Expand Up @@ -362,6 +403,12 @@ zfs_prop_init(void)
"receive_resume_token",
NULL, PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
"<string token>", "RESUMETOK");
zprop_register_string(ZFS_PROP_ENCRYPTION_ROOT, "encryptionroot", NULL,
PROP_READONLY, ZFS_TYPE_DATASET, "<filesystem | volume>",
"ENCROOT");
zprop_register_string(ZFS_PROP_KEYLOCATION, "keylocation",
"none", PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
"prompt | <file URI>", "KEYLOCATION");

/* readonly number properties */
zprop_register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY,
Expand Down Expand Up @@ -410,6 +457,9 @@ zfs_prop_init(void)
ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "<uint64>", "GUID");
zprop_register_number(ZFS_PROP_CREATETXG, "createtxg", 0, PROP_READONLY,
ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "<uint64>", "CREATETXG");
zprop_register_number(ZFS_PROP_PBKDF2_ITERS, "pbkdf2iters",
0, PROP_ONETIME_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
"<iters>", "PBKDF2ITERS");

/* default number properties */
zprop_register_number(ZFS_PROP_QUOTA, "quota", 0, PROP_DEFAULT,
Expand Down Expand Up @@ -460,8 +510,16 @@ zfs_prop_init(void)
PROP_READONLY, ZFS_TYPE_DATASET, "OBJSETID");
zprop_register_hidden(ZFS_PROP_INCONSISTENT, "inconsistent",
PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET, "INCONSISTENT");
zprop_register_hidden(ZFS_PROP_IVSET_GUID, "ivsetguid",
PROP_TYPE_NUMBER, PROP_READONLY,
ZFS_TYPE_DATASET | ZFS_TYPE_BOOKMARK, "IVSETGUID");
zprop_register_hidden(ZFS_PROP_PREV_SNAP, "prevsnap", PROP_TYPE_STRING,
PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "PREVSNAP");
zprop_register_hidden(ZFS_PROP_PBKDF2_SALT, "pbkdf2salt",
PROP_TYPE_NUMBER, PROP_ONETIME_DEFAULT,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "PBKDF2SALT");
zprop_register_hidden(ZFS_PROP_KEY_GUID, "keyguid", PROP_TYPE_NUMBER,
PROP_READONLY, ZFS_TYPE_DATASET, "KEYGUID");

/* oddball properties */
zprop_register_impl(ZFS_PROP_CREATION, "creation", PROP_TYPE_NUMBER, 0,
Expand Down Expand Up @@ -602,7 +660,8 @@ boolean_t
zfs_prop_readonly(zfs_prop_t prop)
{
return (zfs_prop_table[prop].pd_attr == PROP_READONLY ||
zfs_prop_table[prop].pd_attr == PROP_ONETIME);
zfs_prop_table[prop].pd_attr == PROP_ONETIME ||
zfs_prop_table[prop].pd_attr == PROP_ONETIME_DEFAULT);
}

/*
Expand All @@ -620,7 +679,8 @@ zfs_prop_visible(zfs_prop_t prop)
boolean_t
zfs_prop_setonce(zfs_prop_t prop)
{
return (zfs_prop_table[prop].pd_attr == PROP_ONETIME);
return (zfs_prop_table[prop].pd_attr == PROP_ONETIME ||
zfs_prop_table[prop].pd_attr == PROP_ONETIME_DEFAULT);
}

const char *
Expand Down Expand Up @@ -655,6 +715,40 @@ zfs_prop_inheritable(zfs_prop_t prop)
zfs_prop_table[prop].pd_attr == PROP_ONETIME);
}

/*
* Returns TRUE if property is one of the encryption properties that requires
* a loaded encryption key to modify.
*/
boolean_t
zfs_prop_encryption_key_param(zfs_prop_t prop)
{
/*
* keylocation does not count as an encryption property. It can be
* changed at will without needing the master keys.
*/
return (prop == ZFS_PROP_PBKDF2_SALT || prop == ZFS_PROP_PBKDF2_ITERS ||
prop == ZFS_PROP_KEYFORMAT);
}

/*
* Helper function used by both kernelspace and userspace to check the
* keylocation property. If encrypted is set, the keylocation must be valid
* for an encrypted dataset.
*/
boolean_t
zfs_prop_valid_keylocation(const char *str, boolean_t encrypted)
{
if (strcmp("none", str) == 0)
return (!encrypted);
else if (strcmp("prompt", str) == 0)
return (B_TRUE);
else if (strlen(str) > 8 && strncmp("file:///", str, 8) == 0)
return (B_TRUE);

return (B_FALSE);
}


#ifndef _KERNEL

/*
Expand Down
7 changes: 5 additions & 2 deletions usr/src/common/zfs/zfs_prop.h
Expand Up @@ -51,9 +51,12 @@ typedef enum {
* ONETIME properties are a sort of conglomeration of READONLY
* and INHERIT. They can be set only during object creation,
* after that they are READONLY. If not explicitly set during
* creation, they can be inherited.
* creation, they can be inherited. ONETIME_DEFAULT properties
* work the same way, but they will default instead of
* inheriting a value.
*/
PROP_ONETIME
PROP_ONETIME,
PROP_ONETIME_DEFAULT
} zprop_attr_t;

typedef struct zfs_index {
Expand Down
2 changes: 1 addition & 1 deletion usr/src/lib/Makefile
Expand Up @@ -676,7 +676,7 @@ libvolmgt: libadm
libvrrpadm: libdladm libscf
libvscan: libscf libsecdb
libzfs: libdevid libgen libuutil libadm libavl libefi libidmap \
libumem libtsol libzfs_core
libumem libtsol libzfs_core libcryptoutil pkcs11 libmd libcmdutils
libzfs_jni: libdiskmgt libzfs
libzonecfg: libuuid libsysevent libsec libbrand libpool libscf libproc \
libuutil libbsm libsecdb
Expand Down
4 changes: 2 additions & 2 deletions usr/src/lib/libuutil/common/libuutil.h
Expand Up @@ -245,7 +245,7 @@ void uu_list_pool_destroy(uu_list_pool_t *);
* usage:
*
* foo_t *a;
* a = malloc(sizeof(*a));
* a = malloc(sizeof (*a));
* uu_list_node_init(a, &a->foo_list, pool);
* ...
* uu_list_node_fini(a, &a->foo_list, pool);
Expand Down Expand Up @@ -348,7 +348,7 @@ void uu_avl_pool_destroy(uu_avl_pool_t *);
* usage:
*
* foo_t *a;
* a = malloc(sizeof(*a));
* a = malloc(sizeof (*a));
* uu_avl_node_init(a, &a->foo_avl, pool);
* ...
* uu_avl_node_fini(a, &a->foo_avl, pool);
Expand Down
10 changes: 9 additions & 1 deletion usr/src/lib/libzfs/Makefile.com
Expand Up @@ -41,6 +41,7 @@ OBJS_SHARED= \
OBJS_COMMON= \
libzfs_changelist.o \
libzfs_config.o \
libzfs_crypto.o \
libzfs_dataset.o \
libzfs_diff.o \
libzfs_fru.o \
Expand Down Expand Up @@ -72,7 +73,8 @@ INCS += -I../../libc/inc
CSTD= $(CSTD_GNU99)
C99LMODE= -Xc99=%all
LDLIBS += -lc -lm -ldevid -lgen -lnvpair -luutil -lavl -lefi \
-ladm -lidmap -ltsol -lmd -lumem -lzfs_core -lcmdutils
-ladm -lidmap -ltsol -lcryptoutil -lpkcs11 -lmd -lumem -lzfs_core \
-lcmdutils
CPPFLAGS += $(INCS) -D_LARGEFILE64_SOURCE=1 -D_REENTRANT
$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG

Expand All @@ -89,6 +91,12 @@ SRCS= $(OBJS_COMMON:%.o=$(SRCDIR)/%.c) \
$(OBJS_SHARED:%.o=$(SRC)/common/zfs/%.c)
$(LINTLIB) := SRCS= $(SRCDIR)/$(LINTSRC)

# lint complains about unused inline functions, even though
# they are "inline", not "static inline", with "extern inline"
# implementations and usage in libzpool.
LINTFLAGS += -erroff=E_STATIC_UNUSED
LINTFLAGS64 += -erroff=E_STATIC_UNUSED

.KEEP_STATE:

all: $(LIBS)
Expand Down
29 changes: 25 additions & 4 deletions usr/src/lib/libzfs/common/libzfs.h
Expand Up @@ -141,6 +141,7 @@ typedef enum zfs_error {
EZFS_INITIALIZING, /* currently initializing */
EZFS_NO_INITIALIZE, /* no active initialize */
EZFS_NO_RESILVER_DEFER, /* pool doesn't support resilver_defer */
EZFS_CRYPTOFAILED, /* failed to setup encryption */
EZFS_UNKNOWN
} zfs_error_t;

Expand Down Expand Up @@ -336,6 +337,7 @@ typedef enum {
ZPOOL_STATUS_IO_FAILURE_CONTINUE, /* failed I/O, failmode 'continue' */
ZPOOL_STATUS_IO_FAILURE_MMP, /* failed MMP, failmode not 'panic' */
ZPOOL_STATUS_BAD_LOG, /* cannot read log chain(s) */
ZPOOL_STATUS_ERRATA, /* informational errata available */

/*
* If the pool has unsupported features but can still be opened in
Expand Down Expand Up @@ -371,8 +373,10 @@ typedef enum {
ZPOOL_STATUS_OK
} zpool_status_t;

extern zpool_status_t zpool_get_status(zpool_handle_t *, char **);
extern zpool_status_t zpool_import_status(nvlist_t *, char **);
extern zpool_status_t zpool_get_status(zpool_handle_t *, char **,
zpool_errata_t *);
extern zpool_status_t zpool_import_status(nvlist_t *, char **,
zpool_errata_t *);
extern void zpool_dump_ddt(const ddt_stat_t *dds, const ddt_histogram_t *ddh);

/*
Expand Down Expand Up @@ -474,8 +478,8 @@ extern uint64_t zfs_prop_default_numeric(zfs_prop_t);
extern const char *zfs_prop_column_name(zfs_prop_t);
extern boolean_t zfs_prop_align_right(zfs_prop_t);

extern nvlist_t *zfs_valid_proplist(libzfs_handle_t *, zfs_type_t,
nvlist_t *, uint64_t, zfs_handle_t *, zpool_handle_t *, const char *);
extern nvlist_t *zfs_valid_proplist(libzfs_handle_t *, zfs_type_t, nvlist_t *,
uint64_t, zfs_handle_t *, zpool_handle_t *, boolean_t, const char *);

extern const char *zfs_prop_to_name(zfs_prop_t);
extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
Expand Down Expand Up @@ -505,6 +509,19 @@ extern nvlist_t *zfs_get_recvd_props(zfs_handle_t *);
extern nvlist_t *zfs_get_clones_nvl(zfs_handle_t *);


/*
* zfs encryption management
*/
extern int zfs_crypto_get_encryption_root(zfs_handle_t *, boolean_t *, char *);
extern int zfs_crypto_create(libzfs_handle_t *, char *, nvlist_t *, nvlist_t *,
uint8_t **, uint_t *);
extern int zfs_crypto_clone_check(libzfs_handle_t *, zfs_handle_t *, char *,
nvlist_t *);
extern int zfs_crypto_attempt_load_keys(libzfs_handle_t *, char *);
extern int zfs_crypto_load_key(zfs_handle_t *, boolean_t, char *);
extern int zfs_crypto_unload_key(zfs_handle_t *);
extern int zfs_crypto_rewrap(zfs_handle_t *, nvlist_t *, boolean_t);

typedef struct zprop_list {
int pl_prop;
char *pl_user_prop;
Expand Down Expand Up @@ -653,6 +670,9 @@ typedef struct sendflags {

/* compressed WRITE records are permitted */
boolean_t compress;

/* raw encrypted records are permitted */
boolean_t raw;
} sendflags_t;

typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
Expand Down Expand Up @@ -737,6 +757,7 @@ extern const char *zfs_type_to_name(zfs_type_t);
extern void zfs_refresh_properties(zfs_handle_t *);
extern int zfs_name_valid(const char *, zfs_type_t);
extern zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, char *, zfs_type_t);
extern int zfs_parent_name(zfs_handle_t *, char *, size_t);
extern boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *,
zfs_type_t);
extern int zfs_spa_version(zfs_handle_t *, int *);
Expand Down
6 changes: 5 additions & 1 deletion usr/src/lib/libzfs/common/libzfs_changelist.c
Expand Up @@ -225,6 +225,7 @@ changelist_postfix(prop_changelist_t *clp)
boolean_t sharenfs;
boolean_t sharesmb;
boolean_t mounted;
boolean_t needs_key;

/*
* If we are in the global zone, but this dataset is exported
Expand Down Expand Up @@ -253,9 +254,12 @@ changelist_postfix(prop_changelist_t *clp)
shareopts, sizeof (shareopts), NULL, NULL, 0,
B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));

needs_key = (zfs_prop_get_int(cn->cn_handle,
ZFS_PROP_KEYSTATUS) == ZFS_KEYSTATUS_UNAVAILABLE);

mounted = zfs_is_mounted(cn->cn_handle, NULL);

if (!mounted && (cn->cn_mounted ||
if (!mounted && !needs_key && (cn->cn_mounted ||
((sharenfs || sharesmb || clp->cl_waslegacy) &&
(zfs_prop_get_int(cn->cn_handle,
ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON)))) {
Expand Down
1,529 changes: 1,529 additions & 0 deletions usr/src/lib/libzfs/common/libzfs_crypto.c

Large diffs are not rendered by default.

133 changes: 123 additions & 10 deletions usr/src/lib/libzfs/common/libzfs_dataset.c
Expand Up @@ -59,6 +59,7 @@
#include <sys/dnode.h>
#include <sys/spa.h>
#include <sys/zap.h>
#include <sys/dsl_crypt.h>
#include <libzfs.h>

#include "zfs_namecheck.h"
Expand Down Expand Up @@ -951,7 +952,7 @@ zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
nvlist_t *
zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl,
const char *errbuf)
boolean_t key_params_ok, const char *errbuf)
{
nvpair_t *elem;
uint64_t intval;
Expand Down Expand Up @@ -1108,7 +1109,8 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
}

if (zfs_prop_readonly(prop) &&
(!zfs_prop_setonce(prop) || zhp != NULL)) {
!(zfs_prop_setonce(prop) && zhp == NULL) &&
!(zfs_prop_encryption_key_param(prop) && key_params_ok)) {
zfs_error_aux(hdl,
dgettext(TEXT_DOMAIN, "'%s' is readonly"),
propname);
Expand Down Expand Up @@ -1403,6 +1405,48 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,

break;

case ZFS_PROP_KEYLOCATION:
if (!zfs_prop_valid_keylocation(strval, B_FALSE)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"invalid keylocation"));
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
goto error;
}

if (zhp != NULL) {
uint64_t crypt =
zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION);

if (crypt == ZIO_CRYPT_OFF &&
strcmp(strval, "none") != 0) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"keylocation must be 'none' "
"for unencrypted datasets"));
(void) zfs_error(hdl, EZFS_BADPROP,
errbuf);
goto error;
} else if (crypt != ZIO_CRYPT_OFF &&
strcmp(strval, "none") == 0) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"keylocation must not be 'none' "
"for encrypted datasets"));
(void) zfs_error(hdl, EZFS_BADPROP,
errbuf);
goto error;
}
}
break;

case ZFS_PROP_PBKDF2_ITERS:
if (intval < MIN_PBKDF2_ITERATIONS) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"minimum pbkdf2 iterations is %u"),
MIN_PBKDF2_ITERATIONS);
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
goto error;
}
break;

case ZFS_PROP_UTF8ONLY:
chosen_utf = (int)intval;
break;
Expand Down Expand Up @@ -1476,6 +1520,27 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
break;
}
}

/* check encryption properties */
if (zhp != NULL) {
int64_t crypt = zfs_prop_get_int(zhp,
ZFS_PROP_ENCRYPTION);

switch (prop) {
case ZFS_PROP_COPIES:
if (crypt != ZIO_CRYPT_OFF && intval > 2) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"encrypted datasets cannot have "
"3 copies"));
(void) zfs_error(hdl, EZFS_BADPROP,
errbuf);
goto error;
}
break;
default:
break;
}
}
}

/*
Expand Down Expand Up @@ -1688,6 +1753,16 @@ zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
}
break;

case EACCES:
if (prop == ZFS_PROP_KEYLOCATION) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"keylocation may only be set on encryption roots"));
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
} else {
(void) zfs_standard_error(hdl, err, errbuf);
}
break;

case EOVERFLOW:
/*
* This platform can't address a volume this big.
Expand Down Expand Up @@ -1757,7 +1832,7 @@ zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props)

if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props,
zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl,
errbuf)) == NULL)
B_FALSE, errbuf)) == NULL)
goto error;

/*
Expand Down Expand Up @@ -3254,6 +3329,12 @@ parent_name(const char *path, char *buf, size_t buflen)
return (0);
}

int
zfs_parent_name(zfs_handle_t *zhp, char *buf, size_t buflen)
{
return (parent_name(zfs_get_name(zhp), buf, buflen));
}

/*
* If accept_ancestor is false, then check to make sure that the given path has
* a parent, and that it exists. If accept_ancestor is true, then find the
Expand Down Expand Up @@ -3486,7 +3567,10 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
int ret;
uint64_t size = 0;
uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
uint8_t *wkeydata = NULL;
uint_t wkeylen = 0;
char errbuf[1024];
char parent[MAXNAMELEN];
uint64_t zoned;
enum lzc_dataset_type ost;
zpool_handle_t *zpool_handle;
Expand Down Expand Up @@ -3539,7 +3623,7 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
return (-1);

if (props && (props = zfs_valid_proplist(hdl, type, props,
zoned, NULL, zpool_handle, errbuf)) == 0) {
zoned, NULL, zpool_handle, B_TRUE, errbuf)) == 0) {
zpool_close(zpool_handle);
return (-1);
}
Expand Down Expand Up @@ -3591,15 +3675,21 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
}
}

(void) parent_name(path, parent, sizeof (parent));
if (zfs_crypto_create(hdl, parent, props, NULL, &wkeydata,
&wkeylen) != 0) {
nvlist_free(props);
return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf));
}

/* create the dataset */
ret = lzc_create(path, ost, props);
ret = lzc_create(path, ost, props, wkeydata, wkeylen);
nvlist_free(props);
if (wkeydata != NULL)
free(wkeydata);

/* check for failure */
if (ret != 0) {
char parent[ZFS_MAX_DATASET_NAME_LEN];
(void) parent_name(path, parent, sizeof (parent));

switch (errno) {
case ENOENT:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
Expand All @@ -3620,6 +3710,12 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"invalid property value(s) specified"));
return (zfs_error(hdl, EZFS_BADPROP, errbuf));
case EACCES:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"encryption root's key is not loaded "
"or provided"));
return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf));

#ifdef _ILP32
case EOVERFLOW:
/*
Expand Down Expand Up @@ -3815,14 +3911,19 @@ zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
type = ZFS_TYPE_FILESYSTEM;
}
if ((props = zfs_valid_proplist(hdl, type, props, zoned,
zhp, zhp->zpool_hdl, errbuf)) == NULL)
zhp, zhp->zpool_hdl, B_TRUE, errbuf)) == NULL)
return (-1);
if (zfs_fix_auto_resv(zhp, props) == -1) {
nvlist_free(props);
return (-1);
}
}

if (zfs_crypto_clone_check(hdl, zhp, parent, props) != 0) {
nvlist_free(props);
return (zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf));
}

ret = lzc_clone(target, zhp->zfs_name, props);
nvlist_free(props);

Expand Down Expand Up @@ -4001,7 +4102,7 @@ zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)

if (props != NULL &&
(props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) {
props, B_FALSE, NULL, zpool_hdl, B_FALSE, errbuf)) == NULL) {
zpool_close(zpool_hdl);
return (-1);
}
Expand Down Expand Up @@ -4392,6 +4493,18 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
"a child dataset already has a snapshot "
"with the new name"));
(void) zfs_error(hdl, EZFS_EXISTS, errbuf);
} else if (errno == EACCES) {
if (zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) ==
ZIO_CRYPT_OFF) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"cannot rename an unencrypted dataset to "
"be a decendent of an encrypted one"));
} else {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"cannot move encryption child outside of "
"its encryption root"));
}
(void) zfs_error(hdl, EZFS_CRYPTOFAILED, errbuf);
} else {
(void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
}
Expand Down
5 changes: 5 additions & 0 deletions usr/src/lib/libzfs/common/libzfs_diff.c
Expand Up @@ -112,6 +112,11 @@ get_stats_for_obj(differ_info_t *di, const char *dsname, uint64_t obj,
"The sys_config privilege or diff delegated permission "
"is needed\nto discover path names"));
return (-1);
} else if (di->zerr == EACCES) {
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN,
"Key must be loaded to discover path names"));
return (-1);
} else {
(void) snprintf(di->errbuf, sizeof (di->errbuf),
dgettext(TEXT_DOMAIN,
Expand Down
1 change: 1 addition & 0 deletions usr/src/lib/libzfs/common/libzfs_iter.c
Expand Up @@ -191,6 +191,7 @@ zfs_iter_bookmarks(zfs_handle_t *zhp, zfs_iter_f func, void *data)
fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_GUID));
fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATETXG));
fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATION));
fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_IVSET_GUID));

if ((err = lzc_get_bookmarks(zhp->zfs_name, props, &bmarks)) != 0)
goto out;
Expand Down
46 changes: 46 additions & 0 deletions usr/src/lib/libzfs/common/libzfs_mount.c
Expand Up @@ -80,6 +80,7 @@
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/dsl_crypt.h>

#include <libzfs.h>

Expand Down Expand Up @@ -339,6 +340,8 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
char mountpoint[ZFS_MAXPROPLEN];
char mntopts[MNT_LINE_MAX];
libzfs_handle_t *hdl = zhp->zfs_hdl;
uint64_t keystatus;
int rc;

if (options == NULL)
mntopts[0] = '\0';
Expand All @@ -354,6 +357,39 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
return (0);

/*
* If the filesystem is encrypted the key must be loaded in order to
* mount. If the key isn't loaded, the MS_CRYPT flag decides whether
* or not we attempt to load the keys. Note: we must call
* zfs_refresh_properties() here since some callers of this function
* (most notably zpool_enable_datasets()) may implicitly load our key
* by loading the parent's key first.
*/
if (zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) != ZIO_CRYPT_OFF) {
zfs_refresh_properties(zhp);
keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);

/*
* If the key is unavailable and MS_CRYPT is set give the
* user a chance to enter the key. Otherwise just fail
* immediately.
*/
if (keystatus == ZFS_KEYSTATUS_UNAVAILABLE) {
if (flags & MS_CRYPT) {
rc = zfs_crypto_load_key(zhp, B_FALSE, NULL);
if (rc != 0)
return (rc);
} else {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"encryption key not loaded"));
return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
mountpoint));
}
}

}

/* Create the directory if it doesn't already exist */
if (lstat(mountpoint, &buf) != 0) {
if (mkdirp(mountpoint, 0755) != 0) {
Expand Down Expand Up @@ -1121,6 +1157,12 @@ zfs_iter_cb(zfs_handle_t *zhp, void *data)
return (0);
}

if (zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS) ==
ZFS_KEYSTATUS_UNAVAILABLE) {
zfs_close(zhp);
return (0);
}

/*
* If this filesystem is inconsistent and has a receive resume
* token, we can not mount it.
Expand Down Expand Up @@ -1313,6 +1355,10 @@ zfs_mount_one(zfs_handle_t *zhp, void *arg)
mount_state_t *ms = arg;
int ret = 0;

if (zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS) ==
ZFS_KEYSTATUS_UNAVAILABLE)
return (0);

if (zfs_mount(zhp, ms->ms_mntopts, ms->ms_mntflags) != 0)
ret = ms->ms_mntstatus = -1;
return (ret);
Expand Down
28 changes: 27 additions & 1 deletion usr/src/lib/libzfs/common/libzfs_pool.c
Expand Up @@ -1162,6 +1162,9 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
zfs_cmd_t zc = { 0 };
nvlist_t *zc_fsprops = NULL;
nvlist_t *zc_props = NULL;
nvlist_t *hidden_args = NULL;
uint8_t *wkeydata = NULL;
uint_t wkeylen = 0;
char msg[1024];
int ret = -1;

Expand Down Expand Up @@ -1192,7 +1195,7 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
strcmp(zonestr, "on") == 0);

if ((zc_fsprops = zfs_valid_proplist(hdl, ZFS_TYPE_FILESYSTEM,
fsprops, zoned, NULL, NULL, msg)) == NULL) {
fsprops, zoned, NULL, NULL, B_TRUE, msg)) == NULL) {
goto create_failed;
}

Expand All @@ -1210,10 +1213,27 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
(nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) {
goto create_failed;
}
if (zfs_crypto_create(hdl, NULL, zc_fsprops, props,
&wkeydata, &wkeylen) != 0) {
(void) zfs_error(hdl, EZFS_CRYPTOFAILED, msg);
goto create_failed;
}
if (nvlist_add_nvlist(zc_props,
ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) {
goto create_failed;
}
if (wkeydata != NULL) {
if (nvlist_alloc(&hidden_args, NV_UNIQUE_NAME, 0) != 0)
goto create_failed;

if (nvlist_add_uint8_array(hidden_args, "wkeydata",
wkeydata, wkeylen) != 0)
goto create_failed;

if (nvlist_add_nvlist(zc_props, ZPOOL_HIDDEN_ARGS,
hidden_args) != 0)
goto create_failed;
}
}

if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
Expand All @@ -1226,6 +1246,9 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
zcmd_free_nvlists(&zc);
nvlist_free(zc_props);
nvlist_free(zc_fsprops);
nvlist_free(hidden_args);
if (wkeydata != NULL)
free(wkeydata);

switch (errno) {
case EBUSY:
Expand Down Expand Up @@ -1286,6 +1309,9 @@ zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
zcmd_free_nvlists(&zc);
nvlist_free(zc_props);
nvlist_free(zc_fsprops);
nvlist_free(hidden_args);
if (wkeydata != NULL)
free(wkeydata);
return (ret);
}

Expand Down
622 changes: 555 additions & 67 deletions usr/src/lib/libzfs/common/libzfs_sendrecv.c

Large diffs are not rendered by default.

20 changes: 15 additions & 5 deletions usr/src/lib/libzfs/common/libzfs_status.c
Expand Up @@ -198,7 +198,7 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
* only picks the most damaging of all the current errors to report.
*/
static zpool_status_t
check_status(nvlist_t *config, boolean_t isimport)
check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap)
{
nvlist_t *nvroot;
vdev_stat_t *vs;
Expand All @@ -209,6 +209,7 @@ check_status(nvlist_t *config, boolean_t isimport)
uint64_t stateval;
uint64_t suspended;
uint64_t hostid = 0;
uint64_t errata = 0;
unsigned long system_hostid = get_system_hostid();

verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
Expand Down Expand Up @@ -368,6 +369,15 @@ check_status(nvlist_t *config, boolean_t isimport)
if (find_vdev_problem(nvroot, vdev_removed))
return (ZPOOL_STATUS_REMOVED_DEV);

/*
* Informational errata available.
*/
(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRATA, &errata);
if (errata) {
*erratap = errata;
return (ZPOOL_STATUS_ERRATA);
}

/*
* Outdated, but usable, version
*/
Expand Down Expand Up @@ -403,9 +413,9 @@ check_status(nvlist_t *config, boolean_t isimport)
}

zpool_status_t
zpool_get_status(zpool_handle_t *zhp, char **msgid)
zpool_get_status(zpool_handle_t *zhp, char **msgid, zpool_errata_t *errata)
{
zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE);
zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata);

if (ret >= NMSGID)
*msgid = NULL;
Expand All @@ -416,9 +426,9 @@ zpool_get_status(zpool_handle_t *zhp, char **msgid)
}

zpool_status_t
zpool_import_status(nvlist_t *config, char **msgid)
zpool_import_status(nvlist_t *config, char **msgid, zpool_errata_t *errata)
{
zpool_status_t ret = check_status(config, B_TRUE);
zpool_status_t ret = check_status(config, B_TRUE, errata);

if (ret >= NMSGID)
*msgid = NULL;
Expand Down
2 changes: 2 additions & 0 deletions usr/src/lib/libzfs/common/libzfs_util.c
Expand Up @@ -263,6 +263,8 @@ libzfs_error_description(libzfs_handle_t *hdl)
case EZFS_NO_RESILVER_DEFER:
return (dgettext(TEXT_DOMAIN, "this action requires the "
"resilver_defer feature"));
case EZFS_CRYPTOFAILED:
return (dgettext(TEXT_DOMAIN, "encryption failure"));
case EZFS_UNKNOWN:
return (dgettext(TEXT_DOMAIN, "unknown error"));
default:
Expand Down
5 changes: 5 additions & 0 deletions usr/src/lib/libzfs/common/mapfile-vers
Expand Up @@ -71,6 +71,11 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zfs_close;
zfs_create;
zfs_create_ancestors;
zfs_crypto_attempt_load_keys;
zfs_crypto_get_encryption_root;
zfs_crypto_load_key;
zfs_crypto_rewrap;
zfs_crypto_unload_key;
zfs_dataset_exists;
zfs_deleg_share_nfs;
zfs_destroy;
Expand Down
107 changes: 95 additions & 12 deletions usr/src/lib/libzfs_core/common/libzfs_core.c
Expand Up @@ -189,34 +189,49 @@ lzc_ioctl(zfs_ioc_t ioc, const char *name,
}

out:
fnvlist_pack_free(packed, size);
if (packed != NULL)
fnvlist_pack_free(packed, size);
free((void *)(uintptr_t)zc.zc_nvlist_dst);
return (error);
}

int
lzc_create(const char *fsname, enum lzc_dataset_type type, nvlist_t *props)
lzc_create(const char *fsname, enum lzc_dataset_type type, nvlist_t *props,
uint8_t *wkeydata, uint_t wkeylen)
{
int error;
nvlist_t *hidden_args = NULL;
nvlist_t *args = fnvlist_alloc();

fnvlist_add_int32(args, "type", (dmu_objset_type_t)type);
if (props != NULL)
fnvlist_add_nvlist(args, "props", props);

if (wkeydata != NULL) {
hidden_args = fnvlist_alloc();
fnvlist_add_uint8_array(hidden_args, "wkeydata", wkeydata,
wkeylen);
fnvlist_add_nvlist(args, ZPOOL_HIDDEN_ARGS, hidden_args);
}

error = lzc_ioctl(ZFS_IOC_CREATE, fsname, args, NULL);
nvlist_free(hidden_args);
nvlist_free(args);
return (error);
}

int
lzc_clone(const char *fsname, const char *origin,
nvlist_t *props)
lzc_clone(const char *fsname, const char *origin, nvlist_t *props)
{
int error;
nvlist_t *hidden_args = NULL;
nvlist_t *args = fnvlist_alloc();

fnvlist_add_string(args, "origin", origin);
if (props != NULL)
fnvlist_add_nvlist(args, "props", props);
error = lzc_ioctl(ZFS_IOC_CLONE, fsname, args, NULL);
nvlist_free(hidden_args);
nvlist_free(args);
return (error);
}
Expand Down Expand Up @@ -584,6 +599,8 @@ lzc_send_resume(const char *snapname, const char *from, int fd,
fnvlist_add_boolean(args, "embedok");
if (flags & LZC_SEND_FLAG_COMPRESS)
fnvlist_add_boolean(args, "compressok");
if (flags & LZC_SEND_FLAG_RAW)
fnvlist_add_boolean(args, "rawok");
if (resumeobj != 0 || resumeoff != 0) {
fnvlist_add_uint64(args, "resume_object", resumeobj);
fnvlist_add_uint64(args, "resume_offset", resumeoff);
Expand Down Expand Up @@ -654,7 +671,7 @@ recv_read(int fd, void *buf, int ilen)

static int
recv_impl(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, boolean_t resumable, int fd,
boolean_t force, boolean_t resumable, boolean_t raw, int fd,
const dmu_replay_record_t *begin_record)
{
/*
Expand Down Expand Up @@ -747,9 +764,10 @@ recv_impl(const char *snapname, nvlist_t *props, const char *origin,
*/
int
lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, int fd)
boolean_t raw, boolean_t force, int fd)
{
return (recv_impl(snapname, props, origin, force, B_FALSE, fd, NULL));
return (recv_impl(snapname, props, origin, force, B_FALSE, raw, fd,
NULL));
}

/*
Expand All @@ -760,9 +778,10 @@ lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
*/
int
lzc_receive_resumable(const char *snapname, nvlist_t *props, const char *origin,
boolean_t force, int fd)
boolean_t force, boolean_t raw, int fd)
{
return (recv_impl(snapname, props, origin, force, B_TRUE, fd, NULL));
return (recv_impl(snapname, props, origin, force, B_TRUE, raw, fd,
NULL));
}

/*
Expand All @@ -778,12 +797,12 @@ lzc_receive_resumable(const char *snapname, nvlist_t *props, const char *origin,
*/
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)
const char *origin, boolean_t force, boolean_t resumable, boolean_t raw,
int fd, const dmu_replay_record_t *begin_record)
{
if (begin_record == NULL)
return (EINVAL);
return (recv_impl(snapname, props, origin, force, resumable, fd,
return (recv_impl(snapname, props, origin, force, resumable, raw, fd,
begin_record));
}

Expand Down Expand Up @@ -882,6 +901,7 @@ lzc_bookmark(nvlist_t *bookmarks, nvlist_t **errlist)
* "guid" - globally unique identifier of the snapshot it refers to
* "createtxg" - txg when the snapshot it refers to was created
* "creation" - timestamp when the snapshot it refers to was created
* "ivsetguid" - IVset guid for identifying encrypted snapshots
*
* The format of the returned nvlist as follows:
* <short name of bookmark> -> {
Expand Down Expand Up @@ -1115,3 +1135,66 @@ lzc_initialize(const char *poolname, pool_initialize_func_t cmd_type,

return (error);
}

/*
* Performs key management functions
*
* crypto_cmd should be a value from zfs_ioc_crypto_cmd_t. If the command
* specifies to load or change a wrapping key, the key should be specified in
* the hidden_args nvlist so that it is not logged
*/
int
lzc_load_key(const char *fsname, boolean_t noop, uint8_t *wkeydata,
uint_t wkeylen)
{
int error;
nvlist_t *ioc_args;
nvlist_t *hidden_args;

if (wkeydata == NULL)
return (EINVAL);

ioc_args = fnvlist_alloc();
hidden_args = fnvlist_alloc();
fnvlist_add_uint8_array(hidden_args, "wkeydata", wkeydata, wkeylen);
fnvlist_add_nvlist(ioc_args, ZPOOL_HIDDEN_ARGS, hidden_args);
if (noop)
fnvlist_add_boolean(ioc_args, "noop");
error = lzc_ioctl(ZFS_IOC_LOAD_KEY, fsname, ioc_args, NULL);
nvlist_free(hidden_args);
nvlist_free(ioc_args);

return (error);
}

int
lzc_unload_key(const char *fsname)
{
return (lzc_ioctl(ZFS_IOC_UNLOAD_KEY, fsname, NULL, NULL));
}

int
lzc_change_key(const char *fsname, uint64_t crypt_cmd, nvlist_t *props,
uint8_t *wkeydata, uint_t wkeylen)
{
int error;
nvlist_t *ioc_args = fnvlist_alloc();
nvlist_t *hidden_args = NULL;

fnvlist_add_uint64(ioc_args, "crypt_cmd", crypt_cmd);

if (wkeydata != NULL) {
hidden_args = fnvlist_alloc();
fnvlist_add_uint8_array(hidden_args, "wkeydata", wkeydata,
wkeylen);
fnvlist_add_nvlist(ioc_args, ZPOOL_HIDDEN_ARGS, hidden_args);
}

if (props != NULL)
fnvlist_add_nvlist(ioc_args, "props", props);

error = lzc_ioctl(ZFS_IOC_CHANGE_KEY, fsname, ioc_args, NULL);
nvlist_free(hidden_args);
nvlist_free(ioc_args);
return (error);
}
16 changes: 11 additions & 5 deletions usr/src/lib/libzfs_core/common/libzfs_core.h
Expand Up @@ -52,7 +52,8 @@ enum lzc_dataset_type {

int lzc_remap(const char *fsname);
int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **);
int lzc_create(const char *, enum lzc_dataset_type, nvlist_t *);
int lzc_create(const char *, enum lzc_dataset_type, nvlist_t *, uint8_t *,
uint_t);
int lzc_clone(const char *, const char *, nvlist_t *);
int lzc_promote(const char *, char *, int);
int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **);
Expand All @@ -61,6 +62,9 @@ int lzc_get_bookmarks(const char *, nvlist_t *, nvlist_t **);
int lzc_destroy_bookmarks(nvlist_t *, nvlist_t **);
int lzc_initialize(const char *, pool_initialize_func_t, nvlist_t *,
nvlist_t **);
int lzc_load_key(const char *, boolean_t, uint8_t *, uint_t);
int lzc_unload_key(const char *);
int lzc_change_key(const char *, uint64_t, nvlist_t *, uint8_t *, uint_t);

int lzc_snaprange_space(const char *, const char *, uint64_t *);

Expand All @@ -71,7 +75,8 @@ int lzc_get_holds(const char *, nvlist_t **);
enum lzc_send_flags {
LZC_SEND_FLAG_EMBED_DATA = 1 << 0,
LZC_SEND_FLAG_LARGE_BLOCK = 1 << 1,
LZC_SEND_FLAG_COMPRESS = 1 << 2
LZC_SEND_FLAG_COMPRESS = 1 << 2,
LZC_SEND_FLAG_RAW = 1 << 3
};

int lzc_send(const char *, const char *, int, enum lzc_send_flags);
Expand All @@ -81,11 +86,12 @@ int lzc_send_space(const char *, const char *, enum lzc_send_flags, 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 *,
int lzc_receive(const char *, nvlist_t *, const char *, boolean_t,
boolean_t, int);
int lzc_receive_resumable(const char *, nvlist_t *, const char *,
boolean_t, boolean_t, int);
int lzc_receive_with_header(const char *, nvlist_t *, const char *, boolean_t,
boolean_t, int, const struct dmu_replay_record *);
boolean_t, boolean_t, int, const struct dmu_replay_record *);

boolean_t lzc_exists(const char *);

Expand Down
3 changes: 3 additions & 0 deletions usr/src/lib/libzfs_core/common/mapfile-vers
Expand Up @@ -74,6 +74,9 @@ SYMBOL_VERSION ILLUMOS_0.1 {
lzc_channel_program_nosync;
lzc_clone;
lzc_create;
lzc_load_key;
lzc_unload_key;
lzc_change_key;
lzc_destroy_bookmarks;
lzc_destroy_snaps;
lzc_exists;
Expand Down
2 changes: 1 addition & 1 deletion usr/src/lib/libzfs_jni/common/libzfs_jni_dataset.c
Expand Up @@ -382,7 +382,7 @@ populate_PoolBean(JNIEnv *env, zpool_handle_t *zphp, zfs_handle_t *zhp,
(*env)->CallVoidMethod(env, object->object,
pool_stats->method_setPoolStatus,
zjni_pool_status_to_obj(env,
zpool_get_status(zphp, &msgid)));
zpool_get_status(zphp, &msgid, NULL)));

(*env)->CallVoidMethod(env, object->object,
pool_stats->method_setPoolVersion,
Expand Down
3 changes: 2 additions & 1 deletion usr/src/lib/libzfs_jni/common/libzfs_jni_pool.c
Expand Up @@ -407,7 +407,8 @@ populate_ImportablePoolBean(JNIEnv *env, ImportablePoolBean_t *bean,

(*env)->CallVoidMethod(env, object->object,
pool_stats->method_setPoolStatus,
zjni_pool_status_to_obj(env, zpool_import_status(config, &c)));
zjni_pool_status_to_obj(env, zpool_import_status(config, &c,
NULL)));

(*env)->CallVoidMethod(env, object->object,
pool_stats->method_setPoolVersion, (jlong)version);
Expand Down
89 changes: 89 additions & 0 deletions usr/src/lib/libzpool/common/kernel.c
Expand Up @@ -42,6 +42,11 @@
#include <sys/utsname.h>
#include <sys/systeminfo.h>
#include <libzfs.h>
#include <sys/crypto/common.h>
#include <sys/crypto/impl.h>
#include <sys/crypto/api.h>
#include <sys/sha2.h>
#include <crypto/aes/aes_impl.h>

extern void system_taskq_init(void);
extern void system_taskq_fini(void);
Expand Down Expand Up @@ -595,3 +600,87 @@ geterror(struct buf *bp)
}
return (error);
}

int
crypto_create_ctx_template(crypto_mechanism_t *mech,
crypto_key_t *key, crypto_ctx_template_t *tmpl, int kmflag)
{
return (0);
}

crypto_mech_type_t
crypto_mech2id(crypto_mech_name_t name)
{
return (CRYPTO_MECH_INVALID);
}

int
crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data,
crypto_key_t *key, crypto_ctx_template_t impl,
crypto_data_t *mac, crypto_call_req_t *cr)
{
return (0);
}

int
crypto_encrypt(crypto_mechanism_t *mech, crypto_data_t *plaintext,
crypto_key_t *key, crypto_ctx_template_t tmpl,
crypto_data_t *ciphertext, crypto_call_req_t *cr)
{
return (0);
}

/* This could probably be a weak reference */
int
crypto_decrypt(crypto_mechanism_t *mech, crypto_data_t *plaintext,
crypto_key_t *key, crypto_ctx_template_t tmpl,
crypto_data_t *ciphertext, crypto_call_req_t *cr)
{
return (0);
}


int
crypto_digest_final(crypto_context_t context, crypto_data_t *digest,
crypto_call_req_t *cr)
{
return (0);
}

int
crypto_digest_update(crypto_context_t context, crypto_data_t *data,
crypto_call_req_t *cr)
{
return (0);
}

int
crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp,
crypto_call_req_t *crq)
{
return (0);
}

void
crypto_destroy_ctx_template(crypto_ctx_template_t tmpl)
{
}

extern int crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key,
crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
crypto_call_req_t *cr)
{
return (0);
}

extern int crypto_mac_update(crypto_context_t ctx, crypto_data_t *data,
crypto_call_req_t *cr)
{
return (0);
}

extern int crypto_mac_final(crypto_context_t ctx, crypto_data_t *data,
crypto_call_req_t *cr)
{
return (0);
}
466 changes: 445 additions & 21 deletions usr/src/man/man1m/zfs.1m

Large diffs are not rendered by default.

40 changes: 36 additions & 4 deletions usr/src/man/man1m/zpool.1m
Expand Up @@ -89,7 +89,7 @@
.Nm
.Cm import
.Fl a
.Op Fl DfmN
.Op Fl DflmN
.Op Fl F Op Fl n
.Op Fl c Ar cachefile Ns | Ns Fl d Ar dir
.Op Fl o Ar mntopts
Expand Down Expand Up @@ -168,7 +168,7 @@
.Ar pool
.Nm
.Cm split
.Op Fl gLnP
.Op Fl gLlnP
.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
.Op Fl R Ar root
.Ar pool newpool
Expand Down Expand Up @@ -1276,7 +1276,7 @@ Lists destroyed pools only.
.Nm
.Cm import
.Fl a
.Op Fl DfmN
.Op Fl DflmN
.Op Fl F Op Fl n
.Op Fl c Ar cachefile Ns | Ns Fl d Ar dir
.Op Fl o Ar mntopts
Expand Down Expand Up @@ -1326,6 +1326,16 @@ transactions.
Not all damaged pools can be recovered by using this option.
If successful, the data from the discarded transactions is irretrievably lost.
This option is ignored if the pool is importable or already imported.
.It Fl l
Indicates that this command will request encryption keys for all encrypted
datasets it attempts to mount as it is bringing the pool online.
Note that if any datasets have a
.Sy keylocation
of
.Sy prompt
this command will block waiting for the keys to be entered.
Without this flag encrypted datasets will be left unavailable until the keys are
loaded.
.It Fl m
Allows a pool to import when there is a missing log device.
Recent transactions can be lost because the log device will be discarded.
Expand Down Expand Up @@ -1423,6 +1433,18 @@ transactions.
Not all damaged pools can be recovered by using this option.
If successful, the data from the discarded transactions is irretrievably lost.
This option is ignored if the pool is importable or already imported.
.It Fl l
Indicates that the zpool command will request encryption keys for all
encrypted datasets it attempts to mount as it is bringing the pool
online.
This is equivalent to running
.Nm Cm mount
on each encrypted dataset immediately after the pool is imported.
If any datasets have a
.Sy prompt
keysource this command will block waiting for the key to be entered.
Otherwise, encrypted datasets will be left unavailable until the keys are
loaded.
.It Fl m
Allows a pool to import when there is a missing log device.
Recent transactions can be lost because the log device will be discarded.
Expand Down Expand Up @@ -1858,7 +1880,7 @@ values.
.It Xo
.Nm
.Cm split
.Op Fl gLnP
.Op Fl gLlnP
.Oo Fl o Ar property Ns = Ns Ar value Oc Ns ...
.Op Fl R Ar root
.Ar pool newpool
Expand All @@ -1884,6 +1906,16 @@ Display real paths for vdevs resolving all symbolic links.
This can be used to look up the current block device name regardless of the
.Pa /dev/disk/
path used to open it.
.It Fl l
Indicates that this command will request encryption keys for all encrypted
datasets it attempts to mount as it is bringing the new pool online.
Note that if any datasets have a
.Sy keylocation
of
.Sy prompt
this command will block waiting for the keys to be entered.
Without this flag encrypted datasets will be left unavailable and unmounted
until the keys are loaded.
.It Fl n
Do dry run, do not actually perform the split.
Print out the expected configuration of
Expand Down
41 changes: 41 additions & 0 deletions usr/src/man/man5/zpool-features.5
Expand Up @@ -623,6 +623,27 @@ Booting off of pools using \fBskein\fR is supported.

.RE

.sp
.ne 2
.na
\fB\fBbookmark_v2\fR\fR
.ad
.RS 4n
.TS
l l .
GUID com.datto:bookmark_v2
READ\-ONLY COMPATIBLE no
DEPENDENCIES extensible_dataset
.TE

This feature enables the creation and management of larger bookmarks which are
needed for other features in ZFS.

This feature becomes \fBactive\fR when a v2 bookmark is created and will be
returned to the \fBenabled\fR state when all v2 bookmarks are destroyed.

.RE

.sp
.ne 2
.na
Expand Down Expand Up @@ -682,6 +703,26 @@ This feature becomes \fBactive\fR when a dedicated allocation class vdev
(dedup or special) is created with zpool create or zpool add. With device
removal, it can be returned to the \fBenabled\fR state if all the top-level
vdevs from an allocation class are removed.
.RE

.sp
.ne 2
.na
\fB\fBcom.datto:encryption\fR\fR
.ad
.RS 4n
.TS
l l .
GUID com.datto:encryption
READ\-ONLY COMPATIBLE no
DEPENDENCIES extensible_dataset
.TE

This feature enables the creation and management of natively encrypted datasets.

This feature becomes \fBactive\fR when an encrypted dataset is created
and will be returned to the \fBenabled\fR state when all datasets that
use this feature are destroyed.

.RE
.sp
Expand Down
142 changes: 142 additions & 0 deletions usr/src/pkg/manifests/system-test-zfstest.mf
Expand Up @@ -48,12 +48,14 @@ dir path=opt/zfs-tests/tests/functional/clean_mirror
dir path=opt/zfs-tests/tests/functional/cli_root
dir path=opt/zfs-tests/tests/functional/cli_root/zdb
dir path=opt/zfs-tests/tests/functional/cli_root/zfs
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_change-key
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_clone
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_copies
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_create
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_destroy
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_get
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_inherit
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_load-key
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_mount
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_program
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_promote
Expand All @@ -67,6 +69,7 @@ dir path=opt/zfs-tests/tests/functional/cli_root/zfs_send
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_set
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_share
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_snapshot
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_unload-key
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_unmount
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_unshare
dir path=opt/zfs-tests/tests/functional/cli_root/zfs_upgrade
Expand Down Expand Up @@ -696,6 +699,31 @@ file path=opt/zfs-tests/tests/functional/cli_root/zfs/setup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs/zfs_001_neg mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs/zfs_002_pos mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs/zfs_003_neg mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_change-key/cleanup \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_change-key/setup \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_child \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_format \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_inherit \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_load \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_location \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_change-key/zfs_change-key_pbkdf2iters \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_clone/cleanup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_clone/setup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_001_neg \
Expand All @@ -718,6 +746,9 @@ file path=opt/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_009_neg \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_010_pos \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_encrypted \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_copies/cleanup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_copies/setup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies.cfg \
Expand Down Expand Up @@ -790,6 +821,12 @@ file \
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib \
mode=0444
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_crypt_combos \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_encrypted \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_destroy/cleanup \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_destroy/setup mode=0555
Expand Down Expand Up @@ -886,6 +923,32 @@ file \
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_inherit/zfs_inherit_003_pos \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_load-key/cleanup \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_load-key/setup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key.cfg \
mode=0444
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_all \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_common.kshlib \
mode=0444
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_file \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_location \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_noop \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_load-key/zfs_load-key_recursive \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_mount/cleanup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_mount/setup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount.cfg \
Expand Down Expand Up @@ -924,6 +987,9 @@ file path=opt/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_all_fail \
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_all_mountpoints \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_encrypted \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_program/cleanup \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_program/setup mode=0555
Expand Down Expand Up @@ -958,6 +1024,9 @@ file \
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_008_pos \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_encryptionroot \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_property/cleanup \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_property/setup mode=0555
Expand Down Expand Up @@ -1009,6 +1078,17 @@ file \
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_014_pos \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_from_encrypted \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_raw_incremental \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_to_encrypted \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_remap/cleanup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_remap/setup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_remap/zfs_remap_cliargs \
Expand Down Expand Up @@ -1064,6 +1144,12 @@ file \
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_014_neg \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_encrypted_child \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_to_encrypted \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_reservation/cleanup \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_reservation/setup \
Expand Down Expand Up @@ -1113,6 +1199,13 @@ file path=opt/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_006_pos \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_007_pos \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_encrypted_unloaded \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_raw \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_set/cache_001_pos \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_set/cache_002_neg \
Expand Down Expand Up @@ -1175,6 +1268,8 @@ file path=opt/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_003_neg \
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib \
mode=0444
file path=opt/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_keylocation \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_share/cleanup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_share/setup mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share.cfg \
Expand Down Expand Up @@ -1234,6 +1329,19 @@ file \
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_009_pos \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_unload-key/cleanup \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_unload-key/setup \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_unload-key/zfs_unload-key \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_unload-key/zfs_unload-key_all \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zfs_unload-key/zfs_unload-key_recursive \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_unmount/cleanup \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zfs_unmount/setup mode=0555
Expand Down Expand Up @@ -1455,6 +1563,12 @@ file \
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_024_pos \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_crypt_combos \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_encrypted \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_001_pos \
mode=0555
Expand Down Expand Up @@ -1540,11 +1654,16 @@ file \
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_history/zpool_history_002_pos \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_import/blockfiles/missing_ivset.dat.bz2 \
mode=0444
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_import/blockfiles/unclean_export.dat.bz2 \
mode=0444
file path=opt/zfs-tests/tests/functional/cli_root/zpool_import/cleanup \
mode=0555
file path=opt/zfs-tests/tests/functional/cli_root/zpool_import/cryptv0.dat.bz2 \
mode=0444
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_import/import_cachefile_device_added \
mode=0555
Expand Down Expand Up @@ -1627,6 +1746,18 @@ file \
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_all_001_pos \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_encrypted \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_encrypted_load \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_errata3 \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_errata4 \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_features_001_pos \
mode=0555
Expand Down Expand Up @@ -1799,6 +1930,9 @@ file \
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_005_pos \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_encrypted_unloaded \
mode=0555
file \
path=opt/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_multiple_copies \
mode=0555
Expand Down Expand Up @@ -2672,9 +2806,17 @@ file path=opt/zfs-tests/tests/functional/rsend/send-c_volume mode=0555
file path=opt/zfs-tests/tests/functional/rsend/send-c_zstreamdump mode=0555
file path=opt/zfs-tests/tests/functional/rsend/send-cpL_varied_recsize \
mode=0555
file path=opt/zfs-tests/tests/functional/rsend/send_encrypted_files mode=0555
file path=opt/zfs-tests/tests/functional/rsend/send_encrypted_hierarchy \
mode=0555
file path=opt/zfs-tests/tests/functional/rsend/send_encrypted_truncated_files \
mode=0555
file path=opt/zfs-tests/tests/functional/rsend/send_freeobjects mode=0555
file path=opt/zfs-tests/tests/functional/rsend/send_mixed_raw mode=0555
file path=opt/zfs-tests/tests/functional/rsend/send_realloc_dnode_size \
mode=0555
file path=opt/zfs-tests/tests/functional/rsend/send_realloc_encrypted_files \
mode=0555
file path=opt/zfs-tests/tests/functional/rsend/setup mode=0555
file path=opt/zfs-tests/tests/functional/scrub_mirror/cleanup mode=0555
file path=opt/zfs-tests/tests/functional/scrub_mirror/default.cfg mode=0444
Expand Down
47 changes: 35 additions & 12 deletions usr/src/test/zfs-tests/runfiles/delphix.run
Expand Up @@ -113,11 +113,16 @@ post =
[/opt/zfs-tests/tests/functional/cli_root/zfs]
tests = ['zfs_001_neg', 'zfs_002_pos', 'zfs_003_neg']

[/opt/zfs-tests/tests/functional/cli_root/zfs_change-key]
tests = ['zfs_change-key', 'zfs_change-key_child', 'zfs_change-key_format',
'zfs_change-key_inherit', 'zfs_change-key_load', 'zfs_change-key_location',
'zfs_change-key_pbkdf2iters']

[/opt/zfs-tests/tests/functional/cli_root/zfs_clone]
tests = ['zfs_clone_001_neg', 'zfs_clone_002_pos', 'zfs_clone_003_pos',
'zfs_clone_004_pos', 'zfs_clone_005_pos', 'zfs_clone_006_pos',
'zfs_clone_007_pos', 'zfs_clone_008_neg', 'zfs_clone_009_neg',
'zfs_clone_010_pos']
'zfs_clone_010_pos', 'zfs_clone_encrypted']

[/opt/zfs-tests/tests/functional/cli_root/zfs_copies]
tests = ['zfs_copies_001_pos', 'zfs_copies_002_pos', 'zfs_copies_003_pos',
Expand All @@ -128,7 +133,8 @@ tests = ['zfs_create_001_pos', 'zfs_create_002_pos', 'zfs_create_003_pos',
'zfs_create_004_pos', 'zfs_create_005_pos', 'zfs_create_006_pos',
'zfs_create_007_pos', 'zfs_create_008_neg', 'zfs_create_009_neg',
'zfs_create_010_neg', 'zfs_create_011_pos', 'zfs_create_012_pos',
'zfs_create_013_pos']
'zfs_create_013_pos', 'zfs_create_encrypted',
'zfs_create_crypt_combos']

[/opt/zfs-tests/tests/functional/cli_root/zfs_destroy]
tests = ['zfs_destroy_001_pos', 'zfs_destroy_002_pos', 'zfs_destroy_003_pos',
Expand All @@ -146,20 +152,25 @@ tests = ['zfs_get_001_pos', 'zfs_get_002_pos', 'zfs_get_003_pos',
[/opt/zfs-tests/tests/functional/cli_root/zfs_inherit]
tests = ['zfs_inherit_001_neg', 'zfs_inherit_002_neg', 'zfs_inherit_003_pos']

[/opt/zfs-tests/tests/functional/cli_root/zfs_load-key]
tests = ['zfs_load-key', 'zfs_load-key_all', 'zfs_load-key_file',
'zfs_load-key_location', 'zfs_load-key_noop', 'zfs_load-key_recursive']

[/opt/zfs-tests/tests/functional/cli_root/zfs_mount]
tests = ['zfs_mount_001_pos', 'zfs_mount_002_pos', 'zfs_mount_003_pos',
'zfs_mount_004_pos', 'zfs_mount_005_pos', 'zfs_mount_006_pos',
'zfs_mount_007_pos', 'zfs_mount_008_pos', 'zfs_mount_009_neg',
'zfs_mount_010_neg', 'zfs_mount_011_neg', 'zfs_mount_012_neg',
'zfs_mount_all_001_pos', 'zfs_mount_all_fail', 'zfs_mount_all_mountpoints']
'zfs_mount_all_001_pos', 'zfs_mount_all_fail', 'zfs_mount_all_mountpoints',
'zfs_mount_encrypted']

[/opt/zfs-tests/tests/functional/cli_root/zfs_program]
tests = ['zfs_program_json']

[/opt/zfs-tests/tests/functional/cli_root/zfs_promote]
tests = ['zfs_promote_001_pos', 'zfs_promote_002_pos', 'zfs_promote_003_pos',
'zfs_promote_004_pos', 'zfs_promote_005_pos', 'zfs_promote_006_neg',
'zfs_promote_007_neg', 'zfs_promote_008_pos']
'zfs_promote_007_neg', 'zfs_promote_008_pos', 'zfs_promote_encryptionroot']

[/opt/zfs-tests/tests/functional/cli_root/zfs_property]
tests = ['zfs_written_property_001_pos']
Expand All @@ -169,7 +180,9 @@ tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_003_pos',
'zfs_receive_005_neg', 'zfs_receive_006_pos',
'zfs_receive_007_neg', 'zfs_receive_008_pos', 'zfs_receive_009_neg',
'zfs_receive_010_pos', 'zfs_receive_011_pos', 'zfs_receive_012_pos',
'zfs_receive_013_pos', 'zfs_receive_014_pos']
'zfs_receive_013_pos', 'zfs_receive_014_pos',
'zfs_receive_from_encrypted', 'zfs_receive_raw',
'zfs_receive_raw_incremental', 'zfs_receive_to_encrypted']

[/opt/zfs-tests/tests/functional/cli_root/zfs_remap]
tests = ['zfs_remap_cliargs', 'zfs_remap_obsolete_counts']
Expand All @@ -179,7 +192,8 @@ tests = ['zfs_rename_001_pos', 'zfs_rename_002_pos', 'zfs_rename_003_pos',
'zfs_rename_004_neg', 'zfs_rename_005_neg', 'zfs_rename_006_pos',
'zfs_rename_007_pos', 'zfs_rename_008_pos', 'zfs_rename_009_neg',
'zfs_rename_010_neg', 'zfs_rename_011_pos', 'zfs_rename_012_neg',
'zfs_rename_013_pos', 'zfs_rename_014_neg']
'zfs_rename_013_pos', 'zfs_rename_014_neg', 'zfs_rename_encrypted_child',
'zfs_rename_to_encrypted']

[/opt/zfs-tests/tests/functional/cli_root/zfs_reservation]
tests = ['zfs_reservation_001_pos', 'zfs_reservation_002_pos']
Expand All @@ -191,7 +205,7 @@ tests = ['zfs_rollback_001_pos', 'zfs_rollback_002_pos',
[/opt/zfs-tests/tests/functional/cli_root/zfs_send]
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_007_pos']
'zfs_send_007_pos', 'zfs_send_encrypted', 'zfs_send_raw']

[/opt/zfs-tests/tests/functional/cli_root/zfs_set]
tests = ['cache_001_pos', 'cache_002_neg', 'canmount_001_pos',
Expand All @@ -202,7 +216,7 @@ tests = ['cache_001_pos', 'cache_002_neg', 'canmount_001_pos',
'ro_props_001_pos', 'share_mount_001_neg', 'snapdir_001_pos',
'user_property_001_pos', 'user_property_002_pos', 'user_property_003_neg',
'user_property_004_pos', 'version_001_neg', 'zfs_set_001_neg',
'zfs_set_002_neg', 'zfs_set_003_neg']
'zfs_set_002_neg', 'zfs_set_003_neg', 'zfs_set_keylocation']

[/opt/zfs-tests/tests/functional/cli_root/zfs_share]
tests = ['zfs_share_001_pos', 'zfs_share_002_pos', 'zfs_share_003_pos',
Expand All @@ -216,6 +230,9 @@ tests = ['zfs_snapshot_001_neg', 'zfs_snapshot_002_neg',
'zfs_snapshot_006_pos', 'zfs_snapshot_007_neg', 'zfs_snapshot_008_neg',
'zfs_snapshot_009_pos']

[/opt/zfs-tests/tests/functional/cli_root/zfs_unload-key]
tests = ['zfs_unload-key', 'zfs_unload-key_all', 'zfs_unload-key_recursive']

[/opt/zfs-tests/tests/functional/cli_root/zfs_unmount]
tests = ['zfs_unmount_001_pos', 'zfs_unmount_002_pos', 'zfs_unmount_003_pos',
'zfs_unmount_004_pos', 'zfs_unmount_005_pos', 'zfs_unmount_006_pos',
Expand Down Expand Up @@ -258,6 +275,7 @@ tests = ['zpool_create_001_pos', 'zpool_create_002_pos',
'zpool_create_018_pos', 'zpool_create_019_pos', 'zpool_create_020_pos',
'zpool_create_021_pos', 'zpool_create_022_pos', 'zpool_create_023_neg',
'zpool_create_024_pos',
'zpool_create_encrypted', 'zpool_create_crypt_combos',
'zpool_create_features_001_pos', 'zpool_create_features_002_pos',
'zpool_create_features_003_pos', 'zpool_create_features_004_neg',
'zpool_create_tempname']
Expand Down Expand Up @@ -306,7 +324,8 @@ tests = ['zpool_import_001_pos', 'zpool_import_002_pos',
'import_rewind_device_replaced',
'import_cachefile_shared_device',
'import_paths_changed',
'import_devices_missing']
'import_devices_missing',
'zpool_import_encrypted', 'zpool_import_encrypted_load']

[/opt/zfs-tests/tests/functional/cli_root/zpool_labelclear]
tests = ['zpool_labelclear_active', 'zpool_labelclear_exported']
Expand Down Expand Up @@ -346,7 +365,8 @@ tags = ['functional', 'cli_root', 'zpool_resilver']
[/opt/zfs-tests/tests/functional/cli_root/zpool_scrub]
tests = ['zpool_scrub_001_neg', 'zpool_scrub_002_pos', 'zpool_scrub_003_pos',
'zpool_scrub_004_pos', 'zpool_scrub_005_pos', 'zpool_scrub_print_repairing',
'zpool_scrub_offline_device', 'zpool_scrub_multiple_copies']
'zpool_scrub_offline_device', 'zpool_scrub_multiple_copies',
'zpool_scrub_encrypted_unloaded']

[/opt/zfs-tests/tests/functional/cli_root/zpool_set]
tests = ['zpool_set_001_pos', 'zpool_set_002_neg', 'zpool_set_003_neg']
Expand Down Expand Up @@ -408,7 +428,7 @@ tests = ['ctime_001_pos' ]
tests = ['zfs_allow_001_pos', 'zfs_allow_002_pos',
'zfs_allow_004_pos', 'zfs_allow_005_pos', 'zfs_allow_006_pos',
'zfs_allow_007_pos', 'zfs_allow_008_pos', 'zfs_allow_009_neg',
'zfs_allow_010_pos', 'zfs_allow_011_neg', 'zfs_allow_012_neg',
'zfs_allow_011_neg', 'zfs_allow_012_neg',
'zfs_unallow_001_pos', 'zfs_unallow_002_pos', 'zfs_unallow_003_pos',
'zfs_unallow_004_pos', 'zfs_unallow_005_pos', 'zfs_unallow_006_pos',
'zfs_unallow_007_neg', 'zfs_unallow_008_neg']
Expand Down Expand Up @@ -583,7 +603,10 @@ tests = ['rsend_001_pos', 'rsend_002_pos', 'rsend_003_pos', 'rsend_004_pos',
'send-c_lz4_disabled', 'send-c_recv_lz4_disabled',
'send-c_mixed_compression', 'send-c_stream_size_estimate', 'send-cD',
'send-c_embedded_blocks', 'send-c_resume', 'send-cpL_varied_recsize',
'send-c_recv_dedup']
'send-c_recv_dedup', 'send_encrypted_files', 'send_encrypted_hierarchy',
'send_encrypted_truncated_files',
'send_realloc_encrypted_files',
'send_mixed_raw']

[/opt/zfs-tests/tests/functional/scrub_mirror]
tests = ['scrub_mirror_001_pos', 'scrub_mirror_002_pos',
Expand Down