* Note: these aren't static because we want dladdr() to work.
*/
ztest_func_t ztest_dmu_read_write;
+ ztest_func_t ztest_dmu_read_write_zcopy;
ztest_func_t ztest_dmu_write_parallel;
ztest_func_t ztest_dmu_object_alloc_free;
+ztest_func_t ztest_dmu_commit_callbacks;
ztest_func_t ztest_zap;
ztest_func_t ztest_zap_parallel;
ztest_func_t ztest_traverse;
ztest_info_t ztest_info[] = {
{ ztest_dmu_read_write, 1, &zopt_always },
+ { ztest_dmu_read_write_zcopy, 1, &zopt_always },
{ ztest_dmu_write_parallel, 30, &zopt_always },
{ ztest_dmu_object_alloc_free, 1, &zopt_always },
+ { ztest_dmu_commit_callbacks, 10, &zopt_always },
{ ztest_zap, 30, &zopt_always },
{ ztest_zap_parallel, 100, &zopt_always },
{ ztest_dsl_prop_get_set, 1, &zopt_sometimes },
(longlong_t)newsize, replacing, error, expected_error);
}
- (void) mutex_unlock(&ztest_shared->zs_vdev_lock);
+ (void) pthread_mutex_unlock(&ztest_shared->zs_vdev_lock);
}
+ /*
+ * Callback function which expands the physical size of the vdev.
+ */
+ vdev_t *
+ grow_vdev(vdev_t *vd, void *arg)
+ {
+ spa_t *spa = vd->vdev_spa;
+ size_t *newsize = arg;
+ size_t fsize;
+ int fd;
+
+ ASSERT(spa_config_held(spa, SCL_STATE, RW_READER) == SCL_STATE);
+ ASSERT(vd->vdev_ops->vdev_op_leaf);
+
+ if ((fd = open(vd->vdev_path, O_RDWR)) == -1)
+ return (vd);
+
+ fsize = lseek(fd, 0, SEEK_END);
+ (void) ftruncate(fd, *newsize);
+
+ if (zopt_verbose >= 6) {
+ (void) printf("%s grew from %lu to %lu bytes\n",
+ vd->vdev_path, (ulong_t)fsize, (ulong_t)*newsize);
+ }
+ (void) close(fd);
+ return (NULL);
+ }
+
+ /*
+ * Callback function which expands a given vdev by calling vdev_online().
+ */
+ /* ARGSUSED */
+ vdev_t *
+ online_vdev(vdev_t *vd, void *arg)
+ {
+ spa_t *spa = vd->vdev_spa;
+ vdev_t *tvd = vd->vdev_top;
+ vdev_t *pvd = vd->vdev_parent;
+ uint64_t guid = vd->vdev_guid;
+
+ ASSERT(spa_config_held(spa, SCL_STATE, RW_READER) == SCL_STATE);
+ ASSERT(vd->vdev_ops->vdev_op_leaf);
+
+ /* Calling vdev_online will initialize the new metaslabs */
+ spa_config_exit(spa, SCL_STATE, spa);
+ (void) vdev_online(spa, guid, ZFS_ONLINE_EXPAND, NULL);
+ spa_config_enter(spa, SCL_STATE, spa, RW_READER);
+
+ /*
+ * Since we dropped the lock we need to ensure that we're
+ * still talking to the original vdev. It's possible this
+ * vdev may have been detached/replaced while we were
+ * trying to online it.
+ */
+ if (vd != vdev_lookup_by_guid(tvd, guid) || vd->vdev_parent != pvd) {
+ if (zopt_verbose >= 6) {
+ (void) printf("vdev %p has disappeared, was "
+ "guid %llu\n", (void *)vd, (u_longlong_t)guid);
+ }
+ return (vd);
+ }
+ return (NULL);
+ }
+
+ /*
+ * Traverse the vdev tree calling the supplied function.
+ * We continue to walk the tree until we either have walked all
+ * children or we receive a non-NULL return from the callback.
+ * If a NULL callback is passed, then we just return back the first
+ * leaf vdev we encounter.
+ */
+ vdev_t *
+ vdev_walk_tree(vdev_t *vd, vdev_t *(*func)(vdev_t *, void *), void *arg)
+ {
+ if (vd->vdev_ops->vdev_op_leaf) {
+ if (func == NULL)
+ return (vd);
+ else
+ return (func(vd, arg));
+ }
+
+ for (uint_t c = 0; c < vd->vdev_children; c++) {
+ vdev_t *cvd = vd->vdev_child[c];
+ if ((cvd = vdev_walk_tree(cvd, func, arg)) != NULL)
+ return (cvd);
+ }
+ return (NULL);
+ }
+
/*
* Verify that dynamic LUN growth works as expected.
*/
ztest_record_enospc("dmu_take_snapshot");
else if (error != 0 && error != EEXIST)
fatal(0, "dmu_take_snapshot() = %d", error);
- (void) rw_unlock(&ztest_shared->zs_name_lock);
+ (void) pthread_rwlock_unlock(&ztest_shared->zs_name_lock);
}
+ /*
+ * Cleanup non-standard snapshots and clones.
+ */
+ void
+ ztest_dsl_dataset_cleanup(char *osname, uint64_t curval)
+ {
+ char snap1name[100];
+ char clone1name[100];
+ char snap2name[100];
+ char clone2name[100];
+ char snap3name[100];
+ int error;
+
+ (void) snprintf(snap1name, 100, "%s@s1_%llu", osname, curval);
+ (void) snprintf(clone1name, 100, "%s/c1_%llu", osname, curval);
+ (void) snprintf(snap2name, 100, "%s@s2_%llu", clone1name, curval);
+ (void) snprintf(clone2name, 100, "%s/c2_%llu", osname, curval);
+ (void) snprintf(snap3name, 100, "%s@s3_%llu", clone1name, curval);
+
+ error = dmu_objset_destroy(clone2name);
+ if (error && error != ENOENT)
+ fatal(0, "dmu_objset_destroy(%s) = %d", clone2name, error);
+ error = dmu_objset_destroy(snap3name);
+ if (error && error != ENOENT)
+ fatal(0, "dmu_objset_destroy(%s) = %d", snap3name, error);
+ error = dmu_objset_destroy(snap2name);
+ if (error && error != ENOENT)
+ fatal(0, "dmu_objset_destroy(%s) = %d", snap2name, error);
+ error = dmu_objset_destroy(clone1name);
+ if (error && error != ENOENT)
+ fatal(0, "dmu_objset_destroy(%s) = %d", clone1name, error);
+ error = dmu_objset_destroy(snap1name);
+ if (error && error != ENOENT)
+ fatal(0, "dmu_objset_destroy(%s) = %d", snap1name, error);
+ }
+
+ /*
+ * Verify dsl_dataset_promote handles EBUSY
+ */
+ void
+ ztest_dsl_dataset_promote_busy(ztest_args_t *za)
+ {
+ int error;
+ objset_t *os = za->za_os;
+ objset_t *clone;
+ dsl_dataset_t *ds;
+ char snap1name[100];
+ char clone1name[100];
+ char snap2name[100];
+ char clone2name[100];
+ char snap3name[100];
+ char osname[MAXNAMELEN];
+ uint64_t curval = za->za_instance;
+
+ (void) rw_rdlock(&ztest_shared->zs_name_lock);
+
+ dmu_objset_name(os, osname);
+ ztest_dsl_dataset_cleanup(osname, curval);
+
+ (void) snprintf(snap1name, 100, "%s@s1_%llu", osname, curval);
+ (void) snprintf(clone1name, 100, "%s/c1_%llu", osname, curval);
+ (void) snprintf(snap2name, 100, "%s@s2_%llu", clone1name, curval);
+ (void) snprintf(clone2name, 100, "%s/c2_%llu", osname, curval);
+ (void) snprintf(snap3name, 100, "%s@s3_%llu", clone1name, curval);
+
+ error = dmu_objset_snapshot(osname, strchr(snap1name, '@')+1,
+ NULL, FALSE);
+ if (error && error != EEXIST) {
+ if (error == ENOSPC) {
+ ztest_record_enospc("dmu_take_snapshot");
+ goto out;
+ }
+ fatal(0, "dmu_take_snapshot(%s) = %d", snap1name, error);
+ }
+
+ error = dmu_objset_open(snap1name, DMU_OST_OTHER,
+ DS_MODE_USER | DS_MODE_READONLY, &clone);
+ if (error)
+ fatal(0, "dmu_open_snapshot(%s) = %d", snap1name, error);
+
+ error = dmu_objset_create(clone1name, DMU_OST_OTHER, clone, 0,
+ NULL, NULL);
+ dmu_objset_close(clone);
+ if (error) {
+ if (error == ENOSPC) {
+ ztest_record_enospc("dmu_objset_create");
+ goto out;
+ }
+ fatal(0, "dmu_objset_create(%s) = %d", clone1name, error);
+ }
+
+ error = dmu_objset_snapshot(clone1name, strchr(snap2name, '@')+1,
+ NULL, FALSE);
+ if (error && error != EEXIST) {
+ if (error == ENOSPC) {
+ ztest_record_enospc("dmu_take_snapshot");
+ goto out;
+ }
+ fatal(0, "dmu_open_snapshot(%s) = %d", snap2name, error);
+ }
+
+ error = dmu_objset_snapshot(clone1name, strchr(snap3name, '@')+1,
+ NULL, FALSE);
+ if (error && error != EEXIST) {
+ if (error == ENOSPC) {
+ ztest_record_enospc("dmu_take_snapshot");
+ goto out;
+ }
+ fatal(0, "dmu_open_snapshot(%s) = %d", snap3name, error);
+ }
+
+ error = dmu_objset_open(snap3name, DMU_OST_OTHER,
+ DS_MODE_USER | DS_MODE_READONLY, &clone);
+ if (error)
+ fatal(0, "dmu_open_snapshot(%s) = %d", snap3name, error);
+
+ error = dmu_objset_create(clone2name, DMU_OST_OTHER, clone, 0,
+ NULL, NULL);
+ dmu_objset_close(clone);
+ if (error) {
+ if (error == ENOSPC) {
+ ztest_record_enospc("dmu_objset_create");
+ goto out;
+ }
+ fatal(0, "dmu_objset_create(%s) = %d", clone2name, error);
+ }
+
+ error = dsl_dataset_own(snap1name, DS_MODE_READONLY, FTAG, &ds);
+ if (error)
+ fatal(0, "dsl_dataset_own(%s) = %d", snap1name, error);
+ error = dsl_dataset_promote(clone2name);
+ if (error != EBUSY)
+ fatal(0, "dsl_dataset_promote(%s), %d, not EBUSY", clone2name,
+ error);
+ dsl_dataset_disown(ds, FTAG);
+
+ out:
+ ztest_dsl_dataset_cleanup(osname, curval);
+
+ (void) rw_unlock(&ztest_shared->zs_name_lock);
+ }
+
/*
* Verify that dmu_object_{alloc,free} work as expected.
*/
za->za_dbuf = NULL;
} else if (do_free) {
VERIFY(dmu_free_range(os, ZTEST_DIROBJ, off, bs, tx) == 0);
- } else {
+ } else if (abuf == NULL) {
dmu_write(os, ZTEST_DIROBJ, off, btsize, wbt, tx);
+ } else {
+ bcopy(wbt, abuf->b_data, btsize);
+ dmu_assign_arcbuf(bonus_db, off, abuf, tx);
+ dmu_buf_rele(bonus_db, FTAG);
}
- (void) mutex_unlock(lp);
+ (void) pthread_mutex_unlock(lp);
if (ztest_random(1000) == 0)
(void) poll(NULL, 0, 1); /* open dn_notxholds window */
spa_vdev_state_enter(spa);
vdev_clear(spa, NULL);
(void) spa_vdev_state_exit(spa, NULL, 0);
- zio_resume(spa);
+ (void) zio_resume(spa);
}
+ return (NULL);
}
static void *
(void) snprintf(name, 100, "%s/%s_%d", pool, pool, d);
if (zopt_verbose >= 3)
(void) printf("Destroying %s to free up space\n", name);
+
+ /* Cleanup any non-standard clones and snapshots */
+ ztest_dsl_dataset_cleanup(name, za[d].za_instance);
+
(void) dmu_objset_find(name, ztest_destroy_cb, &za[d],
DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
- (void) rw_unlock(&ztest_shared->zs_name_lock);
+ (void) pthread_rwlock_unlock(&ztest_shared->zs_name_lock);
}
txg_wait_synced(spa_get_dsl(spa), 0);