*/
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
*/
/*
* At random times, the child self-immolates with a SIGKILL.
* This is the software equivalent of pulling the power cord.
* The parent then runs the test again, using the existing
- * storage pool, as many times as desired. If backwards compatability
+ * storage pool, as many times as desired. If backwards compatibility
* testing is enabled ztest will sometimes run the "older" version
* of ztest after a SIGKILL.
*
#include <sys/zio.h>
#include <sys/zil.h>
#include <sys/zil_impl.h>
+#include <sys/zfs_rlock.h>
#include <sys/vdev_impl.h>
#include <sys/vdev_file.h>
#include <sys/spa_impl.h>
#include <sys/metaslab_impl.h>
#include <sys/dsl_prop.h>
#include <sys/dsl_dataset.h>
+#include <sys/dsl_destroy.h>
#include <sys/dsl_scan.h>
#include <sys/zio_checksum.h>
#include <sys/refcount.h>
#include <sys/zfeature.h>
+#include <sys/dsl_userhold.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <umem.h>
-#include <dlfcn.h>
#include <ctype.h>
#include <math.h>
#include <sys/fs/zfs.h>
+#include <zfs_fletcher.h>
#include <libnvpair.h>
+#ifdef __GLIBC__
+#include <execinfo.h> /* for backtrace() */
+#endif
static int ztest_fd_data = -1;
static int ztest_fd_rand = -1;
.zo_mirrors = 2,
.zo_raidz = 4,
.zo_raidz_parity = 1,
- .zo_vdev_size = SPA_MINDEVSIZE,
+ .zo_vdev_size = SPA_MINDEVSIZE * 2,
.zo_datasets = 7,
.zo_threads = 23,
.zo_passtime = 60, /* 60 seconds */
extern uint64_t metaslab_gang_bang;
extern uint64_t metaslab_df_alloc_threshold;
+extern int metaslab_preload_limit;
static ztest_shared_opts_t *ztest_shared_opts;
static ztest_shared_opts_t ztest_opts;
ZTEST_IO_WRITE_ZEROES,
ZTEST_IO_TRUNCATE,
ZTEST_IO_SETATTR,
+ ZTEST_IO_REWRITE,
ZTEST_IO_TYPES
};
uint64_t bt_magic;
uint64_t bt_objset;
uint64_t bt_object;
+ uint64_t bt_dnodesize;
uint64_t bt_offset;
uint64_t bt_gen;
uint64_t bt_txg;
uint64_t bw_data;
} bufwad_t;
-/*
- * XXX -- fix zfs range locks to be generic so we can use them here.
- */
-typedef enum {
- RL_READER,
- RL_WRITER,
- RL_APPEND
-} rl_type_t;
-
typedef struct rll {
void *rll_writer;
int rll_readers;
kcondvar_t rll_cv;
} rll_t;
-typedef struct rl {
- uint64_t rl_object;
- uint64_t rl_offset;
- uint64_t rl_size;
- rll_t *rl_lock;
-} rl_t;
+typedef struct zll {
+ list_t z_list;
+ kmutex_t z_lock;
+} zll_t;
#define ZTEST_RANGE_LOCKS 64
#define ZTEST_OBJECT_LOCKS 64
dmu_object_type_t od_crtype;
uint64_t od_blocksize;
uint64_t od_crblocksize;
+ uint64_t od_crdnodesize;
uint64_t od_gen;
uint64_t od_crgen;
char od_name[MAXNAMELEN];
typedef struct ztest_ds {
ztest_shared_ds_t *zd_shared;
objset_t *zd_os;
- krwlock_t zd_zilog_lock;
+ rwlock_t zd_zilog_lock;
zilog_t *zd_zilog;
ztest_od_t *zd_od; /* debugging aid */
char zd_name[MAXNAMELEN];
kmutex_t zd_dirobj_lock;
rll_t zd_object_lock[ZTEST_OBJECT_LOCKS];
- rll_t zd_range_lock[ZTEST_RANGE_LOCKS];
+ zll_t zd_range_lock[ZTEST_RANGE_LOCKS];
} ztest_ds_t;
/*
ztest_func_t *zi_func; /* test function */
uint64_t zi_iters; /* iterations per execution */
uint64_t *zi_interval; /* execute every <interval> seconds */
+ const char *zi_funcname; /* name of test function */
} ztest_info_t;
typedef struct ztest_shared_callstate {
static ztest_shared_callstate_t *ztest_shared_callstate;
#define ZTEST_GET_SHARED_CALLSTATE(c) (&ztest_shared_callstate[c])
-/*
- * Note: these aren't static because we want dladdr() to work.
- */
ztest_func_t ztest_dmu_read_write;
ztest_func_t ztest_dmu_write_parallel;
ztest_func_t ztest_dmu_object_alloc_free;
ztest_func_t ztest_vdev_aux_add_remove;
ztest_func_t ztest_split_pool;
ztest_func_t ztest_reguid;
+ztest_func_t ztest_spa_upgrade;
+ztest_func_t ztest_fletcher;
+ztest_func_t ztest_verify_dnode_bt;
uint64_t zopt_always = 0ULL * NANOSEC; /* all the time */
uint64_t zopt_incessant = 1ULL * NANOSEC / 10; /* every 1/10 second */
uint64_t zopt_sometimes = 10ULL * NANOSEC; /* every 10 seconds */
uint64_t zopt_rarely = 60ULL * NANOSEC; /* every 60 seconds */
+#define ZTI_INIT(func, iters, interval) \
+ { .zi_func = (func), \
+ .zi_iters = (iters), \
+ .zi_interval = (interval), \
+ .zi_funcname = # func }
+
ztest_info_t ztest_info[] = {
- { ztest_dmu_read_write, 1, &zopt_always },
- { ztest_dmu_write_parallel, 10, &zopt_always },
- { ztest_dmu_object_alloc_free, 1, &zopt_always },
- { ztest_dmu_commit_callbacks, 1, &zopt_always },
- { ztest_zap, 30, &zopt_always },
- { ztest_zap_parallel, 100, &zopt_always },
- { ztest_split_pool, 1, &zopt_always },
- { ztest_zil_commit, 1, &zopt_incessant },
- { ztest_zil_remount, 1, &zopt_sometimes },
- { ztest_dmu_read_write_zcopy, 1, &zopt_often },
- { ztest_dmu_objset_create_destroy, 1, &zopt_often },
- { ztest_dsl_prop_get_set, 1, &zopt_often },
- { ztest_spa_prop_get_set, 1, &zopt_sometimes },
+ ZTI_INIT(ztest_dmu_read_write, 1, &zopt_always),
+ ZTI_INIT(ztest_dmu_write_parallel, 10, &zopt_always),
+ ZTI_INIT(ztest_dmu_object_alloc_free, 1, &zopt_always),
+ ZTI_INIT(ztest_dmu_commit_callbacks, 1, &zopt_always),
+ ZTI_INIT(ztest_zap, 30, &zopt_always),
+ ZTI_INIT(ztest_zap_parallel, 100, &zopt_always),
+ ZTI_INIT(ztest_split_pool, 1, &zopt_always),
+ ZTI_INIT(ztest_zil_commit, 1, &zopt_incessant),
+ ZTI_INIT(ztest_zil_remount, 1, &zopt_sometimes),
+ ZTI_INIT(ztest_dmu_read_write_zcopy, 1, &zopt_often),
+ ZTI_INIT(ztest_dmu_objset_create_destroy, 1, &zopt_often),
+ ZTI_INIT(ztest_dsl_prop_get_set, 1, &zopt_often),
+ ZTI_INIT(ztest_spa_prop_get_set, 1, &zopt_sometimes),
#if 0
- { ztest_dmu_prealloc, 1, &zopt_sometimes },
+ ZTI_INIT(ztest_dmu_prealloc, 1, &zopt_sometimes),
#endif
- { ztest_fzap, 1, &zopt_sometimes },
- { ztest_dmu_snapshot_create_destroy, 1, &zopt_sometimes },
- { ztest_spa_create_destroy, 1, &zopt_sometimes },
- { ztest_fault_inject, 1, &zopt_sometimes },
- { ztest_ddt_repair, 1, &zopt_sometimes },
- { ztest_dmu_snapshot_hold, 1, &zopt_sometimes },
- { ztest_reguid, 1, &zopt_sometimes },
- { ztest_spa_rename, 1, &zopt_rarely },
- { ztest_scrub, 1, &zopt_rarely },
- { ztest_dsl_dataset_promote_busy, 1, &zopt_rarely },
- { ztest_vdev_attach_detach, 1, &zopt_rarely },
- { ztest_vdev_LUN_growth, 1, &zopt_rarely },
- { ztest_vdev_add_remove, 1,
- &ztest_opts.zo_vdevtime },
- { ztest_vdev_aux_add_remove, 1,
- &ztest_opts.zo_vdevtime },
+ ZTI_INIT(ztest_fzap, 1, &zopt_sometimes),
+ ZTI_INIT(ztest_dmu_snapshot_create_destroy, 1, &zopt_sometimes),
+ ZTI_INIT(ztest_spa_create_destroy, 1, &zopt_sometimes),
+ ZTI_INIT(ztest_fault_inject, 1, &zopt_sometimes),
+ ZTI_INIT(ztest_ddt_repair, 1, &zopt_sometimes),
+ ZTI_INIT(ztest_dmu_snapshot_hold, 1, &zopt_sometimes),
+ ZTI_INIT(ztest_reguid, 1, &zopt_rarely),
+ ZTI_INIT(ztest_spa_rename, 1, &zopt_rarely),
+ ZTI_INIT(ztest_scrub, 1, &zopt_rarely),
+ ZTI_INIT(ztest_spa_upgrade, 1, &zopt_rarely),
+ ZTI_INIT(ztest_dsl_dataset_promote_busy, 1, &zopt_rarely),
+ ZTI_INIT(ztest_vdev_attach_detach, 1, &zopt_sometimes),
+ ZTI_INIT(ztest_vdev_LUN_growth, 1, &zopt_rarely),
+ ZTI_INIT(ztest_vdev_add_remove, 1, &ztest_opts.zo_vdevtime),
+ ZTI_INIT(ztest_vdev_aux_add_remove, 1, &ztest_opts.zo_vdevtime),
+ ZTI_INIT(ztest_fletcher, 1, &zopt_rarely),
+ ZTI_INIT(ztest_verify_dnode_bt, 1, &zopt_sometimes),
};
#define ZTEST_FUNCS (sizeof (ztest_info) / sizeof (ztest_info_t))
* this lock as writer. Grabbing the lock as reader will ensure that the
* namespace does not change while the lock is held.
*/
-static krwlock_t ztest_name_lock;
+static rwlock_t ztest_name_lock;
static boolean_t ztest_dump_core = B_TRUE;
static boolean_t ztest_exiting;
return ("fail,contents"); /* $UMEM_LOGGING setting */
}
+#define BACKTRACE_SZ 100
+
+static void sig_handler(int signo)
+{
+ struct sigaction action;
+#ifdef __GLIBC__ /* backtrace() is a GNU extension */
+ int nptrs;
+ void *buffer[BACKTRACE_SZ];
+
+ nptrs = backtrace(buffer, BACKTRACE_SZ);
+ backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
+#endif
+
+ /*
+ * Restore default action and re-raise signal so SIGSEGV and
+ * SIGABRT can trigger a core dump.
+ */
+ action.sa_handler = SIG_DFL;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ (void) sigaction(signo, &action, NULL);
+ raise(signo);
+}
+
#define FATAL_MSG_SZ 1024
char *fatal_msg;
{
zs->zs_alloc = metaslab_class_get_alloc(spa_normal_class(ztest_spa));
zs->zs_space = metaslab_class_get_space(spa_normal_class(ztest_spa));
+
+ /*
+ * Before we kill off ztest, make sure that the config is updated.
+ * See comment above spa_config_sync().
+ */
+ mutex_enter(&spa_namespace_lock);
+ spa_config_sync(ztest_spa, B_FALSE, B_FALSE);
+ mutex_exit(&spa_namespace_lock);
+
(void) kill(getpid(), SIGKILL);
}
ztest_get_ashift(void)
{
if (ztest_opts.zo_ashift == 0)
- return (SPA_MINBLOCKSHIFT + ztest_random(3));
+ return (SPA_MINBLOCKSHIFT + ztest_random(5));
return (ztest_opts.zo_ashift);
}
static nvlist_t *
-make_vdev_file(char *path, char *aux, size_t size, uint64_t ashift)
+make_vdev_file(char *path, char *aux, char *pool, size_t size, uint64_t ashift)
{
char *pathbuf;
uint64_t vdev;
vdev = ztest_shared->zs_vdev_aux;
(void) snprintf(path, MAXPATHLEN,
ztest_aux_template, ztest_opts.zo_dir,
- ztest_opts.zo_pool, aux, vdev);
+ pool == NULL ? ztest_opts.zo_pool : pool,
+ aux, vdev);
} else {
vdev = ztest_shared->zs_vdev_next_leaf++;
(void) snprintf(path, MAXPATHLEN,
ztest_dev_template, ztest_opts.zo_dir,
- ztest_opts.zo_pool, vdev);
+ pool == NULL ? ztest_opts.zo_pool : pool, vdev);
}
}
}
static nvlist_t *
-make_vdev_raidz(char *path, char *aux, size_t size, uint64_t ashift, int r)
+make_vdev_raidz(char *path, char *aux, char *pool, size_t size,
+ uint64_t ashift, int r)
{
nvlist_t *raidz, **child;
int c;
if (r < 2)
- return (make_vdev_file(path, aux, size, ashift));
+ return (make_vdev_file(path, aux, pool, size, ashift));
child = umem_alloc(r * sizeof (nvlist_t *), UMEM_NOFAIL);
for (c = 0; c < r; c++)
- child[c] = make_vdev_file(path, aux, size, ashift);
+ child[c] = make_vdev_file(path, aux, pool, size, ashift);
VERIFY(nvlist_alloc(&raidz, NV_UNIQUE_NAME, 0) == 0);
VERIFY(nvlist_add_string(raidz, ZPOOL_CONFIG_TYPE,
}
static nvlist_t *
-make_vdev_mirror(char *path, char *aux, size_t size, uint64_t ashift,
- int r, int m)
+make_vdev_mirror(char *path, char *aux, char *pool, size_t size,
+ uint64_t ashift, int r, int m)
{
nvlist_t *mirror, **child;
int c;
if (m < 1)
- return (make_vdev_raidz(path, aux, size, ashift, r));
+ return (make_vdev_raidz(path, aux, pool, size, ashift, r));
child = umem_alloc(m * sizeof (nvlist_t *), UMEM_NOFAIL);
for (c = 0; c < m; c++)
- child[c] = make_vdev_raidz(path, aux, size, ashift, r);
+ child[c] = make_vdev_raidz(path, aux, pool, size, ashift, r);
VERIFY(nvlist_alloc(&mirror, NV_UNIQUE_NAME, 0) == 0);
VERIFY(nvlist_add_string(mirror, ZPOOL_CONFIG_TYPE,
}
static nvlist_t *
-make_vdev_root(char *path, char *aux, size_t size, uint64_t ashift,
- int log, int r, int m, int t)
+make_vdev_root(char *path, char *aux, char *pool, size_t size, uint64_t ashift,
+ int log, int r, int m, int t)
{
nvlist_t *root, **child;
int c;
child = umem_alloc(t * sizeof (nvlist_t *), UMEM_NOFAIL);
for (c = 0; c < t; c++) {
- child[c] = make_vdev_mirror(path, aux, size, ashift, r, m);
+ child[c] = make_vdev_mirror(path, aux, pool, size, ashift,
+ r, m);
VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
log) == 0);
}
return (root);
}
+/*
+ * Find a random spa version. Returns back a random spa version in the
+ * range [initial_version, SPA_VERSION_FEATURES].
+ */
+static uint64_t
+ztest_random_spa_version(uint64_t initial_version)
+{
+ uint64_t version = initial_version;
+
+ if (version <= SPA_VERSION_BEFORE_FEATURES) {
+ version = version +
+ ztest_random(SPA_VERSION_BEFORE_FEATURES - version + 1);
+ }
+
+ if (version > SPA_VERSION_BEFORE_FEATURES)
+ version = SPA_VERSION_FEATURES;
+
+ ASSERT(SPA_VERSION_IS_SUPPORTED(version));
+ return (version);
+}
+
static int
ztest_random_blocksize(void)
{
- return (1 << (SPA_MINBLOCKSHIFT +
- ztest_random(SPA_MAXBLOCKSHIFT - SPA_MINBLOCKSHIFT + 1)));
+ /*
+ * Choose a block size >= the ashift.
+ * If the SPA supports new MAXBLOCKSIZE, test up to 1MB blocks.
+ */
+ int maxbs = SPA_OLD_MAXBLOCKSHIFT;
+ if (spa_maxblocksize(ztest_spa) == SPA_MAXBLOCKSIZE)
+ maxbs = 20;
+ uint64_t block_shift =
+ ztest_random(maxbs - ztest_spa->spa_max_ashift + 1);
+ return (1 << (SPA_MINBLOCKSHIFT + block_shift));
+}
+
+static int
+ztest_random_dnodesize(void)
+{
+ int slots;
+ int max_slots = spa_maxdnodesize(ztest_spa) >> DNODE_SHIFT;
+
+ if (max_slots == DNODE_MIN_SLOTS)
+ return (DNODE_MIN_SIZE);
+
+ /*
+ * Weight the random distribution more heavily toward smaller
+ * dnode sizes since that is more likely to reflect real-world
+ * usage.
+ */
+ ASSERT3U(max_slots, >, 4);
+ switch (ztest_random(10)) {
+ case 0:
+ slots = 5 + ztest_random(max_slots - 4);
+ break;
+ case 1 ... 4:
+ slots = 2 + ztest_random(3);
+ break;
+ default:
+ slots = 1;
+ break;
+ }
+
+ return (slots << DNODE_SHIFT);
}
static int
uint64_t curval;
int error;
- error = dsl_prop_set(osname, propname,
- (inherit ? ZPROP_SRC_NONE : ZPROP_SRC_LOCAL),
- sizeof (value), 1, &value);
+ error = dsl_prop_set_int(osname, propname,
+ (inherit ? ZPROP_SRC_NONE : ZPROP_SRC_LOCAL), value);
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
return (error);
}
- ASSERT3U(error, ==, 0);
+ ASSERT0(error);
setpoint = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
- VERIFY3U(dsl_prop_get(osname, propname, sizeof (curval),
- 1, &curval, setpoint), ==, 0);
+ VERIFY0(dsl_prop_get_integer(osname, propname, &curval, setpoint));
if (ztest_opts.zo_verbose >= 6) {
- VERIFY(zfs_prop_index_to_string(prop, curval, &valname) == 0);
- (void) printf("%s %s = %s at '%s'\n",
- osname, propname, valname, setpoint);
+ int err;
+
+ err = zfs_prop_index_to_string(prop, curval, &valname);
+ if (err)
+ (void) printf("%s %s = %llu at '%s'\n",
+ osname, propname, (unsigned long long)curval,
+ setpoint);
+ else
+ (void) printf("%s %s = %s at '%s'\n",
+ osname, propname, valname, setpoint);
}
umem_free(setpoint, MAXPATHLEN);
ztest_record_enospc(FTAG);
return (error);
}
- ASSERT3U(error, ==, 0);
+ ASSERT0(error);
return (error);
}
+
+/*
+ * Object and range lock mechanics
+ */
+typedef struct {
+ list_node_t z_lnode;
+ refcount_t z_refcnt;
+ uint64_t z_object;
+ zfs_rlock_t z_range_lock;
+} ztest_znode_t;
+
+typedef struct {
+ rl_t *z_rl;
+ ztest_znode_t *z_ztznode;
+} ztest_zrl_t;
+
+static ztest_znode_t *
+ztest_znode_init(uint64_t object)
+{
+ ztest_znode_t *zp = umem_alloc(sizeof (*zp), UMEM_NOFAIL);
+
+ list_link_init(&zp->z_lnode);
+ refcount_create(&zp->z_refcnt);
+ zp->z_object = object;
+ zfs_rlock_init(&zp->z_range_lock);
+
+ return (zp);
+}
+
+static void
+ztest_znode_fini(ztest_znode_t *zp)
+{
+ ASSERT(refcount_is_zero(&zp->z_refcnt));
+ zfs_rlock_destroy(&zp->z_range_lock);
+ zp->z_object = 0;
+ refcount_destroy(&zp->z_refcnt);
+ list_link_init(&zp->z_lnode);
+ umem_free(zp, sizeof (*zp));
+}
+
+static void
+ztest_zll_init(zll_t *zll)
+{
+ mutex_init(&zll->z_lock, NULL, MUTEX_DEFAULT, NULL);
+ list_create(&zll->z_list, sizeof (ztest_znode_t),
+ offsetof(ztest_znode_t, z_lnode));
+}
+
+static void
+ztest_zll_destroy(zll_t *zll)
+{
+ list_destroy(&zll->z_list);
+ mutex_destroy(&zll->z_lock);
+}
+
+#define RL_TAG "range_lock"
+static ztest_znode_t *
+ztest_znode_get(ztest_ds_t *zd, uint64_t object)
+{
+ zll_t *zll = &zd->zd_range_lock[object & (ZTEST_OBJECT_LOCKS - 1)];
+ ztest_znode_t *zp = NULL;
+ mutex_enter(&zll->z_lock);
+ for (zp = list_head(&zll->z_list); (zp);
+ zp = list_next(&zll->z_list, zp)) {
+ if (zp->z_object == object) {
+ refcount_add(&zp->z_refcnt, RL_TAG);
+ break;
+ }
+ }
+ if (zp == NULL) {
+ zp = ztest_znode_init(object);
+ refcount_add(&zp->z_refcnt, RL_TAG);
+ list_insert_head(&zll->z_list, zp);
+ }
+ mutex_exit(&zll->z_lock);
+ return (zp);
+}
+
+static void
+ztest_znode_put(ztest_ds_t *zd, ztest_znode_t *zp)
+{
+ zll_t *zll = NULL;
+ ASSERT3U(zp->z_object, !=, 0);
+ zll = &zd->zd_range_lock[zp->z_object & (ZTEST_OBJECT_LOCKS - 1)];
+ mutex_enter(&zll->z_lock);
+ refcount_remove(&zp->z_refcnt, RL_TAG);
+ if (refcount_is_zero(&zp->z_refcnt)) {
+ list_remove(&zll->z_list, zp);
+ ztest_znode_fini(zp);
+ }
+ mutex_exit(&zll->z_lock);
+}
+
+
static void
ztest_rll_init(rll_t *rll)
{
ztest_rll_unlock(rll);
}
-static rl_t *
-ztest_range_lock(ztest_ds_t *zd, uint64_t object, uint64_t offset,
- uint64_t size, rl_type_t type)
+static ztest_zrl_t *
+ztest_zrl_init(rl_t *rl, ztest_znode_t *zp)
{
- uint64_t hash = object ^ (offset % (ZTEST_RANGE_LOCKS + 1));
- rll_t *rll = &zd->zd_range_lock[hash & (ZTEST_RANGE_LOCKS - 1)];
- rl_t *rl;
-
- rl = umem_alloc(sizeof (*rl), UMEM_NOFAIL);
- rl->rl_object = object;
- rl->rl_offset = offset;
- rl->rl_size = size;
- rl->rl_lock = rll;
-
- ztest_rll_lock(rll, type);
-
- return (rl);
+ ztest_zrl_t *zrl = umem_alloc(sizeof (*zrl), UMEM_NOFAIL);
+ zrl->z_rl = rl;
+ zrl->z_ztznode = zp;
+ return (zrl);
}
static void
-ztest_range_unlock(rl_t *rl)
+ztest_zrl_fini(ztest_zrl_t *zrl)
{
- rll_t *rll = rl->rl_lock;
+ umem_free(zrl, sizeof (*zrl));
+}
- ztest_rll_unlock(rll);
+static ztest_zrl_t *
+ztest_range_lock(ztest_ds_t *zd, uint64_t object, uint64_t offset,
+ uint64_t size, rl_type_t type)
+{
+ ztest_znode_t *zp = ztest_znode_get(zd, object);
+ rl_t *rl = zfs_range_lock(&zp->z_range_lock, offset,
+ size, type);
+ return (ztest_zrl_init(rl, zp));
+}
- umem_free(rl, sizeof (*rl));
+static void
+ztest_range_unlock(ztest_ds_t *zd, ztest_zrl_t *zrl)
+{
+ zfs_range_unlock(zrl->z_rl);
+ ztest_znode_put(zd, zrl->z_ztznode);
+ ztest_zrl_fini(zrl);
}
static void
if (zd->zd_shared != NULL)
zd->zd_shared->zd_seq = 0;
- rw_init(&zd->zd_zilog_lock, NULL, RW_DEFAULT, NULL);
+ VERIFY(rwlock_init(&zd->zd_zilog_lock, USYNC_THREAD, NULL) == 0);
mutex_init(&zd->zd_dirobj_lock, NULL, MUTEX_DEFAULT, NULL);
for (l = 0; l < ZTEST_OBJECT_LOCKS; l++)
ztest_rll_init(&zd->zd_object_lock[l]);
for (l = 0; l < ZTEST_RANGE_LOCKS; l++)
- ztest_rll_init(&zd->zd_range_lock[l]);
+ ztest_zll_init(&zd->zd_range_lock[l]);
}
static void
int l;
mutex_destroy(&zd->zd_dirobj_lock);
- rw_destroy(&zd->zd_zilog_lock);
+ (void) rwlock_destroy(&zd->zd_zilog_lock);
for (l = 0; l < ZTEST_OBJECT_LOCKS; l++)
ztest_rll_destroy(&zd->zd_object_lock[l]);
for (l = 0; l < ZTEST_RANGE_LOCKS; l++)
- ztest_rll_destroy(&zd->zd_range_lock[l]);
+ ztest_zll_destroy(&zd->zd_range_lock[l]);
}
#define TXG_MIGHTWAIT (ztest_random(10) == 0 ? TXG_NOWAIT : TXG_WAIT)
static void
ztest_bt_generate(ztest_block_tag_t *bt, objset_t *os, uint64_t object,
- uint64_t offset, uint64_t gen, uint64_t txg, uint64_t crtxg)
+ uint64_t dnodesize, uint64_t offset, uint64_t gen, uint64_t txg,
+ uint64_t crtxg)
{
bt->bt_magic = BT_MAGIC;
bt->bt_objset = dmu_objset_id(os);
bt->bt_object = object;
+ bt->bt_dnodesize = dnodesize;
bt->bt_offset = offset;
bt->bt_gen = gen;
bt->bt_txg = txg;
static void
ztest_bt_verify(ztest_block_tag_t *bt, objset_t *os, uint64_t object,
- uint64_t offset, uint64_t gen, uint64_t txg, uint64_t crtxg)
+ uint64_t dnodesize, uint64_t offset, uint64_t gen, uint64_t txg,
+ uint64_t crtxg)
{
- ASSERT(bt->bt_magic == BT_MAGIC);
- ASSERT(bt->bt_objset == dmu_objset_id(os));
- ASSERT(bt->bt_object == object);
- ASSERT(bt->bt_offset == offset);
- ASSERT(bt->bt_gen <= gen);
- ASSERT(bt->bt_txg <= txg);
- ASSERT(bt->bt_crtxg == crtxg);
+ ASSERT3U(bt->bt_magic, ==, BT_MAGIC);
+ ASSERT3U(bt->bt_objset, ==, dmu_objset_id(os));
+ ASSERT3U(bt->bt_object, ==, object);
+ ASSERT3U(bt->bt_dnodesize, ==, dnodesize);
+ ASSERT3U(bt->bt_offset, ==, offset);
+ ASSERT3U(bt->bt_gen, <=, gen);
+ ASSERT3U(bt->bt_txg, <=, txg);
+ ASSERT3U(bt->bt_crtxg, ==, crtxg);
}
static ztest_block_tag_t *
return (bt);
}
+/*
+ * Generate a token to fill up unused bonus buffer space. Try to make
+ * it unique to the object, generation, and offset to verify that data
+ * is not getting overwritten by data from other dnodes.
+ */
+#define ZTEST_BONUS_FILL_TOKEN(obj, ds, gen, offset) \
+ (((ds) << 48) | ((gen) << 32) | ((obj) << 8) | (offset))
+
+/*
+ * Fill up the unused bonus buffer region before the block tag with a
+ * verifiable pattern. Filling the whole bonus area with non-zero data
+ * helps ensure that all dnode traversal code properly skips the
+ * interior regions of large dnodes.
+ */
+void
+ztest_fill_unused_bonus(dmu_buf_t *db, void *end, uint64_t obj,
+ objset_t *os, uint64_t gen)
+{
+ uint64_t *bonusp;
+
+ ASSERT(IS_P2ALIGNED((char *)end - (char *)db->db_data, 8));
+
+ for (bonusp = db->db_data; bonusp < (uint64_t *)end; bonusp++) {
+ uint64_t token = ZTEST_BONUS_FILL_TOKEN(obj, dmu_objset_id(os),
+ gen, bonusp - (uint64_t *)db->db_data);
+ *bonusp = token;
+ }
+}
+
+/*
+ * Verify that the unused area of a bonus buffer is filled with the
+ * expected tokens.
+ */
+void
+ztest_verify_unused_bonus(dmu_buf_t *db, void *end, uint64_t obj,
+ objset_t *os, uint64_t gen)
+{
+ uint64_t *bonusp;
+
+ for (bonusp = db->db_data; bonusp < (uint64_t *)end; bonusp++) {
+ uint64_t token = ZTEST_BONUS_FILL_TOKEN(obj, dmu_objset_id(os),
+ gen, bonusp - (uint64_t *)db->db_data);
+ VERIFY3U(*bonusp, ==, token);
+ }
+}
+
/*
* ZIL logging ops
*/
#define lrz_blocksize lr_uid
#define lrz_ibshift lr_gid
#define lrz_bonustype lr_rdev
-#define lrz_bonuslen lr_crtime[1]
+#define lrz_dnodesize lr_crtime[1]
static void
ztest_log_create(ztest_ds_t *zd, dmu_tx_t *tx, lr_create_t *lr)
dmu_tx_t *tx;
uint64_t txg;
int error = 0;
+ int bonuslen;
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
return (ENOSPC);
ASSERT(dmu_objset_zil(os)->zl_replay == !!lr->lr_foid);
+ bonuslen = DN_BONUS_SIZE(lr->lrz_dnodesize);
if (lr->lrz_type == DMU_OT_ZAP_OTHER) {
if (lr->lr_foid == 0) {
- lr->lr_foid = zap_create(os,
+ lr->lr_foid = zap_create_dnsize(os,
lr->lrz_type, lr->lrz_bonustype,
- lr->lrz_bonuslen, tx);
+ bonuslen, lr->lrz_dnodesize, tx);
} else {
- error = zap_create_claim(os, lr->lr_foid,
+ error = zap_create_claim_dnsize(os, lr->lr_foid,
lr->lrz_type, lr->lrz_bonustype,
- lr->lrz_bonuslen, tx);
+ bonuslen, lr->lrz_dnodesize, tx);
}
} else {
if (lr->lr_foid == 0) {
- lr->lr_foid = dmu_object_alloc(os,
+ lr->lr_foid = dmu_object_alloc_dnsize(os,
lr->lrz_type, 0, lr->lrz_bonustype,
- lr->lrz_bonuslen, tx);
+ bonuslen, lr->lrz_dnodesize, tx);
} else {
- error = dmu_object_claim(os, lr->lr_foid,
+ error = dmu_object_claim_dnsize(os, lr->lr_foid,
lr->lrz_type, 0, lr->lrz_bonustype,
- lr->lrz_bonuslen, tx);
+ bonuslen, lr->lrz_dnodesize, tx);
}
}
VERIFY3U(0, ==, dmu_bonus_hold(os, lr->lr_foid, FTAG, &db));
bbt = ztest_bt_bonus(db);
dmu_buf_will_dirty(db, tx);
- ztest_bt_generate(bbt, os, lr->lr_foid, -1ULL, lr->lr_gen, txg, txg);
+ ztest_bt_generate(bbt, os, lr->lr_foid, lr->lrz_dnodesize, -1ULL,
+ lr->lr_gen, txg, txg);
+ ztest_fill_unused_bonus(db, bbt, lr->lr_foid, os, lr->lr_gen);
dmu_buf_rele(db, FTAG);
VERIFY3U(0, ==, zap_add(os, lr->lr_doid, name, sizeof (uint64_t), 1,
dmu_tx_t *tx;
dmu_buf_t *db;
arc_buf_t *abuf = NULL;
- rl_t *rl;
+ ztest_zrl_t *rl;
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
if (abuf != NULL)
dmu_return_arcbuf(abuf);
dmu_buf_rele(db, FTAG);
- ztest_range_unlock(rl);
+ ztest_range_unlock(zd, rl);
ztest_object_unlock(zd, lr->lr_foid);
return (ENOSPC);
}
VERIFY(dmu_read(os, lr->lr_foid, offset,
sizeof (rbt), &rbt, prefetch) == 0);
if (rbt.bt_magic == BT_MAGIC) {
- ztest_bt_verify(&rbt, os, lr->lr_foid,
+ ztest_bt_verify(&rbt, os, lr->lr_foid, 0,
offset, gen, txg, crtxg);
}
}
* as it was when the write was generated.
*/
if (zd->zd_zilog->zl_replay) {
- ztest_bt_verify(bt, os, lr->lr_foid, offset,
+ ztest_bt_verify(bt, os, lr->lr_foid, 0, offset,
MAX(gen, bt->bt_gen), MAX(txg, lrtxg),
bt->bt_crtxg);
}
* Set the bt's gen/txg to the bonus buffer's gen/txg
* so that all of the usual ASSERTs will work.
*/
- ztest_bt_generate(bt, os, lr->lr_foid, offset, gen, txg, crtxg);
+ ztest_bt_generate(bt, os, lr->lr_foid, 0, offset, gen, txg,
+ crtxg);
}
if (abuf == NULL) {
dmu_tx_commit(tx);
- ztest_range_unlock(rl);
+ ztest_range_unlock(zd, rl);
ztest_object_unlock(zd, lr->lr_foid);
return (0);
objset_t *os = zd->zd_os;
dmu_tx_t *tx;
uint64_t txg;
- rl_t *rl;
+ ztest_zrl_t *rl;
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
if (txg == 0) {
- ztest_range_unlock(rl);
+ ztest_range_unlock(zd, rl);
ztest_object_unlock(zd, lr->lr_foid);
return (ENOSPC);
}
dmu_tx_commit(tx);
- ztest_range_unlock(rl);
+ ztest_range_unlock(zd, rl);
ztest_object_unlock(zd, lr->lr_foid);
return (0);
dmu_tx_t *tx;
dmu_buf_t *db;
ztest_block_tag_t *bbt;
- uint64_t txg, lrtxg, crtxg;
+ uint64_t txg, lrtxg, crtxg, dnodesize;
if (byteswap)
byteswap_uint64_array(lr, sizeof (*lr));
ASSERT3U(bbt->bt_magic, ==, BT_MAGIC);
crtxg = bbt->bt_crtxg;
lrtxg = lr->lr_common.lrc_txg;
+ dnodesize = bbt->bt_dnodesize;
if (zd->zd_zilog->zl_replay) {
ASSERT(lr->lr_size != 0);
/*
* Verify that the current bonus buffer is not newer than our txg.
*/
- ztest_bt_verify(bbt, os, lr->lr_foid, -1ULL, lr->lr_mode,
+ ztest_bt_verify(bbt, os, lr->lr_foid, dnodesize, -1ULL, lr->lr_mode,
MAX(txg, lrtxg), crtxg);
dmu_buf_will_dirty(db, tx);
ASSERT3U(lr->lr_size, >=, sizeof (*bbt));
ASSERT3U(lr->lr_size, <=, db->db_size);
- VERIFY3U(dmu_set_bonus(db, lr->lr_size, tx), ==, 0);
+ VERIFY0(dmu_set_bonus(db, lr->lr_size, tx));
bbt = ztest_bt_bonus(db);
- ztest_bt_generate(bbt, os, lr->lr_foid, -1ULL, lr->lr_mode, txg, crtxg);
-
+ ztest_bt_generate(bbt, os, lr->lr_foid, dnodesize, -1ULL, lr->lr_mode,
+ txg, crtxg);
+ ztest_fill_unused_bonus(db, bbt, lr->lr_foid, os, bbt->bt_gen);
dmu_buf_rele(db, FTAG);
(void) ztest_log_setattr(zd, tx, lr);
return (0);
}
-zil_replay_func_t *ztest_replay_vector[TX_MAX_TYPE] = {
+zil_replay_func_t ztest_replay_vector[TX_MAX_TYPE] = {
NULL, /* 0 no such transaction type */
- (zil_replay_func_t *)ztest_replay_create, /* TX_CREATE */
+ (zil_replay_func_t)ztest_replay_create, /* TX_CREATE */
NULL, /* TX_MKDIR */
NULL, /* TX_MKXATTR */
NULL, /* TX_SYMLINK */
- (zil_replay_func_t *)ztest_replay_remove, /* TX_REMOVE */
+ (zil_replay_func_t)ztest_replay_remove, /* TX_REMOVE */
NULL, /* TX_RMDIR */
NULL, /* TX_LINK */
NULL, /* TX_RENAME */
- (zil_replay_func_t *)ztest_replay_write, /* TX_WRITE */
- (zil_replay_func_t *)ztest_replay_truncate, /* TX_TRUNCATE */
- (zil_replay_func_t *)ztest_replay_setattr, /* TX_SETATTR */
+ (zil_replay_func_t)ztest_replay_write, /* TX_WRITE */
+ (zil_replay_func_t)ztest_replay_truncate, /* TX_TRUNCATE */
+ (zil_replay_func_t)ztest_replay_setattr, /* TX_SETATTR */
NULL, /* TX_ACL */
NULL, /* TX_CREATE_ACL */
NULL, /* TX_CREATE_ATTR */
/*
* ZIL get_data callbacks
*/
+typedef struct ztest_zgd_private {
+ ztest_ds_t *z_zd;
+ ztest_zrl_t *z_rl;
+ uint64_t z_object;
+} ztest_zgd_private_t;
static void
ztest_get_done(zgd_t *zgd, int error)
{
- ztest_ds_t *zd = zgd->zgd_private;
- uint64_t object = zgd->zgd_rl->rl_object;
+ ztest_zgd_private_t *zzp = zgd->zgd_private;
+ ztest_ds_t *zd = zzp->z_zd;
+ uint64_t object = zzp->z_object;
if (zgd->zgd_db)
dmu_buf_rele(zgd->zgd_db, zgd);
- ztest_range_unlock(zgd->zgd_rl);
+ ztest_range_unlock(zd, zzp->z_rl);
ztest_object_unlock(zd, object);
if (error == 0 && zgd->zgd_bp)
zil_add_block(zgd->zgd_zilog, zgd->zgd_bp);
umem_free(zgd, sizeof (*zgd));
+ umem_free(zzp, sizeof (*zzp));
}
static int
dmu_buf_t *db;
zgd_t *zgd;
int error;
+ ztest_zgd_private_t *zgd_private;
ztest_object_lock(zd, object, RL_READER);
error = dmu_bonus_hold(os, object, FTAG, &db);
zgd = umem_zalloc(sizeof (*zgd), UMEM_NOFAIL);
zgd->zgd_zilog = zd->zd_zilog;
- zgd->zgd_private = zd;
+ zgd_private = umem_zalloc(sizeof (ztest_zgd_private_t), UMEM_NOFAIL);
+ zgd_private->z_zd = zd;
+ zgd_private->z_object = object;
+ zgd->zgd_private = zgd_private;
if (buf != NULL) { /* immediate write */
- zgd->zgd_rl = ztest_range_lock(zd, object, offset, size,
+ zgd_private->z_rl = ztest_range_lock(zd, object, offset, size,
RL_READER);
error = dmu_read(os, object, offset, size, buf,
offset = 0;
}
- zgd->zgd_rl = ztest_range_lock(zd, object, offset, size,
+ zgd_private->z_rl = ztest_range_lock(zd, object, offset, size,
RL_READER);
error = dmu_buf_hold(os, object, offset, zgd, &db,
DMU_READ_NO_PREFETCH);
if (error == 0) {
+ blkptr_t *obp = dmu_buf_get_blkptr(db);
+ if (obp) {
+ ASSERT(BP_IS_HOLE(bp));
+ *bp = *obp;
+ }
+
zgd->zgd_db = db;
zgd->zgd_bp = bp;
lr->lrz_blocksize = od->od_crblocksize;
lr->lrz_ibshift = ztest_random_ibshift();
lr->lrz_bonustype = DMU_OT_UINT64_OTHER;
- lr->lrz_bonuslen = dmu_bonus_max();
+ lr->lrz_dnodesize = od->od_crdnodesize;
lr->lr_gen = od->od_crgen;
lr->lr_crtime[0] = time(NULL);
continue;
}
+ /*
+ * No object was found.
+ */
if (od->od_object == 0)
continue;
objset_t *os = zd->zd_os;
dmu_tx_t *tx;
uint64_t txg;
- rl_t *rl;
+ ztest_zrl_t *rl;
txg_wait_synced(dmu_objset_pool(os), 0);
(void) dmu_free_long_range(os, object, offset, size);
}
- ztest_range_unlock(rl);
+ ztest_range_unlock(zd, rl);
ztest_object_unlock(zd, object);
}
static void
ztest_io(ztest_ds_t *zd, uint64_t object, uint64_t offset)
{
+ int err;
ztest_block_tag_t wbt;
dmu_object_info_t doi;
enum ztest_io_type io_type;
if (ztest_random(2) == 0)
io_type = ZTEST_IO_WRITE_TAG;
- (void) rw_enter(&zd->zd_zilog_lock, RW_READER);
+ (void) rw_rdlock(&zd->zd_zilog_lock);
switch (io_type) {
case ZTEST_IO_WRITE_TAG:
- ztest_bt_generate(&wbt, zd->zd_os, object, offset, 0, 0, 0);
+ ztest_bt_generate(&wbt, zd->zd_os, object, doi.doi_dnodesize,
+ offset, 0, 0, 0);
(void) ztest_write(zd, object, offset, sizeof (wbt), &wbt);
break;
break;
default:
break;
+
+ case ZTEST_IO_REWRITE:
+ (void) rw_rdlock(&ztest_name_lock);
+ err = ztest_dsl_prop_set_uint64(zd->zd_name,
+ ZFS_PROP_CHECKSUM, spa_dedup_checksum(ztest_spa),
+ B_FALSE);
+ VERIFY(err == 0 || err == ENOSPC);
+ err = ztest_dsl_prop_set_uint64(zd->zd_name,
+ ZFS_PROP_COMPRESSION,
+ ztest_random_dsl_prop(ZFS_PROP_COMPRESSION),
+ B_FALSE);
+ VERIFY(err == 0 || err == ENOSPC);
+ (void) rw_unlock(&ztest_name_lock);
+
+ VERIFY0(dmu_read(zd->zd_os, object, offset, blocksize, data,
+ DMU_READ_NO_PREFETCH));
+
+ (void) ztest_write(zd, object, offset, blocksize, data);
+ break;
}
- (void) rw_exit(&zd->zd_zilog_lock);
+ (void) rw_unlock(&zd->zd_zilog_lock);
umem_free(data, blocksize);
}
*/
static void
ztest_od_init(ztest_od_t *od, uint64_t id, char *tag, uint64_t index,
- dmu_object_type_t type, uint64_t blocksize, uint64_t gen)
+ dmu_object_type_t type, uint64_t blocksize, uint64_t dnodesize,
+ uint64_t gen)
{
od->od_dir = ZTEST_DIROBJ;
od->od_object = 0;
od->od_crtype = type;
od->od_crblocksize = blocksize ? blocksize : ztest_random_blocksize();
+ od->od_crdnodesize = dnodesize ? dnodesize : ztest_random_dnodesize();
od->od_crgen = gen;
od->od_type = DMU_OT_NONE;
{
zilog_t *zilog = zd->zd_zilog;
- (void) rw_enter(&zd->zd_zilog_lock, RW_READER);
+ (void) rw_rdlock(&zd->zd_zilog_lock);
zil_commit(zilog, ztest_random(ZTEST_OBJECTS));
zd->zd_shared->zd_seq = zilog->zl_commit_lr_seq;
mutex_exit(&zilog->zl_lock);
- (void) rw_exit(&zd->zd_zilog_lock);
+ (void) rw_unlock(&zd->zd_zilog_lock);
}
/*
{
objset_t *os = zd->zd_os;
+ /*
+ * We grab the zd_dirobj_lock to ensure that no other thread is
+ * updating the zil (i.e. adding in-memory log records) and the
+ * zd_zilog_lock to block any I/O.
+ */
mutex_enter(&zd->zd_dirobj_lock);
- (void) rw_enter(&zd->zd_zilog_lock, RW_WRITER);
+ (void) rw_wrlock(&zd->zd_zilog_lock);
/* zfs_sb_teardown() */
zil_close(zd->zd_zilog);
VERIFY(zil_open(os, ztest_get_data) == zd->zd_zilog);
zil_replay(os, zd, ztest_replay_vector);
- (void) rw_exit(&zd->zd_zilog_lock);
+ (void) rw_unlock(&zd->zd_zilog_lock);
mutex_exit(&zd->zd_dirobj_lock);
}
/*
* Attempt to create using a bad file.
*/
- nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 0, 1);
+ nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
VERIFY3U(ENOENT, ==,
- spa_create("ztest_bad_file", nvroot, NULL, NULL, NULL));
+ spa_create("ztest_bad_file", nvroot, NULL, NULL));
nvlist_free(nvroot);
/*
* Attempt to create using a bad mirror.
*/
- nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 2, 1);
+ nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 2, 1);
VERIFY3U(ENOENT, ==,
- spa_create("ztest_bad_mirror", nvroot, NULL, NULL, NULL));
+ spa_create("ztest_bad_mirror", nvroot, NULL, NULL));
nvlist_free(nvroot);
/*
* Attempt to create an existing pool. It shouldn't matter
* what's in the nvroot; we should fail with EEXIST.
*/
- (void) rw_enter(&ztest_name_lock, RW_READER);
- nvroot = make_vdev_root("/dev/bogus", NULL, 0, 0, 0, 0, 0, 1);
- VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL, NULL));
+ (void) rw_rdlock(&ztest_name_lock);
+ nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
+ VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL));
nvlist_free(nvroot);
VERIFY3U(0, ==, spa_open(zo->zo_pool, &spa, FTAG));
VERIFY3U(EBUSY, ==, spa_destroy(zo->zo_pool));
spa_close(spa, FTAG);
- (void) rw_exit(&ztest_name_lock);
+ (void) rw_unlock(&ztest_name_lock);
+}
+
+/* ARGSUSED */
+void
+ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
+{
+ spa_t *spa;
+ uint64_t initial_version = SPA_VERSION_INITIAL;
+ uint64_t version, newversion;
+ nvlist_t *nvroot, *props;
+ char *name;
+
+ mutex_enter(&ztest_vdev_lock);
+ name = kmem_asprintf("%s_upgrade", ztest_opts.zo_pool);
+
+ /*
+ * Clean up from previous runs.
+ */
+ (void) spa_destroy(name);
+
+ nvroot = make_vdev_root(NULL, NULL, name, ztest_opts.zo_vdev_size, 0,
+ 0, ztest_opts.zo_raidz, ztest_opts.zo_mirrors, 1);
+
+ /*
+ * If we're configuring a RAIDZ device then make sure that the
+ * the initial version is capable of supporting that feature.
+ */
+ switch (ztest_opts.zo_raidz_parity) {
+ case 0:
+ case 1:
+ initial_version = SPA_VERSION_INITIAL;
+ break;
+ case 2:
+ initial_version = SPA_VERSION_RAIDZ2;
+ break;
+ case 3:
+ initial_version = SPA_VERSION_RAIDZ3;
+ break;
+ }
+
+ /*
+ * Create a pool with a spa version that can be upgraded. Pick
+ * a value between initial_version and SPA_VERSION_BEFORE_FEATURES.
+ */
+ do {
+ version = ztest_random_spa_version(initial_version);
+ } while (version > SPA_VERSION_BEFORE_FEATURES);
+
+ props = fnvlist_alloc();
+ fnvlist_add_uint64(props,
+ zpool_prop_to_name(ZPOOL_PROP_VERSION), version);
+ VERIFY3S(spa_create(name, nvroot, props, NULL), ==, 0);
+ fnvlist_free(nvroot);
+ fnvlist_free(props);
+
+ VERIFY3S(spa_open(name, &spa, FTAG), ==, 0);
+ VERIFY3U(spa_version(spa), ==, version);
+ newversion = ztest_random_spa_version(version + 1);
+
+ if (ztest_opts.zo_verbose >= 4) {
+ (void) printf("upgrading spa version from %llu to %llu\n",
+ (u_longlong_t)version, (u_longlong_t)newversion);
+ }
+
+ spa_upgrade(spa, newversion);
+ VERIFY3U(spa_version(spa), >, version);
+ VERIFY3U(spa_version(spa), ==, fnvlist_lookup_uint64(spa->spa_config,
+ zpool_prop_to_name(ZPOOL_PROP_VERSION)));
+ spa_close(spa, FTAG);
+
+ strfree(name);
+ mutex_exit(&ztest_vdev_lock);
}
static vdev_t *
int error;
mutex_enter(&ztest_vdev_lock);
- leaves =
- MAX(zs->zs_mirrors + zs->zs_splits, 1) * ztest_opts.zo_raidz;
+ leaves = MAX(zs->zs_mirrors + zs->zs_splits, 1) * ztest_opts.zo_raidz;
spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
* prevent a race between removing a slog (dmu_objset_find)
* and destroying a dataset. Removing the slog will
* grab a reference on the dataset which may cause
- * dmu_objset_destroy() to fail with EBUSY thus
+ * dsl_destroy_head() to fail with EBUSY thus
* leaving the dataset in an inconsistent state.
*/
- rw_enter(&ztest_name_lock, RW_WRITER);
+ rw_wrlock(&ztest_name_lock);
error = spa_vdev_remove(spa, guid, B_FALSE);
- rw_exit(&ztest_name_lock);
+ rw_unlock(&ztest_name_lock);
if (error && error != EEXIST)
fatal(0, "spa_vdev_remove() = %d", error);
/*
* Make 1/4 of the devices be log devices.
*/
- nvroot = make_vdev_root(NULL, NULL,
+ nvroot = make_vdev_root(NULL, NULL, NULL,
ztest_opts.zo_vdev_size, 0,
ztest_random(4) == 0, ztest_opts.zo_raidz,
zs->zs_mirrors, 1);
zs->zs_vdev_aux = 0;
for (;;) {
int c;
- (void) snprintf(path, sizeof (path), ztest_aux_template,
+ (void) snprintf(path, MAXPATHLEN, ztest_aux_template,
ztest_opts.zo_dir, ztest_opts.zo_pool, aux,
zs->zs_vdev_aux);
for (c = 0; c < sav->sav_count; c++)
/*
* Add a new device.
*/
- nvlist_t *nvroot = make_vdev_root(NULL, aux,
+ nvlist_t *nvroot = make_vdev_root(NULL, aux, NULL,
(ztest_opts.zo_vdev_size * 5) / 4, 0, 0, 0, 0, 1);
error = spa_vdev_add(spa, nvroot);
if (error != 0)
spa_config_exit(spa, SCL_VDEV, FTAG);
- (void) rw_enter(&ztest_name_lock, RW_WRITER);
+ (void) rw_wrlock(&ztest_name_lock);
error = spa_vdev_split_mirror(spa, "splitp", config, NULL, B_FALSE);
- (void) rw_exit(&ztest_name_lock);
+ (void) rw_unlock(&ztest_name_lock);
nvlist_free(config);
uint64_t leaf, top;
uint64_t ashift = ztest_get_ashift();
uint64_t oldguid, pguid;
- size_t oldsize, newsize;
+ uint64_t oldsize, newsize;
char *oldpath, *newpath;
int replacing;
int oldvd_has_siblings = B_FALSE;
/*
* Build the nvlist describing newpath.
*/
- root = make_vdev_root(newpath, NULL, newvd == NULL ? newsize : 0,
+ root = make_vdev_root(newpath, NULL, NULL, newvd == NULL ? newsize : 0,
ashift, 0, 0, 0, 1);
error = spa_vdev_attach(spa, oldguid, root, replacing);
if (error != expected_error && expected_error != EBUSY) {
fatal(0, "attach (%s %llu, %s %llu, %d) "
"returned %d, expected %d",
- oldpath, (longlong_t)oldsize, newpath,
- (longlong_t)newsize, replacing, error, expected_error);
+ oldpath, oldsize, newpath,
+ newsize, replacing, error, expected_error);
}
out:
mutex_exit(&ztest_vdev_lock);
/*
* Verify that the dataset contains a directory object.
*/
- VERIFY3U(0, ==, dmu_objset_hold(name, FTAG, &os));
+ VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_TRUE, FTAG, &os));
error = dmu_object_info(os, ZTEST_DIROBJ, &doi);
if (error != ENOENT) {
/* We could have crashed in the middle of destroying it */
- ASSERT3U(error, ==, 0);
+ ASSERT0(error);
ASSERT3U(doi.doi_type, ==, DMU_OT_ZAP_OTHER);
ASSERT3S(doi.doi_physical_blocks_512, >=, 0);
}
- dmu_objset_rele(os, FTAG);
+ dmu_objset_disown(os, FTAG);
/*
* Destroy the dataset.
*/
- VERIFY3U(0, ==, dmu_objset_destroy(name, B_FALSE));
+ if (strchr(name, '@') != NULL) {
+ VERIFY0(dsl_destroy_snapshot(name, B_FALSE));
+ } else {
+ VERIFY0(dsl_destroy_head(name));
+ }
return (0);
}
char snapname[MAXNAMELEN];
int error;
- (void) snprintf(snapname, MAXNAMELEN, "%s@%llu", osname,
- (u_longlong_t)id);
+ (void) snprintf(snapname, sizeof (snapname), "%llu", (u_longlong_t)id);
- error = dmu_objset_snapshot(osname, strchr(snapname, '@') + 1,
- NULL, NULL, B_FALSE, B_FALSE, -1);
+ error = dmu_objset_snapshot_one(osname, snapname);
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
return (B_FALSE);
}
- if (error != 0 && error != EEXIST)
- fatal(0, "ztest_snapshot_create(%s) = %d", snapname, error);
+ if (error != 0 && error != EEXIST) {
+ fatal(0, "ztest_snapshot_create(%s@%s) = %d", osname,
+ snapname, error);
+ }
return (B_TRUE);
}
(void) snprintf(snapname, MAXNAMELEN, "%s@%llu", osname,
(u_longlong_t)id);
- error = dmu_objset_destroy(snapname, B_FALSE);
+ error = dsl_destroy_snapshot(snapname, B_FALSE);
if (error != 0 && error != ENOENT)
fatal(0, "ztest_snapshot_destroy(%s) = %d", snapname, error);
return (B_TRUE);
zdtmp = umem_alloc(sizeof (ztest_ds_t), UMEM_NOFAIL);
name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL);
- (void) rw_enter(&ztest_name_lock, RW_READER);
+ (void) rw_rdlock(&ztest_name_lock);
(void) snprintf(name, MAXNAMELEN, "%s/temp_%llu",
ztest_opts.zo_pool, (u_longlong_t)id);
/*
* If this dataset exists from a previous run, process its replay log
- * half of the time. If we don't replay it, then dmu_objset_destroy()
+ * half of the time. If we don't replay it, then dsl_destroy_head()
* (invoked from ztest_objset_destroy_cb()) should just throw it away.
*/
if (ztest_random(2) == 0 &&
/*
* Verify that the destroyed dataset is no longer in the namespace.
*/
- VERIFY3U(ENOENT, ==, dmu_objset_hold(name, FTAG, &os));
+ VERIFY3U(ENOENT, ==, dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
+ FTAG, &os));
/*
* Verify that we can create a new dataset.
fatal(0, "dmu_objset_create(%s) = %d", name, error);
}
- VERIFY3U(0, ==,
- dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os));
+ VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os));
ztest_zd_init(zdtmp, NULL, os);
dmu_objset_disown(os, FTAG);
ztest_zd_fini(zdtmp);
out:
- (void) rw_exit(&ztest_name_lock);
+ (void) rw_unlock(&ztest_name_lock);
umem_free(name, MAXNAMELEN);
umem_free(zdtmp, sizeof (ztest_ds_t));
void
ztest_dmu_snapshot_create_destroy(ztest_ds_t *zd, uint64_t id)
{
- (void) rw_enter(&ztest_name_lock, RW_READER);
+ (void) rw_rdlock(&ztest_name_lock);
(void) ztest_snapshot_destroy(zd->zd_name, id);
(void) ztest_snapshot_create(zd->zd_name, id);
- (void) rw_exit(&ztest_name_lock);
+ (void) rw_unlock(&ztest_name_lock);
}
/*
(void) snprintf(snap3name, MAXNAMELEN, "%s@s3_%llu",
clone1name, (u_longlong_t)id);
- error = dmu_objset_destroy(clone2name, B_FALSE);
+ error = dsl_destroy_head(clone2name);
if (error && error != ENOENT)
- fatal(0, "dmu_objset_destroy(%s) = %d", clone2name, error);
- error = dmu_objset_destroy(snap3name, B_FALSE);
+ fatal(0, "dsl_destroy_head(%s) = %d", clone2name, error);
+ error = dsl_destroy_snapshot(snap3name, B_FALSE);
if (error && error != ENOENT)
- fatal(0, "dmu_objset_destroy(%s) = %d", snap3name, error);
- error = dmu_objset_destroy(snap2name, B_FALSE);
+ fatal(0, "dsl_destroy_snapshot(%s) = %d", snap3name, error);
+ error = dsl_destroy_snapshot(snap2name, B_FALSE);
if (error && error != ENOENT)
- fatal(0, "dmu_objset_destroy(%s) = %d", snap2name, error);
- error = dmu_objset_destroy(clone1name, B_FALSE);
+ fatal(0, "dsl_destroy_snapshot(%s) = %d", snap2name, error);
+ error = dsl_destroy_head(clone1name);
if (error && error != ENOENT)
- fatal(0, "dmu_objset_destroy(%s) = %d", clone1name, error);
- error = dmu_objset_destroy(snap1name, B_FALSE);
+ fatal(0, "dsl_destroy_head(%s) = %d", clone1name, error);
+ error = dsl_destroy_snapshot(snap1name, B_FALSE);
if (error && error != ENOENT)
- fatal(0, "dmu_objset_destroy(%s) = %d", snap1name, error);
+ fatal(0, "dsl_destroy_snapshot(%s) = %d", snap1name, error);
umem_free(snap1name, MAXNAMELEN);
umem_free(clone1name, MAXNAMELEN);
void
ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
{
- objset_t *clone;
- dsl_dataset_t *ds;
+ objset_t *os;
char *snap1name;
char *clone1name;
char *snap2name;
clone2name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL);
snap3name = umem_alloc(MAXNAMELEN, UMEM_NOFAIL);
- (void) rw_enter(&ztest_name_lock, RW_READER);
+ (void) rw_rdlock(&ztest_name_lock);
ztest_dsl_dataset_cleanup(osname, id);
(void) snprintf(snap3name, MAXNAMELEN, "%s@s3_%llu",
clone1name, (u_longlong_t)id);
- error = dmu_objset_snapshot(osname, strchr(snap1name, '@')+1,
- NULL, NULL, B_FALSE, B_FALSE, -1);
+ error = dmu_objset_snapshot_one(osname, strchr(snap1name, '@') + 1);
if (error && error != EEXIST) {
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
fatal(0, "dmu_take_snapshot(%s) = %d", snap1name, error);
}
- error = dmu_objset_hold(snap1name, FTAG, &clone);
- if (error)
- fatal(0, "dmu_open_snapshot(%s) = %d", snap1name, error);
-
- error = dmu_objset_clone(clone1name, dmu_objset_ds(clone), 0);
- dmu_objset_rele(clone, FTAG);
+ error = dmu_objset_clone(clone1name, snap1name);
if (error) {
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
fatal(0, "dmu_objset_create(%s) = %d", clone1name, error);
}
- error = dmu_objset_snapshot(clone1name, strchr(snap2name, '@')+1,
- NULL, NULL, B_FALSE, B_FALSE, -1);
+ error = dmu_objset_snapshot_one(clone1name, strchr(snap2name, '@') + 1);
if (error && error != EEXIST) {
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
fatal(0, "dmu_open_snapshot(%s) = %d", snap2name, error);
}
- error = dmu_objset_snapshot(clone1name, strchr(snap3name, '@')+1,
- NULL, NULL, B_FALSE, B_FALSE, -1);
+ error = dmu_objset_snapshot_one(clone1name, strchr(snap3name, '@') + 1);
if (error && error != EEXIST) {
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
fatal(0, "dmu_open_snapshot(%s) = %d", snap3name, error);
}
- error = dmu_objset_hold(snap3name, FTAG, &clone);
- if (error)
- fatal(0, "dmu_open_snapshot(%s) = %d", snap3name, error);
-
- error = dmu_objset_clone(clone2name, dmu_objset_ds(clone), 0);
- dmu_objset_rele(clone, FTAG);
+ error = dmu_objset_clone(clone2name, snap3name);
if (error) {
if (error == ENOSPC) {
ztest_record_enospc(FTAG);
fatal(0, "dmu_objset_create(%s) = %d", clone2name, error);
}
- error = dsl_dataset_own(snap2name, B_FALSE, FTAG, &ds);
+ error = dmu_objset_own(snap2name, DMU_OST_ANY, B_TRUE, FTAG, &os);
if (error)
- fatal(0, "dsl_dataset_own(%s) = %d", snap2name, error);
+ fatal(0, "dmu_objset_own(%s) = %d", snap2name, error);
error = dsl_dataset_promote(clone2name, NULL);
+ if (error == ENOSPC) {
+ dmu_objset_disown(os, FTAG);
+ ztest_record_enospc(FTAG);
+ goto out;
+ }
if (error != EBUSY)
fatal(0, "dsl_dataset_promote(%s), %d, not EBUSY", clone2name,
error);
- dsl_dataset_disown(ds, FTAG);
+ dmu_objset_disown(os, FTAG);
out:
ztest_dsl_dataset_cleanup(osname, id);
- (void) rw_exit(&ztest_name_lock);
+ (void) rw_unlock(&ztest_name_lock);
umem_free(snap1name, MAXNAMELEN);
umem_free(clone1name, MAXNAMELEN);
}
#undef OD_ARRAY_SIZE
-#define OD_ARRAY_SIZE 4
+#define OD_ARRAY_SIZE 4
/*
* Verify that dmu_object_{alloc,free} work as expected.
int size;
int b;
- size = sizeof(ztest_od_t) * OD_ARRAY_SIZE;
+ size = sizeof (ztest_od_t) * OD_ARRAY_SIZE;
od = umem_alloc(size, UMEM_NOFAIL);
batchsize = OD_ARRAY_SIZE;
for (b = 0; b < batchsize; b++)
- ztest_od_init(od + b, id, FTAG, b, DMU_OT_UINT64_OTHER, 0, 0);
+ ztest_od_init(od + b, id, FTAG, b, DMU_OT_UINT64_OTHER,
+ 0, 0, 0);
/*
* Destroy the previous batch of objects, create a new batch,
}
#undef OD_ARRAY_SIZE
-#define OD_ARRAY_SIZE 2
+#define OD_ARRAY_SIZE 2
/*
* Verify that dmu_{read,write} work as expected.
ztest_od_t *od;
objset_t *os = zd->zd_os;
- size = sizeof(ztest_od_t) * OD_ARRAY_SIZE;
+ size = sizeof (ztest_od_t) * OD_ARRAY_SIZE;
od = umem_alloc(size, UMEM_NOFAIL);
dmu_tx_t *tx;
int i, freeit, error;
/*
* Read the directory info. If it's the first time, set things up.
*/
- ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, chunksize);
- ztest_od_init(od + 1, id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, chunksize);
+ ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, chunksize);
+ ztest_od_init(od + 1, id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, 0,
+ chunksize);
if (ztest_object_init(zd, od, size, B_FALSE) != 0) {
umem_free(od, size);
*/
n = ztest_random(regions) * stride + ztest_random(width);
s = 1 + ztest_random(2 * width - 1);
- dmu_prefetch(os, bigobj, n * chunksize, s * chunksize);
+ dmu_prefetch(os, bigobj, 0, n * chunksize, s * chunksize,
+ ZIO_PRIORITY_SYNC_READ);
/*
* Pick a random index and compute the offsets into packobj and bigobj.
*/
error = dmu_read(os, packobj, packoff, packsize, packbuf,
DMU_READ_PREFETCH);
- ASSERT3U(error, ==, 0);
+ ASSERT0(error);
error = dmu_read(os, bigobj, bigoff, bigsize, bigbuf,
DMU_READ_PREFETCH);
- ASSERT3U(error, ==, 0);
+ ASSERT0(error);
/*
* Get a tx for the mods to both packobj and bigobj.
else
dmu_tx_hold_write(tx, bigobj, bigoff, bigsize);
+ /* This accounts for setting the checksum/compression. */
+ dmu_tx_hold_bonus(tx, bigobj);
+
txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
if (txg == 0) {
umem_free(packbuf, packsize);
return;
}
- dmu_object_set_checksum(os, bigobj,
- (enum zio_checksum)ztest_random_dsl_prop(ZFS_PROP_CHECKSUM), tx);
+ enum zio_checksum cksum;
+ do {
+ cksum = (enum zio_checksum)
+ ztest_random_dsl_prop(ZFS_PROP_CHECKSUM);
+ } while (cksum >= ZIO_CHECKSUM_LEGACY_FUNCTIONS);
+ dmu_object_set_checksum(os, bigobj, cksum, tx);
- dmu_object_set_compress(os, bigobj,
- (enum zio_compress)ztest_random_dsl_prop(ZFS_PROP_COMPRESSION), tx);
+ enum zio_compress comp;
+ do {
+ comp = (enum zio_compress)
+ ztest_random_dsl_prop(ZFS_PROP_COMPRESSION);
+ } while (comp >= ZIO_COMPRESS_LEGACY_FUNCTIONS);
+ dmu_object_set_compress(os, bigobj, comp, tx);
/*
* For each index from n to n + s, verify that the existing bufwad
}
#undef OD_ARRAY_SIZE
-#define OD_ARRAY_SIZE 2
+#define OD_ARRAY_SIZE 2
void
ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id)
arc_buf_t **bigbuf_arcbufs;
dmu_object_info_t doi;
- size = sizeof(ztest_od_t) * OD_ARRAY_SIZE;
+ size = sizeof (ztest_od_t) * OD_ARRAY_SIZE;
od = umem_alloc(size, UMEM_NOFAIL);
/*
/*
* Read the directory info. If it's the first time, set things up.
*/
- ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0);
- ztest_od_init(od + 1, id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, chunksize);
+ ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0, 0);
+ ztest_od_init(od + 1, id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, 0,
+ chunksize);
if (ztest_object_init(zd, od, size, B_FALSE) != 0) {
* assign an arcbuf to a dbuf.
*/
for (j = 0; j < s; j++) {
- if (i != 5) {
+ if (i != 5 || chunksize < (SPA_MINBLOCKSIZE * 2)) {
bigbuf_arcbufs[j] =
dmu_request_arcbuf(bonus_db, chunksize);
} else {
umem_free(packbuf, packsize);
umem_free(bigbuf, bigsize);
for (j = 0; j < s; j++) {
- if (i != 5) {
+ if (i != 5 ||
+ chunksize < (SPA_MINBLOCKSIZE * 2)) {
dmu_return_arcbuf(bigbuf_arcbufs[j]);
} else {
dmu_return_arcbuf(
if (i != 0 || ztest_random(2) != 0) {
error = dmu_read(os, packobj, packoff,
packsize, packbuf, DMU_READ_PREFETCH);
- ASSERT3U(error, ==, 0);
+ ASSERT0(error);
error = dmu_read(os, bigobj, bigoff, bigsize,
bigbuf, DMU_READ_PREFETCH);
- ASSERT3U(error, ==, 0);
+ ASSERT0(error);
}
compare_and_update_pbbufs(s, packbuf, bigbuf, bigsize,
n, chunksize, txg);
}
for (off = bigoff, j = 0; j < s; j++, off += chunksize) {
dmu_buf_t *dbt;
- if (i != 5) {
+ if (i != 5 || chunksize < (SPA_MINBLOCKSIZE * 2)) {
bcopy((caddr_t)bigbuf + (off - bigoff),
bigbuf_arcbufs[j]->b_data, chunksize);
} else {
VERIFY(dmu_buf_hold(os, bigobj, off,
FTAG, &dbt, DMU_READ_NO_PREFETCH) == 0);
}
- if (i != 5) {
+ if (i != 5 || chunksize < (SPA_MINBLOCKSIZE * 2)) {
dmu_assign_arcbuf(bonus_db, off,
bigbuf_arcbufs[j], tx);
} else {
{
ztest_od_t *od;
- od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL);
+ od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
uint64_t offset = (1ULL << (ztest_random(20) + 43)) +
(ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT);
* to verify that parallel writes to an object -- even to the
* same blocks within the object -- doesn't cause any trouble.
*/
- ztest_od_init(od, ID_PARALLEL, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0);
+ ztest_od_init(od, ID_PARALLEL, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, 0);
if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0)
return;
while (ztest_random(10) != 0)
ztest_io(zd, od->od_object, offset);
- umem_free(od, sizeof(ztest_od_t));
+ umem_free(od, sizeof (ztest_od_t));
}
void
uint64_t blocksize = ztest_random_blocksize();
void *data;
- od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL);
+ od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
- ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0);
+ ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0, 0);
- if (ztest_object_init(zd, od, sizeof (ztest_od_t), !ztest_random(2)) != 0) {
- umem_free(od, sizeof(ztest_od_t));
+ if (ztest_object_init(zd, od, sizeof (ztest_od_t),
+ !ztest_random(2)) != 0) {
+ umem_free(od, sizeof (ztest_od_t));
return;
}
if (ztest_truncate(zd, od->od_object, offset, count * blocksize) != 0) {
- umem_free(od, sizeof(ztest_od_t));
+ umem_free(od, sizeof (ztest_od_t));
return;
}
}
umem_free(data, blocksize);
- umem_free(od, sizeof(ztest_od_t));
+ umem_free(od, sizeof (ztest_od_t));
}
/*
int error;
char *hc[2] = { "s.acl.h", ".s.open.h.hyLZlg" };
- od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL);
- ztest_od_init(od, id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0);
+ od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+ ztest_od_init(od, id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0, 0);
if (ztest_object_init(zd, od, sizeof (ztest_od_t),
!ztest_random(2)) != 0)
if (error == ENOENT)
goto out;
- ASSERT3U(error, ==, 0);
+ ASSERT0(error);
tx = dmu_tx_create(os);
dmu_tx_hold_zap(tx, object, B_TRUE, NULL);
VERIFY3U(0, ==, zap_remove(os, object, propname, tx));
dmu_tx_commit(tx);
out:
- umem_free(od, sizeof(ztest_od_t));
+ umem_free(od, sizeof (ztest_od_t));
}
/*
uint64_t object, txg;
int i;
- od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL);
- ztest_od_init(od, id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0);
+ od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+ ztest_od_init(od, id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0, 0);
if (ztest_object_init(zd, od, sizeof (ztest_od_t),
!ztest_random(2)) != 0)
dmu_tx_commit(tx);
}
out:
- umem_free(od, sizeof(ztest_od_t));
+ umem_free(od, sizeof (ztest_od_t));
}
/* ARGSUSED */
char name[20], string_value[20];
void *data;
- od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL);
- ztest_od_init(od, ID_PARALLEL, FTAG, micro, DMU_OT_ZAP_OTHER, 0, 0);
+ od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+ ztest_od_init(od, ID_PARALLEL, FTAG, micro, DMU_OT_ZAP_OTHER, 0, 0, 0);
if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) {
- umem_free(od, sizeof(ztest_od_t));
+ umem_free(od, sizeof (ztest_od_t));
return;
}
}
count = -1ULL;
- VERIFY(zap_count(os, object, &count) == 0);
+ VERIFY0(zap_count(os, object, &count));
ASSERT(count != -1ULL);
/*
if (tx != NULL)
dmu_tx_commit(tx);
- umem_free(od, sizeof(ztest_od_t));
+ umem_free(od, sizeof (ztest_od_t));
}
/*
data->zcd_called = B_TRUE;
if (error == ECANCELED) {
- ASSERT3U(data->zcd_txg, ==, 0);
+ ASSERT0(data->zcd_txg);
ASSERT(!data->zcd_added);
/*
uint64_t old_txg, txg;
int i, error = 0;
- od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL);
- ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0);
+ od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+ ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, 0);
if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) {
- umem_free(od, sizeof(ztest_od_t));
+ umem_free(od, sizeof (ztest_od_t));
return;
}
umem_free(cb_data[i], sizeof (ztest_cb_data_t));
}
- umem_free(od, sizeof(ztest_od_t));
+ umem_free(od, sizeof (ztest_od_t));
return;
}
dmu_tx_commit(tx);
- umem_free(od, sizeof(ztest_od_t));
+ umem_free(od, sizeof (ztest_od_t));
+}
+
+/*
+ * Visit each object in the dataset. Verify that its properties
+ * are consistent what was stored in the block tag when it was created,
+ * and that its unused bonus buffer space has not been overwritten.
+ */
+void
+ztest_verify_dnode_bt(ztest_ds_t *zd, uint64_t id)
+{
+ objset_t *os = zd->zd_os;
+ uint64_t obj;
+ int err = 0;
+
+ for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 0)) {
+ ztest_block_tag_t *bt = NULL;
+ dmu_object_info_t doi;
+ dmu_buf_t *db;
+
+ if (dmu_bonus_hold(os, obj, FTAG, &db) != 0)
+ continue;
+
+ dmu_object_info_from_db(db, &doi);
+ if (doi.doi_bonus_size >= sizeof (*bt))
+ bt = ztest_bt_bonus(db);
+
+ if (bt && bt->bt_magic == BT_MAGIC) {
+ ztest_bt_verify(bt, os, obj, doi.doi_dnodesize,
+ bt->bt_offset, bt->bt_gen, bt->bt_txg,
+ bt->bt_crtxg);
+ ztest_verify_unused_bonus(db, bt, obj, os, bt->bt_gen);
+ }
+
+ dmu_buf_rele(db, FTAG);
+ }
}
/* ARGSUSED */
};
int p;
- (void) rw_enter(&ztest_name_lock, RW_READER);
+ (void) rw_rdlock(&ztest_name_lock);
for (p = 0; p < sizeof (proplist) / sizeof (proplist[0]); p++)
(void) ztest_dsl_prop_set_uint64(zd->zd_name, proplist[p],
ztest_random_dsl_prop(proplist[p]), (int)ztest_random(2));
- (void) rw_exit(&ztest_name_lock);
+ VERIFY0(ztest_dsl_prop_set_uint64(zd->zd_name, ZFS_PROP_RECORDSIZE,
+ ztest_random_blocksize(), (int)ztest_random(2)));
+
+ (void) rw_unlock(&ztest_name_lock);
}
/* ARGSUSED */
{
nvlist_t *props = NULL;
- (void) rw_enter(&ztest_name_lock, RW_READER);
+ (void) rw_rdlock(&ztest_name_lock);
(void) ztest_spa_prop_set_uint64(ZPOOL_PROP_DEDUPDITTO,
ZIO_DEDUPDITTO_MIN + ztest_random(ZIO_DEDUPDITTO_MIN));
- VERIFY3U(spa_prop_get(ztest_spa, &props), ==, 0);
+ VERIFY0(spa_prop_get(ztest_spa, &props));
if (ztest_opts.zo_verbose >= 6)
dump_nvlist(props, 4);
nvlist_free(props);
- (void) rw_exit(&ztest_name_lock);
+ (void) rw_unlock(&ztest_name_lock);
+}
+
+static int
+user_release_one(const char *snapname, const char *holdname)
+{
+ nvlist_t *snaps, *holds;
+ int error;
+
+ snaps = fnvlist_alloc();
+ holds = fnvlist_alloc();
+ fnvlist_add_boolean(holds, holdname);
+ fnvlist_add_nvlist(snaps, snapname, holds);
+ fnvlist_free(holds);
+ error = dsl_dataset_user_release(snaps, NULL);
+ fnvlist_free(snaps);
+ return (error);
}
/*
char clonename[100];
char tag[100];
char osname[MAXNAMELEN];
+ nvlist_t *holds;
- (void) rw_enter(&ztest_name_lock, RW_READER);
+ (void) rw_rdlock(&ztest_name_lock);
dmu_objset_name(os, osname);
- (void) snprintf(snapname, 100, "sh1_%llu", (u_longlong_t)id);
- (void) snprintf(fullname, 100, "%s@%s", osname, snapname);
- (void) snprintf(clonename, 100, "%s/ch1_%llu",osname,(u_longlong_t)id);
- (void) snprintf(tag, 100, "tag_%llu", (u_longlong_t)id);
+ (void) snprintf(snapname, sizeof (snapname), "sh1_%llu",
+ (u_longlong_t)id);
+ (void) snprintf(fullname, sizeof (fullname), "%s@%s", osname, snapname);
+ (void) snprintf(clonename, sizeof (clonename),
+ "%s/ch1_%llu", osname, (u_longlong_t)id);
+ (void) snprintf(tag, sizeof (tag), "tag_%llu", (u_longlong_t)id);
/*
* Clean up from any previous run.
*/
- (void) dmu_objset_destroy(clonename, B_FALSE);
- (void) dsl_dataset_user_release(osname, snapname, tag, B_FALSE);
- (void) dmu_objset_destroy(fullname, B_FALSE);
+ error = dsl_destroy_head(clonename);
+ if (error != ENOENT)
+ ASSERT0(error);
+ error = user_release_one(fullname, tag);
+ if (error != ESRCH && error != ENOENT)
+ ASSERT0(error);
+ error = dsl_destroy_snapshot(fullname, B_FALSE);
+ if (error != ENOENT)
+ ASSERT0(error);
/*
* Create snapshot, clone it, mark snap for deferred destroy,
* destroy clone, verify snap was also destroyed.
*/
- error = dmu_objset_snapshot(osname, snapname, NULL, NULL, FALSE,
- FALSE, -1);
+ error = dmu_objset_snapshot_one(osname, snapname);
if (error) {
if (error == ENOSPC) {
ztest_record_enospc("dmu_objset_snapshot");
fatal(0, "dmu_objset_snapshot(%s) = %d", fullname, error);
}
- error = dmu_objset_hold(fullname, FTAG, &origin);
- if (error)
- fatal(0, "dmu_objset_hold(%s) = %d", fullname, error);
-
- error = dmu_objset_clone(clonename, dmu_objset_ds(origin), 0);
- dmu_objset_rele(origin, FTAG);
+ error = dmu_objset_clone(clonename, fullname);
if (error) {
if (error == ENOSPC) {
ztest_record_enospc("dmu_objset_clone");
fatal(0, "dmu_objset_clone(%s) = %d", clonename, error);
}
- error = dmu_objset_destroy(fullname, B_TRUE);
+ error = dsl_destroy_snapshot(fullname, B_TRUE);
if (error) {
- fatal(0, "dmu_objset_destroy(%s, B_TRUE) = %d",
+ fatal(0, "dsl_destroy_snapshot(%s, B_TRUE) = %d",
fullname, error);
}
- error = dmu_objset_destroy(clonename, B_FALSE);
+ error = dsl_destroy_head(clonename);
if (error)
- fatal(0, "dmu_objset_destroy(%s) = %d", clonename, error);
+ fatal(0, "dsl_destroy_head(%s) = %d", clonename, error);
error = dmu_objset_hold(fullname, FTAG, &origin);
if (error != ENOENT)
* destroy a held snapshot, mark for deferred destroy,
* release hold, verify snapshot was destroyed.
*/
- error = dmu_objset_snapshot(osname, snapname, NULL, NULL, FALSE,
- FALSE, -1);
+ error = dmu_objset_snapshot_one(osname, snapname);
if (error) {
if (error == ENOSPC) {
ztest_record_enospc("dmu_objset_snapshot");
fatal(0, "dmu_objset_snapshot(%s) = %d", fullname, error);
}
- error = dsl_dataset_user_hold(osname, snapname, tag, B_FALSE,
- B_TRUE, -1);
- if (error)
- fatal(0, "dsl_dataset_user_hold(%s)", fullname, tag);
+ holds = fnvlist_alloc();
+ fnvlist_add_string(holds, fullname, tag);
+ error = dsl_dataset_user_hold(holds, 0, NULL);
+ fnvlist_free(holds);
+
+ if (error == ENOSPC) {
+ ztest_record_enospc("dsl_dataset_user_hold");
+ goto out;
+ } else if (error) {
+ fatal(0, "dsl_dataset_user_hold(%s, %s) = %u",
+ fullname, tag, error);
+ }
- error = dmu_objset_destroy(fullname, B_FALSE);
+ error = dsl_destroy_snapshot(fullname, B_FALSE);
if (error != EBUSY) {
- fatal(0, "dmu_objset_destroy(%s, B_FALSE) = %d",
+ fatal(0, "dsl_destroy_snapshot(%s, B_FALSE) = %d",
fullname, error);
}
- error = dmu_objset_destroy(fullname, B_TRUE);
+ error = dsl_destroy_snapshot(fullname, B_TRUE);
if (error) {
- fatal(0, "dmu_objset_destroy(%s, B_TRUE) = %d",
+ fatal(0, "dsl_destroy_snapshot(%s, B_TRUE) = %d",
fullname, error);
}
- error = dsl_dataset_user_release(osname, snapname, tag, B_FALSE);
+ error = user_release_one(fullname, tag);
if (error)
- fatal(0, "dsl_dataset_user_release(%s)", fullname, tag);
+ fatal(0, "user_release_one(%s, %s) = %d", fullname, tag, error);
- VERIFY(dmu_objset_hold(fullname, FTAG, &origin) == ENOENT);
+ VERIFY3U(dmu_objset_hold(fullname, FTAG, &origin), ==, ENOENT);
out:
- (void) rw_exit(&ztest_name_lock);
+ (void) rw_unlock(&ztest_name_lock);
}
/*
ASSERT(leaves >= 1);
+ /*
+ * Grab the name lock as reader. There are some operations
+ * which don't like to have their vdevs changed while
+ * they are in progress (i.e. spa_change_guid). Those
+ * operations will have grabbed the name lock as writer.
+ */
+ (void) rw_rdlock(&ztest_name_lock);
+
/*
* We need SCL_STATE here because we're going to look at vd0->vdev_tsd.
*/
if (vd0 != NULL && vd0->vdev_top->vdev_islog)
islog = B_TRUE;
- if (vd0 != NULL && maxfaults != 1) {
+ /*
+ * If the top-level vdev needs to be resilvered
+ * then we only allow faults on the device that is
+ * resilvering.
+ */
+ if (vd0 != NULL && maxfaults != 1 &&
+ (!vdev_resilver_needed(vd0->vdev_top, NULL, NULL) ||
+ vd0->vdev_resilver_txg != 0)) {
/*
* Make vd0 explicitly claim to be unreadable,
* or unwriteable, or reach behind its back
if (sav->sav_count == 0) {
spa_config_exit(spa, SCL_STATE, FTAG);
+ (void) rw_unlock(&ztest_name_lock);
goto out;
}
vd0 = sav->sav_vdevs[ztest_random(sav->sav_count)];
}
spa_config_exit(spa, SCL_STATE, FTAG);
+ (void) rw_unlock(&ztest_name_lock);
/*
* If we can tolerate two or more faults, or we're dealing
* prevent a race between offlining a slog and
* destroying a dataset. Offlining the slog will
* grab a reference on the dataset which may cause
- * dmu_objset_destroy() to fail with EBUSY thus
+ * dsl_destroy_head() to fail with EBUSY thus
* leaving the dataset in an inconsistent state.
*/
if (islog)
- (void) rw_enter(&ztest_name_lock,
- RW_WRITER);
+ (void) rw_wrlock(&ztest_name_lock);
VERIFY(vdev_offline(spa, guid0, flags) != EBUSY);
if (islog)
- (void) rw_exit(&ztest_name_lock);
+ (void) rw_unlock(&ztest_name_lock);
} else {
+ /*
+ * Ideally we would like to be able to randomly
+ * call vdev_[on|off]line without holding locks
+ * to force unpredictable failures but the side
+ * effects of vdev_[on|off]line prevent us from
+ * doing so. We grab the ztest_vdev_lock here to
+ * prevent a race between injection testing and
+ * aux_vdev removal.
+ */
+ mutex_enter(&ztest_vdev_lock);
(void) vdev_online(spa, guid0, 0, NULL);
+ mutex_exit(&ztest_vdev_lock);
}
}
fsize = lseek(fd, 0, SEEK_END);
while (--iters != 0) {
+ /*
+ * The offset must be chosen carefully to ensure that
+ * we do not inject a given logical block with errors
+ * on two different leaf devices, because ZFS can not
+ * tolerate that (if maxfaults==1).
+ *
+ * We divide each leaf into chunks of size
+ * (# leaves * SPA_MAXBLOCKSIZE * 4). Within each chunk
+ * there is a series of ranges to which we can inject errors.
+ * Each range can accept errors on only a single leaf vdev.
+ * The error injection ranges are separated by ranges
+ * which we will not inject errors on any device (DMZs).
+ * Each DMZ must be large enough such that a single block
+ * can not straddle it, so that a single block can not be
+ * a target in two different injection ranges (on different
+ * leaf vdevs).
+ *
+ * For example, with 3 leaves, each chunk looks like:
+ * 0 to 32M: injection range for leaf 0
+ * 32M to 64M: DMZ - no injection allowed
+ * 64M to 96M: injection range for leaf 1
+ * 96M to 128M: DMZ - no injection allowed
+ * 128M to 160M: injection range for leaf 2
+ * 160M to 192M: DMZ - no injection allowed
+ */
offset = ztest_random(fsize / (leaves << bshift)) *
(leaves << bshift) + (leaf << bshift) +
(ztest_random(1ULL << (bshift - 1)) & -8ULL);
blocksize = ztest_random_blocksize();
blocksize = MIN(blocksize, 2048); /* because we write so many */
- od = umem_alloc(sizeof(ztest_od_t), UMEM_NOFAIL);
- ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0);
+ od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+ ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0, 0);
if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) {
- umem_free(od, sizeof(ztest_od_t));
+ umem_free(od, sizeof (ztest_od_t));
return;
}
* Take the name lock as writer to prevent anyone else from changing
* the pool and dataset properies we need to maintain during this test.
*/
- (void) rw_enter(&ztest_name_lock, RW_WRITER);
+ (void) rw_wrlock(&ztest_name_lock);
if (ztest_dsl_prop_set_uint64(zd->zd_name, ZFS_PROP_DEDUP, checksum,
B_FALSE) != 0 ||
ztest_dsl_prop_set_uint64(zd->zd_name, ZFS_PROP_COPIES, 1,
B_FALSE) != 0) {
- (void) rw_exit(&ztest_name_lock);
- umem_free(od, sizeof(ztest_od_t));
+ (void) rw_unlock(&ztest_name_lock);
+ umem_free(od, sizeof (ztest_od_t));
return;
}
dmu_tx_hold_write(tx, object, 0, copies * blocksize);
txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
if (txg == 0) {
- (void) rw_exit(&ztest_name_lock);
- umem_free(od, sizeof(ztest_od_t));
+ (void) rw_unlock(&ztest_name_lock);
+ umem_free(od, sizeof (ztest_od_t));
return;
}
*/
for (i = 0; i < copies; i++) {
uint64_t offset = i * blocksize;
- VERIFY(dmu_buf_hold(os, object, offset, FTAG, &db,
- DMU_READ_NO_PREFETCH) == 0);
+ int error = dmu_buf_hold(os, object, offset, FTAG, &db,
+ DMU_READ_NO_PREFETCH);
+ if (error != 0) {
+ fatal(B_FALSE, "dmu_buf_hold(%p, %llu, %llu) = %u",
+ os, (long long)object, (long long) offset, error);
+ }
ASSERT(db->db_offset == offset);
ASSERT(db->db_size == blocksize);
ASSERT(ztest_pattern_match(db->db_data, db->db_size, pattern) ||
/*
* Find out what block we got.
*/
- VERIFY(dmu_buf_hold(os, object, 0, FTAG, &db,
- DMU_READ_NO_PREFETCH) == 0);
+ VERIFY0(dmu_buf_hold(os, object, 0, FTAG, &db,
+ DMU_READ_NO_PREFETCH));
blk = *((dmu_buf_impl_t *)db)->db_blkptr;
dmu_buf_rele(db, FTAG);
zio_buf_free(buf, psize);
- (void) rw_exit(&ztest_name_lock);
- umem_free(od, sizeof(ztest_od_t));
+ (void) rw_unlock(&ztest_name_lock);
+ umem_free(od, sizeof (ztest_od_t));
}
/*
orig = spa_guid(spa);
load = spa_load_guid(spa);
- (void) rw_enter(&ztest_name_lock, RW_WRITER);
+ (void) rw_wrlock(&ztest_name_lock);
error = spa_change_guid(spa);
- (void) rw_exit(&ztest_name_lock);
+ (void) rw_unlock(&ztest_name_lock);
if (error != 0)
return;
- if (ztest_opts.zo_verbose >= 3) {
+ if (ztest_opts.zo_verbose >= 4) {
(void) printf("Changed guid old %llu -> %llu\n",
(u_longlong_t)orig, (u_longlong_t)spa_guid(spa));
}
char *oldname, *newname;
spa_t *spa;
- (void) rw_enter(&ztest_name_lock, RW_WRITER);
+ (void) rw_wrlock(&ztest_name_lock);
oldname = ztest_opts.zo_pool;
newname = umem_alloc(strlen(oldname) + 5, UMEM_NOFAIL);
umem_free(newname, strlen(newname) + 1);
- (void) rw_exit(&ztest_name_lock);
+ (void) rw_unlock(&ztest_name_lock);
+}
+
+void
+ztest_fletcher(ztest_ds_t *zd, uint64_t id)
+{
+ hrtime_t end = gethrtime() + NANOSEC;
+
+ while (gethrtime() <= end) {
+ int run_count = 100;
+ void *buf;
+ uint32_t size;
+ int *ptr;
+ int i;
+ zio_cksum_t zc_ref;
+ zio_cksum_t zc_ref_byteswap;
+
+ size = ztest_random_blocksize();
+ buf = umem_alloc(size, UMEM_NOFAIL);
+
+ for (i = 0, ptr = buf; i < size / sizeof (*ptr); i++, ptr++)
+ *ptr = ztest_random(UINT_MAX);
+
+ VERIFY0(fletcher_4_impl_set("scalar"));
+ fletcher_4_native(buf, size, &zc_ref);
+ fletcher_4_byteswap(buf, size, &zc_ref_byteswap);
+
+ VERIFY0(fletcher_4_impl_set("cycle"));
+ while (run_count-- > 0) {
+ zio_cksum_t zc;
+ zio_cksum_t zc_byteswap;
+
+ fletcher_4_byteswap(buf, size, &zc_byteswap);
+ fletcher_4_native(buf, size, &zc);
+
+ VERIFY0(bcmp(&zc, &zc_ref, sizeof (zc)));
+ VERIFY0(bcmp(&zc_byteswap, &zc_ref_byteswap,
+ sizeof (zc_byteswap)));
+ }
+
+ umem_free(buf, size);
+ }
+}
+
+static int
+ztest_check_path(char *path)
+{
+ struct stat s;
+ /* return true on success */
+ return (!stat(path, &s));
+}
+
+static void
+ztest_get_zdb_bin(char *bin, int len)
+{
+ char *zdb_path;
+ /*
+ * Try to use ZDB_PATH and in-tree zdb path. If not successful, just
+ * let popen to search through PATH.
+ */
+ if ((zdb_path = getenv("ZDB_PATH"))) {
+ strlcpy(bin, zdb_path, len); /* In env */
+ if (!ztest_check_path(bin)) {
+ ztest_dump_core = 0;
+ fatal(1, "invalid ZDB_PATH '%s'", bin);
+ }
+ return;
+ }
+
+ VERIFY(realpath(getexecname(), bin) != NULL);
+ if (strstr(bin, "/ztest/")) {
+ strstr(bin, "/ztest/")[0] = '\0'; /* In-tree */
+ strcat(bin, "/zdb/zdb");
+ if (ztest_check_path(bin))
+ return;
+ }
+ strcpy(bin, "zdb");
}
/*
char *bin;
char *zdb;
char *zbuf;
+ const int len = MAXPATHLEN + MAXNAMELEN + 20;
FILE *fp;
- bin = umem_alloc(MAXPATHLEN + MAXNAMELEN + 20, UMEM_NOFAIL);
- zdb = umem_alloc(MAXPATHLEN + MAXNAMELEN + 20, UMEM_NOFAIL);
+ bin = umem_alloc(len, UMEM_NOFAIL);
+ zdb = umem_alloc(len, UMEM_NOFAIL);
zbuf = umem_alloc(1024, UMEM_NOFAIL);
- VERIFY(realpath(getexecname(), bin) != NULL);
- if (strncmp(bin, "/usr/sbin/ztest", 15) == 0) {
- strcpy(bin, "/usr/sbin/zdb"); /* Installed */
- } else if (strncmp(bin, "/sbin/ztest", 11) == 0) {
- strcpy(bin, "/sbin/zdb"); /* Installed */
- } else {
- strstr(bin, "/ztest/")[0] = '\0'; /* In-tree */
- strcat(bin, "/zdb/zdb");
- }
+ ztest_get_zdb_bin(bin, len);
(void) sprintf(zdb,
- "%s -bcc%s%s -U %s %s",
+ "%s -bcc%s%s -d -U %s %s",
bin,
ztest_opts.zo_verbose >= 3 ? "s" : "",
ztest_opts.zo_verbose >= 4 ? "v" : "",
else
fatal(0, "'%s' died with signal %d", zdb, WTERMSIG(status));
out:
- umem_free(bin, MAXPATHLEN + MAXNAMELEN + 20);
- umem_free(zdb, MAXPATHLEN + MAXNAMELEN + 20);
+ umem_free(bin, len);
+ umem_free(zdb, len);
umem_free(zbuf, 1024);
}
nvlist_t *config, *newconfig;
uint64_t pool_guid;
spa_t *spa;
+ int error;
if (ztest_opts.zo_verbose >= 4) {
(void) printf("import/export: old = %s, new = %s\n",
/*
* Import it under the new name.
*/
- VERIFY3U(0, ==, spa_import(newname, config, NULL, 0));
+ error = spa_import(newname, config, NULL, 0);
+ if (error != 0) {
+ dump_nvlist(config, 0);
+ fatal(B_FALSE, "couldn't import pool %s as %s: error %u",
+ oldname, newname, error);
+ }
ztest_walk_pool_directory("pools after import");
return (NULL);
}
-#define GRACE 300
+#define GRACE 300
#if 0
static void
atomic_add_64(&zc->zc_count, 1);
atomic_add_64(&zc->zc_time, functime);
- if (ztest_opts.zo_verbose >= 4) {
- Dl_info dli;
- (void) dladdr((void *)zi->zi_func, &dli);
+ if (ztest_opts.zo_verbose >= 4)
(void) printf("%6.2f sec in %s\n",
- (double)functime / NANOSEC, dli.dli_sname);
- }
+ (double)functime / NANOSEC, zi->zi_funcname);
}
static void *
ztest_dataset_name(name, ztest_opts.zo_pool, d);
- (void) rw_enter(&ztest_name_lock, RW_READER);
+ (void) rw_rdlock(&ztest_name_lock);
error = ztest_dataset_create(name);
if (error == ENOSPC) {
- (void) rw_exit(&ztest_name_lock);
+ (void) rw_unlock(&ztest_name_lock);
ztest_record_enospc(FTAG);
return (error);
}
ASSERT(error == 0 || error == EEXIST);
- VERIFY3U(dmu_objset_hold(name, zd, &os), ==, 0);
- (void) rw_exit(&ztest_name_lock);
+ VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, zd, &os));
+ (void) rw_unlock(&ztest_name_lock);
ztest_zd_init(zd, ZTEST_GET_SHARED_DS(d), os);
ztest_ds_t *zd = &ztest_ds[d];
zil_close(zd->zd_zilog);
- dmu_objset_rele(zd->zd_os, zd);
+ dmu_objset_disown(zd->zd_os, zd);
ztest_zd_fini(zd);
}
* Initialize parent/child shared state.
*/
mutex_init(&ztest_vdev_lock, NULL, MUTEX_DEFAULT, NULL);
- rw_init(&ztest_name_lock, NULL, RW_DEFAULT, NULL);
+ VERIFY(rwlock_init(&ztest_name_lock, USYNC_THREAD, NULL) == 0);
zs->zs_thread_start = gethrtime();
zs->zs_thread_stop =
* Open our pool.
*/
kernel_init(FREAD | FWRITE);
- VERIFY(spa_open(ztest_opts.zo_pool, &spa, FTAG) == 0);
+ VERIFY0(spa_open(ztest_opts.zo_pool, &spa, FTAG));
spa->spa_debug = B_TRUE;
+ metaslab_preload_limit = ztest_random(20) + 1;
ztest_spa = spa;
- VERIFY3U(0, ==, dmu_objset_hold(ztest_opts.zo_pool, FTAG, &os));
+ VERIFY0(dmu_objset_own(ztest_opts.zo_pool,
+ DMU_OST_ANY, B_TRUE, FTAG, &os));
zs->zs_guid = dmu_objset_fsid_guid(os);
- dmu_objset_rele(os, FTAG);
+ dmu_objset_disown(os, FTAG);
spa->spa_dedup_ditto = 2 * ZIO_DEDUPDITTO_MIN;
* Right before closing the pool, kick off a bunch of async I/O;
* spa_close() should wait for it to complete.
*/
- for (object = 1; object < 50; object++)
- dmu_prefetch(spa->spa_meta_objset, object, 0, 1ULL << 20);
+ for (object = 1; object < 50; object++) {
+ dmu_prefetch(spa->spa_meta_objset, object, 0, 0, 1ULL << 20,
+ ZIO_PRIORITY_SYNC_READ);
+ }
/* Verify that at least one commit cb was called in a timely fashion */
if (zc_cb_counter >= ZTEST_COMMIT_CB_MIN_REG)
- VERIFY3U(zc_min_txg_delay, ==, 0);
+ VERIFY0(zc_min_txg_delay);
spa_close(spa, FTAG);
list_destroy(&zcl.zcl_callbacks);
mutex_destroy(&zcl.zcl_callbacks_lock);
- rw_destroy(&ztest_name_lock);
+ (void) rwlock_destroy(&ztest_name_lock);
mutex_destroy(&ztest_vdev_lock);
}
kernel_init(FREAD | FWRITE);
VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
VERIFY3U(0, ==, ztest_dataset_open(0));
+ spa->spa_debug = B_TRUE;
+ ztest_spa = spa;
/*
* Force the first log block to be transactionally allocated.
*/
spa_freeze(spa);
+ /*
+ * Because it is hard to predict how much space a write will actually
+ * require beforehand, we leave ourselves some fudge space to write over
+ * capacity.
+ */
+ uint64_t capacity = metaslab_class_get_space(spa_normal_class(spa)) / 2;
+
/*
* Run tests that generate log records but don't alter the pool config
* or depend on DSL sync tasks (snapshots, objset create/destroy, etc).
* We do a txg_wait_synced() after each iteration to force the txg
* to increase well beyond the last synced value in the uberblock.
* The ZIL should be OK with that.
+ *
+ * Run a random number of times less than zo_maxloops and ensure we do
+ * not run out of space on the pool.
*/
while (ztest_random(10) != 0 &&
- numloops++ < ztest_opts.zo_maxloops) {
- ztest_dmu_write_parallel(zd, 0);
- ztest_dmu_object_alloc_free(zd, 0);
+ numloops++ < ztest_opts.zo_maxloops &&
+ metaslab_class_get_alloc(spa_normal_class(spa)) < capacity) {
+ ztest_od_t od;
+ ztest_od_init(&od, 0, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, 0);
+ VERIFY0(ztest_object_init(zd, &od, sizeof (od), B_FALSE));
+ ztest_io(zd, od.od_object,
+ ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT);
txg_wait_synced(spa_get_dsl(spa), 0);
}
int i;
mutex_init(&ztest_vdev_lock, NULL, MUTEX_DEFAULT, NULL);
- rw_init(&ztest_name_lock, NULL, RW_DEFAULT, NULL);
+ VERIFY(rwlock_init(&ztest_name_lock, USYNC_THREAD, NULL) == 0);
kernel_init(FREAD | FWRITE);
ztest_shared->zs_vdev_next_leaf = 0;
zs->zs_splits = 0;
zs->zs_mirrors = ztest_opts.zo_mirrors;
- nvroot = make_vdev_root(NULL, NULL, ztest_opts.zo_vdev_size, 0,
+ nvroot = make_vdev_root(NULL, NULL, NULL, ztest_opts.zo_vdev_size, 0,
0, ztest_opts.zo_raidz, zs->zs_mirrors, 1);
props = make_random_props();
for (i = 0; i < SPA_FEATURES; i++) {
VERIFY3U(0, ==, nvlist_add_uint64(props, buf, 0));
free(buf);
}
- VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props,
- NULL, NULL));
+ VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props, NULL));
nvlist_free(nvroot);
+ nvlist_free(props);
VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
zs->zs_metaslab_sz =
ztest_run_zdb(ztest_opts.zo_pool);
- rw_destroy(&ztest_name_lock);
+ (void) rwlock_destroy(&ztest_name_lock);
mutex_destroy(&ztest_vdev_lock);
}
boolean_t hasalt;
int f;
char *fd_data_str = getenv("ZTEST_FD_DATA");
+ struct sigaction action;
(void) setvbuf(stdout, NULL, _IOLBF, 0);
+ dprintf_setup(&argc, argv);
+
+ action.sa_handler = sig_handler;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+
+ if (sigaction(SIGSEGV, &action, NULL) < 0) {
+ (void) fprintf(stderr, "ztest: cannot catch SIGSEGV: %s.\n",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (sigaction(SIGABRT, &action, NULL) < 0) {
+ (void) fprintf(stderr, "ztest: cannot catch SIGABRT: %s.\n",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
ztest_fd_rand = open("/dev/urandom", O_RDONLY);
ASSERT3S(ztest_fd_rand, >=, 0);
if (!fd_data_str) {
- dprintf_setup(&argc, argv);
process_options(argc, argv);
setup_data_fd();
(void) printf("%7s %9s %s\n",
"-----", "----", "--------");
for (f = 0; f < ZTEST_FUNCS; f++) {
- Dl_info dli;
-
zi = &ztest_info[f];
zc = ZTEST_GET_SHARED_CALLSTATE(f);
print_time(zc->zc_time, timebuf);
- (void) dladdr((void *)zi->zi_func, &dli);
(void) printf("%7llu %9s %s\n",
(u_longlong_t)zc->zc_count, timebuf,
- dli.dli_sname);
+ zi->zi_funcname);
}
(void) printf("\n");
}