This commit is contained in:
Paul Dagnelie 2024-07-31 11:11:30 +12:00 committed by GitHub
commit fae924da12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
81 changed files with 6487 additions and 9117 deletions

View File

@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2019 by Delphix. All rights reserved.
* Copyright (c) 2011, 2024 by Delphix. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright 2016 Nexenta Systems, Inc.
* Copyright (c) 2017, 2018 Lawrence Livermore National Security, LLC.
@ -5790,6 +5790,7 @@ zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
if (BP_GET_DEDUP(bp)) {
ddt_t *ddt;
ddt_entry_t *dde;
ASSERT3P(zilog, ==, NULL);
ddt = ddt_select(zcb->zcb_spa, bp);
ddt_enter(ddt);
@ -5807,9 +5808,19 @@ zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
ddt_exit(ddt);
}
VERIFY3U(zio_wait(zio_claim(NULL, zcb->zcb_spa,
/*
* Theoretically, we could try to track leaks here, but it would
* require also importing the shared log pool and processing the
* chain map and space maps for it. ZDB currently doesn't have
* much facility to support multiple pools at once, so we leave this
* for future work.
*/
if (zilog && zilog->zl_spa != zilog->zl_io_spa)
return;
VERIFY0(zio_wait(zio_claim(NULL, zcb->zcb_spa,
refcnt ? 0 : spa_min_claim_txg(zcb->zcb_spa),
bp, NULL, NULL, ZIO_FLAG_CANFAIL)), ==, 0);
bp, NULL, NULL, ZIO_FLAG_CANFAIL)));
}
static void
@ -6802,6 +6813,48 @@ zdb_brt_entry_compare(const void *zcn1, const void *zcn2)
return (cmp);
}
static int
chain_map_count_blk_cb(spa_t *spa, const blkptr_t *bp, void *arg)
{
(void) spa;
zdb_cb_t *zbc = arg;
zdb_count_block(zbc, NULL, bp, ZDB_OT_OTHER);
return (0);
}
static int
chain_map_count_lr_cb(spa_t *spa, const lr_t *lrc, void *arg)
{
(void) spa;
zdb_cb_t *zbc = arg;
lr_write_t *lr = (lr_write_t *)lrc;
blkptr_t *bp = &lr->lr_blkptr;
if (lrc->lrc_txtype != TX_WRITE || BP_IS_HOLE(bp))
return (0);
zdb_count_block(zbc, NULL, bp, ZDB_OT_OTHER);
return (0);
}
/*
* Count the blocks in the chain maps.
*/
static void
chain_map_count_blocks(spa_t *spa, zdb_cb_t *zbc)
{
avl_tree_t *pool_t = &spa->spa_chain_map;
for (spa_chain_map_pool_t *pool_node = avl_first(pool_t);
pool_node != NULL; pool_node = AVL_NEXT(pool_t, pool_node)) {
avl_tree_t *os_t = &pool_node->scmp_os_tree;
for (spa_chain_map_os_t *os_node = avl_first(os_t);
os_node != NULL; os_node = AVL_NEXT(os_t, os_node)) {
(void) zil_parse_raw(spa, &os_node->scmo_chain_head,
chain_map_count_blk_cb, chain_map_count_lr_cb,
zbc);
}
}
}
static int
dump_block_stats(spa_t *spa)
{
@ -6865,6 +6918,10 @@ dump_block_stats(spa_t *spa)
deleted_livelists_count_blocks(spa, zcb);
if (spa_is_shared_log(spa)) {
chain_map_count_blocks(spa, zcb);
}
if (dump_opt['c'] > 1)
flags |= TRAVERSE_PREFETCH_DATA;
@ -7219,7 +7276,7 @@ zdb_ddt_add_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
zdb_ddt_entry_t *zdde, zdde_search;
if (zb->zb_level == ZB_DNODE_LEVEL || BP_IS_HOLE(bp) ||
BP_IS_EMBEDDED(bp))
BP_IS_EMBEDDED(bp) || (zilog && zilog->zl_spa != zilog->zl_io_spa))
return (0);
if (dump_opt['S'] > 1 && zb->zb_level == ZB_ROOT_LEVEL) {
@ -7990,6 +8047,8 @@ dump_mos_leaks(spa_t *spa)
scip_next_mapping_object);
mos_obj_refd(spa->spa_condensing_indirect_phys.
scip_prev_obsolete_sm_object);
if (spa_is_shared_log(spa))
mos_obj_refd(spa->spa_dsl_pool->dp_chain_map_obj);
if (spa->spa_condensing_indirect_phys.scip_next_mapping_object != 0) {
vdev_indirect_mapping_t *vim =
vdev_indirect_mapping_open(mos,
@ -8152,6 +8211,57 @@ dump_log_spacemap_obsolete_stats(spa_t *spa)
(u_longlong_t)lsos.lsos_total_entries);
}
static void print_blkptr(const blkptr_t *bp)
{
char blkbuf[BP_SPRINTF_LEN];
snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
if (dump_opt['Z'] && BP_GET_COMPRESS(bp) == ZIO_COMPRESS_ZSTD)
snprintf_zstd_header(spa, blkbuf, sizeof (blkbuf), bp);
(void) printf("%s\n", blkbuf);
}
static int
chain_map_dump_blk_cb(spa_t *spa, const blkptr_t *bp, void *arg)
{
(void) spa, (void) arg;
printf("\t\t\tBP: ");
print_blkptr(bp);
return (0);
}
static int
chain_map_dump_lr_cb(spa_t *spa, const lr_t *lrc, void *arg)
{
(void) spa, (void) arg;
lr_write_t *lr = (lr_write_t *)lrc;
blkptr_t *bp = &lr->lr_blkptr;
printf("\t\t\tLR BP: ");
print_blkptr(bp);
return (0);
}
static void
dump_chain_map(spa_t *spa)
{
(void) printf("Chain map contents:\n");
avl_tree_t *pool_t = &spa->spa_chain_map;
for (spa_chain_map_pool_t *pool_node = avl_first(pool_t);
pool_node != NULL; pool_node = AVL_NEXT(pool_t, pool_node)) {
avl_tree_t *os_t = &pool_node->scmp_os_tree;
(void) printf("\tPool entry: %s\n", pool_node->scmp_name);
for (spa_chain_map_os_t *os_node = avl_first(os_t);
os_node != NULL; os_node = AVL_NEXT(os_t, os_node)) {
(void) printf("\t\tObjset entry: %"PRIu64"\n\t\t\t",
os_node->scmo_id);
print_blkptr(&os_node->scmo_chain_head);
(void) zil_parse_raw(spa, &os_node->scmo_chain_head,
chain_map_dump_blk_cb, chain_map_dump_lr_cb, NULL);
}
}
}
static void
dump_zpool(spa_t *spa)
{
@ -8233,6 +8343,9 @@ dump_zpool(spa_t *spa)
(void) dmu_objset_find(spa_name(spa), dump_one_objset,
NULL, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
if (spa_is_shared_log(spa))
dump_chain_map(spa);
if (rc == 0 && !dump_opt['L'])
rc = dump_mos_leaks(spa);

View File

@ -104,7 +104,7 @@ fatal(spa_t *spa, const void *tag, const char *fmt, ...)
if (spa != NULL) {
spa_close(spa, tag);
(void) spa_export(g_pool, NULL, B_TRUE, B_FALSE);
(void) spa_export(g_pool, NULL, B_TRUE, B_FALSE, NULL);
}
va_start(ap, fmt);
@ -1015,7 +1015,8 @@ main(int argc, char **argv)
usage();
}
if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_FALSE) != 0) {
if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_FALSE,
NULL) != 0) {
fatal(NULL, FTAG, "pool export failed; "
"changes may not be committed to disk\n");
}

View File

@ -111,6 +111,7 @@ static int zpool_do_split(int, char **);
static int zpool_do_initialize(int, char **);
static int zpool_do_scrub(int, char **);
static int zpool_do_resilver(int, char **);
static int zpool_do_recycle(int, char **);
static int zpool_do_trim(int, char **);
static int zpool_do_import(int, char **);
@ -182,6 +183,7 @@ typedef enum {
HELP_REMOVE,
HELP_INITIALIZE,
HELP_SCRUB,
HELP_RECYCLE,
HELP_RESILVER,
HELP_TRIM,
HELP_STATUS,
@ -326,6 +328,7 @@ static zpool_command_t command_table[] = {
{ "split", zpool_do_split, HELP_SPLIT },
{ NULL },
{ "initialize", zpool_do_initialize, HELP_INITIALIZE },
{ "recycle", zpool_do_recycle, HELP_RECYCLE },
{ "resilver", zpool_do_resilver, HELP_RESILVER },
{ "scrub", zpool_do_scrub, HELP_SCRUB },
{ "trim", zpool_do_trim, HELP_TRIM },
@ -368,7 +371,8 @@ get_usage(zpool_help_t idx)
case HELP_CLEAR:
return (gettext("\tclear [[--power]|[-nF]] <pool> [device]\n"));
case HELP_CREATE:
return (gettext("\tcreate [-fnd] [-o property=value] ... \n"
return (gettext("\tcreate [-fndL] [-l pool] ... \n"
"\t [-o property=value] ... \n"
"\t [-O file-system-property=value] ... \n"
"\t [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
case HELP_CHECKPOINT:
@ -387,9 +391,10 @@ get_usage(zpool_help_t idx)
"\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] [-l] [-f] [-m] [-N] "
"[-R root] [-F [-n]]\n"
"\t [--rewind-to-checkpoint] <pool | id> [newpool]\n"));
"\t [-d dir | -c cachefile] [-D] [-l] [-f] "
"[-m [-L pool]] [-N] [-R root]\n"
"\t [-F [-n]] [--rewind-to-checkpoint] <pool | id> "
"[newpool]\n"));
case HELP_IOSTAT:
return (gettext("\tiostat [[[-c [script1,script2,...]"
"[-lq]]|[-rw]] [-T d | u] [-ghHLpPvy]\n"
@ -422,6 +427,8 @@ get_usage(zpool_help_t idx)
"[<device> ...]\n"));
case HELP_SCRUB:
return (gettext("\tscrub [-s | -p] [-w] [-e] <pool> ...\n"));
case HELP_RECYCLE:
return (gettext("\trecycle [-nv] <pool> ...\n"));
case HELP_RESILVER:
return (gettext("\tresilver <pool> ...\n"));
case HELP_TRIM:
@ -1169,10 +1176,13 @@ zpool_do_add(int argc, char **argv)
&props, B_TRUE) == 0);
}
}
uint64_t shared_log;
boolean_t has_shared_log = nvlist_lookup_uint64(config,
ZPOOL_CONFIG_SHARED_LOG_POOL, &shared_log) == 0;
/* pass off to make_root_vdev for processing */
nvroot = make_root_vdev(zhp, props, !check_inuse,
check_replication, B_FALSE, dryrun, argc, argv);
check_replication, B_FALSE, dryrun, has_shared_log, argc, argv);
if (nvroot == NULL) {
zpool_close(zhp);
return (1);
@ -1632,9 +1642,11 @@ zpool_do_create(int argc, char **argv)
nvlist_t *fsprops = NULL;
nvlist_t *props = NULL;
char *propval;
zpool_handle_t *shared_log_pool = NULL;
boolean_t is_shared_log = B_FALSE;
/* check options */
while ((c = getopt(argc, argv, ":fndR:m:o:O:t:")) != -1) {
while ((c = getopt(argc, argv, ":fndR:m:o:O:t:l:L")) != -1) {
switch (c) {
case 'f':
force = B_TRUE;
@ -1733,6 +1745,17 @@ zpool_do_create(int argc, char **argv)
goto errout;
tname = optarg;
break;
case 'l':
shared_log_pool = zpool_open(g_zfs, optarg);
if (shared_log_pool == NULL) {
(void) fprintf(stderr, gettext("could not open "
"shared log pool '%s'"), optarg);
goto errout;
}
break;
case 'L':
is_shared_log = B_TRUE;
break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
@ -1773,9 +1796,17 @@ zpool_do_create(int argc, char **argv)
/* pass off to make_root_vdev for bulk processing */
nvroot = make_root_vdev(NULL, props, force, !force, B_FALSE, dryrun,
argc - 1, argv + 1);
shared_log_pool != NULL, argc - 1, argv + 1);
if (nvroot == NULL)
goto errout;
if (shared_log_pool) {
fnvlist_add_uint64(nvroot, ZPOOL_CONFIG_SHARED_LOG_POOL,
fnvlist_lookup_uint64(zpool_get_config(shared_log_pool,
NULL), ZPOOL_CONFIG_POOL_GUID));
}
if (is_shared_log)
fnvlist_add_boolean(nvroot, ZPOOL_CONFIG_IS_SHARED_LOG);
/* make_root_vdev() allows 0 toplevel children if there are spares */
if (!zfs_allocatable_devs(nvroot)) {
@ -2518,7 +2549,8 @@ vdev_health_check_cb(void *hdl_data, nvlist_t *nv, void *data)
*/
static void
print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
nvlist_t *nv, int depth, boolean_t isspare, vdev_rebuild_stat_t *vrs)
nvlist_t *nv, int depth, boolean_t isspare, boolean_t recurse,
vdev_rebuild_stat_t *vrs)
{
nvlist_t **child, *root;
uint_t c, i, vsc, children;
@ -2798,7 +2830,7 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
(void) printf("\n");
for (c = 0; c < children; c++) {
for (c = 0; c < children && recurse; c++) {
uint64_t islog = B_FALSE, ishole = B_FALSE;
/* Don't print logs or holes here */
@ -2822,7 +2854,7 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
vname = zpool_vdev_name(g_zfs, zhp, child[c],
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
print_status_config(zhp, cb, vname, child[c], depth + 2,
isspare, vrs);
isspare, B_TRUE, vrs);
free(vname);
}
}
@ -2833,7 +2865,7 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
*/
static void
print_import_config(status_cbdata_t *cb, const char *name, nvlist_t *nv,
int depth)
int depth, boolean_t recurse)
{
nvlist_t **child;
uint_t c, children;
@ -2899,7 +2931,7 @@ print_import_config(status_cbdata_t *cb, const char *name, nvlist_t *nv,
}
(void) printf("\n");
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
if (!recurse || nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
&child, &children) != 0)
return;
@ -2915,7 +2947,7 @@ print_import_config(status_cbdata_t *cb, const char *name, nvlist_t *nv,
vname = zpool_vdev_name(g_zfs, NULL, child[c],
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
print_import_config(cb, vname, child[c], depth + 2);
print_import_config(cb, vname, child[c], depth + 2, B_TRUE);
free(vname);
}
@ -2996,13 +3028,70 @@ print_class_vdevs(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv,
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
if (cb->cb_print_status)
print_status_config(zhp, cb, name, child[c], 2,
B_FALSE, NULL);
B_FALSE, B_TRUE, NULL);
else
print_import_config(cb, name, child[c], 2);
print_import_config(cb, name, child[c], 2, B_TRUE);
free(name);
}
}
/*
* Find a pool with a matching GUID.
*/
typedef struct find_cbdata {
uint64_t cb_guid;
zpool_handle_t *cb_zhp;
} find_cbdata_t;
static int
find_pool(zpool_handle_t *zhp, void *data)
{
find_cbdata_t *cbp = data;
if (cbp->cb_guid ==
zpool_get_prop_int(zhp, ZPOOL_PROP_GUID, NULL)) {
cbp->cb_zhp = zhp;
return (1);
}
zpool_close(zhp);
return (0);
}
/*
* Given a pool GUID, find the matching pool.
*/
static zpool_handle_t *
find_by_guid(libzfs_handle_t *zhdl, uint64_t pool_guid)
{
find_cbdata_t cb;
cb.cb_guid = pool_guid;
if (zpool_iter(zhdl, find_pool, &cb) != 1)
return (NULL);
return (cb.cb_zhp);
}
static void
print_shared_log(zpool_handle_t *zhp, status_cbdata_t *cb,
uint64_t shared_log_guid)
{
(void) printf(gettext("\tshared log\n"));
zpool_handle_t *shared_log = find_by_guid(g_zfs, shared_log_guid);
VERIFY(shared_log);
nvlist_t *shared_log_config = zpool_get_config(shared_log, NULL);
nvlist_t *nvroot;
VERIFY0(nvlist_lookup_nvlist(shared_log_config, ZPOOL_CONFIG_VDEV_TREE,
&nvroot));
const char *name = zpool_get_name(shared_log);
if (cb->cb_print_status)
print_status_config(zhp, cb, name, nvroot, 2,
B_FALSE, B_FALSE, NULL);
else
print_import_config(cb, name, nvroot, 2, B_FALSE);
zpool_close(shared_log);
}
/*
* Display the status for the given pool.
*/
@ -3376,7 +3465,7 @@ show_import(nvlist_t *config, boolean_t report_error)
if (cb.cb_namewidth < 10)
cb.cb_namewidth = 10;
print_import_config(&cb, name, nvroot, 0);
print_import_config(&cb, name, nvroot, 0, B_TRUE);
print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_BIAS_DEDUP);
print_class_vdevs(NULL, &cb, nvroot, VDEV_ALLOC_BIAS_SPECIAL);
@ -3578,10 +3667,31 @@ import_pools(nvlist_t *pools, nvlist_t *props, char *mntopts, int flags,
uint_t npools = 0;
int err = 0;
nvpair_t *elem = NULL, *next = NULL;
boolean_t first = B_TRUE;
tpool_t *tp = NULL;
if (import->do_all) {
tp = tpool_create(1, 5 * sysconf(_SC_NPROCESSORS_ONLN),
0, NULL);
elem = nvlist_next_nvpair(pools, NULL);
next = nvlist_next_nvpair(pools, elem);
while (elem != NULL) {
verify(nvpair_value_nvlist(elem, &config) == 0);
if (fnvlist_lookup_boolean(config,
ZPOOL_CONFIG_IS_SHARED_LOG)) {
err = do_import(config, NULL, mntopts, props,
flags, mount_tp_nthr);
first = B_FALSE;
fnvlist_remove_nvpair(pools, elem);
}
elem = next;
next = nvlist_next_nvpair(pools, elem);
}
if (err != 0)
return (err);
}
/*
@ -3590,9 +3700,6 @@ import_pools(nvlist_t *pools, nvlist_t *props, char *mntopts, int flags,
* post-process the list to deal with pool state and possible
* duplicate names.
*/
int err = 0;
nvpair_t *elem = NULL;
boolean_t first = B_TRUE;
if (!pool_specified && import->do_all) {
while ((elem = nvlist_next_nvpair(pools, elem)) != NULL)
npools++;
@ -3694,6 +3801,11 @@ import_pools(nvlist_t *pools, nvlist_t *props, char *mntopts, int flags,
"no such pool available\n"), orig_name);
err = B_TRUE;
} else {
if (import->shared_log_guid) {
fnvlist_add_uint64(found_config,
ZPOOL_CONFIG_SHARED_LOG_POOL,
import->shared_log_guid);
}
err |= do_import(found_config, new_name,
mntopts, props, flags, mount_tp_nthr);
}
@ -3982,6 +4094,7 @@ zpool_do_import(int argc, char **argv)
char *cachefile = NULL;
importargs_t idata = { 0 };
char *endptr;
zpool_handle_t *shared_log_pool = NULL;
struct option long_options[] = {
{"rewind-to-checkpoint", no_argument, NULL, CHECKPOINT_OPT},
@ -3989,7 +4102,7 @@ zpool_do_import(int argc, char **argv)
};
/* check options */
while ((c = getopt_long(argc, argv, ":aCc:d:DEfFlmnNo:R:stT:VX",
while ((c = getopt_long(argc, argv, ":aCc:d:DEfFlL:mnNo:R:stT:VX",
long_options, NULL)) != -1) {
switch (c) {
case 'a':
@ -4015,6 +4128,14 @@ zpool_do_import(int argc, char **argv)
case 'l':
flags |= ZFS_IMPORT_LOAD_KEYS;
break;
case 'L':
shared_log_pool = zpool_open(g_zfs, optarg);
if (shared_log_pool == NULL) {
(void) fprintf(stderr, gettext("could not open "
"shared log pool '%s'"), optarg);
goto error;
}
break;
case 'm':
flags |= ZFS_IMPORT_MISSING_LOG;
break;
@ -4087,6 +4208,16 @@ zpool_do_import(int argc, char **argv)
argc -= optind;
argv += optind;
if (shared_log_pool != NULL && ! (flags & ZFS_IMPORT_MISSING_LOG)) {
(void) fprintf(stderr, gettext("-L requires -m\n"));
usage(B_FALSE);
}
if (shared_log_pool != NULL && do_all) {
(void) fprintf(stderr, gettext("-L is incompatible with -a\n"));
usage(B_FALSE);
}
if (cachefile && nsearch != 0) {
(void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
usage(B_FALSE);
@ -4210,6 +4341,10 @@ zpool_do_import(int argc, char **argv)
idata.policy = policy;
idata.do_destroyed = do_destroyed;
idata.do_all = do_all;
if (shared_log_pool) {
idata.shared_log_guid = fnvlist_lookup_uint64(zpool_get_config(
shared_log_pool, NULL), ZPOOL_CONFIG_POOL_GUID);
}
libpc_handle_t lpch = {
.lpc_lib_handle = g_zfs,
@ -6569,7 +6704,7 @@ print_one_column(zpool_prop_t prop, uint64_t value, const char *str,
*/
static void
print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
list_cbdata_t *cb, int depth, boolean_t isspare)
list_cbdata_t *cb, int depth, boolean_t isspare, boolean_t recurse)
{
nvlist_t **child;
vdev_stat_t *vs;
@ -6577,7 +6712,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
char *vname;
boolean_t scripted = cb->cb_scripted;
uint64_t islog = B_FALSE;
const char *dashes = "%-*s - - - - "
const char *dashes = "%*s%-*s - - - - "
"- - - - -\n";
verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
@ -6647,7 +6782,7 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
(void) fputc('\n', stdout);
}
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
if (!recurse || nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
&child, &children) != 0)
return;
@ -6668,7 +6803,8 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
vname = zpool_vdev_name(g_zfs, zhp, child[c],
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
print_list_stats(zhp, vname, child[c], cb, depth + 2, B_FALSE);
print_list_stats(zhp, vname, child[c], cb, depth + 2, B_FALSE,
B_TRUE);
free(vname);
}
@ -6696,27 +6832,45 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
if (!printed) {
/* LINTED E_SEC_PRINTF_VAR_FMT */
(void) printf(dashes, cb->cb_namewidth,
class_name[n]);
(void) printf(dashes, depth + 2, "",
cb->cb_namewidth, class_name[n]);
printed = B_TRUE;
}
vname = zpool_vdev_name(g_zfs, zhp, child[c],
cb->cb_name_flags | VDEV_NAME_TYPE_ID);
print_list_stats(zhp, vname, child[c], cb, depth + 2,
B_FALSE);
print_list_stats(zhp, vname, child[c], cb, depth + 4,
B_FALSE, B_TRUE);
free(vname);
}
}
uint64_t shared_log_guid;
if (name == NULL && nvlist_lookup_uint64(zpool_get_config(zhp, NULL),
ZPOOL_CONFIG_SHARED_LOG_POOL, &shared_log_guid) == 0) {
(void) printf(dashes, depth + 2, "", cb->cb_namewidth,
"shared log");
zpool_handle_t *shared_log = find_by_guid(g_zfs,
shared_log_guid);
VERIFY(shared_log);
nvlist_t *shared_log_config = zpool_get_config(shared_log,
NULL);
nvlist_t *nvroot;
VERIFY0(nvlist_lookup_nvlist(shared_log_config,
ZPOOL_CONFIG_VDEV_TREE, &nvroot));
print_list_stats(shared_log, zpool_get_name(shared_log), nvroot,
cb, depth + 4, B_FALSE, B_FALSE);
zpool_close(shared_log);
}
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
&child, &children) == 0 && children > 0) {
/* LINTED E_SEC_PRINTF_VAR_FMT */
(void) printf(dashes, cb->cb_namewidth, "cache");
(void) printf(dashes, depth + 2, "", cb->cb_namewidth, "cache");
for (c = 0; c < children; c++) {
vname = zpool_vdev_name(g_zfs, zhp, child[c],
cb->cb_name_flags);
print_list_stats(zhp, vname, child[c], cb, depth + 2,
B_FALSE);
print_list_stats(zhp, vname, child[c], cb, depth + 4,
B_FALSE, B_TRUE);
free(vname);
}
}
@ -6724,12 +6878,12 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
&children) == 0 && children > 0) {
/* LINTED E_SEC_PRINTF_VAR_FMT */
(void) printf(dashes, cb->cb_namewidth, "spare");
(void) printf(dashes, depth + 2, "", cb->cb_namewidth, "spare");
for (c = 0; c < children; c++) {
vname = zpool_vdev_name(g_zfs, zhp, child[c],
cb->cb_name_flags);
print_list_stats(zhp, vname, child[c], cb, depth + 2,
B_TRUE);
print_list_stats(zhp, vname, child[c], cb, depth + 4,
B_TRUE, B_TRUE);
free(vname);
}
}
@ -6751,7 +6905,7 @@ list_callback(zpool_handle_t *zhp, void *data)
config = zpool_get_config(zhp, NULL);
verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
&nvroot) == 0);
print_list_stats(zhp, NULL, nvroot, cbp, 0, B_FALSE);
print_list_stats(zhp, NULL, nvroot, cbp, 0, B_FALSE, B_TRUE);
}
return (0);
@ -6908,7 +7062,7 @@ zpool_do_attach_or_replace(int argc, char **argv, int replacing)
boolean_t rebuild = B_FALSE;
boolean_t wait = B_FALSE;
int c;
nvlist_t *nvroot;
nvlist_t *nvroot, *config;
char *poolname, *old_disk, *new_disk;
zpool_handle_t *zhp;
nvlist_t *props = NULL;
@ -6991,7 +7145,7 @@ zpool_do_attach_or_replace(int argc, char **argv, int replacing)
return (1);
}
if (zpool_get_config(zhp, NULL) == NULL) {
if ((config = zpool_get_config(zhp, NULL)) == NULL) {
(void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
poolname);
zpool_close(zhp);
@ -7013,8 +7167,12 @@ zpool_do_attach_or_replace(int argc, char **argv, int replacing)
}
}
uint64_t shared_log;
boolean_t has_shared_log = nvlist_lookup_uint64(config,
ZPOOL_CONFIG_SHARED_LOG_POOL, &shared_log) == 0;
nvroot = make_root_vdev(zhp, props, force, B_FALSE, replacing, B_FALSE,
argc, argv);
has_shared_log, argc, argv);
if (nvroot == NULL) {
zpool_close(zhp);
nvlist_free(props);
@ -7938,6 +8096,116 @@ zpool_do_resilver(int argc, char **argv)
B_FALSE, scrub_callback, &cb));
}
struct recycle_data {
boolean_t dryrun;
boolean_t verbose;
};
static void
print_recycle_info(nvlist_t *nvl, boolean_t dryrun)
{
printf("Cleaned up%s: [", dryrun ? " (dry run)" : "");
nvpair_t *elem = NULL;
boolean_t first = B_TRUE;
while ((elem = nvlist_next_nvpair(nvl, elem))) {
printf("%s%s", first ? "" : ",\n\t", nvpair_name(elem));
first = B_FALSE;
}
printf("]\n");
}
static int
recycle_callback(zpool_handle_t *zhp, void *data)
{
struct recycle_data *rd = data;
nvlist_t *nvl;
int err = lzc_recycle(zpool_get_name(zhp), NULL, rd->dryrun, &nvl);
if (err)
return (err);
if (rd->verbose)
print_recycle_info(nvl, rd->dryrun);
nvlist_free(nvl);
return (0);
}
/*
* zpool recycle [-a] [-n] [-v] <pool> [pool]...
*
* Cleans up chain maps for non-attached client pools
*/
int
zpool_do_recycle(int argc, char **argv)
{
int c;
struct recycle_data rd = {0};
boolean_t doall = B_FALSE;
/* check options */
while ((c = getopt(argc, argv, "nva")) != -1) {
switch (c) {
case 'n':
rd.dryrun = B_TRUE;
zfs_fallthrough;
case 'v':
rd.verbose = B_TRUE;
break;
case 'a':
doall = B_TRUE;
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
usage(B_FALSE);
}
}
argc -= optind;
argv += optind;
if (argc < 1) {
(void) fprintf(stderr, gettext("missing pool name argument\n"));
usage(B_FALSE);
} else if (argc == 1 && !doall) {
(void) fprintf(stderr, gettext("missing client pools\n"));
usage(B_FALSE);
} else if (argc > 1 && doall) {
(void) fprintf(stderr, gettext("specific client pools and "
"do_all\n"));
usage(B_FALSE);
}
if (doall) {
return (for_each_pool(argc, argv, B_TRUE, NULL, ZFS_TYPE_POOL,
B_FALSE, recycle_callback, &rd));
}
const char *pool = argv[0];
argc--;
argv++;
nvlist_t *clients = NULL;
if (argc > 0)
clients = fnvlist_alloc();
while (argc > 0) {
fnvlist_add_boolean(clients, argv[0]);
argc--;
argv++;
}
nvlist_t *nvl;
int err = lzc_recycle(pool, clients, rd.dryrun, &nvl);
if (clients)
nvlist_free(clients);
if (err)
return (err);
if (rd.verbose)
print_recycle_info(nvl, rd.dryrun);
nvlist_free(nvl);
return (0);
}
/*
* zpool trim [-d] [-r <rate>] [-c | -s] <pool> [<device> ...]
*
@ -8838,7 +9106,8 @@ print_spares(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **spares,
for (i = 0; i < nspares; i++) {
name = zpool_vdev_name(g_zfs, zhp, spares[i],
cb->cb_name_flags);
print_status_config(zhp, cb, name, spares[i], 2, B_TRUE, NULL);
print_status_config(zhp, cb, name, spares[i], 2, B_TRUE, B_TRUE,
NULL);
free(name);
}
}
@ -8859,7 +9128,7 @@ print_l2cache(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **l2cache,
name = zpool_vdev_name(g_zfs, zhp, l2cache[i],
cb->cb_name_flags);
print_status_config(zhp, cb, name, l2cache[i], 2,
B_FALSE, NULL);
B_FALSE, B_TRUE, NULL);
free(name);
}
}
@ -9401,12 +9670,18 @@ status_callback(zpool_handle_t *zhp, void *data)
printf("\n");
print_status_config(zhp, cbp, zpool_get_name(zhp), nvroot, 0,
B_FALSE, NULL);
B_FALSE, B_TRUE, NULL);
print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_BIAS_DEDUP);
print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_BIAS_SPECIAL);
print_class_vdevs(zhp, cbp, nvroot, VDEV_ALLOC_CLASS_LOGS);
uint64_t shared_log_guid;
if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SHARED_LOG_POOL,
&shared_log_guid) == 0) {
print_shared_log(zhp, cbp, shared_log_guid);
}
if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
&l2cache, &nl2cache) == 0)
print_l2cache(zhp, cbp, l2cache, nl2cache);

View File

@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023 by Delphix. All rights reserved.
*/
#ifndef ZPOOL_UTIL_H
@ -57,8 +58,8 @@ char *zpool_get_cmd_search_path(void);
*/
nvlist_t *make_root_vdev(zpool_handle_t *zhp, nvlist_t *props, int force,
int check_rep, boolean_t replacing, boolean_t dryrun, int argc,
char **argv);
int check_rep, boolean_t replacing, boolean_t dryrun,
boolean_t have_shlog, int argc, char **argv);
nvlist_t *split_mirror_vdev(zpool_handle_t *zhp, char *newname,
nvlist_t *props, splitflags_t flags, int argc, char **argv);

View File

@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2018 by Delphix. All rights reserved.
* Copyright (c) 2013, 2023 by Delphix. All rights reserved.
* Copyright (c) 2016, 2017 Intel Corporation.
* Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
*/
@ -1488,7 +1488,7 @@ draid_config_by_type(nvlist_t *nv, const char *type, uint64_t children)
* because the program is just going to exit anyway.
*/
static nvlist_t *
construct_spec(nvlist_t *props, int argc, char **argv)
construct_spec(nvlist_t *props, boolean_t have_shlog, int argc, char **argv)
{
nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
@ -1735,6 +1735,12 @@ construct_spec(nvlist_t *props, int argc, char **argv)
goto spec_out;
}
if (seen_logs && have_shlog) {
(void) fprintf(stderr, gettext("invalid vdev specification: "
"cannot mix shared log and log devices"));
goto spec_out;
}
if (seen_logs && nlogs == 0) {
(void) fprintf(stderr, gettext("invalid vdev specification: "
"log requires at least 1 device\n"));
@ -1779,7 +1785,8 @@ split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
uint_t c, children;
if (argc > 0) {
if ((newroot = construct_spec(props, argc, argv)) == NULL) {
if ((newroot = construct_spec(props, B_FALSE, argc, argv)) ==
NULL) {
(void) fprintf(stderr, gettext("Unable to build a "
"pool from the specified devices\n"));
return (NULL);
@ -1853,7 +1860,8 @@ num_normal_vdevs(nvlist_t *nvroot)
*/
nvlist_t *
make_root_vdev(zpool_handle_t *zhp, nvlist_t *props, int force, int check_rep,
boolean_t replacing, boolean_t dryrun, int argc, char **argv)
boolean_t replacing, boolean_t dryrun, boolean_t have_shlog, int argc,
char **argv)
{
nvlist_t *newroot;
nvlist_t *poolconfig = NULL;
@ -1864,7 +1872,7 @@ make_root_vdev(zpool_handle_t *zhp, nvlist_t *props, int force, int check_rep,
* that we have a valid specification, and that all devices can be
* opened.
*/
if ((newroot = construct_spec(props, argc, argv)) == NULL)
if ((newroot = construct_spec(props, have_shlog, argc, argv)) == NULL)
return (NULL);
if (zhp && ((poolconfig = zpool_get_config(zhp, NULL)) == NULL)) {

View File

@ -3048,7 +3048,7 @@ ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
* an export concurrently.
*/
VERIFY0(spa_open(zo->zo_pool, &spa, FTAG));
int error = spa_destroy(zo->zo_pool);
int error = spa_destroy(zo->zo_pool, NULL);
if (error != EBUSY && error != ZFS_ERR_EXPORT_IN_PROGRESS) {
fatal(B_FALSE, "spa_destroy(%s) returned unexpected value %d",
spa->spa_name, error);
@ -3150,7 +3150,7 @@ ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
/*
* Clean up from previous runs.
*/
(void) spa_destroy(name);
(void) spa_destroy(name, NULL);
raidz_children = ztest_get_raidz_children(ztest_spa);
@ -3604,7 +3604,7 @@ ztest_split_pool(ztest_ds_t *zd, uint64_t id)
}
/* clean up the old pool, if any */
(void) spa_destroy("splitp");
(void) spa_destroy("splitp", NULL);
spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
@ -7384,7 +7384,7 @@ ztest_spa_import_export(char *oldname, char *newname)
/*
* Clean up from previous runs.
*/
(void) spa_destroy(newname);
(void) spa_destroy(newname, NULL);
/*
* Get the pool's configuration and guid.
@ -7405,7 +7405,7 @@ ztest_spa_import_export(char *oldname, char *newname)
/*
* Export it.
*/
VERIFY0(spa_export(oldname, &config, B_FALSE, B_FALSE));
VERIFY0(spa_export(oldname, &config, B_FALSE, B_FALSE, NULL));
ztest_walk_pool_directory("pools after export");
@ -8556,7 +8556,7 @@ ztest_init(ztest_shared_t *zs)
/*
* Create the storage pool.
*/
(void) spa_destroy(ztest_opts.zo_pool);
(void) spa_destroy(ztest_opts.zo_pool, NULL);
ztest_shared->zs_vdev_next_leaf = 0;
zs->zs_splits = 0;
zs->zs_mirrors = ztest_opts.zo_mirrors;

View File

@ -159,6 +159,8 @@ typedef enum zfs_error {
EZFS_SHAREFAILED, /* filesystem share failed */
EZFS_RAIDZ_EXPAND_IN_PROGRESS, /* a raidz is currently expanding */
EZFS_ASHIFT_MISMATCH, /* can't add vdevs with different ashifts */
/* Operation cannot be performed on a shared log pool */
EZFS_SHAREDLOG,
EZFS_UNKNOWN
} zfs_error_t;
@ -344,6 +346,7 @@ _LIBZFS_H uint64_t zpool_vdev_path_to_guid(zpool_handle_t *zhp,
const char *path);
_LIBZFS_H const char *zpool_get_state_str(zpool_handle_t *);
_LIBZFS_H zpool_handle_t *zpool_get_shared_log(zpool_handle_t *);
/*
* Functions to manage pool properties

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2012, 2020 by Delphix. All rights reserved.
* Copyright (c) 2012, 2023 by Delphix. All rights reserved.
* Copyright 2017 RackTop Systems.
* Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
* Copyright (c) 2019 Datto Inc.
@ -156,11 +156,18 @@ _LIBZFS_CORE_H int lzc_wait_fs(const char *, zfs_wait_activity_t, boolean_t *);
_LIBZFS_CORE_H int lzc_set_bootenv(const char *, const nvlist_t *);
_LIBZFS_CORE_H int lzc_get_bootenv(const char *, nvlist_t **);
_LIBZFS_CORE_H int lzc_recycle(const char *, nvlist_t *, boolean_t,
nvlist_t **);
_LIBZFS_CORE_H int lzc_get_vdev_prop(const char *, nvlist_t *, nvlist_t **);
_LIBZFS_CORE_H int lzc_set_vdev_prop(const char *, nvlist_t *, nvlist_t **);
_LIBZFS_CORE_H int lzc_scrub(zfs_ioc_t, const char *, nvlist_t *, nvlist_t **);
_LIBZFS_CORE_H int lzc_pool_destroy(const char *, const char *, nvlist_t **);
_LIBZFS_CORE_H int lzc_pool_export(const char *, const char *, boolean_t,
boolean_t, nvlist_t **);
#ifdef __cplusplus
}
#endif

View File

@ -81,6 +81,7 @@ typedef struct importargs {
nvlist_t *policy; /* load policy (max txg, rewind, etc.) */
boolean_t do_destroyed;
boolean_t do_all;
uint64_t shared_log_guid;
} importargs_t;
typedef struct libpc_handle {

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright 2014 HybridCluster. All rights reserved.
@ -390,6 +390,7 @@ typedef struct dmu_buf {
#define DMU_POOL_ZPOOL_CHECKPOINT "com.delphix:zpool_checkpoint"
#define DMU_POOL_LOG_SPACEMAP_ZAP "com.delphix:log_spacemap_zap"
#define DMU_POOL_DELETED_CLONES "com.delphix:deleted_clones"
#define DMU_POOL_CHAIN_MAP_OBJ "com.delphix:chain_map_obj"
/*
* Allocate an object from this objset. The range of object numbers

View File

@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
/*
* Copyright (c) 2012, 2016 by Delphix. All rights reserved.
* Copyright (c) 2012, 2013 by Delphix. All rights reserved.
*/
#ifndef _SYS_DMU_TX_H
@ -154,6 +154,7 @@ void dmu_tx_wait(dmu_tx_t *tx);
*/
extern dmu_tx_t *dmu_tx_create_assigned(struct dsl_pool *dp, uint64_t txg);
dmu_tx_t *dmu_tx_create_mos(struct dsl_pool *dp);
/*
* These routines are only called by the DMU.
*/

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2018 by Delphix. All rights reserved.
* Copyright (c) 2013, 2023 by Delphix. All rights reserved.
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
*/
@ -106,6 +106,7 @@ typedef struct dsl_pool {
uint64_t dp_bptree_obj;
uint64_t dp_empty_bpobj;
bpobj_t dp_obsolete_bpobj;
uint64_t dp_chain_map_obj;
struct dsl_scan *dp_scan;

View File

@ -851,6 +851,8 @@ typedef struct zpool_load_policy {
#define ZPOOL_CONFIG_EXPANSION_TIME "expansion_time" /* not stored */
#define ZPOOL_CONFIG_REBUILD_STATS "org.openzfs:rebuild_stats"
#define ZPOOL_CONFIG_COMPATIBILITY "compatibility"
#define ZPOOL_CONFIG_SHARED_LOG_POOL "com.delphix:shared_log_pool"
#define ZPOOL_CONFIG_IS_SHARED_LOG "com.delphix:is_shared_log"
/*
* The persistent vdev state is stored as separate values rather than a single
@ -1518,7 +1520,10 @@ typedef enum zfs_ioc {
ZFS_IOC_VDEV_GET_PROPS, /* 0x5a55 */
ZFS_IOC_VDEV_SET_PROPS, /* 0x5a56 */
ZFS_IOC_POOL_SCRUB, /* 0x5a57 */
ZFS_IOC_POOL_PREFETCH, /* 0x5a58 */
ZFS_IOC_POOL_PREFETCH, /* 0x5158 */
ZFS_IOC_POOL_RECYCLE, /* 0x5a59 */
ZFS_IOC_POOL_DESTROY_NEW, /* 0x5a59 */
ZFS_IOC_POOL_EXPORT_NEW, /* 0x5a5a */
/*
* Per-platform (Optional) - 8/128 numbers reserved.
@ -1748,6 +1753,23 @@ typedef enum {
*/
#define ZPOOL_PREFETCH_TYPE "prefetch_type"
/*
* The following names are used when invoking ZFS_IOC_POOL_RECYCLE.
*/
#define ZPOOL_RECYCLE_DRYRUN "dryrun"
#define ZPOOL_RECYCLE_CLIENTS "clients"
/*
* The following are names used when invoking ZFS_IOC_POOL_EXPORT_NEW.
*/
#define ZPOOL_EXPORT_FORCE "force"
#define ZPOOL_EXPORT_HARDFORCE "hardforce"
/*
* Name that is used to convey client information for shared log pools.
*/
#define ZPOOL_SHARED_LOG_CLIENTS "clients"
/*
* Flags for ZFS_IOC_VDEV_SET_STATE
*/

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2018 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
* Copyright (c) 2017, Intel Corporation.
*/
@ -37,14 +37,20 @@
extern "C" {
#endif
typedef enum metaslab_type {
METASLAB_TYPE_NORMAL,
METASLAB_TYPE_VIRTUAL,
} metaslab_type_t;
typedef struct metaslab_ops {
const char *msop_name;
uint64_t (*msop_alloc)(metaslab_t *, uint64_t);
metaslab_type_t msop_type;
} metaslab_ops_t;
extern const metaslab_ops_t zfs_metaslab_ops;
extern const metaslab_ops_t zfs_virtual_ops;
int metaslab_init(metaslab_group_t *, uint64_t, uint64_t, uint64_t,
metaslab_t **);

View File

@ -24,7 +24,7 @@
*/
/*
* Copyright (c) 2011, 2019 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
*/
#ifndef _SYS_METASLAB_IMPL_H
@ -179,7 +179,15 @@ typedef struct metaslab_class_allocator {
struct metaslab_class {
kmutex_t mc_lock;
spa_t *mc_spa;
const metaslab_ops_t *mc_ops;
const metaslab_ops_t *mc_ops;
/*
* If this field is set, this is a "virtual" metaslab class. In
* actuality, the allocations will be done by the spa this is pointing
* to, using another pool for our storage. This enables the shared
* SLOG architecture. If this field is set, most of the other fields
* in this metaslab class are not used, and should be unset.
*/
struct spa *mc_virtual;
/*
* Track the number of metaslab groups that have been initialized

View File

@ -749,11 +749,11 @@ extern int spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
extern int spa_import(char *pool, nvlist_t *config, nvlist_t *props,
uint64_t flags);
extern nvlist_t *spa_tryimport(nvlist_t *tryconfig);
extern int spa_destroy(const char *pool);
extern int spa_destroy(const char *pool, nvlist_t *ounvl);
extern int spa_checkpoint(const char *pool);
extern int spa_checkpoint_discard(const char *pool);
extern int spa_export(const char *pool, nvlist_t **oldconfig, boolean_t force,
boolean_t hardforce);
boolean_t hardforce, nvlist_t *outnvl);
extern int spa_reset(const char *pool);
extern void spa_async_request(spa_t *spa, int flag);
extern void spa_async_unrequest(spa_t *spa, int flag);
@ -836,6 +836,8 @@ void spa_select_allocator(zio_t *zio);
extern kmutex_t spa_namespace_lock;
extern avl_tree_t spa_namespace_avl;
extern kcondvar_t spa_namespace_cv;
extern avl_tree_t spa_shared_log_avl;
extern kmutex_t spa_shared_log_lock;
/*
* SPA configuration functions in spa_config.c
@ -1028,7 +1030,8 @@ extern void spa_altroot(spa_t *, char *, size_t);
extern uint32_t spa_sync_pass(spa_t *spa);
extern char *spa_name(spa_t *spa);
extern uint64_t spa_guid(spa_t *spa);
extern uint64_t spa_load_guid(spa_t *spa);
extern uint64_t spa_const_guid(const spa_t *spa);
extern uint64_t spa_load_guid(const spa_t *spa);
extern uint64_t spa_last_synced_txg(spa_t *spa);
extern uint64_t spa_first_txg(spa_t *spa);
extern uint64_t spa_syncing_txg(spa_t *spa);
@ -1123,7 +1126,8 @@ extern boolean_t spa_multihost(spa_t *spa);
extern uint32_t spa_get_hostid(spa_t *spa);
extern void spa_activate_allocation_classes(spa_t *, dmu_tx_t *);
extern boolean_t spa_livelist_delete_check(spa_t *spa);
extern boolean_t spa_is_shared_log(const spa_t *spa);
extern boolean_t spa_uses_shared_log(const spa_t *spa);
extern boolean_t spa_mmp_remote_host_activity(spa_t *spa);
extern spa_mode_t spa_mode(spa_t *spa);
@ -1221,6 +1225,17 @@ extern void spa_export_os(spa_t *spa);
extern void spa_activate_os(spa_t *spa);
extern void spa_deactivate_os(spa_t *spa);
extern void spa_zil_map_insert(spa_t *spa, objset_t *os,
const blkptr_t *prev_bp, blkptr_t *bp);
extern void spa_zil_map_set_final(spa_t *spa, objset_t *os, blkptr_t *bp);
extern void spa_zil_delete(spa_t *spa, objset_t *os);
extern void spa_zil_header_convert(spa_t *spa, objset_t *os, blkptr_t *bp);
extern void spa_zil_header_mask(spa_t *spa, blkptr_t *bp);
extern spa_t *spa_get_shared_log_pool(spa_t *spa);
extern int spa_recycle_all(spa_t *spa, boolean_t dryrun, nvlist_t *outnvl);
extern int spa_recycle_clients(spa_t *spa, nvlist_t *clients,
boolean_t dryrun, nvlist_t *outnvl);
/* module param call functions */
int param_set_deadman_ziotime(ZFS_MODULE_PARAM_ARGS);
int param_set_deadman_synctime(ZFS_MODULE_PARAM_ARGS);

View File

@ -217,6 +217,44 @@ typedef enum spa_config_source {
SPA_CONFIG_SRC_MOS /* MOS, but not always from right txg */
} spa_config_source_t;
typedef enum spa_pool_type {
SPA_TYPE_NORMAL = 0,
SPA_TYPE_SHARED_LOG,
} spa_pool_type_t;
typedef struct spa_zil_update_head {
avl_node_t szuh_avl;
list_t szuh_list;
uint64_t szuh_id;
blkptr_t szuh_chain_head;
boolean_t szuh_set;
// Only used for the special once-per-pool entry
boolean_t szuh_force;
} spa_zil_update_head_t;
typedef struct spa_zil_update {
list_node_t szu_list;
blkptr_t szu_chain_head;
} spa_zil_update_t;
typedef struct spa_zil_chain_map_value {
char szcmv_pool_name[ZFS_MAX_DATASET_NAME_LEN];
blkptr_t szcmv_bp;
} spa_zil_chain_map_value_t;
typedef struct spa_chain_map_os {
avl_node_t scmo_avl;
uint64_t scmo_id;
blkptr_t scmo_chain_head;
} spa_chain_map_os_t;
typedef struct spa_chain_map_pool {
avl_node_t scmp_avl;
uint64_t scmp_guid;
char scmp_name[ZFS_MAX_DATASET_NAME_LEN];
avl_tree_t scmp_os_tree;
} spa_chain_map_pool_t;
struct spa {
/*
* Fields protected by spa_namespace_lock.
@ -224,6 +262,9 @@ struct spa {
char spa_name[ZFS_MAX_DATASET_NAME_LEN]; /* pool name */
char *spa_comment; /* comment */
avl_node_t spa_avl; /* node in spa_namespace_avl */
avl_node_t spa_log_avl; /* node in spa_shared_log_avl */
/* node in spa_registered_clients */
list_node_t spa_client_node;
nvlist_t *spa_config; /* last synced config */
nvlist_t *spa_config_syncing; /* currently syncing config */
nvlist_t *spa_config_splitting; /* config for splitting */
@ -244,6 +285,13 @@ struct spa {
boolean_t spa_is_initializing; /* true while opening pool */
boolean_t spa_is_exporting; /* true while exporting pool */
kthread_t *spa_export_thread; /* valid during pool export */
/* true if pool's log device is shared log */
boolean_t spa_uses_shared_log;
/*
* true if pool was imported with MISSING_LOGS and couldn't find
* its shared log pool
*/
boolean_t spa_discarding_shared_log;
kthread_t *spa_load_thread; /* loading, no namespace lock */
metaslab_class_t *spa_normal_class; /* normal data class */
metaslab_class_t *spa_log_class; /* intent log data class */
@ -303,6 +351,7 @@ struct spa {
boolean_t spa_extreme_rewind; /* rewind past deferred frees */
kmutex_t spa_scrub_lock; /* resilver/scrub lock */
uint64_t spa_scrub_inflight; /* in-flight scrub bytes */
spa_pool_type_t spa_pool_type;
/* in-flight verification bytes */
uint64_t spa_load_verify_bytes;
@ -477,6 +526,17 @@ struct spa {
*/
spa_config_lock_t spa_config_lock[SCL_LOCKS]; /* config changes */
zfs_refcount_t spa_refcount; /* number of opens */
/* Only used if type is shared log */
kmutex_t spa_chain_map_lock;
avl_tree_t spa_chain_map;
list_t spa_registered_clients;
/* Only used during syncing context if using shared log */
kmutex_t spa_zil_map_lock;
avl_tree_t spa_zil_map;
list_t spa_zil_deletes;
taskq_t *spa_chain_map_taskq;
};
extern char *spa_config_path;
@ -495,6 +555,7 @@ extern void spa_set_deadman_ziotime(hrtime_t ns);
extern const char *spa_history_zone(void);
extern const char *zfs_active_allocator;
extern int param_set_active_allocator_common(const char *val);
extern void spa_set_pool_type(spa_t *);
#ifdef __cplusplus
}

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2012, 2023 by Delphix. All rights reserved.
*/
/* Portions Copyright 2010 Robert Milkowski */
@ -563,10 +563,15 @@ typedef int zil_parse_lr_func_t(zilog_t *zilog, const lr_t *lr, void *arg,
typedef int zil_replay_func_t(void *arg1, void *arg2, boolean_t byteswap);
typedef int zil_get_data_t(void *arg, uint64_t arg2, lr_write_t *lr, char *dbuf,
struct lwb *lwb, zio_t *zio);
typedef int zil_parse_raw_blk_func_t(spa_t *spa, const blkptr_t *bp, void *arg);
typedef int zil_parse_raw_lr_func_t(spa_t *spa, const lr_t *lr, void *arg);
extern int zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func,
zil_parse_lr_func_t *parse_lr_func, void *arg, uint64_t txg,
boolean_t decrypt);
extern int zil_parse_raw(spa_t *spa, const blkptr_t *bp,
zil_parse_raw_blk_func_t *parse_func,
zil_parse_raw_lr_func_t *parse_lr_func, void *arg);
extern void zil_init(void);
extern void zil_fini(void);
@ -594,6 +599,8 @@ extern void zil_commit_impl(zilog_t *zilog, uint64_t oid);
extern void zil_remove_async(zilog_t *zilog, uint64_t oid);
extern int zil_reset(const char *osname, void *txarg);
extern int zil_clear(struct dsl_pool *dp,
struct dsl_dataset *ds, void *txarg);
extern int zil_claim(struct dsl_pool *dp,
struct dsl_dataset *ds, void *txarg);
extern int zil_check_log_chain(struct dsl_pool *dp,
@ -620,6 +627,8 @@ extern void zil_sums_fini(zil_sums_t *zs);
extern void zil_kstat_values_update(zil_kstat_values_t *zs,
zil_sums_t *zil_sums);
extern boolean_t zil_shared_log(zilog_t *zl);
extern int zil_replay_disable;
#ifdef __cplusplus

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2012, 2023 by Delphix. All rights reserved.
*/
/* Portions Copyright 2010 Robert Milkowski */
@ -190,6 +190,7 @@ struct zilog {
kmutex_t zl_lock; /* protects most zilog_t fields */
struct dsl_pool *zl_dmu_pool; /* DSL pool */
spa_t *zl_spa; /* handle for read/write log */
spa_t *zl_io_spa; /* handle for read/write log */
const zil_header_t *zl_header; /* log header buffer */
objset_t *zl_os; /* object set we're logging */
zil_get_data_t *zl_get_data; /* callback to get object content */

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2011, 2018 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2017, Intel Corporation.
@ -82,6 +82,7 @@ typedef enum spa_feature {
SPA_FEATURE_AVZ_V2,
SPA_FEATURE_REDACTION_LIST_SPILL,
SPA_FEATURE_RAIDZ_EXPANSION,
SPA_FEATURE_SHARED_LOG,
SPA_FEATURES
} spa_feature_t;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2019 Joyent, Inc.
* Copyright (c) 2011, 2020 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
* Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
* Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
* Copyright (c) 2013 Martin Matuska. All rights reserved.
@ -3869,6 +3869,10 @@ 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 EINVAL:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"cannot create filesystem in shared log pool"));
return (zfs_error(hdl, EZFS_SHAREDLOG, errbuf));
#ifdef _ILP32
case EOVERFLOW:
/*

View File

@ -246,6 +246,39 @@ zpool_pool_state_to_name(pool_state_t state)
return (gettext("UNKNOWN"));
}
struct shared_log_cbdata {
uint64_t guid;
zpool_handle_t *shared_log_pool;
};
static int
shared_log_cb(zpool_handle_t *hdl, void *arg)
{
struct shared_log_cbdata *data = arg;
if (fnvlist_lookup_uint64(hdl->zpool_config, ZPOOL_CONFIG_POOL_GUID) ==
data->guid) {
data->shared_log_pool = hdl;
}
return (0);
}
zpool_handle_t *
zpool_get_shared_log(zpool_handle_t *zhp)
{
uint64_t guid;
if (nvlist_lookup_uint64(zhp->zpool_config,
ZPOOL_CONFIG_SHARED_LOG_POOL, &guid) != 0) {
return (NULL);
}
struct shared_log_cbdata data;
data.guid = guid;
int err = zpool_iter(zhp->zpool_hdl, shared_log_cb, &data);
if (err != 0) {
return (NULL);
}
return (data.shared_log_pool);
}
/*
* Given a pool handle, return the pool health string ("ONLINE", "DEGRADED",
* "SUSPENDED", etc).
@ -272,6 +305,10 @@ zpool_get_state_str(zpool_handle_t *zhp)
vdev_stat_t *vs = (vdev_stat_t *)fnvlist_lookup_uint64_array(
nvroot, ZPOOL_CONFIG_VDEV_STATS, &vsc);
str = zpool_state_to_name(vs->vs_state, vs->vs_aux);
zpool_handle_t *shared_log = zpool_get_shared_log(zhp);
if (vs->vs_state == VDEV_STATE_HEALTHY && shared_log != NULL) {
str = zpool_get_state_str(shared_log);
}
}
return (str);
}
@ -1681,23 +1718,48 @@ zpool_destroy(zpool_handle_t *zhp, const char *log_str)
libzfs_handle_t *hdl = zhp->zpool_hdl;
char errbuf[ERRBUFLEN];
if (zhp->zpool_state == POOL_STATE_ACTIVE &&
(zfp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_FILESYSTEM)) == NULL)
return (-1);
nvlist_t *outnvl;
int err = lzc_pool_destroy(zhp->zpool_name, log_str, &outnvl);
if (err == ZFS_ERR_IOC_CMD_UNAVAIL) {
if (zhp->zpool_state == POOL_STATE_ACTIVE &&
(zfp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_FILESYSTEM))
== NULL)
return (-1);
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_history = (uint64_t)(uintptr_t)log_str;
(void) strlcpy(zc.zc_name, zhp->zpool_name,
sizeof (zc.zc_name));
zc.zc_history = (uint64_t)(uintptr_t)log_str;
if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0)
err = errno;
else
err = 0;
}
if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
if (err != 0) {
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
"cannot destroy '%s'"), zhp->zpool_name);
if (errno == EROFS) {
if (err == EROFS) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"one or more devices is read only"));
(void) zfs_error(hdl, EZFS_BADDEV, errbuf);
} else if (err == EBUSY && outnvl != NULL) {
nvlist_t *clients = fnvlist_lookup_nvlist(outnvl,
ZPOOL_SHARED_LOG_CLIENTS);
nvpair_t *elem = nvlist_next_nvpair(clients, NULL);
char buf[ERRBUFLEN];
int idx = snprintf(buf, ERRBUFLEN, "%s",
nvpair_name(elem));
while ((elem = nvlist_next_nvpair(clients, elem))
!= NULL && idx < ERRBUFLEN) {
idx += snprintf(buf + idx, ERRBUFLEN - idx,
", %s", nvpair_name(elem));
}
zfs_error_aux(hdl, "pool has active clients: %s", buf);
(void) zfs_error(hdl, EZFS_BUSY, errbuf);
fnvlist_free(outnvl);
} else {
(void) zpool_standard_error(hdl, errno, errbuf);
(void) zpool_standard_error(hdl, err, errbuf);
}
if (zfp)
@ -1897,27 +1959,52 @@ zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce,
{
zfs_cmd_t zc = {"\0"};
(void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
zc.zc_cookie = force;
zc.zc_guid = hardforce;
zc.zc_history = (uint64_t)(uintptr_t)log_str;
nvlist_t *outnvl;
int err = lzc_pool_export(zhp->zpool_name, log_str, force, hardforce,
&outnvl);
if (err == ZFS_ERR_IOC_CMD_UNAVAIL) {
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
switch (errno) {
case EXDEV:
zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
"use '-f' to override the following errors:\n"
"'%s' has an active shared spare which could be"
" used by other pools once '%s' is exported."),
zhp->zpool_name, zhp->zpool_name);
return (zfs_error_fmt(zhp->zpool_hdl, EZFS_ACTIVE_SPARE,
dgettext(TEXT_DOMAIN, "cannot export '%s'"),
zhp->zpool_name));
default:
return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
dgettext(TEXT_DOMAIN, "cannot export '%s'"),
zhp->zpool_name));
(void) strlcpy(zc.zc_name, zhp->zpool_name,
sizeof (zc.zc_name));
zc.zc_cookie = force;
zc.zc_guid = hardforce;
zc.zc_history = (uint64_t)(uintptr_t)log_str;
if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0)
err = errno;
else
err = 0;
}
if (err == EXDEV) {
zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
"use '-f' to override the following errors:\n"
"'%s' has an active shared spare which could be"
" used by other pools once '%s' is exported."),
zhp->zpool_name, zhp->zpool_name);
return (zfs_error_fmt(zhp->zpool_hdl, EZFS_ACTIVE_SPARE,
dgettext(TEXT_DOMAIN, "cannot export '%s'"),
zhp->zpool_name));
} else if (err == EBUSY && outnvl != NULL) {
libzfs_handle_t *hdl = zhp->zpool_hdl;
nvlist_t *clients = fnvlist_lookup_nvlist(outnvl,
ZPOOL_SHARED_LOG_CLIENTS);
nvpair_t *elem = nvlist_next_nvpair(clients, NULL);
char buf[ERRBUFLEN];
int idx = snprintf(buf, ERRBUFLEN, "%s", nvpair_name(elem));
while ((elem = nvlist_next_nvpair(clients, elem)) != NULL &&
idx < ERRBUFLEN) {
idx += snprintf(buf + idx, ERRBUFLEN - idx, ", %s",
nvpair_name(elem));
}
fnvlist_free(outnvl);
zfs_error_aux(hdl, "pool has active clients: %s", buf);
return (zfs_error_fmt(hdl, EZFS_BUSY, dgettext(TEXT_DOMAIN,
"cannot export '%s'"), zhp->zpool_name));
} else if (err != 0) {
return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
dgettext(TEXT_DOMAIN, "cannot export '%s'"),
zhp->zpool_name));
}
return (0);
@ -2350,6 +2437,11 @@ zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
"the maximum allowable length"));
(void) zfs_error(hdl, EZFS_NAMETOOLONG, desc);
break;
case ESRCH:
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"shared log pool no longer contains this client"));
(void) zfs_error(hdl, EZFS_NOENT, desc);
break;
default:
(void) zpool_standard_error(hdl, error, desc);
zpool_explain_recover(hdl,

View File

@ -510,6 +510,10 @@ zpool_get_status(zpool_handle_t *zhp, const char **msgid,
zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata,
compatibility);
if (ret == ZPOOL_STATUS_OK && zpool_get_shared_log(zhp)) {
ret = check_status(zpool_get_shared_log(zhp)->zpool_config,
B_FALSE, errata, compatibility);
}
if (msgid != NULL) {
if (ret >= NMSGID)

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2012, 2020 by Delphix. All rights reserved.
* Copyright (c) 2012, 2023 by Delphix. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright 2017 RackTop Systems.
* Copyright (c) 2017 Open-E, Inc. All Rights Reserved.
@ -1927,3 +1927,39 @@ lzc_get_bootenv(const char *pool, nvlist_t **outnvl)
{
return (lzc_ioctl(ZFS_IOC_GET_BOOTENV, pool, NULL, outnvl));
}
int
lzc_recycle(const char *pool, nvlist_t *clients, boolean_t dryrun,
nvlist_t **outnvl)
{
nvlist_t *args = fnvlist_alloc();
fnvlist_add_boolean_value(args, ZPOOL_RECYCLE_DRYRUN, dryrun);
if (clients != NULL)
fnvlist_add_nvlist(args, ZPOOL_RECYCLE_CLIENTS, clients);
int err = lzc_ioctl(ZFS_IOC_POOL_RECYCLE, pool, args, outnvl);
fnvlist_free(args);
return (err);
}
int
lzc_pool_destroy(const char *pool, const char *log_str, nvlist_t **outnvl)
{
nvlist_t *args = fnvlist_alloc();
fnvlist_add_string(args, ZPOOL_HIST_CMD, log_str);
int err = lzc_ioctl(ZFS_IOC_POOL_DESTROY_NEW, pool, args, outnvl);
fnvlist_free(args);
return (err);
}
int
lzc_pool_export(const char *pool, const char *log_str, boolean_t force,
boolean_t hardforce, nvlist_t **outnvl)
{
nvlist_t *args = fnvlist_alloc();
fnvlist_add_string(args, ZPOOL_HIST_CMD, log_str);
fnvlist_add_boolean_value(args, ZPOOL_EXPORT_FORCE, force);
fnvlist_add_boolean_value(args, ZPOOL_EXPORT_HARDFORCE, hardforce);
int err = lzc_ioctl(ZFS_IOC_POOL_EXPORT_NEW, pool, args, outnvl);
fnvlist_free(args);
return (err);
}

View File

@ -16,6 +16,67 @@
</elf-function-symbols>
<abi-instr address-size='64' path='lib/libzfsbootenv/lzbe_device.c' language='LANG_C99'>
<type-decl name='char' size-in-bits='8' id='a84c031d'/>
<type-decl name='int' size-in-bits='32' id='95e97e5e'/>
<type-decl name='unnamed-enum-underlying-type-32' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='9cac1fee'/>
<type-decl name='void' id='48b5725f'/>
<enum-decl name='lzbe_flags' id='2b77720b'>
<underlying-type type-id='9cac1fee'/>
<enumerator name='lzbe_add' value='0'/>
<enumerator name='lzbe_replace' value='1'/>
</enum-decl>
<typedef-decl name='lzbe_flags_t' type-id='2b77720b' id='a1936f04'/>
<pointer-type-def type-id='a84c031d' size-in-bits='64' id='26a90f95'/>
<pointer-type-def type-id='26a90f95' size-in-bits='64' id='9b23c9ad'/>
<qualified-type-def type-id='a84c031d' const='yes' id='9b45d938'/>
<pointer-type-def type-id='9b45d938' size-in-bits='64' id='80f4b756'/>
<function-decl name='lzbe_set_boot_device' mangled-name='lzbe_set_boot_device' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_set_boot_device'>
<parameter type-id='80f4b756' name='pool'/>
<parameter type-id='a1936f04' name='flag'/>
<parameter type-id='80f4b756' name='device'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='lzbe_get_boot_device' mangled-name='lzbe_get_boot_device' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_get_boot_device'>
<parameter type-id='80f4b756' name='pool'/>
<parameter type-id='9b23c9ad' name='device'/>
<return type-id='95e97e5e'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfsbootenv/lzbe_pair.c' language='LANG_C99'>
<type-decl name='unsigned long int' size-in-bits='64' id='7359adad'/>
<typedef-decl name='size_t' type-id='7359adad' id='b59d7dce'/>
<pointer-type-def type-id='48b5725f' size-in-bits='64' id='eaa32e2f'/>
<pointer-type-def type-id='eaa32e2f' size-in-bits='64' id='63e171df'/>
<function-decl name='lzbe_nvlist_get' mangled-name='lzbe_nvlist_get' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_nvlist_get'>
<parameter type-id='80f4b756' name='pool'/>
<parameter type-id='80f4b756' name='key'/>
<parameter type-id='63e171df' name='ptr'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='lzbe_nvlist_set' mangled-name='lzbe_nvlist_set' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_nvlist_set'>
<parameter type-id='80f4b756' name='pool'/>
<parameter type-id='80f4b756' name='key'/>
<parameter type-id='eaa32e2f' name='ptr'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='lzbe_nvlist_free' mangled-name='lzbe_nvlist_free' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_nvlist_free'>
<parameter type-id='eaa32e2f' name='ptr'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='lzbe_add_pair' mangled-name='lzbe_add_pair' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_add_pair'>
<parameter type-id='eaa32e2f' name='ptr'/>
<parameter type-id='80f4b756' name='key'/>
<parameter type-id='80f4b756' name='type'/>
<parameter type-id='eaa32e2f' name='value'/>
<parameter type-id='b59d7dce' name='size'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='lzbe_remove_pair' mangled-name='lzbe_remove_pair' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_remove_pair'>
<parameter type-id='eaa32e2f' name='ptr'/>
<parameter type-id='80f4b756' name='key'/>
<return type-id='95e97e5e'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfsbootenv/lzbe_util.c' language='LANG_C99'>
<array-type-def dimensions='1' type-id='a84c031d' size-in-bits='8' id='89feb1ec'>
<subrange length='1' type-id='7359adad' id='52f813b4'/>
</array-type-def>
@ -25,55 +86,9 @@
<class-decl name='_IO_codecvt' is-struct='yes' visibility='default' is-declaration-only='yes' id='a4036571'/>
<class-decl name='_IO_marker' is-struct='yes' visibility='default' is-declaration-only='yes' id='010ae0b9'/>
<class-decl name='_IO_wide_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='79bd3751'/>
<class-decl name='libzfs_handle' is-struct='yes' visibility='default' is-declaration-only='yes' id='c8a9d9d8'/>
<class-decl name='zpool_handle' is-struct='yes' visibility='default' is-declaration-only='yes' id='67002a8a'/>
<type-decl name='int' size-in-bits='32' id='95e97e5e'/>
<type-decl name='long int' size-in-bits='64' id='bd54fe1a'/>
<type-decl name='signed char' size-in-bits='8' id='28577a57'/>
<type-decl name='unnamed-enum-underlying-type-32' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='9cac1fee'/>
<type-decl name='unsigned int' size-in-bits='32' id='f0981eeb'/>
<type-decl name='unsigned long int' size-in-bits='64' id='7359adad'/>
<type-decl name='unsigned short int' size-in-bits='16' id='8efea9e5'/>
<type-decl name='variadic parameter type' id='2c1145c5'/>
<type-decl name='void' id='48b5725f'/>
<typedef-decl name='zpool_handle_t' type-id='67002a8a' id='b1efc708'/>
<typedef-decl name='libzfs_handle_t' type-id='c8a9d9d8' id='95942d0c'/>
<enum-decl name='lzbe_flags' id='2b77720b'>
<underlying-type type-id='9cac1fee'/>
<enumerator name='lzbe_add' value='0'/>
<enumerator name='lzbe_replace' value='1'/>
</enum-decl>
<typedef-decl name='lzbe_flags_t' type-id='2b77720b' id='a1936f04'/>
<class-decl name='nvlist' size-in-bits='192' is-struct='yes' visibility='default' id='ac266fd9'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='nvl_version' type-id='3ff5601b' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='32'>
<var-decl name='nvl_nvflag' type-id='8f92235e' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='64'>
<var-decl name='nvl_priv' type-id='9c313c2d' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='128'>
<var-decl name='nvl_flag' type-id='8f92235e' visibility='default'/>
</data-member>
<data-member access='public' layout-offset-in-bits='160'>
<var-decl name='nvl_pad' type-id='3ff5601b' visibility='default'/>
</data-member>
</class-decl>
<typedef-decl name='nvlist_t' type-id='ac266fd9' id='8e8d4be3'/>
<enum-decl name='boolean_t' naming-typedef-id='c19b74c3' id='f58c8277'>
<underlying-type type-id='9cac1fee'/>
<enumerator name='B_FALSE' value='0'/>
<enumerator name='B_TRUE' value='1'/>
</enum-decl>
<typedef-decl name='boolean_t' type-id='f58c8277' id='c19b74c3'/>
<typedef-decl name='int32_t' type-id='33f57a65' id='3ff5601b'/>
<typedef-decl name='uint32_t' type-id='62f1140c' id='8f92235e'/>
<typedef-decl name='uint64_t' type-id='8910171f' id='9c313c2d'/>
<typedef-decl name='__int32_t' type-id='95e97e5e' id='33f57a65'/>
<typedef-decl name='__uint32_t' type-id='f0981eeb' id='62f1140c'/>
<typedef-decl name='__uint64_t' type-id='7359adad' id='8910171f'/>
<typedef-decl name='__off_t' type-id='bd54fe1a' id='79989e9c'/>
<typedef-decl name='__off64_t' type-id='bd54fe1a' id='724e4de6'/>
<typedef-decl name='FILE' type-id='ec1ed955' id='aa12d1ba'/>
@ -167,413 +182,15 @@
<var-decl name='_unused2' type-id='664ac0b7' visibility='default'/>
</data-member>
</class-decl>
<typedef-decl name='size_t' type-id='7359adad' id='b59d7dce'/>
<pointer-type-def type-id='aa12d1ba' size-in-bits='64' id='822cd80b'/>
<qualified-type-def type-id='822cd80b' restrict='yes' id='e75a27e9'/>
<pointer-type-def type-id='ec1ed955' size-in-bits='64' id='dca988a5'/>
<pointer-type-def type-id='a4036571' size-in-bits='64' id='570f8c59'/>
<pointer-type-def type-id='bb4788fa' size-in-bits='64' id='cecf4ea7'/>
<pointer-type-def type-id='010ae0b9' size-in-bits='64' id='e4c6fa61'/>
<pointer-type-def type-id='79bd3751' size-in-bits='64' id='c65a1f29'/>
<pointer-type-def type-id='a84c031d' size-in-bits='64' id='26a90f95'/>
<pointer-type-def type-id='26a90f95' size-in-bits='64' id='9b23c9ad'/>
<qualified-type-def type-id='9b23c9ad' restrict='yes' id='8c85230f'/>
<qualified-type-def type-id='a84c031d' const='yes' id='9b45d938'/>
<pointer-type-def type-id='9b45d938' size-in-bits='64' id='80f4b756'/>
<qualified-type-def type-id='80f4b756' restrict='yes' id='9d26089a'/>
<pointer-type-def type-id='80f4b756' size-in-bits='64' id='7d3cd834'/>
<qualified-type-def type-id='8e8d4be3' const='yes' id='693c3853'/>
<pointer-type-def type-id='693c3853' size-in-bits='64' id='22cce67b'/>
<pointer-type-def type-id='95942d0c' size-in-bits='64' id='b0382bb3'/>
<pointer-type-def type-id='8e8d4be3' size-in-bits='64' id='5ce45b60'/>
<pointer-type-def type-id='5ce45b60' size-in-bits='64' id='857bb57e'/>
<pointer-type-def type-id='9c313c2d' size-in-bits='64' id='5d6479ae'/>
<pointer-type-def type-id='48b5725f' size-in-bits='64' id='eaa32e2f'/>
<pointer-type-def type-id='b1efc708' size-in-bits='64' id='4c81de99'/>
<class-decl name='_IO_codecvt' is-struct='yes' visibility='default' is-declaration-only='yes' id='a4036571'/>
<class-decl name='_IO_marker' is-struct='yes' visibility='default' is-declaration-only='yes' id='010ae0b9'/>
<class-decl name='_IO_wide_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='79bd3751'/>
<class-decl name='libzfs_handle' is-struct='yes' visibility='default' is-declaration-only='yes' id='c8a9d9d8'/>
<class-decl name='zpool_handle' is-struct='yes' visibility='default' is-declaration-only='yes' id='67002a8a'/>
<function-decl name='libzfs_init' visibility='default' binding='global' size-in-bits='64'>
<return type-id='b0382bb3'/>
</function-decl>
<function-decl name='libzfs_fini' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='b0382bb3'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='libzfs_error_description' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='b0382bb3'/>
<return type-id='80f4b756'/>
</function-decl>
<function-decl name='zpool_open' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='b0382bb3'/>
<parameter type-id='80f4b756'/>
<return type-id='4c81de99'/>
</function-decl>
<function-decl name='zpool_close' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='4c81de99'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='zpool_set_bootenv' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='4c81de99'/>
<parameter type-id='22cce67b'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='zpool_get_bootenv' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='4c81de99'/>
<parameter type-id='857bb57e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_free' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='nvlist_lookup_uint64' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='22cce67b'/>
<parameter type-id='80f4b756'/>
<parameter type-id='5d6479ae'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_lookup_string' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='22cce67b'/>
<parameter type-id='80f4b756'/>
<parameter type-id='7d3cd834'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_exists' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='22cce67b'/>
<parameter type-id='80f4b756'/>
<return type-id='c19b74c3'/>
</function-decl>
<function-decl name='fnvlist_alloc' visibility='default' binding='global' size-in-bits='64'>
<return type-id='5ce45b60'/>
</function-decl>
<function-decl name='fnvlist_free' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='fnvlist_add_uint64' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='9c313c2d'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='fnvlist_add_string' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='fnvlist_remove' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='free' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='eaa32e2f'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='strncmp' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<parameter type-id='b59d7dce'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='strdup' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<return type-id='26a90f95'/>
</function-decl>
<function-decl name='strlen' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<return type-id='b59d7dce'/>
</function-decl>
<function-decl name='__fprintf_chk' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='e75a27e9'/>
<parameter type-id='95e97e5e'/>
<parameter type-id='9d26089a'/>
<parameter is-variadic='yes'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='__asprintf_chk' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='8c85230f'/>
<parameter type-id='95e97e5e'/>
<parameter type-id='9d26089a'/>
<parameter is-variadic='yes'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='lzbe_set_boot_device' mangled-name='lzbe_set_boot_device' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_set_boot_device'>
<parameter type-id='80f4b756' name='pool'/>
<parameter type-id='a1936f04' name='flag'/>
<parameter type-id='80f4b756' name='device'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='lzbe_get_boot_device' mangled-name='lzbe_get_boot_device' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_get_boot_device'>
<parameter type-id='80f4b756' name='pool'/>
<parameter type-id='9b23c9ad' name='device'/>
<return type-id='95e97e5e'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfsbootenv/lzbe_pair.c' language='LANG_C99'>
<type-decl name='short int' size-in-bits='16' id='a2185560'/>
<type-decl name='unsigned char' size-in-bits='8' id='002ac4a6'/>
<typedef-decl name='uchar_t' type-id='002ac4a6' id='d8bf0010'/>
<typedef-decl name='uint_t' type-id='f0981eeb' id='3502e3ff'/>
<typedef-decl name='int8_t' type-id='2171a512' id='ee31ee44'/>
<typedef-decl name='int16_t' type-id='03896e23' id='23bd8cb5'/>
<typedef-decl name='int64_t' type-id='0c9942d2' id='9da381c4'/>
<typedef-decl name='uint8_t' type-id='c51d6389' id='b96825af'/>
<typedef-decl name='uint16_t' type-id='253c2d2a' id='149c6638'/>
<typedef-decl name='__int8_t' type-id='28577a57' id='2171a512'/>
<typedef-decl name='__uint8_t' type-id='002ac4a6' id='c51d6389'/>
<typedef-decl name='__int16_t' type-id='a2185560' id='03896e23'/>
<typedef-decl name='__uint16_t' type-id='8efea9e5' id='253c2d2a'/>
<typedef-decl name='__int64_t' type-id='bd54fe1a' id='0c9942d2'/>
<qualified-type-def type-id='c19b74c3' const='yes' id='12373e33'/>
<pointer-type-def type-id='12373e33' size-in-bits='64' id='c5f6c15b'/>
<qualified-type-def type-id='80f4b756' const='yes' id='b99c00c9'/>
<pointer-type-def type-id='b99c00c9' size-in-bits='64' id='13956559'/>
<qualified-type-def type-id='23bd8cb5' const='yes' id='75f7b0c5'/>
<pointer-type-def type-id='75f7b0c5' size-in-bits='64' id='a3eb883d'/>
<qualified-type-def type-id='3ff5601b' const='yes' id='922df12b'/>
<pointer-type-def type-id='922df12b' size-in-bits='64' id='1f526493'/>
<qualified-type-def type-id='9da381c4' const='yes' id='f07b7694'/>
<pointer-type-def type-id='f07b7694' size-in-bits='64' id='505bed1a'/>
<qualified-type-def type-id='ee31ee44' const='yes' id='721c32d4'/>
<pointer-type-def type-id='721c32d4' size-in-bits='64' id='a06445da'/>
<qualified-type-def type-id='22cce67b' const='yes' id='d2816df0'/>
<pointer-type-def type-id='d2816df0' size-in-bits='64' id='3bbfee2e'/>
<qualified-type-def type-id='d8bf0010' const='yes' id='a9125480'/>
<pointer-type-def type-id='a9125480' size-in-bits='64' id='d1db479e'/>
<qualified-type-def type-id='149c6638' const='yes' id='b01a5ac8'/>
<pointer-type-def type-id='b01a5ac8' size-in-bits='64' id='1b7d11c6'/>
<qualified-type-def type-id='8f92235e' const='yes' id='b9930aae'/>
<pointer-type-def type-id='b9930aae' size-in-bits='64' id='a6798dcc'/>
<qualified-type-def type-id='9c313c2d' const='yes' id='c3b7ba7d'/>
<pointer-type-def type-id='c3b7ba7d' size-in-bits='64' id='713a56f5'/>
<qualified-type-def type-id='b96825af' const='yes' id='2b61797f'/>
<pointer-type-def type-id='2b61797f' size-in-bits='64' id='9f7200cf'/>
<pointer-type-def type-id='eaa32e2f' size-in-bits='64' id='63e171df'/>
<function-decl name='nvlist_alloc' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='857bb57e'/>
<parameter type-id='3502e3ff'/>
<parameter type-id='95e97e5e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_dup' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='22cce67b'/>
<parameter type-id='857bb57e'/>
<parameter type-id='95e97e5e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_boolean_value' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='c19b74c3'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_byte' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='d8bf0010'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_int8' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='ee31ee44'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_uint8' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='b96825af'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_int16' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='23bd8cb5'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_uint16' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='149c6638'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_int32' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='3ff5601b'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_uint32' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='8f92235e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_int64' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='9da381c4'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_uint64' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='9c313c2d'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_string' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_nvlist' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='22cce67b'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_boolean_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='c5f6c15b'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_byte_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='d1db479e'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_int8_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='a06445da'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_uint8_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='9f7200cf'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_int16_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='a3eb883d'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_uint16_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='1b7d11c6'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_int32_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='1f526493'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_uint32_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='a6798dcc'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_int64_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='505bed1a'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_uint64_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='713a56f5'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_string_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='13956559'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_add_nvlist_array' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='3bbfee2e'/>
<parameter type-id='3502e3ff'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_remove_all' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='nvlist_lookup_nvlist' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='5ce45b60'/>
<parameter type-id='80f4b756'/>
<parameter type-id='857bb57e'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='strcmp' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='80f4b756'/>
<parameter type-id='80f4b756'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='lzbe_nvlist_get' mangled-name='lzbe_nvlist_get' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_nvlist_get'>
<parameter type-id='80f4b756' name='pool'/>
<parameter type-id='80f4b756' name='key'/>
<parameter type-id='63e171df' name='ptr'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='lzbe_nvlist_set' mangled-name='lzbe_nvlist_set' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_nvlist_set'>
<parameter type-id='80f4b756' name='pool'/>
<parameter type-id='80f4b756' name='key'/>
<parameter type-id='eaa32e2f' name='ptr'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='lzbe_nvlist_free' mangled-name='lzbe_nvlist_free' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_nvlist_free'>
<parameter type-id='eaa32e2f' name='ptr'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='lzbe_add_pair' mangled-name='lzbe_add_pair' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_add_pair'>
<parameter type-id='eaa32e2f' name='ptr'/>
<parameter type-id='80f4b756' name='key'/>
<parameter type-id='80f4b756' name='type'/>
<parameter type-id='eaa32e2f' name='value'/>
<parameter type-id='b59d7dce' name='size'/>
<return type-id='95e97e5e'/>
</function-decl>
<function-decl name='lzbe_remove_pair' mangled-name='lzbe_remove_pair' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_remove_pair'>
<parameter type-id='eaa32e2f' name='ptr'/>
<parameter type-id='80f4b756' name='key'/>
<return type-id='95e97e5e'/>
</function-decl>
</abi-instr>
<abi-instr address-size='64' path='lib/libzfsbootenv/lzbe_util.c' language='LANG_C99'>
<function-decl name='nvlist_print' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='822cd80b'/>
<parameter type-id='5ce45b60'/>
<return type-id='48b5725f'/>
</function-decl>
<function-decl name='lzbe_bootenv_print' mangled-name='lzbe_bootenv_print' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='lzbe_bootenv_print'>
<parameter type-id='80f4b756' name='pool'/>
<parameter type-id='80f4b756' name='nvlist'/>

View File

@ -21,7 +21,7 @@
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2012, 2024 by Delphix. All rights reserved.
* Copyright 2015 RackTop Systems.
* Copyright (c) 2016, Intel Corporation.
* Copyright (c) 2021, Colm Buckley <colm@tuatha.org>
@ -635,6 +635,18 @@ get_configs(libpc_handle_t *hdl, pool_list_t *pl, boolean_t active_ok,
ZPOOL_CONFIG_HOSTNAME, hostname);
}
if (nvlist_lookup_uint64(tmp,
ZPOOL_CONFIG_SHARED_LOG_POOL, &guid) == 0) {
fnvlist_add_uint64(config,
ZPOOL_CONFIG_SHARED_LOG_POOL, guid);
}
if (fnvlist_lookup_boolean(tmp,
ZPOOL_CONFIG_IS_SHARED_LOG)) {
fnvlist_add_boolean(config,
ZPOOL_CONFIG_IS_SHARED_LOG);
}
config_seen = B_TRUE;
}
@ -1511,6 +1523,11 @@ zpool_find_import_impl(libpc_handle_t *hdl, importargs_t *iarg,
iarg->guid == this_guid;
}
if (matched) {
if (iarg->shared_log_guid) {
fnvlist_add_uint64(config,
ZPOOL_CONFIG_SHARED_LOG_POOL,
iarg->shared_log_guid);
}
/*
* Verify all remaining entries can be opened
* exclusively. This will prune all underlying

View File

@ -19,7 +19,7 @@
.\" CDDL HEADER END
.\"
.\" Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright (c) 2012, 2018 by Delphix. All rights reserved.
.\" Copyright (c) 2012, 2023 by Delphix. All rights reserved.
.\" Copyright (c) 2012 Cyril Plisko. All Rights Reserved.
.\" Copyright (c) 2017 Datto Inc.
.\" Copyright (c) 2018 George Melikov. All Rights Reserved.
@ -178,6 +178,13 @@ However, raidz vdev types are not supported for the intent log.
For more information, see the
.Sx Intent Log
section.
.It Sy shared log
A separate ZFS storage pool used as a shared intent log device.
Only one shared log can be specified at pool creation or import, and a normal
log device cannot also be specified.
For more information, see the
.Sx Intent Log
section.
.It Sy dedup
A device solely dedicated for deduplication tables.
The redundancy of this device should match the redundancy of the other normal
@ -395,6 +402,9 @@ In addition, log devices are imported and exported as part of the pool
that contains them.
Mirrored devices can be removed by specifying the top-level mirror vdev.
.
A shared log pool can be used as a log device; this pool can be used by
several different "client" pools to provide easier management of space
to be used for the intent log.
.Ss Cache Devices
Devices can be added to a storage pool as
.Qq cache devices .

View File

@ -19,7 +19,7 @@
.\" CDDL HEADER END
.\"
.\" Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright (c) 2012, 2018 by Delphix. All rights reserved.
.\" Copyright (c) 2012, 2023 by Delphix. All rights reserved.
.\" Copyright (c) 2012 Cyril Plisko. All Rights Reserved.
.\" Copyright (c) 2017 Datto Inc.
.\" Copyright (c) 2018 George Melikov. All Rights Reserved.
@ -37,8 +37,9 @@
.Sh SYNOPSIS
.Nm zpool
.Cm create
.Op Fl dfn
.Op Fl dfnL
.Op Fl m Ar mountpoint
.Op Fl l Ar pool
.Oo Fl o Ar property Ns = Ns Ar value Oc Ns
.Oo Fl o Sy feature@ Ns Ar feature Ns = Ns Ar value Oc
.Op Fl o Ar compatibility Ns = Ns Sy off Ns | Ns Sy legacy Ns | Ns Ar file Ns Oo , Ns Ar file Oc Ns
@ -167,6 +168,18 @@ Displays the configuration that would be used without actually creating the
pool.
The actual pool creation can still fail due to insufficient privileges or
device sharing.
.It Fl L
Create the pool as a shared log pool.
Shared log pools cannot have filesystems or ZVOLs created in them, but they
can be used as a virtual log device by several other pools, allowing more
efficient use of physical log devices.
Only one shared log pool can be imported on the system at a given
time.
.It Fl l Ar pool
Create the pool using the provided pool as the log device.
The provided pool must be a shared log pool (created using the
.Fl L
flag), and no other log devices can be specified as part of the vdev tree.
.It Fl o Ar property Ns = Ns Ar value
Sets the given pool properties.
See

View File

@ -19,7 +19,7 @@
.\" CDDL HEADER END
.\"
.\" Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright (c) 2012, 2018 by Delphix. All rights reserved.
.\" Copyright (c) 2012, 2023 by Delphix. All rights reserved.
.\" Copyright (c) 2012 Cyril Plisko. All Rights Reserved.
.\" Copyright (c) 2017 Datto Inc.
.\" Copyright (c) 2018 George Melikov. All Rights Reserved.
@ -50,8 +50,9 @@
.Op Fl R Ar root
.Nm zpool
.Cm import
.Op Fl Dflmt
.Op Fl Dflt
.Op Fl F Op Fl nTX
.Op Fl m Op Fl L Ar pool
.Op Fl -rewind-to-checkpoint
.Op Fl c Ar cachefile Ns | Ns Fl d Ar dir Ns | Ns Ar device
.Op Fl o Ar mntopts
@ -256,8 +257,9 @@ health of your pool and should only be used as a last resort.
.It Xo
.Nm zpool
.Cm import
.Op Fl Dflmt
.Op Fl Dflt
.Op Fl F Op Fl nTX
.Op Fl m Op Fl L Ar pool
.Op Fl c Ar cachefile Ns | Ns Fl d Ar dir Ns | Ns Ar device
.Op Fl o Ar mntopts
.Oo Fl o Ar property Ns = Ns Ar value Oc Ns
@ -330,6 +332,12 @@ 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.
.It Fl L
Causes the pool to switch to using the specified shared log pool when
imported.
Requires the
.Fl m
flag.
.It Fl n
Used with the
.Fl F

70
man/man8/zpool-recycle.8 Normal file
View File

@ -0,0 +1,70 @@
.\"
.\" CDDL HEADER START
.\"
.\" The contents of this file are subject to the terms of the
.\" Common Development and Distribution License (the "License").
.\" You may not use this file except in compliance with the License.
.\"
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
.\" or https://opensource.org/licenses/CDDL-1.0.
.\" See the License for the specific language governing permissions
.\" and limitations under the License.
.\"
.\" When distributing Covered Code, include this CDDL HEADER in each
.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
.\" If applicable, add the following below this CDDL HEADER, with the
.\" fields enclosed by brackets "[]" replaced with your own identifying
.\" information: Portions Copyright [yyyy] [name of copyright owner]
.\"
.\" CDDL HEADER END
.\"
.\" Copyright (c) 2023 by Delphix. All rights reserved.
.\"
.Dd February 13, 2023
.Dt ZPOOL-RECYCLE 8
.Os
.
.Sh NAME
.Nm zpool-recycle
.Nd recycle space used by shared log ZIL chains
.Sh SYNOPSIS
.Nm zpool
.Cm recycle
.Op Fl n
.Op Ar pool
.
.Sh DESCRIPTION
Client pools (from
.Nm zpool
.Cm create
.Fl l
) store their ZIL logs on the shared log pool (from
.Nm zpool
.Cm create
.Fl L
).
When a client pool is deleted with
.Nm zpool
.Cm destroy
, any space used in the shared log pool is reclaimed.
However, if a client pool is exported and will not be imported again
(e.g. because the disks were damaged or removed), any space associated with
it in the shared log pool remains allocated.
.Nm zpool
.Cm recycle
will reclaim space in the shared log pool that is referenced by any
non-imported client pools.
These non-imported client pools will have their logs deleted; if they are
subsequently imported,
.Nm zpool
.Cm import
.Fl m
will need to be used to ignore the missing logs, discarding any recent
transactions.
.
.Sh OPTIONS
.Bl -tag -width "-n"
.It Fl n
Do not actually perform any deletions, just print out the list of pool
GUIDs that would be affected.
.El

View File

@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
* Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
*/
@ -246,6 +246,8 @@ spa_import_rootpool(const char *name, bool checkpointrewind)
spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
error = spa_config_parse(spa, &rvd, nvtop, NULL, 0,
VDEV_ALLOC_ROOTPOOL);
if (error == 0)
spa_set_pool_type(spa);
spa_config_exit(spa, SCL_ALL, FTAG);
if (error) {
mutex_exit(&spa_namespace_lock);

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2011, 2018 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
@ -754,6 +754,11 @@ zpool_feature_init(void)
"Support for raidz expansion",
ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL, sfeatures);
zfeature_register(SPA_FEATURE_SHARED_LOG,
"com.delphix:shared_log", "shared_log",
"Support for shared log pools.", 0, ZFEATURE_TYPE_BOOLEAN, NULL,
sfeatures);
zfs_mod_list_supported_free(sfeatures);
}

View File

@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020 by Delphix. All rights reserved.
* Copyright (c) 2012, 2023 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
@ -658,6 +658,8 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
if (ds == NULL || !ds->ds_is_snapshot)
os->os_zil_header = os->os_phys->os_zil_header;
if (spa_uses_shared_log(spa))
spa_zil_header_convert(spa, os, &os->os_zil_header.zh_log);
os->os_zil = zil_alloc(os, &os->os_zil_header);
for (i = 0; i < TXG_SIZE; i++) {
@ -1192,6 +1194,9 @@ dmu_objset_create_check(void *arg, dmu_tx_t *tx)
const char *tail;
int error;
if (spa_is_shared_log(dp->dp_spa))
return (SET_ERROR(EINVAL));
if (strchr(doca->doca_name, '@') != NULL)
return (SET_ERROR(EINVAL));
@ -1720,6 +1725,10 @@ sync_meta_dnode_task(void *arg)
*/
zil_sync(os->os_zil, tx);
os->os_phys->os_zil_header = os->os_zil_header;
if (os->os_spa->spa_uses_shared_log) {
spa_zil_header_mask(os->os_spa,
&os->os_phys->os_zil_header.zh_log);
}
zio_nowait(soa->soa_zio);
mutex_destroy(&soa->soa_mutex);

View File

@ -21,7 +21,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2012, 2017 by Delphix. All rights reserved.
* Copyright (c) 2012, 2023 by Delphix. All rights reserved.
*/
#include <sys/dmu.h>
@ -75,6 +75,14 @@ dmu_tx_create_dd(dsl_dir_t *dd)
return (tx);
}
dmu_tx_t *
dmu_tx_create_mos(dsl_pool_t *dp)
{
dmu_tx_t *tx = dmu_tx_create_dd(dp->dp_mos_dir);
tx->tx_objset = dp->dp_meta_objset;
return (tx);
}
dmu_tx_t *
dmu_tx_create(objset_t *os)
{

View File

@ -726,7 +726,8 @@ kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
* It's a block in the intent log. It has no
* accounting, so just free it.
*/
dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp);
if (!zil_shared_log(zilog))
dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp);
} else {
ASSERT(zilog == NULL);
ASSERT3U(BP_GET_LOGICAL_BIRTH(bp), >,

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 by Delphix. All rights reserved.
* Copyright (c) 2012, 2022 by Delphix. All rights reserved.
* Copyright (c) 2013 Martin Matuska. All rights reserved.
* Copyright (c) 2014 Joyent, Inc. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
@ -1303,7 +1303,7 @@ top_of_function:
* refreservation values. Also, if checkrefquota is set, test if
* allocating this space would exceed the dataset's refquota.
*/
if (first && tx->tx_objset) {
if (first && tx->tx_objset && tx->tx_objset->os_dsl_dataset) {
int error;
dsl_dataset_t *ds = tx->tx_objset->os_dsl_dataset;

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
@ -170,6 +170,9 @@ static int zfs_zil_clean_taskq_nthr_pct = 100;
static int zfs_zil_clean_taskq_minalloc = 1024;
static int zfs_zil_clean_taskq_maxalloc = 1024 * 1024;
static unsigned int chain_map_zap_default_bs = 17;
static unsigned int chain_map_zap_default_ibs = 15;
int
dsl_pool_open_special_dir(dsl_pool_t *dp, const char *name, dsl_dir_t **ddp)
{
@ -360,6 +363,14 @@ dsl_pool_open(dsl_pool_t *dp)
if (err)
goto out;
if (spa_is_shared_log(dp->dp_spa)) {
err = zap_lookup(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
DMU_POOL_CHAIN_MAP_OBJ, sizeof (uint64_t), 1,
&dp->dp_chain_map_obj);
if (err != 0)
goto out;
}
err = dsl_scan_init(dp, dp->dp_tx.tx_open_txg);
out:
@ -548,6 +559,17 @@ dsl_pool_create(spa_t *spa, nvlist_t *zplprops __attribute__((unused)),
#endif
dsl_dataset_rele_flags(ds, DS_HOLD_FLAG_DECRYPT, FTAG);
if (spa_is_shared_log(spa)) {
dp->dp_chain_map_obj = zap_create_flags(dp->dp_meta_objset, 0,
ZAP_FLAG_HASH64 | ZAP_FLAG_UINT64_KEY |
ZAP_FLAG_PRE_HASHED_KEY, DMU_OTN_ZAP_METADATA,
chain_map_zap_default_bs, chain_map_zap_default_ibs,
DMU_OT_NONE, 0, tx);
VERIFY0(zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
DMU_POOL_CHAIN_MAP_OBJ, sizeof (uint64_t), 1,
&dp->dp_chain_map_obj, tx));
}
dmu_tx_commit(tx);
rrw_exit(&dp->dp_config_rwlock, FTAG);

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2019 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
* Copyright (c) 2015, Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2017, Intel Corporation.
@ -1660,6 +1660,12 @@ static metaslab_ops_t metaslab_allocators[] = {
{ "new-dynamic", metaslab_ndf_alloc },
};
const metaslab_ops_t zfs_virtual_ops = {
"virtual",
NULL,
METASLAB_TYPE_VIRTUAL
};
static int
spa_find_allocator_byname(const char *val)
{
@ -2866,6 +2872,10 @@ metaslab_fini(metaslab_t *msp)
range_tree_destroy(msp->ms_unflushed_frees);
for (int t = 0; t < TXG_SIZE; t++) {
if (spa_is_shared_log(spa) &&
spa_load_state(spa) != SPA_LOAD_NONE) {
range_tree_vacate(msp->ms_allocating[t], NULL, NULL);
}
range_tree_destroy(msp->ms_allocating[t]);
}
for (int t = 0; t < TXG_DEFER_SIZE; t++) {
@ -5845,6 +5855,19 @@ metaslab_alloc(spa_t *spa, metaslab_class_t *mc, uint64_t psize, blkptr_t *bp,
int ndvas, uint64_t txg, blkptr_t *hintbp, int flags,
zio_alloc_list_t *zal, zio_t *zio, int allocator)
{
if (mc->mc_ops->msop_type == METASLAB_TYPE_VIRTUAL) {
ASSERT3P(mc->mc_virtual, !=, NULL);
spa_t *target_spa = mc->mc_virtual;
dmu_tx_t *tx = dmu_tx_create_mos(target_spa->spa_dsl_pool);
VERIFY0(dmu_tx_assign(tx, TXG_WAIT | TXG_NOTHROTTLE));
uint64_t target_txg = dmu_tx_get_txg(tx);
int ret = metaslab_alloc(target_spa,
spa_normal_class(target_spa), psize, bp, ndvas, target_txg,
hintbp, flags, zal, zio, allocator);
dmu_tx_commit(tx);
return (ret);
}
dva_t *dva = bp->blk_dva;
dva_t *hintdva = (hintbp != NULL) ? hintbp->blk_dva : NULL;
int error = 0;
@ -5861,7 +5884,7 @@ metaslab_alloc(spa_t *spa, metaslab_class_t *mc, uint64_t psize, blkptr_t *bp,
}
ASSERT(ndvas > 0 && ndvas <= spa_max_replication(spa));
ASSERT(BP_GET_NDVAS(bp) == 0);
ASSERT0(BP_GET_NDVAS(bp));
ASSERT(hintbp == NULL || ndvas <= BP_GET_NDVAS(hintbp));
ASSERT3P(zal, !=, NULL);
@ -5887,8 +5910,8 @@ metaslab_alloc(spa_t *spa, metaslab_class_t *mc, uint64_t psize, blkptr_t *bp,
DVA_GET_VDEV(&dva[d]), zio, flags, allocator);
}
}
ASSERT(error == 0);
ASSERT(BP_GET_NDVAS(bp) == ndvas);
ASSERT0(error);
ASSERT3U(BP_GET_NDVAS(bp), ==, ndvas);
spa_config_exit(spa, SCL_ALLOC, FTAG);

View File

@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
/*
* Copyright (c) 2013, 2019 by Delphix. All rights reserved.
* Copyright (c) 2013, 2023 by Delphix. All rights reserved.
* Copyright (c) 2015, Nexenta Systems, Inc. All rights reserved.
*/
@ -618,7 +618,7 @@ range_tree_verify_not_present(range_tree_t *rt, uint64_t off, uint64_t size)
{
range_seg_t *rs = range_tree_find(rt, off, size);
if (rs != NULL)
panic("segment already in tree; rs=%p", (void *)rs);
panic("segment already in tree; rt=%px rs=%px", rt, (void *)rs);
}
boolean_t

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2017 by Delphix. All rights reserved.
* Copyright (c) 2017, 2023 by Delphix. All rights reserved.
*/
/*
@ -544,6 +544,10 @@ spa_checkpoint(const char *pool)
error = spa_open(pool, &spa, FTAG);
if (error != 0)
return (error);
if (spa_uses_shared_log(spa) || spa_is_shared_log(spa)) {
spa_close(spa, FTAG);
return (SET_ERROR(ENOTSUP));
}
mutex_enter(&spa->spa_vdev_top_lock);

View File

@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2011, 2020 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
* Copyright 2017 Joyent, Inc.
* Copyright (c) 2021, Colm Buckley <colm@tuatha.org>
*/
@ -466,6 +466,11 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
if (spa->spa_compatibility != NULL)
fnvlist_add_string(config, ZPOOL_CONFIG_COMPATIBILITY,
spa->spa_compatibility);
if (spa->spa_uses_shared_log)
fnvlist_add_uint64(config, ZPOOL_CONFIG_SHARED_LOG_POOL,
spa_guid(spa_get_shared_log_pool(spa)));
if (spa_is_shared_log(spa))
fnvlist_add_boolean(config, ZPOOL_CONFIG_IS_SHARED_LOG);
hostid = spa_get_hostid(spa);
if (hostid != 0)

View File

@ -238,6 +238,8 @@
avl_tree_t spa_namespace_avl;
kmutex_t spa_namespace_lock;
avl_tree_t spa_shared_log_avl;
kmutex_t spa_shared_log_lock;
kcondvar_t spa_namespace_cv;
static const int spa_max_replication_override = SPA_DVAS_PER_BP;
@ -445,6 +447,42 @@ static int zfs_user_indirect_is_special = B_TRUE;
*/
static uint_t zfs_special_class_metadata_reserve_pct = 25;
void
spa_set_pool_type(spa_t *spa)
{
ASSERT3P(spa->spa_root_vdev, !=, NULL);
/*
* Must hold all of spa_config locks.
*/
ASSERT3U(spa_config_held(spa, SCL_ALL, RW_WRITER), ==, SCL_ALL);
if (fnvlist_lookup_boolean(spa->spa_config,
ZPOOL_CONFIG_IS_SHARED_LOG)) {
spa->spa_pool_type = SPA_TYPE_SHARED_LOG;
avl_index_t where;
mutex_enter(&spa_shared_log_lock);
if (avl_find(&spa_shared_log_avl, spa, &where) == NULL)
avl_insert(&spa_shared_log_avl, spa, where);
mutex_exit(&spa_shared_log_lock);
} else {
spa->spa_pool_type = SPA_TYPE_NORMAL;
}
}
boolean_t
spa_is_shared_log(const spa_t *spa)
{
return (spa->spa_pool_type == SPA_TYPE_SHARED_LOG);
}
boolean_t
spa_uses_shared_log(const spa_t *spa)
{
return (spa->spa_uses_shared_log);
}
/*
* ==========================================================================
* SPA config locking
@ -685,6 +723,15 @@ spa_log_sm_sort_by_txg(const void *va, const void *vb)
return (TREE_CMP(a->sls_txg, b->sls_txg));
}
static int
spa_guid_compare(const void *a1, const void *a2)
{
const spa_t *s1 = a1;
const spa_t *s2 = a2;
return (TREE_CMP(spa_const_guid(s1), spa_const_guid(s2)));
}
/*
* Create an uninitialized spa_t with the given name. Requires
* spa_namespace_lock. The caller must ensure that the spa_t doesn't already
@ -714,6 +761,8 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
mutex_init(&spa->spa_feat_stats_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa->spa_flushed_ms_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa->spa_activities_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa->spa_chain_map_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa->spa_zil_map_lock, NULL, MUTEX_DEFAULT, NULL);
cv_init(&spa->spa_async_cv, NULL, CV_DEFAULT, NULL);
cv_init(&spa->spa_evicting_os_cv, NULL, CV_DEFAULT, NULL);
@ -777,6 +826,8 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
sizeof (metaslab_t), offsetof(metaslab_t, ms_spa_txg_node));
avl_create(&spa->spa_sm_logs_by_txg, spa_log_sm_sort_by_txg,
sizeof (spa_log_sm_t), offsetof(spa_log_sm_t, sls_node));
list_create(&spa->spa_registered_clients, sizeof (spa_t),
offsetof(spa_t, spa_client_node));
list_create(&spa->spa_log_summary, sizeof (log_summary_entry_t),
offsetof(log_summary_entry_t, lse_node));
@ -852,6 +903,12 @@ spa_remove(spa_t *spa)
avl_remove(&spa_namespace_avl, spa);
if (spa_is_shared_log(spa)) {
mutex_enter(&spa_shared_log_lock);
avl_remove(&spa_shared_log_avl, spa);
mutex_exit(&spa_shared_log_lock);
}
if (spa->spa_root)
spa_strfree(spa->spa_root);
@ -875,6 +932,7 @@ spa_remove(spa_t *spa)
avl_destroy(&spa->spa_metaslabs_by_flushed);
avl_destroy(&spa->spa_sm_logs_by_txg);
list_destroy(&spa->spa_registered_clients);
list_destroy(&spa->spa_log_summary);
list_destroy(&spa->spa_config_list);
list_destroy(&spa->spa_leaf_list);
@ -916,6 +974,7 @@ spa_remove(spa_t *spa)
mutex_destroy(&spa->spa_vdev_top_lock);
mutex_destroy(&spa->spa_feat_stats_lock);
mutex_destroy(&spa->spa_activities_lock);
mutex_destroy(&spa->spa_chain_map_lock);
kmem_free(spa, sizeof (spa_t));
}
@ -1747,6 +1806,20 @@ spa_name(spa_t *spa)
return (spa->spa_name);
}
uint64_t
spa_const_guid(const spa_t *spa)
{
/*
* If we fail to parse the config during spa_load(), we can go through
* the error path (which posts an ereport) and end up here with no root
* vdev. We stash the original pool guid in 'spa_config_guid' to handle
* this case.
*/
if (spa->spa_root_vdev == NULL)
return (spa->spa_config_guid);
return (spa->spa_root_vdev->vdev_guid);
}
uint64_t
spa_guid(spa_t *spa)
{
@ -1776,7 +1849,7 @@ spa_guid(spa_t *spa)
}
uint64_t
spa_load_guid(spa_t *spa)
spa_load_guid(const spa_t *spa)
{
/*
* This is a GUID that exists solely as a reference for the
@ -2535,6 +2608,7 @@ void
spa_init(spa_mode_t mode)
{
mutex_init(&spa_namespace_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa_shared_log_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa_spare_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&spa_l2cache_lock, NULL, MUTEX_DEFAULT, NULL);
cv_init(&spa_namespace_cv, NULL, CV_DEFAULT, NULL);
@ -2548,6 +2622,9 @@ spa_init(spa_mode_t mode)
avl_create(&spa_l2cache_avl, spa_l2cache_compare, sizeof (spa_aux_t),
offsetof(spa_aux_t, aux_avl));
avl_create(&spa_shared_log_avl, spa_guid_compare, sizeof (spa_t),
offsetof(spa_t, spa_log_avl));
spa_mode_global = mode;
#ifndef _KERNEL
@ -2623,6 +2700,7 @@ spa_fini(void)
cv_destroy(&spa_namespace_cv);
mutex_destroy(&spa_namespace_lock);
mutex_destroy(&spa_shared_log_lock);
mutex_destroy(&spa_spare_lock);
mutex_destroy(&spa_l2cache_lock);
}
@ -2635,7 +2713,8 @@ spa_fini(void)
boolean_t
spa_has_slogs(spa_t *spa)
{
return (spa->spa_log_class->mc_groups != 0);
return (spa->spa_log_class->mc_groups != 0 ||
spa->spa_log_class->mc_virtual != NULL);
}
spa_log_state_t

View File

@ -332,7 +332,7 @@ zap_leaf_array_match(zap_leaf_t *l, zap_name_t *zn,
if (zap_getflags(zn->zn_zap) & ZAP_FLAG_UINT64_KEY) {
uint64_t *thiskey =
kmem_alloc(array_numints * sizeof (*thiskey), KM_SLEEP);
ASSERT(zn->zn_key_intlen == sizeof (*thiskey));
ASSERT3S(zn->zn_key_intlen, ==, sizeof (*thiskey));
zap_leaf_array_read(l, chunk, sizeof (*thiskey), array_numints,
sizeof (*thiskey), array_numints, thiskey);
@ -342,7 +342,7 @@ zap_leaf_array_match(zap_leaf_t *l, zap_name_t *zn,
return (match);
}
ASSERT(zn->zn_key_intlen == 1);
ASSERT3S(zn->zn_key_intlen, ==, 1);
if (zn->zn_matchtype & MT_NORMALIZE) {
char *thisname = kmem_alloc(array_numints, KM_SLEEP);

View File

@ -353,19 +353,24 @@ zpl_earlier_version(const char *name, int version)
}
static void
zfs_log_history(zfs_cmd_t *zc)
zfs_log_history_string(const char *pool, const char *buf)
{
spa_t *spa;
char *buf;
if ((buf = history_str_get(zc)) == NULL)
return;
if (spa_open(zc->zc_name, &spa, FTAG) == 0) {
if (spa_open(pool, &spa, FTAG) == 0) {
if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY)
(void) spa_history_log(spa, buf);
spa_close(spa, FTAG);
}
}
static void
zfs_log_history(zfs_cmd_t *zc)
{
char *buf;
if ((buf = history_str_get(zc)) == NULL)
return;
zfs_log_history_string(zc->zc_name, buf);
history_str_free(buf);
}
@ -1502,7 +1507,7 @@ zfs_ioc_pool_create(zfs_cmd_t *zc)
*/
if (!error && (error = zfs_set_prop_nvlist(spa_name,
ZPROP_SRC_LOCAL, rootprops, NULL)) != 0) {
(void) spa_destroy(spa_name);
(void) spa_destroy(spa_name, NULL);
unload_wkey = B_FALSE; /* spa_destroy() unloads wrapping keys */
}
@ -1521,7 +1526,23 @@ zfs_ioc_pool_destroy(zfs_cmd_t *zc)
{
int error;
zfs_log_history(zc);
error = spa_destroy(zc->zc_name);
error = spa_destroy(zc->zc_name, NULL);
return (error);
}
static const zfs_ioc_key_t zfs_keys_pool_destroy_new[] = {
{ZPOOL_HIST_CMD, DATA_TYPE_STRING, 0},
};
static int
zfs_ioc_pool_destroy_new(const char *pool, nvlist_t *innvl, nvlist_t *outnvl)
{
int error;
zfs_log_history_string(pool, fnvlist_lookup_string(innvl,
ZPOOL_HIST_CMD));
error = spa_destroy(pool, outnvl);
return (error);
}
@ -1571,7 +1592,28 @@ zfs_ioc_pool_export(zfs_cmd_t *zc)
boolean_t hardforce = (boolean_t)zc->zc_guid;
zfs_log_history(zc);
error = spa_export(zc->zc_name, NULL, force, hardforce);
error = spa_export(zc->zc_name, NULL, force, hardforce, NULL);
return (error);
}
static const zfs_ioc_key_t zfs_keys_pool_export_new[] = {
{ZPOOL_HIST_CMD, DATA_TYPE_STRING, 0},
{ZPOOL_EXPORT_FORCE, DATA_TYPE_BOOLEAN_VALUE, 0},
{ZPOOL_EXPORT_HARDFORCE, DATA_TYPE_BOOLEAN_VALUE, 0},
};
static int
zfs_ioc_pool_export_new(const char *pool, nvlist_t *innvl, nvlist_t *outnvl)
{
int error;
zfs_log_history_string(pool,
fnvlist_lookup_string(innvl, ZPOOL_HIST_CMD));
error = spa_export(pool, NULL,
fnvlist_lookup_boolean_value(innvl, ZPOOL_EXPORT_FORCE),
fnvlist_lookup_boolean_value(innvl, ZPOOL_EXPORT_HARDFORCE),
outnvl);
return (error);
}
@ -7101,6 +7143,41 @@ error:
return (ret);
}
static const zfs_ioc_key_t zfs_keys_pool_recycle[] = {
{ZPOOL_RECYCLE_DRYRUN, DATA_TYPE_BOOLEAN_VALUE, 0},
{ZPOOL_RECYCLE_CLIENTS, DATA_TYPE_NVLIST, ZK_OPTIONAL},
};
static int
zfs_ioc_pool_recycle(const char *pool, nvlist_t *innvl, nvlist_t *outnvl)
{
int err;
boolean_t rc, dryrun = B_FALSE;
spa_t *spa;
nvlist_t *clients = NULL;
if ((err = spa_open(pool, &spa, FTAG)) != 0)
return (err);
if (innvl) {
err = nvlist_lookup_boolean_value(innvl, ZPOOL_RECYCLE_DRYRUN,
&rc);
if (err == 0)
dryrun = rc;
nvlist_lookup_nvlist(innvl, ZPOOL_RECYCLE_CLIENTS,
&clients);
}
if (clients) {
err = spa_recycle_clients(spa, clients, dryrun, outnvl);
} else {
err = spa_recycle_all(spa, dryrun, outnvl);
}
spa_close(spa, FTAG);
return (0);
}
static zfs_ioc_vec_t zfs_ioc_vec[ZFS_IOC_LAST - ZFS_IOC_FIRST];
static void
@ -7402,6 +7479,21 @@ zfs_ioctl_init(void)
POOL_CHECK_NONE, B_FALSE, B_FALSE,
zfs_keys_get_props, ARRAY_SIZE(zfs_keys_get_props));
zfs_ioctl_register("zpool_recycle", ZFS_IOC_POOL_RECYCLE,
zfs_ioc_pool_recycle, zfs_secpolicy_config, POOL_NAME,
POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_FALSE, B_FALSE,
zfs_keys_pool_recycle, ARRAY_SIZE(zfs_keys_pool_recycle));
zfs_ioctl_register("zpool_destroy_new", ZFS_IOC_POOL_DESTROY_NEW,
zfs_ioc_pool_destroy_new, zfs_secpolicy_config, POOL_NAME,
POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE,
zfs_keys_pool_destroy_new, ARRAY_SIZE(zfs_keys_pool_destroy_new));
zfs_ioctl_register("zpool_export_new", ZFS_IOC_POOL_EXPORT_NEW,
zfs_ioc_pool_export_new, zfs_secpolicy_config, POOL_NAME,
POOL_CHECK_SUSPENDED, B_FALSE, B_FALSE,
zfs_keys_pool_export_new, ARRAY_SIZE(zfs_keys_pool_export_new));
/* IOCTLS that use the legacy function signature */
zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze,

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2018 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
* Copyright (c) 2014 Integros [integros.com]
* Copyright (c) 2018 Datto Inc.
*/
@ -238,23 +238,16 @@ zil_kstats_global_update(kstat_t *ksp, int rw)
return (0);
}
/*
* Read a log block and make sure it's valid.
*/
static int
zil_read_log_block(zilog_t *zilog, boolean_t decrypt, const blkptr_t *bp,
blkptr_t *nbp, char **begin, char **end, arc_buf_t **abuf)
zil_read_log_block(spa_t *spa, boolean_t decrypt, zio_flag_t zio_flags,
const blkptr_t *bp, blkptr_t *nbp, char **begin, char **end,
arc_buf_t **abuf)
{
zio_flag_t zio_flags = ZIO_FLAG_CANFAIL;
arc_flags_t aflags = ARC_FLAG_WAIT;
zbookmark_phys_t zb;
int error;
if (zilog->zl_header->zh_claim_txg == 0)
zio_flags |= ZIO_FLAG_SPECULATIVE | ZIO_FLAG_SCRUB;
if (!(zilog->zl_header->zh_flags & ZIL_CLAIM_LR_SEQ_VALID))
zio_flags |= ZIO_FLAG_SPECULATIVE;
zio_flags |= ZIO_FLAG_CANFAIL;
if (!decrypt)
zio_flags |= ZIO_FLAG_RAW;
@ -262,7 +255,7 @@ zil_read_log_block(zilog_t *zilog, boolean_t decrypt, const blkptr_t *bp,
SET_BOOKMARK(&zb, bp->blk_cksum.zc_word[ZIL_ZC_OBJSET],
ZB_ZIL_OBJECT, ZB_ZIL_LEVEL, bp->blk_cksum.zc_word[ZIL_ZC_SEQ]);
error = arc_read(NULL, zilog->zl_spa, bp, arc_getbuf_func,
error = arc_read(NULL, spa, bp, arc_getbuf_func,
abuf, ZIO_PRIORITY_SYNC_READ, zio_flags, &aflags, &zb);
if (error == 0) {
@ -346,7 +339,7 @@ zil_read_log_data(zilog_t *zilog, const lr_write_t *lr, void *wbuf)
SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os), lr->lr_foid,
ZB_ZIL_LEVEL, lr->lr_offset / BP_GET_LSIZE(bp));
error = arc_read(NULL, zilog->zl_spa, bp, arc_getbuf_func, &abuf,
error = arc_read(NULL, zilog->zl_io_spa, bp, arc_getbuf_func, &abuf,
ZIO_PRIORITY_SYNC_READ, zio_flags, &aflags, &zb);
if (error == 0) {
@ -453,6 +446,137 @@ zil_kstat_values_update(zil_kstat_values_t *zs, zil_sums_t *zil_sums)
wmsum_value(&zil_sums->zil_itx_metaslab_slog_alloc);
}
/*
* Parse the intent log, and call parse_blk_func for each valid block within
* and parse_lr_func for each valid record within.
*/
static int
zil_parse_raw_impl(spa_t *spa, const blkptr_t *bp,
zil_parse_raw_blk_func_t *parse_blk_func,
zil_parse_raw_lr_func_t *parse_lr_func, void *arg, zio_flag_t zio_flags,
boolean_t decrypt)
{
(void) parse_lr_func;
blkptr_t next_blk = {{{{0}}}};
int error = 0;
for (blkptr_t blk = *bp; !BP_IS_HOLE(&blk); blk = next_blk) {
char *lrp, *end;
arc_buf_t *abuf = NULL;
/*
* We do the read before the parse function so that if the
* parse function frees the block, we still have next_blk so we
* can continue the chain.
*/
int read_error = zil_read_log_block(spa, decrypt, zio_flags,
&blk, &next_blk, &lrp, &end, &abuf);
error = parse_blk_func(spa, &blk, arg);
if (error != 0) {
if (abuf)
arc_buf_destroy(abuf, &abuf);
break;
}
if (read_error != 0) {
if (abuf)
arc_buf_destroy(abuf, &abuf);
error = read_error;
break;
}
int reclen;
for (; lrp < end; lrp += reclen) {
lr_t *lr = (lr_t *)lrp;
reclen = lr->lrc_reclen;
ASSERT3U(reclen, >=, sizeof (lr_t));
ASSERT3U(reclen, <=, end - lrp);
error = parse_lr_func(spa, lr, arg);
if (error != 0)
break;
}
arc_buf_destroy(abuf, &abuf);
}
return (error);
}
/*
* Because we don't have access to the zilog_t, we cannot know when the chain
* is supposed to end. As a result, all IOs need to be marked as speculative.
*/
int
zil_parse_raw(spa_t *spa, const blkptr_t *bp,
zil_parse_raw_blk_func_t *parse_blk_func,
zil_parse_raw_lr_func_t *parse_lr_func, void *arg)
{
return (zil_parse_raw_impl(spa, bp, parse_blk_func, parse_lr_func, arg,
ZIO_FLAG_SPECULATIVE | ZIO_FLAG_SCRUB, B_FALSE));
}
struct parse_arg {
zilog_t *zilog;
zil_parse_blk_func_t *parse_blk_func;
zil_parse_lr_func_t *parse_lr_func;
void *arg;
uint64_t txg;
uint64_t blk_seq;
uint64_t claim_blk_seq;
uint64_t claim_lr_seq;
uint64_t max_blk_seq;
uint64_t max_lr_seq;
uint64_t blk_count;
uint64_t lr_count;
int error;
};
static int
parse_blk_wrapper(spa_t *spa, const blkptr_t *bp, void *arg)
{
(void) spa;
struct parse_arg *pa = arg;
pa->blk_seq = bp->blk_cksum.zc_word[ZIL_ZC_SEQ];
if (pa->blk_seq > pa->claim_blk_seq)
return (EINTR);
int error = pa->parse_blk_func(pa->zilog, bp, pa->arg, pa->txg);
if (error) {
pa->error = error;
return (EINTR);
}
ASSERT3U(pa->max_blk_seq, <, pa->blk_seq);
pa->max_blk_seq = pa->blk_seq;
pa->blk_count++;
if (pa->max_lr_seq == pa->claim_lr_seq &&
pa->max_blk_seq == pa->claim_blk_seq) {
return (EINTR);
}
return (0);
}
static int
parse_lr_wrapper(spa_t *spa, const lr_t *lr, void *arg)
{
(void) spa;
struct parse_arg *pa = arg;
if (lr->lrc_seq > pa->claim_lr_seq)
return (EINTR);
int error = pa->parse_lr_func(pa->zilog, lr, pa->arg, pa->txg);
if (error != 0) {
pa->error = error;
return (EINTR);
}
ASSERT3U(pa->max_lr_seq, <, lr->lrc_seq);
pa->max_lr_seq = lr->lrc_seq;
pa->lr_count++;
return (0);
}
/*
* Parse the intent log, and call parse_func for each valid record within.
*/
@ -463,95 +587,57 @@ zil_parse(zilog_t *zilog, zil_parse_blk_func_t *parse_blk_func,
{
const zil_header_t *zh = zilog->zl_header;
boolean_t claimed = !!zh->zh_claim_txg;
uint64_t claim_blk_seq = claimed ? zh->zh_claim_blk_seq : UINT64_MAX;
uint64_t claim_lr_seq = claimed ? zh->zh_claim_lr_seq : UINT64_MAX;
uint64_t max_blk_seq = 0;
uint64_t max_lr_seq = 0;
uint64_t blk_count = 0;
uint64_t lr_count = 0;
blkptr_t blk, next_blk = {{{{0}}}};
int error = 0;
struct parse_arg arg2;
arg2.claim_blk_seq = claimed ? zh->zh_claim_blk_seq : UINT64_MAX;
arg2.claim_lr_seq = claimed ? zh->zh_claim_lr_seq : UINT64_MAX;
arg2.max_blk_seq = 0;
arg2.max_lr_seq = 0;
arg2.blk_count = 0;
arg2.lr_count = 0;
arg2.arg = arg;
arg2.parse_blk_func = parse_blk_func;
arg2.parse_lr_func = parse_lr_func;
arg2.txg = txg;
arg2.zilog = zilog;
arg2.error = 0;
arg2.blk_seq = 0;
zio_flag_t zio_flags = 0;
if (!claimed)
zio_flags |= ZIO_FLAG_SPECULATIVE | ZIO_FLAG_SCRUB;
if (!(zh->zh_flags & ZIL_CLAIM_LR_SEQ_VALID))
zio_flags |= ZIO_FLAG_SPECULATIVE;
/*
* Old logs didn't record the maximum zh_claim_lr_seq.
*/
if (!(zh->zh_flags & ZIL_CLAIM_LR_SEQ_VALID))
claim_lr_seq = UINT64_MAX;
arg2.claim_lr_seq = UINT64_MAX;
/*
* Starting at the block pointed to by zh_log we read the log chain.
* For each block in the chain we strongly check that block to
* ensure its validity. We stop when an invalid block is found.
* For each block pointer in the chain we call parse_blk_func().
* For each record in each valid block we call parse_lr_func().
* If the log has been claimed, stop if we encounter a sequence
* number greater than the highest claimed sequence number.
*/
zil_bp_tree_init(zilog);
for (blk = zh->zh_log; !BP_IS_HOLE(&blk); blk = next_blk) {
uint64_t blk_seq = blk.blk_cksum.zc_word[ZIL_ZC_SEQ];
int reclen;
char *lrp, *end;
arc_buf_t *abuf = NULL;
int error = zil_parse_raw_impl(zilog->zl_io_spa, &zh->zh_log,
parse_blk_wrapper, parse_lr_wrapper, &arg2, zio_flags, decrypt);
if (blk_seq > claim_blk_seq)
break;
// If this happens, we got an error from zil_read_log_block_spa
if (error != 0 && error != EINTR && claimed) {
char name[ZFS_MAX_DATASET_NAME_LEN];
error = parse_blk_func(zilog, &blk, arg, txg);
if (error != 0)
break;
ASSERT3U(max_blk_seq, <, blk_seq);
max_blk_seq = blk_seq;
blk_count++;
dmu_objset_name(zilog->zl_os, name);
if (max_lr_seq == claim_lr_seq && max_blk_seq == claim_blk_seq)
break;
error = zil_read_log_block(zilog, decrypt, &blk, &next_blk,
&lrp, &end, &abuf);
if (error != 0) {
if (abuf)
arc_buf_destroy(abuf, &abuf);
if (claimed) {
char name[ZFS_MAX_DATASET_NAME_LEN];
dmu_objset_name(zilog->zl_os, name);
cmn_err(CE_WARN, "ZFS read log block error %d, "
"dataset %s, seq 0x%llx\n", error, name,
(u_longlong_t)blk_seq);
}
break;
}
for (; lrp < end; lrp += reclen) {
lr_t *lr = (lr_t *)lrp;
reclen = lr->lrc_reclen;
ASSERT3U(reclen, >=, sizeof (lr_t));
ASSERT3U(reclen, <=, end - lrp);
if (lr->lrc_seq > claim_lr_seq) {
arc_buf_destroy(abuf, &abuf);
goto done;
}
error = parse_lr_func(zilog, lr, arg, txg);
if (error != 0) {
arc_buf_destroy(abuf, &abuf);
goto done;
}
ASSERT3U(max_lr_seq, <, lr->lrc_seq);
max_lr_seq = lr->lrc_seq;
lr_count++;
}
arc_buf_destroy(abuf, &abuf);
cmn_err(CE_WARN, "ZFS read log block error %d, "
"dataset %s, seq 0x%llx\n", error, name,
(u_longlong_t)arg2.blk_seq);
}
done:
if (error == EINTR)
error = arg2.error;
zilog->zl_parse_error = error;
zilog->zl_parse_blk_seq = max_blk_seq;
zilog->zl_parse_lr_seq = max_lr_seq;
zilog->zl_parse_blk_count = blk_count;
zilog->zl_parse_lr_count = lr_count;
zilog->zl_parse_blk_seq = arg2.max_blk_seq;
zilog->zl_parse_lr_seq = arg2.max_lr_seq;
zilog->zl_parse_blk_count = arg2.blk_count;
zilog->zl_parse_lr_count = arg2.lr_count;
zil_bp_tree_fini(zilog);
@ -565,6 +651,8 @@ zil_clear_log_block(zilog_t *zilog, const blkptr_t *bp, void *tx,
(void) tx;
ASSERT(!BP_IS_HOLE(bp));
// We do not support checkpoints of shared log client pools.
ASSERT(!zilog->zl_spa->spa_uses_shared_log);
/*
* As we call this function from the context of a rewind to a
* checkpoint, each ZIL block whose txg is later than the txg
@ -577,7 +665,7 @@ zil_clear_log_block(zilog_t *zilog, const blkptr_t *bp, void *tx,
if (zil_bp_tree_add(zilog, bp) != 0)
return (0);
zio_free(zilog->zl_spa, first_txg, bp);
zio_free(zilog->zl_io_spa, first_txg, bp);
return (0);
}
@ -598,7 +686,8 @@ zil_claim_log_block(zilog_t *zilog, const blkptr_t *bp, void *tx,
* If tx == NULL, just verify that the block is claimable.
*/
if (BP_IS_HOLE(bp) || BP_GET_LOGICAL_BIRTH(bp) < first_txg ||
zil_bp_tree_add(zilog, bp) != 0)
zil_bp_tree_add(zilog, bp) != 0 ||
zilog->zl_spa != zilog->zl_io_spa)
return (0);
return (zio_wait(zio_claim(NULL, zilog->zl_spa,
@ -708,7 +797,8 @@ zil_free_log_block(zilog_t *zilog, const blkptr_t *bp, void *tx,
{
(void) claim_txg;
zio_free(zilog->zl_spa, dmu_tx_get_txg(tx), bp);
if (!zilog->zl_spa->spa_uses_shared_log)
zio_free(zilog->zl_spa, dmu_tx_get_txg(tx), bp);
return (0);
}
@ -725,7 +815,8 @@ zil_free_write(zilog_t *zilog, const lr_t *lrc, void *tx, uint64_t claim_txg)
* If we previously claimed it, we need to free it.
*/
if (BP_GET_LOGICAL_BIRTH(bp) >= claim_txg &&
zil_bp_tree_add(zilog, bp) == 0 && !BP_IS_HOLE(bp)) {
zil_bp_tree_add(zilog, bp) == 0 && !BP_IS_HOLE(bp) &&
!zilog->zl_spa->spa_uses_shared_log) {
zio_free(zilog->zl_spa, dmu_tx_get_txg(tx), bp);
}
@ -966,7 +1057,7 @@ zil_create(zilog_t *zilog)
int error = 0;
boolean_t slog = FALSE;
dsl_dataset_t *ds = dmu_objset_ds(zilog->zl_os);
spa_t *spa = zilog->zl_spa;
/*
* Wait for any previous destroy to complete.
@ -990,14 +1081,23 @@ zil_create(zilog_t *zilog)
txg = dmu_tx_get_txg(tx);
if (!BP_IS_HOLE(&blk)) {
zio_free(zilog->zl_spa, txg, &blk);
if (spa_uses_shared_log(spa)) {
spa_zil_delete(spa, zilog->zl_os);
} else {
zio_free(spa, txg, &blk);
}
BP_ZERO(&blk);
}
error = zio_alloc_zil(zilog->zl_spa, zilog->zl_os, txg, &blk,
error = zio_alloc_zil(spa, zilog->zl_os, txg, &blk,
ZIL_MIN_BLKSZ, &slog);
if (error == 0)
zil_init_log_chain(zilog, &blk);
spa_zil_map_insert(spa, zilog->zl_os, NULL, &blk);
if (spa_uses_shared_log(spa)) {
spa_t *shared_log = spa_get_shared_log_pool(spa);
txg_wait_synced(shared_log->spa_dsl_pool, 0);
}
}
/*
@ -1018,9 +1118,8 @@ zil_create(zilog_t *zilog)
* this until we write the first xattr log record because we
* need to wait for the feature activation to sync out.
*/
if (spa_feature_is_enabled(zilog->zl_spa,
SPA_FEATURE_ZILSAXATTR) && dmu_objset_type(zilog->zl_os) !=
DMU_OST_ZVOL) {
if (spa_feature_is_enabled(spa, SPA_FEATURE_ZILSAXATTR) &&
dmu_objset_type(zilog->zl_os) != DMU_OST_ZVOL) {
mutex_enter(&ds->ds_lock);
ds->ds_feature_activation[SPA_FEATURE_ZILSAXATTR] =
(void *)B_TRUE;
@ -1036,7 +1135,7 @@ zil_create(zilog_t *zilog)
*/
zil_commit_activate_saxattr_feature(zilog);
}
IMPLY(spa_feature_is_enabled(zilog->zl_spa, SPA_FEATURE_ZILSAXATTR) &&
IMPLY(spa_feature_is_enabled(spa, SPA_FEATURE_ZILSAXATTR) &&
dmu_objset_type(zilog->zl_os) != DMU_OST_ZVOL,
dsl_dataset_feature_is_active(ds, SPA_FEATURE_ZILSAXATTR));
@ -1088,11 +1187,14 @@ zil_destroy(zilog_t *zilog, boolean_t keep_first)
if (!list_is_empty(&zilog->zl_lwb_list)) {
ASSERT(zh->zh_claim_txg == 0);
VERIFY(!keep_first);
spa_zil_delete(zilog->zl_spa, zilog->zl_os);
while ((lwb = list_remove_head(&zilog->zl_lwb_list)) != NULL) {
if (lwb->lwb_buf != NULL)
zio_buf_free(lwb->lwb_buf, lwb->lwb_sz);
if (!BP_IS_HOLE(&lwb->lwb_blk))
if (!BP_IS_HOLE(&lwb->lwb_blk) &&
!spa_uses_shared_log(zilog->zl_spa)) {
zio_free(zilog->zl_spa, txg, &lwb->lwb_blk);
}
zil_free_lwb(zilog, lwb);
}
} else if (!keep_first) {
@ -1113,6 +1215,49 @@ zil_destroy_sync(zilog_t *zilog, dmu_tx_t *tx)
zil_free_log_record, tx, zilog->zl_header->zh_claim_txg, B_FALSE);
}
/*
* This function's only job is to clear the zil chain for the given dataset.
* It is called when we're using a shared log pool and we import discarding
* logs.
*/
int
zil_clear(dsl_pool_t *dp, dsl_dataset_t *ds, void *txarg)
{
dmu_tx_t *tx = txarg;
zilog_t *zilog;
zil_header_t *zh;
objset_t *os;
int error;
ASSERT3U(spa_get_log_state(dp->dp_spa), ==, SPA_LOG_CLEAR);
error = dmu_objset_own_obj(dp, ds->ds_object,
DMU_OST_ANY, B_FALSE, B_FALSE, FTAG, &os);
if (error != 0) {
/*
* EBUSY indicates that the objset is inconsistent, in which
* case it can not have a ZIL.
*/
if (error != EBUSY) {
cmn_err(CE_WARN, "can't open objset for %llu, error %u",
(unsigned long long)ds->ds_object, error);
}
return (0);
}
zilog = dmu_objset_zil(os);
zh = zil_header_in_syncing_context(zilog);
ASSERT3U(tx->tx_txg, ==, spa_first_txg(zilog->zl_spa));
BP_ZERO(&zh->zh_log);
if (os->os_encrypted)
os->os_next_write_raw[tx->tx_txg & TXG_MASK] = B_TRUE;
dsl_dataset_dirty(dmu_objset_ds(os), tx);
dmu_objset_disown(os, B_FALSE, FTAG);
return (0);
}
int
zil_claim(dsl_pool_t *dp, dsl_dataset_t *ds, void *txarg)
{
@ -1440,7 +1585,7 @@ zil_lwb_flush_vdevs_done(zio_t *zio)
zil_commit_waiter_t *zcw;
itx_t *itx;
spa_config_exit(zilog->zl_spa, SCL_STATE, lwb);
spa_config_exit(zilog->zl_io_spa, SCL_STATE, lwb);
hrtime_t t = gethrtime() - lwb->lwb_issued_timestamp;
@ -1878,6 +2023,7 @@ static void
zil_lwb_write_issue(zilog_t *zilog, lwb_t *lwb)
{
spa_t *spa = zilog->zl_spa;
spa_t *io_spa = zilog->zl_io_spa;
zil_chain_t *zilc;
boolean_t slog;
zbookmark_phys_t zb;
@ -1893,7 +2039,7 @@ zil_lwb_write_issue(zilog_t *zilog, lwb_t *lwb)
lwb->lwb_nused = lwb->lwb_nfilled;
ASSERT3U(lwb->lwb_nused, <=, lwb->lwb_nmax);
lwb->lwb_root_zio = zio_root(spa, zil_lwb_flush_vdevs_done, lwb,
lwb->lwb_root_zio = zio_root(io_spa, zil_lwb_flush_vdevs_done, lwb,
ZIO_FLAG_CANFAIL);
/*
@ -1926,7 +2072,7 @@ next_lwb:
SET_BOOKMARK(&zb, lwb->lwb_blk.blk_cksum.zc_word[ZIL_ZC_OBJSET],
ZB_ZIL_OBJECT, ZB_ZIL_LEVEL,
lwb->lwb_blk.blk_cksum.zc_word[ZIL_ZC_SEQ]);
lwb->lwb_write_zio = zio_rewrite(lwb->lwb_root_zio, spa, 0,
lwb->lwb_write_zio = zio_rewrite(lwb->lwb_root_zio, io_spa, 0,
&lwb->lwb_blk, lwb_abd, lwb->lwb_sz, zil_lwb_write_done,
lwb, prio, ZIO_FLAG_CANFAIL, &zb);
zil_lwb_add_block(lwb, &lwb->lwb_blk);
@ -1975,11 +2121,14 @@ next_lwb:
&slog);
}
if (error == 0) {
ASSERT3U(BP_GET_LOGICAL_BIRTH(bp), ==, txg);
IMPLY(spa == io_spa, BP_GET_LOGICAL_BIRTH(bp) == txg);
BP_SET_CHECKSUM(bp, nlwb->lwb_slim ? ZIO_CHECKSUM_ZILOG2 :
ZIO_CHECKSUM_ZILOG);
VERIFY(zfs_blkptr_verify(io_spa, bp, BLK_CONFIG_NEEDED,
BLK_VERIFY_HALT));
bp->blk_cksum = lwb->lwb_blk.blk_cksum;
bp->blk_cksum.zc_word[ZIL_ZC_SEQ]++;
spa_zil_map_insert(spa, zilog->zl_os, &lwb->lwb_blk, bp);
}
/*
@ -1993,7 +2142,7 @@ next_lwb:
mutex_exit(&zilog->zl_lwb_io_lock);
dmu_tx_commit(tx);
spa_config_enter(spa, SCL_STATE, lwb, RW_READER);
spa_config_enter(io_spa, SCL_STATE, lwb, RW_READER);
/*
* We've completed all potentially blocking operations. Update the
@ -3726,6 +3875,7 @@ zil_sync(zilog_t *zilog, dmu_tx_t *tx)
*/
zil_init_log_chain(zilog, &blk);
zh->zh_log = blk;
spa_zil_map_set_final(spa, zilog->zl_os, &blk);
} else {
/*
* A destroyed ZIL chain can't contain any TX_SETSAXATTR
@ -3736,7 +3886,11 @@ zil_sync(zilog_t *zilog, dmu_tx_t *tx)
SPA_FEATURE_ZILSAXATTR))
dsl_dataset_deactivate_feature(ds,
SPA_FEATURE_ZILSAXATTR, tx);
spa_zil_delete(spa, zilog->zl_os);
}
mutex_exit(&zilog->zl_lock);
return;
}
while ((lwb = list_head(&zilog->zl_lwb_list)) != NULL) {
@ -3745,7 +3899,7 @@ zil_sync(zilog_t *zilog, dmu_tx_t *tx)
lwb->lwb_alloc_txg > txg || lwb->lwb_max_txg > txg)
break;
list_remove(&zilog->zl_lwb_list, lwb);
if (!BP_IS_HOLE(&lwb->lwb_blk))
if (!BP_IS_HOLE(&lwb->lwb_blk) && !spa->spa_uses_shared_log)
zio_free(spa, txg, &lwb->lwb_blk);
zil_free_lwb(zilog, lwb);
@ -3757,6 +3911,7 @@ zil_sync(zilog_t *zilog, dmu_tx_t *tx)
*/
if (list_is_empty(&zilog->zl_lwb_list))
BP_ZERO(&zh->zh_log);
spa_zil_map_set_final(spa, zilog->zl_os, &zh->zh_log);
}
mutex_exit(&zilog->zl_lock);
@ -3845,6 +4000,13 @@ zil_alloc(objset_t *os, zil_header_t *zh_phys)
zilog->zl_header = zh_phys;
zilog->zl_os = os;
zilog->zl_spa = dmu_objset_spa(os);
zilog->zl_io_spa = spa_get_shared_log_pool(zilog->zl_spa);
if (zilog->zl_io_spa == NULL) {
zilog->zl_io_spa = zilog->zl_spa;
} else {
IMPLY(BP_IS_HOLE(&(zh_phys->zh_log)),
BP_GET_LOGICAL_BIRTH(&zh_phys->zh_log) == 0);
}
zilog->zl_dmu_pool = dmu_objset_pool(os);
zilog->zl_destroy_txg = TXG_INITIAL - 1;
zilog->zl_logbias = dmu_objset_logbias(os);
@ -3932,6 +4094,8 @@ zil_open(objset_t *os, zil_get_data_t *get_data, zil_sums_t *zil_sums)
ASSERT3P(zilog->zl_get_data, ==, NULL);
ASSERT3P(zilog->zl_last_lwb_opened, ==, NULL);
ASSERT(list_is_empty(&zilog->zl_lwb_list));
IMPLY(BP_IS_HOLE(&zilog->zl_header->zh_log),
BP_GET_LOGICAL_BIRTH(&zilog->zl_header->zh_log) == 0);
zilog->zl_get_data = get_data;
zilog->zl_sums = zil_sums;
@ -4352,6 +4516,12 @@ zil_reset(const char *osname, void *arg)
return (0);
}
boolean_t
zil_shared_log(zilog_t *zilog)
{
return (zilog->zl_spa != zilog->zl_io_spa);
}
EXPORT_SYMBOL(zil_alloc);
EXPORT_SYMBOL(zil_free);
EXPORT_SYMBOL(zil_open);

View File

@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022 by Delphix. All rights reserved.
* Copyright (c) 2011, 2023 by Delphix. All rights reserved.
* Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2017, Intel Corporation.
* Copyright (c) 2019, 2023, 2024, Klara Inc.
@ -3884,15 +3884,16 @@ zio_alloc_zil(spa_t *spa, objset_t *os, uint64_t txg, blkptr_t *new_bp,
int flags = METASLAB_ZIL;
int allocator = (uint_t)cityhash4(0, 0, 0,
os->os_dsl_dataset->ds_object) % spa->spa_alloc_count;
boolean_t must_slog = spa_uses_shared_log(spa);
error = metaslab_alloc(spa, spa_log_class(spa), size, new_bp, 1,
txg, NULL, flags, &io_alloc_list, NULL, allocator);
*slog = (error == 0);
if (error != 0) {
*slog = (error == 0 || must_slog);
if (error != 0 && !must_slog) {
error = metaslab_alloc(spa, spa_embedded_log_class(spa), size,
new_bp, 1, txg, NULL, flags,
&io_alloc_list, NULL, allocator);
}
if (error != 0) {
if (error != 0 && !must_slog) {
error = metaslab_alloc(spa, spa_normal_class(spa), size,
new_bp, 1, txg, NULL, flags,
&io_alloc_list, NULL, allocator);

View File

@ -928,6 +928,11 @@ tests = ['scrub_mirror_001_pos', 'scrub_mirror_002_pos',
'scrub_mirror_003_pos', 'scrub_mirror_004_pos']
tags = ['functional', 'scrub_mirror']
[tests/functional/shared_log]
tests = ['shared_log_001_pos', 'shared_log_002_pos', 'shared_log_003_pos', 'shared_log_004_pos',
'shared_log_005_pos', 'shared_log_006_neg', 'shared_log_007_pos', 'shared_log_008_pos']
tags = ['functional', 'shared_log']
[tests/functional/slog]
tests = ['slog_001_pos', 'slog_002_pos', 'slog_003_pos', 'slog_004_pos',
'slog_005_pos', 'slog_006_pos', 'slog_007_pos', 'slog_008_neg',

View File

@ -29,5 +29,4 @@ tests = ['sequential_writes', 'sequential_reads', 'sequential_reads_arc_cached',
'sequential_reads_arc_cached_clone', 'sequential_reads_dbuf_cached',
'random_reads', 'random_writes', 'random_readwrite', 'random_writes_zil',
'random_readwrite_fixed']
post =
tags = ['perf', 'regression']

View File

@ -14,7 +14,7 @@
*/
/*
* Copyright (c) 2018 by Delphix. All rights reserved.
* Copyright (c) 2018, 2023 by Delphix. All rights reserved.
*/
#include <stdio.h>
@ -790,6 +790,18 @@ test_set_bootenv(const char *pool)
nvlist_free(required);
}
static void
test_pool_recycle(const char *pool)
{
nvlist_t *required = fnvlist_alloc();
fnvlist_add_boolean_value(required, "dryrun", B_FALSE);
IOC_INPUT_TEST_WILD(ZFS_IOC_POOL_RECYCLE, pool, required, NULL, 0);
nvlist_free(required);
}
static void
zfs_ioc_input_tests(const char *pool)
{
@ -884,6 +896,8 @@ zfs_ioc_input_tests(const char *pool)
test_scrub(pool);
test_pool_recycle(pool);
/*
* cleanup
*/
@ -1039,6 +1053,7 @@ validate_ioc_values(void)
CHECK(ZFS_IOC_BASE + 83 == ZFS_IOC_WAIT);
CHECK(ZFS_IOC_BASE + 84 == ZFS_IOC_WAIT_FS);
CHECK(ZFS_IOC_BASE + 87 == ZFS_IOC_POOL_SCRUB);
CHECK(ZFS_IOC_BASE + 88 == ZFS_IOC_POOL_RECYCLE);
CHECK(ZFS_IOC_PLATFORM_BASE + 1 == ZFS_IOC_EVENTS_NEXT);
CHECK(ZFS_IOC_PLATFORM_BASE + 2 == ZFS_IOC_EVENTS_CLEAR);
CHECK(ZFS_IOC_PLATFORM_BASE + 3 == ZFS_IOC_EVENTS_SEEK);

View File

@ -21,7 +21,7 @@
#
# Copyright (c) 2009, Sun Microsystems Inc. All rights reserved.
# Copyright (c) 2012, 2020, Delphix. All rights reserved.
# Copyright (c) 2012, 2024, Delphix. All rights reserved.
# Copyright (c) 2017, Tim Chase. All rights reserved.
# Copyright (c) 2017, Nexenta Systems Inc. All rights reserved.
# Copyright (c) 2017, Lawrence Livermore National Security LLC.
@ -1586,10 +1586,10 @@ function create_pool #pool devs_list
if is_global_zone ; then
[[ -d /$pool ]] && rm -rf /$pool
log_must zpool create -f $pool $@
zpool create -f $pool $@
fi
return 0
return $?
}
# Return 0 if destroy successfully or the pool exists; $? otherwise

View File

@ -29,6 +29,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS = \
perf/regression/sequential_reads.ksh \
perf/regression/sequential_writes.ksh \
perf/regression/setup.ksh \
perf/regression/cleanup.ksh \
\
perf/scripts/prefetch_io.sh
@ -363,6 +364,8 @@ nobase_dist_datadir_zfs_tests_tests_DATA += \
functional/rsend/rsend.kshlib \
functional/scrub_mirror/default.cfg \
functional/scrub_mirror/scrub_mirror_common.kshlib \
functional/shared_log/shared_log.cfg \
functional/shared_log/shared_log.kshlib \
functional/slog/slog.cfg \
functional/slog/slog.kshlib \
functional/snapshot/snapshot.cfg \
@ -1942,6 +1945,16 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
functional/scrub_mirror/scrub_mirror_003_pos.ksh \
functional/scrub_mirror/scrub_mirror_004_pos.ksh \
functional/scrub_mirror/setup.ksh \
functional/shared_log/cleanup.ksh \
functional/shared_log/setup.ksh \
functional/shared_log/shared_log_001_pos.ksh \
functional/shared_log/shared_log_002_pos.ksh \
functional/shared_log/shared_log_003_pos.ksh \
functional/shared_log/shared_log_004_pos.ksh \
functional/shared_log/shared_log_005_pos.ksh \
functional/shared_log/shared_log_006_neg.ksh \
functional/shared_log/shared_log_007_pos.ksh \
functional/shared_log/shared_log_008_pos.ksh \
functional/slog/cleanup.ksh \
functional/slog/setup.ksh \
functional/slog/slog_001_pos.ksh \

View File

@ -109,5 +109,6 @@ if is_linux || is_freebsd; then
"feature@block_cloning"
"feature@vdev_zaps_v2"
"feature@raidz_expansion"
"feature@shared_log"
)
fi

View File

@ -0,0 +1,49 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2023 by Delphix. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/shared_log/shared_log.cfg
verify_runnable "global"
zpool import $LOGPOOL
zpool import ${LOGPOOL}2
zpool import $TESTPOOL
zpool import $TESTPOOL2
if datasetexists $TESTPOOL ; then
log_must zpool destroy -f $TESTPOOL
fi
if datasetexists $TESTPOOL2 ; then
log_must zpool destroy -f $TESTPOOL2
fi
if datasetexists $LOGPOOL ; then
log_must zpool destroy -f $LOGPOOL
fi
if datasetexists ${LOGPOOL}2 ; then
log_must zpool destroy -f ${LOGPOOL}2
fi
log_pass

View File

@ -0,0 +1,32 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2023 by Delphix. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/shared_log/shared_log.cfg
verify_runnable "global"
log_pass

View File

@ -0,0 +1,30 @@
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2023 by Delphix. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
export LOGPOOL="${TESTPOOL}_log"
read -r DISK0 DISK1 DISK2 _ <<<"$DISKS"
export DISK0 DISK1 DISK2

View File

@ -0,0 +1,47 @@
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2023 by Delphix. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
. $STF_SUITE/tests/functional/shared_log/shared_log.cfg
function cleanup
{
zpool import $LOGPOOL
zpool import ${LOGPOOL}2
zpool import -m $TESTPOOL
zpool import -m $TESTPOOL2
poolexists $TESTPOOL && destroy_pool $TESTPOOL
poolexists $TESTPOOL2 && destroy_pool $TESTPOOL2
poolexists $LOGPOOL && destroy_pool $LOGPOOL
poolexists ${LOGPOOL}2 && destroy_pool ${LOGPOOL}2
}
function verify_shared_log
{
local target="$1"
local log_pool_name="$2"
zpool list -v $target | grep -A 1 "shared log" | tail -n 1 | grep "^ *$log_pool_name" >/dev/null
return $?
}

View File

@ -0,0 +1,50 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2023 by Delphix. All rights reserved.
#
. $STF_SUITE/tests/functional/shared_log/shared_log.kshlib
#
# DESCRIPTION:
# Creating a pool with a shared log succeeds.
#
# STRATEGY:
# 1. Create shared log pool
# 2. Create client pool with shared log
# 3. Display pool status
#
verify_runnable "global"
log_assert "Creating a pool with a shared log succeeds."
log_onexit cleanup
log_must create_pool $LOGPOOL -L "$DISK0"
log_must create_pool $TESTPOOL -l $LOGPOOL "$DISK1"
log_must verify_shared_log $TESTPOOL $LOGPOOL
verify_pool $LOGPOOL
verify_pool $TESTPOOL
log_pass "Creating a pool with a shared log succeeds."

View File

@ -0,0 +1,61 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2023 by Delphix. All rights reserved.
#
. $STF_SUITE/tests/functional/shared_log/shared_log.kshlib
#
# DESCRIPTION:
# Using a pool with a shared log device succeeds at basic operations.
#
# STRATEGY:
# 1. Create shared log pool & client
# 2. Create sync=always fs on client
# 3. Write data to fs
# 4. Export & import client
# 5. Write data to fs again
#
verify_runnable "global"
log_assert "Using a pool with a shared log device succeeds at basic operations."
log_onexit cleanup
typeset FS="$TESTPOOL/fs"
log_must create_pool $LOGPOOL -L "$DISK0"
log_must create_pool $TESTPOOL -l $LOGPOOL "$DISK1"
log_must verify_shared_log $TESTPOOL $LOGPOOL
log_must zfs create -o sync=always -o recordsize=8k $FS
mntpnt=$(get_prop mountpoint $FS)
log_must dd if=/dev/urandom of="$mntpnt/f1" bs=8k count=128
log_must zpool export $TESTPOOL
log_must zpool import $TESTPOOL
log_must dd if=/dev/urandom of="$mntpnt/f1" bs=8k count=128
verify_pool $LOGPOOL
verify_pool $TESTPOOL
log_pass "Using a pool with a shared log device succeeds at basic operations."

View File

@ -0,0 +1,64 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2023 by Delphix. All rights reserved.
#
. $STF_SUITE/tests/functional/shared_log/shared_log.kshlib
#
# DESCRIPTION:
# Shared log pool can be exported and imported.
#
# STRATEGY:
# 1. Create shared log pool & client
# 2. Write some data to the client pool
# 3. Export client
# 4. Export & import provider
# 5. Import client
# 6. Write data to client
#
verify_runnable "global"
log_assert "Shared log pool can be exported and imported."
log_onexit cleanup
typeset FS="$TESTPOOL/fs"
log_must create_pool $LOGPOOL -L "$DISK0"
log_must create_pool $TESTPOOL -l $LOGPOOL "$DISK1"
log_must verify_shared_log $TESTPOOL $LOGPOOL
log_must zfs create -o sync=always -o recordsize=8k $FS
mntpnt=$(get_prop mountpoint $FS)
log_must dd if=/dev/urandom of="$mntpnt/f1" bs=8k count=128
log_must zpool export $TESTPOOL
log_must zpool export $LOGPOOL
log_must zpool import $LOGPOOL
log_must zpool import $TESTPOOL
log_must dd if=/dev/urandom of="$mntpnt/f2" bs=8k count=128
verify_pool $LOGPOOL
verify_pool $TESTPOOL
log_pass "Shared log pool can be exported and imported."

View File

@ -0,0 +1,70 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2023 by Delphix. All rights reserved.
#
. $STF_SUITE/tests/functional/shared_log/shared_log.kshlib
#
# DESCRIPTION:
# Client pools can be reimported without provider, with flag.
#
# STRATEGY:
# 1. Create shared log pools & client
# 2. Write data to client
# 3. Export client and provider
# 4. Import client with -m
# 5. Export client
# 6. Import client with -m and new provider
#
verify_runnable "global"
log_assert "Client pools can be reimported without provider, with flag."
log_onexit cleanup
typeset FS="$TESTPOOL/fs"
log_must create_pool $LOGPOOL -L "$DISK0"
log_must create_pool ${LOGPOOL}2 -L "$DISK1"
log_must create_pool $TESTPOOL -l $LOGPOOL "$DISK2"
log_must verify_shared_log $TESTPOOL $LOGPOOL
log_must zfs create -o sync=always -o recordsize=8k $FS
mntpnt=$(get_prop mountpoint $FS)
log_must dd if=/dev/urandom of="$mntpnt/f1" bs=8k count=128
log_must zpool export $TESTPOOL
log_must zpool export $LOGPOOL
log_must zpool import -m $TESTPOOL
log_must dd if=/dev/urandom of="$mntpnt/f2" bs=8k count=128
log_must zpool export $TESTPOOL
log_must zpool import $LOGPOOL
log_must zpool import -m -L ${LOGPOOL}2 $TESTPOOL
log_must verify_shared_log $TESTPOOL ${LOGPOOL}2
log_must dd if=/dev/urandom of="$mntpnt/f3" bs=8k count=128
verify_pool $LOGPOOL
verify_pool $LOGPOOL2
verify_pool $TESTPOOL
log_pass "Client pools can be reimported without provider, with flag."

View File

@ -0,0 +1,58 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2023 by Delphix. All rights reserved.
#
. $STF_SUITE/tests/functional/shared_log/shared_log.kshlib
#
# DESCRIPTION:
# Test scrub with client and provider pools.
#
# STRATEGY:
# 1. Create shared log pool & client
# 2. Write some data to the client pool
# 3. Scrub client and provider pools
#
verify_runnable "global"
log_assert "Test scrub with client and provider pools."
log_onexit cleanup
typeset FS="$TESTPOOL/fs"
log_must create_pool $LOGPOOL -L "$DISK0"
log_must create_pool $TESTPOOL -l $LOGPOOL "$DISK1"
log_must verify_shared_log $TESTPOOL $LOGPOOL
log_must zfs create -o sync=always -o recordsize=8k $FS
mntpnt=$(get_prop mountpoint $FS)
log_must dd if=/dev/urandom of="$mntpnt/f1" bs=8k count=128
log_must zpool scrub $LOGPOOL
log_must zpool scrub $TESTPOOL
log_must zpool wait -t scrub $LOGPOOL
log_must zpool wait -t scrub $TESTPOOL
log_pass "Test scrub with client and provider pools."

View File

@ -0,0 +1,78 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2023 by Delphix. All rights reserved.
#
. $STF_SUITE/tests/functional/shared_log/shared_log.kshlib
#
# DESCRIPTION:
# Negative shared log testing.
#
# STRATEGY:
# 1. Attempt to create a client pool with a missing shared log pool
# 2. Attempt to create a client pool with mis-named shared log pool
# 3. Attempt to create a client pool with a shared log and a log device
# 4. Attempt to use a client pool after the shared log has been destroyed
# 5. Attempt to create a client pool when the feature is disabled
# 6. Attempt to export/destroy an active shared log
# 7. Attempt to reguid a client/log pool
# 8. Attempt to checkpoint a client/log pool
#
verify_runnable "global"
log_assert "Negative shared log testing."
log_onexit cleanup
log_mustnot create_pool $TESTPOOL -l $LOGPOOL "$DISK0"
log_must create_pool $TESTPOOL2 "$DISK2"
log_mustnot create_pool $TESTPOOL -l $TESTPOOL2 "$DISK0"
log_must zpool destroy $TESTPOOL2
log_must create_pool $LOGPOOL -L "$DISK0"
log_mustnot create_pool $TESTPOOL -l "${LOGPOOL}2" "$DISK1"
log_mustnot create_pool $TESTPOOL -l $LOGPOOL "$DISK1" log "$DISK2"
log_must create_pool ${LOGPOOL}2 -L "$DISK1"
log_must zpool destroy ${LOGPOOL}2
typeset FS="$LOGPOOL/fs"
log_mustnot zfs create -o sync=always -o recordsize=8k $FS
log_mustnot create_pool $TESTPOOL -l $LOGPOOL -o feature@shared_log=disabled "$DISK1"
log_mustnot create_pool ${LOGPOOL}2 -L -o feature@shared_log=disabled "$DISK1"
log_must create_pool $TESTPOOL -l $LOGPOOL "$DISK1"
log_mustnot zpool export $LOGPOOL
log_mustnot zpool destroy $LOGPOOL
log_mustnot zpool reguid $LOGPOOL
log_mustnot zpool reguid $TESTPOOL
log_mustnot zpool checkpoint $TESTPOOL
log_mustnot zpool checkpoint $LOGPOOL
log_pass "Negative shared log testing."

View File

@ -0,0 +1,51 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2024 by Delphix. All rights reserved.
#
. $STF_SUITE/tests/functional/shared_log/shared_log.kshlib
#
# DESCRIPTION:
# Test fault behavior of shared log pool
#
# STRATEGY:
# 1. Create shared log pool & client
# 2. Fault the provider pool
# 3. Verify the client pool also faults
#
verify_runnable "global"
log_assert "Test fault behavior of shared log pools."
log_onexit cleanup
typeset FS="$TESTPOOL/fs"
log_must create_pool $LOGPOOL -L "$DISK0"
log_must create_pool $TESTPOOL -l $LOGPOOL "$DISK1"
log_must zinject -d "$DISK0" -A degrade $LOGPOOL
log_must eval "zpool status -e $TESTPOOL | grep DEGRADED"
log_pass "Test fault behavior of shared log pools."

View File

@ -0,0 +1,81 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 2024 by Delphix. All rights reserved.
#
. $STF_SUITE/tests/functional/shared_log/shared_log.kshlib
#
# DESCRIPTION:
# Test zpool recycle
#
# STRATEGY:
# 1. Create shared log pool & clients
# 2. Verify zpool recycle -a doesn't recycle anything
# 3. Export clients
# 4. Verify zpool recycle -a recycles everything
# 5. Re-add clients and export both
# 6. Verify zpool recycle of a single client works as expected
# 7. Re-add client and export it
# 8. Verify zpool recycle of multiple clients works as expected
#
verify_runnable "global"
log_assert "Test zpool recycle."
log_onexit cleanup
typeset FS="$TESTPOOL/fs"
log_must create_pool $LOGPOOL -L "$DISK0"
log_must create_pool $TESTPOOL -l $LOGPOOL "$DISK1"
log_must create_pool ${TESTPOOL}2 -l $LOGPOOL "$DISK2"
log_must zfs create -o sync=always ${TESTPOOL}/fs
log_must zfs create -o sync=always ${TESTPOOL}2/fs
log_must dd if=/dev/urandom of=/${TESTPOOL}/fs/f1 bs=128k count=128
log_must dd if=/dev/urandom of=/${TESTPOOL}2/fs/f1 bs=128k count=128
log_must eval "zpool recycle -a -v $LOGPOOL | grep '\\[\\]' >/dev/null"
log_must zpool export $TESTPOOL
log_must zpool export ${TESTPOOL}2
log_must zpool recycle -a -v $LOGPOOL
log_mustnot zpool import $TESTPOOL
log_mustnot zpool import ${TESTPOOL}2
log_must zpool import -m -L $LOGPOOL $TESTPOOL
log_must zpool import -m -L $LOGPOOL ${TESTPOOL}2
log_must dd if=/dev/urandom of=/${TESTPOOL}/fs/f1 bs=128k count=128
log_must zpool export $TESTPOOL
log_must zpool export ${TESTPOOL}2
log_must zpool recycle $LOGPOOL $TESTPOOL
log_mustnot zpool import $TESTPOOL
log_must zpool import -m -L $LOGPOOL $TESTPOOL
log_must dd if=/dev/urandom of=/${TESTPOOL}/fs/f1 bs=128k count=128
log_must zpool export $TESTPOOL
log_must zpool recycle $LOGPOOL $TESTPOOL ${TESTPOOL2}
log_mustnot zpool import $TESTPOOL
log_mustnot zpool import ${TESTPOOL}2
log_pass "Test zpool recycle."

View File

@ -10,7 +10,7 @@
#
#
# Copyright (c) 2015, 2021 by Delphix. All rights reserved.
# Copyright (c) 2015, 2023 by Delphix. All rights reserved.
# Copyright (c) 2016, Intel Corporation.
#
@ -21,6 +21,7 @@ export PERF_RUNTIME=${PERF_RUNTIME:-'180'}
export PERF_RANDSEED=${PERF_RANDSEED:-'1234'}
export PERF_COMPPERCENT=${PERF_COMPPERCENT:-'66'}
export PERF_COMPCHUNK=${PERF_COMPCHUNK:-'4096'}
export PERF_LOG_TYPES=${PERF_LOG_TYPES:-"none slog shared"}
# Default to JSON for fio output
export PERF_FIO_FORMAT=${PERF_FIO_FORMAT:-'json'}
@ -44,12 +45,13 @@ function get_suffix
typeset threads=$1
typeset sync=$2
typeset iosize=$3
typeset log_type=$4
typeset sync_str=$(get_sync_str $sync)
typeset filesystems=$(get_nfilesystems)
typeset suffix="$sync_str.$iosize-ios"
suffix="$suffix.$threads-threads.$filesystems-filesystems"
suffix="$suffix.$threads-threads.$filesystems-filesystems.$log_type-log"
echo $suffix
}
@ -63,9 +65,10 @@ function do_fio_run_impl
typeset threads_per_fs=$5
typeset sync=$6
typeset iosize=$7
typeset log_type=$8
typeset sync_str=$(get_sync_str $sync)
log_note "Running with $threads $sync_str threads, $iosize ios"
log_note "Running with $threads $sync_str threads, $iosize ios with log $log_type"
if [[ -n $threads_per_fs && $threads_per_fs -ne 0 ]]; then
log_must test $do_recreate
@ -73,7 +76,7 @@ function do_fio_run_impl
fi
if $do_recreate; then
recreate_perf_pool
recreate_perf_pool $log_type
#
# A value of zero for "threads_per_fs" is "special", and
@ -127,7 +130,7 @@ function do_fio_run_impl
fi
# This will be part of the output filename.
typeset suffix=$(get_suffix $threads $sync $iosize)
typeset suffix=$(get_suffix $threads $sync $iosize $log_type)
# Start the data collection
do_collect_scripts $suffix
@ -168,20 +171,27 @@ function do_fio_run
typeset script=$1
typeset do_recreate=$2
typeset clear_cache=$3
typeset log_types=$4
typeset threads threads_per_fs sync iosize
for threads in $PERF_NTHREADS; do
for threads_per_fs in $PERF_NTHREADS_PER_FS; do
for sync in $PERF_SYNC_TYPES; do
for iosize in $PERF_IOSIZES; do
do_fio_run_impl \
$script \
$do_recreate \
$clear_cache \
$threads \
$threads_per_fs \
$sync \
$iosize
for logtype in $log_types; do
if [[ $sync == "0" && $logtype != "none" ]]; then
continue
fi
do_fio_run_impl \
$script \
$do_recreate \
$clear_cache \
$threads \
$threads_per_fs \
$sync \
$iosize \
$logtype
done
done
done
done
@ -286,8 +296,10 @@ function clear_zinject_delays
#
function recreate_perf_pool
{
typeset logtype=$1
[[ -n $PERFPOOL ]] || log_fail "The \$PERFPOOL variable isn't set."
log_note "recreating $PERFPOOL with $logtype"
#
# In case there's been some "leaked" zinject delays, or if the
# performance test injected some delays itself, we clear all
@ -297,6 +309,23 @@ function recreate_perf_pool
#
clear_zinject_delays
if [[ $logtype == "none" ]]; then
destroy_pool $PERFPOOL
destroy_pool "${PERFPOOL}_log"
create_pool $PERFPOOL $DISKS
else
typeset disks="${DISKS% *}"
typeset log_disk="${DISKS##* }"
if [[ $logtype == "slog" ]]; then
destroy_pool $PERFPOOL
destroy_pool "${PERFPOOL}_log"
create_pool $PERFPOOL $disks log $log_disk
else
destroy_pool $PERFPOOL
create_pool ${PERFPOOL}_log -L $log_disk
create_pool $PERFPOOL -l ${PERFPOOL}_log $disks
fi
fi
#
# This function handles the case where the pool already exists,
# and will destroy the previous pool and recreate a new pool.

View File

@ -0,0 +1,38 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or https://opensource.org/licenses/CDDL-1.0.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright (c) 20236 by Delphix. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
verify_runnable "global"
if datasetexists $PERFPOOL ; then
log_must destroy_pool $PERFPOOL
fi
if datasetexists ${PERFPOOL}_log ; then
log_must destroy_pool ${PERFPOOL}_log
fi
log_pass

View File

@ -12,7 +12,7 @@
#
#
# Copyright (c) 2015, 2021 by Delphix. All rights reserved.
# Copyright (c) 2015, 2023 by Delphix. All rights reserved.
#
#
@ -45,55 +45,56 @@ function cleanup
# kill fio and iostat
pkill fio
pkill iostat
recreate_perf_pool
}
trap "log_fail \"Measure IO stats during random read load\"" SIGTERM
log_onexit cleanup
recreate_perf_pool
populate_perf_filesystems
for logtype in $PERF_LOG_TYPES; do
recreate_perf_pool $logtype
populate_perf_filesystems
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'16 32'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'8k'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Layout the files to be used by the read tests. Create as many files as the
# largest number of threads. An fio run with fewer threads will use a subset
# of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'16 32'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'8k'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
# Layout the files to be used by the read tests. Create as many files as the
# largest number of threads. An fio run with fewer threads will use a subset
# of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
log_note "Random reads with settings: $(print_perf_settings)"
do_fio_run random_reads.fio false true
log_note "Random reads with settings: $(print_perf_settings)"
do_fio_run random_reads.fio false true $logtype
done
log_pass "Measure IO stats during random read load"

View File

@ -12,7 +12,7 @@
#
#
# Copyright (c) 2015, 2021 by Delphix. All rights reserved.
# Copyright (c) 2015, 2022 by Delphix. All rights reserved.
#
#
@ -45,55 +45,56 @@ function cleanup
# kill fio and iostat
pkill fio
pkill iostat
recreate_perf_pool
}
trap "log_fail \"Measure IO stats during random read load\"" SIGTERM
log_onexit cleanup
recreate_perf_pool
populate_perf_filesystems
for logtype in $PERF_LOG_TYPES; do
recreate_perf_pool $logtype
populate_perf_filesystems
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'32 64'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES='bssplit' # bssplit used instead of fixed sizes
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Layout the files to be used by the readwrite tests. Create as many files
# as the largest number of threads. An fio run with fewer threads will use
# a subset of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'32 64'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES='bssplit' # bssplit used instead of fixed sizes
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Layout the files to be used by the readwrite tests. Create as many files
# as the largest number of threads. An fio run with fewer threads will use
# a subset of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
log_note "Random reads and writes with settings: $(print_perf_settings)"
do_fio_run random_readwrite.fio false true
log_note "Random reads and writes with settings: $(print_perf_settings)"
do_fio_run random_readwrite.fio false true $logtype
done
log_pass "Measure IO stats during random read and write load"

View File

@ -1,4 +1,4 @@
#!/bin/ksh
tests/zfs-tests/tests/perf/regression/random_readwrite_fixed.ksh#!/bin/ksh
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
@ -11,7 +11,7 @@
#
#
# Copyright (c) 2017, 2021 by Delphix. All rights reserved.
# Copyright (c) 2017, 2023 by Delphix. All rights reserved.
#
#
@ -35,57 +35,58 @@ function cleanup
# kill fio and iostat
pkill fio
pkill iostat
recreate_perf_pool
}
trap "log_fail \"Measure IO stats during random read write load\"" SIGTERM
log_onexit cleanup
recreate_perf_pool
populate_perf_filesystems
for logtype in $PERF_LOG_TYPES; do
recreate_perf_pool $logtype
populate_perf_filesystems
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'8k'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'0 1'}
# Layout the files to be used by the readwrite tests. Create as many files
# as the largest number of threads. An fio run with fewer threads will use
# a subset of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"kstat zfs:0 1" "kstat"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
"dtrace -Cs $PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"dtrace -s $PERF_SCRIPTS/profile.d" "profile"
)
fi
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'8k'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'0 1'}
# Layout the files to be used by the readwrite tests. Create as many files
# as the largest number of threads. An fio run with fewer threads will use
# a subset of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"kstat zfs:0 1" "kstat"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
"dtrace -Cs $PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"dtrace -s $PERF_SCRIPTS/profile.d" "profile"
)
fi
log_note "Random reads and writes with settings: $(print_perf_settings)"
do_fio_run random_readwrite_fixed.fio false true
log_note "Random reads and writes with settings: $(print_perf_settings)"
do_fio_run random_readwrite_fixed.fio false true $logtype
done
log_pass "Measure IO stats during random read and write load"

View File

@ -12,7 +12,7 @@
#
#
# Copyright (c) 2015, 2021 by Delphix. All rights reserved.
# Copyright (c) 2015, 2023 by Delphix. All rights reserved.
#
#
@ -44,14 +44,12 @@ function cleanup
# kill fio and iostat
pkill fio
pkill iostat
recreate_perf_pool
}
trap "log_fail \"Measure IO stats during random read load\"" SIGTERM
log_onexit cleanup
recreate_perf_pool
populate_perf_filesystems
recreate_perf_pool none
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
@ -86,5 +84,5 @@ else
fi
log_note "Random writes with settings: $(print_perf_settings)"
do_fio_run random_writes.fio true false
do_fio_run random_writes.fio true false "$PERF_LOG_TYPES"
log_pass "Measure IO stats during random write load"

View File

@ -12,7 +12,7 @@
#
#
# Copyright (c) 2015, 2021 by Delphix. All rights reserved.
# Copyright (c) 2015, 2023 by Delphix. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
@ -26,21 +26,12 @@ function cleanup
pkill fio
pkill iostat
#
# We're using many filesystems depending on the number of
# threads for each test, and there's no good way to get a list
# of all the filesystems that should be destroyed on cleanup
# (i.e. the list of filesystems used for the last test ran).
# Thus, we simply recreate the pool as a way to destroy all
# filesystems and leave a fresh pool behind.
#
recreate_perf_pool
}
trap "log_fail \"Measure IO stats during random write load\"" SIGTERM
log_onexit cleanup
recreate_perf_pool
recreate_perf_pool none
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
@ -82,5 +73,5 @@ else
fi
log_note \
"ZIL specific random write workload with settings: $(print_perf_settings)"
do_fio_run random_writes.fio true false
do_fio_run random_writes.fio true false "$PERF_LOG_TYPES"
log_pass "Measure IO stats during ZIL specific random write workload"

View File

@ -12,7 +12,7 @@
#
#
# Copyright (c) 2015, 2021 by Delphix. All rights reserved.
# Copyright (c) 2015, 2023 by Delphix. All rights reserved.
#
#
@ -43,57 +43,59 @@ function cleanup
# kill fio and iostat
pkill fio
pkill iostat
recreate_perf_pool
}
trap "log_fail \"Measure IO stats during random read load\"" SIGTERM
log_onexit cleanup
recreate_perf_pool
populate_perf_filesystems
for logtype in $PERF_LOG_TYPES; do
recreate_perf_pool $logtype
populate_perf_filesystems
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'8 16'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'128k 1m'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Layout the files to be used by the read tests. Create as many files as the
# largest number of threads. An fio run with fewer threads will use a subset
# of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'8 16'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'128k 1m'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Layout the files to be used by the read tests. Create as many files as the
# largest number of threads. An fio run with fewer threads will use a subset
# of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"$PERF_SCRIPTS/prefetch_io.sh $PERFPOOL 1" "prefetch"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"$PERF_SCRIPTS/prefetch_io.d $PERFPOOL 1" "prefetch"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
log_note "Sequential reads with settings: $(print_perf_settings)"
do_fio_run sequential_reads.fio false true
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"$PERF_SCRIPTS/prefetch_io.sh $PERFPOOL 1" "prefetch"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"$PERF_SCRIPTS/prefetch_io.d $PERFPOOL 1" "prefetch"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
log_note "Sequential reads with settings: $(print_perf_settings)"
do_fio_run sequential_reads.fio false true $logtype
done
log_pass "Measure IO stats during sequential read load"

View File

@ -12,7 +12,7 @@
#
#
# Copyright (c) 2015, 2021 by Delphix. All rights reserved.
# Copyright (c) 2015, 2023 by Delphix. All rights reserved.
#
#
@ -35,57 +35,58 @@ function cleanup
# kill fio and iostat
pkill fio
pkill iostat
recreate_perf_pool
}
trap "log_fail \"Measure IO stats during random read load\"" SIGTERM
log_onexit cleanup
recreate_perf_pool
populate_perf_filesystems
for logtype in $PERF_LOG_TYPES; do
recreate_perf_pool $logtype
populate_perf_filesystems
# Make sure the working set can be cached in the arc. Aim for 1/2 of arc.
export TOTAL_SIZE=$(($(get_max_arc_size) / 2))
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'128k'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Layout the files to be used by the read tests. Create as many files as the
# largest number of threads. An fio run with fewer threads will use a subset
# of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
# Make sure the working set can be cached in the arc. Aim for 1/2 of arc.
export TOTAL_SIZE=$(($(get_max_arc_size) / 2))
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'128k'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Layout the files to be used by the read tests. Create as many files as the
# largest number of threads. An fio run with fewer threads will use a subset
# of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"$PERF_SCRIPTS/prefetch_io.sh $PERFPOOL 1" "prefetch"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"$PERF_SCRIPTS/prefetch_io.d $PERFPOOL 1" "prefetch"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
log_note "Sequential cached reads with settings: $(print_perf_settings)"
do_fio_run sequential_reads.fio false false
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"$PERF_SCRIPTS/prefetch_io.sh $PERFPOOL 1" "prefetch"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"$PERF_SCRIPTS/prefetch_io.d $PERFPOOL 1" "prefetch"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
log_note "Sequential cached reads with settings: $(print_perf_settings)"
do_fio_run sequential_reads.fio false false $logtype
done
log_pass "Measure IO stats during sequential cached read load"

View File

@ -12,7 +12,7 @@
#
#
# Copyright (c) 2015, 2021 by Delphix. All rights reserved.
# Copyright (c) 2015, 2023 by Delphix. All rights reserved.
#
#
@ -41,78 +41,79 @@ function cleanup
# kill fio and iostat
pkill fio
pkill iostat
recreate_perf_pool
}
trap "log_fail \"Measure IO stats during random read load\"" SIGTERM
log_onexit cleanup
recreate_perf_pool
populate_perf_filesystems
for logtype in $PERF_LOG_TYPES; do
recreate_perf_pool $logtype
populate_perf_filesystems
# Make sure the working set can be cached in the arc. Aim for 1/2 of arc.
export TOTAL_SIZE=$(($(get_max_arc_size) / 2))
# Make sure the working set can be cached in the arc. Aim for 1/2 of arc.
export TOTAL_SIZE=$(($(get_max_arc_size) / 2))
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'128k'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Layout the files to be used by the read tests. Create as many files as the
# largest number of threads. An fio run with fewer threads will use a subset
# of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
#
# Only a single filesystem is used by this test. To be defensive, we
# double check that TESTFS only contains a single filesystem. We
# wouldn't want to assume this was the case, and have it actually
# contain multiple filesystem (causing cascading failures later).
#
log_must test $(get_nfilesystems) -eq 1
log_note "Creating snapshot, $TESTSNAP, of $TESTFS"
create_snapshot $TESTFS $TESTSNAP
log_note "Creating clone, $PERFPOOL/$TESTCLONE, from $TESTFS@$TESTSNAP"
create_clone $TESTFS@$TESTSNAP $PERFPOOL/$TESTCLONE
#
# We want to run FIO against the clone we created above, and not the
# clone's originating filesystem. Thus, we override the default behavior
# and explicitly set TESTFS to the clone.
#
export TESTFS=$PERFPOOL/$TESTCLONE
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'128k'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Layout the files to be used by the read tests. Create as many files as the
# largest number of threads. An fio run with fewer threads will use a subset
# of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
#
# Only a single filesystem is used by this test. To be defensive, we
# double check that TESTFS only contains a single filesystem. We
# wouldn't want to assume this was the case, and have it actually
# contain multiple filesystem (causing cascading failures later).
#
log_must test $(get_nfilesystems) -eq 1
log_note "Creating snapshot, $TESTSNAP, of $TESTFS"
create_snapshot $TESTFS $TESTSNAP
log_note "Creating clone, $PERFPOOL/$TESTCLONE, from $TESTFS@$TESTSNAP"
create_clone $TESTFS@$TESTSNAP $PERFPOOL/$TESTCLONE
#
# We want to run FIO against the clone we created above, and not the
# clone's originating filesystem. Thus, we override the default behavior
# and explicitly set TESTFS to the clone.
#
export TESTFS=$PERFPOOL/$TESTCLONE
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"$PERF_SCRIPTS/prefetch_io.sh $PERFPOOL 1" "prefetch"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"$PERF_SCRIPTS/prefetch_io.d $PERFPOOL 1" "prefetch"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
log_note "Sequential cached reads from $DIRECTORY with " \
"ettings: $(print_perf_settings)"
do_fio_run sequential_reads.fio false false
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"$PERF_SCRIPTS/prefetch_io.sh $PERFPOOL 1" "prefetch"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"$PERF_SCRIPTS/prefetch_io.d $PERFPOOL 1" "prefetch"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
log_note "Sequential cached reads from $DIRECTORY with " \
"settings: $(print_perf_settings)"
do_fio_run sequential_reads.fio false false $logtype
done
log_pass "Measure IO stats during sequential cached read load"

View File

@ -12,7 +12,7 @@
#
#
# Copyright (c) 2016, 2021 by Delphix. All rights reserved.
# Copyright (c) 2016, 2023 by Delphix. All rights reserved.
#
#
@ -39,59 +39,60 @@ function cleanup
# kill fio and iostat
pkill fio
pkill iostat
recreate_perf_pool
}
trap "log_fail \"Measure IO stats during sequential read load\"" SIGTERM
log_onexit cleanup
recreate_perf_pool
populate_perf_filesystems
for logtype in $PERF_LOG_TYPES; do
recreate_perf_pool $logtype
populate_perf_filesystems
# Ensure the working set can be cached in the dbuf cache.
export TOTAL_SIZE=$(($(get_dbuf_cache_size) * 3 / 4))
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'64'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'64k'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Layout the files to be used by the read tests. Create as many files as the
# largest number of threads. An fio run with fewer threads will use a subset
# of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
# Ensure the working set can be cached in the dbuf cache.
export TOTAL_SIZE=$(($(get_dbuf_cache_size) * 3 / 4))
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'64'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'64k'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
# Layout the files to be used by the read tests. Create as many files as the
# largest number of threads. An fio run with fewer threads will use a subset
# of the available files.
export NUMJOBS=$(get_max $PERF_NTHREADS)
export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
export DIRECTORY=$(get_directory)
log_must fio $FIO_SCRIPTS/mkfiles.fio
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"$PERF_SCRIPTS/prefetch_io.sh $PERFPOOL 1" "prefetch"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"kstat zfs:0 1" "kstat"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
"dtrace -Cs $PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"dtrace -Cs $PERF_SCRIPTS/prefetch_io.d $PERFPOOL 1" "prefetch"
"dtrace -s $PERF_SCRIPTS/profile.d" "profile"
)
fi
log_note "Sequential cached reads with settings: $(print_perf_settings)"
do_fio_run sequential_reads.fio false false
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"$PERF_SCRIPTS/prefetch_io.sh $PERFPOOL 1" "prefetch"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"kstat zfs:0 1" "kstat"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
"dtrace -Cs $PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"dtrace -Cs $PERF_SCRIPTS/prefetch_io.d $PERFPOOL 1" "prefetch"
"dtrace -s $PERF_SCRIPTS/profile.d" "profile"
)
fi
log_note "Sequential cached reads with settings: $(print_perf_settings)"
do_fio_run sequential_reads.fio false false $logtype
done
log_pass "Measure IO stats during sequential cached read load"

View File

@ -12,7 +12,7 @@
#
#
# Copyright (c) 2015, 2021 by Delphix. All rights reserved.
# Copyright (c) 2015, 2023 by Delphix. All rights reserved.
#
#
@ -44,47 +44,48 @@ function cleanup
# kill fio and iostat
pkill fio
pkill iostat
recreate_perf_pool
}
trap "log_fail \"Measure IO stats during random read load\"" SIGTERM
log_onexit cleanup
recreate_perf_pool
populate_perf_filesystems
for logtype in $PERF_LOG_TYPES; do
recreate_perf_pool $logtype
populate_perf_filesystems
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
export TOTAL_SIZE=$(($(get_prop avail $PERFPOOL) * 3 / 2))
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'16 32'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'8k 1m'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'0 1'}
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
# Variables specific to this test for use by fio.
export PERF_NTHREADS=${PERF_NTHREADS:-'16 32'}
export PERF_NTHREADS_PER_FS=${PERF_NTHREADS_PER_FS:-'0'}
export PERF_IOSIZES=${PERF_IOSIZES:-'8k 1m'}
export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'0 1'}
# Set up the scripts and output files that will log performance data.
lun_list=$(pool_to_lun_list $PERFPOOL)
log_note "Collecting backend IO stats with lun list $lun_list"
if is_linux; then
typeset perf_record_cmd="perf record -F 99 -a -g -q \
-o /dev/stdout -- sleep ${PERF_RUNTIME}"
export collect_scripts=(
"zpool iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
"vmstat -t 1" "vmstat"
"mpstat -P ALL 1" "mpstat"
"iostat -tdxyz 1" "iostat"
"$perf_record_cmd" "perf"
)
else
export collect_scripts=(
"$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
"vmstat -T d 1" "vmstat"
"mpstat -T d 1" "mpstat"
"iostat -T d -xcnz 1" "iostat"
)
fi
log_note "Sequential writes with settings: $(print_perf_settings)"
do_fio_run sequential_writes.fio true false
log_note "Sequential writes with settings: $(print_perf_settings)"
do_fio_run sequential_writes.fio true false $logtype
done
log_pass "Measure IO stats during sequential write load"