Merge commit 'refs/top-bases/linux-kernel-device' into linux-kernel-device
This commit is contained in:
commit
0576c0ce91
|
@ -1,5 +1,7 @@
|
||||||
include $(top_srcdir)/config/Rules.am
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
AM_CFLAGS += -Wframe-larger-than=1024
|
||||||
|
|
||||||
DEFAULT_INCLUDES += \
|
DEFAULT_INCLUDES += \
|
||||||
-I${top_srcdir}/lib/libspl/include \
|
-I${top_srcdir}/lib/libspl/include \
|
||||||
-I${top_srcdir}/lib/libefi/include \
|
-I${top_srcdir}/lib/libefi/include \
|
||||||
|
|
|
@ -4930,21 +4930,12 @@ ztest_resume_thread(void *arg)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
#define GRACE 300
|
||||||
ztest_deadman_thread(void *arg)
|
|
||||||
|
static void
|
||||||
|
ztest_deadman_alarm(int sig)
|
||||||
{
|
{
|
||||||
ztest_shared_t *zs = arg;
|
fatal(0, "failed to complete within %d seconds of deadline", GRACE);
|
||||||
int grace = 300;
|
|
||||||
hrtime_t delta;
|
|
||||||
|
|
||||||
delta = (zs->zs_thread_stop - zs->zs_thread_start) / NANOSEC + grace;
|
|
||||||
|
|
||||||
(void) poll(NULL, 0, (int)(1000 * delta));
|
|
||||||
|
|
||||||
fatal(0, "failed to complete within %d seconds of deadline", grace);
|
|
||||||
thread_exit();
|
|
||||||
|
|
||||||
return (NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -5134,7 +5125,7 @@ ztest_dataset_close(ztest_shared_t *zs, int d)
|
||||||
static void
|
static void
|
||||||
ztest_run(ztest_shared_t *zs)
|
ztest_run(ztest_shared_t *zs)
|
||||||
{
|
{
|
||||||
kthread_t **tid;
|
kt_did_t *tid;
|
||||||
spa_t *spa;
|
spa_t *spa;
|
||||||
kthread_t *resume_thread;
|
kthread_t *resume_thread;
|
||||||
uint64_t object;
|
uint64_t object;
|
||||||
|
@ -5187,10 +5178,10 @@ ztest_run(ztest_shared_t *zs)
|
||||||
spa, TS_RUN, NULL, 0, 0)), !=, NULL);
|
spa, TS_RUN, NULL, 0, 0)), !=, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a deadman thread to abort() if we hang.
|
* Set a deadman alarm to abort() if we hang.
|
||||||
*/
|
*/
|
||||||
VERIFY3P(thread_create(NULL, 0, ztest_deadman_thread, zs,
|
signal(SIGALRM, ztest_deadman_alarm);
|
||||||
TS_RUN, NULL, 0, 0), !=, NULL);
|
alarm((zs->zs_thread_stop - zs->zs_thread_start) / NANOSEC + GRACE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verify that we can safely inquire about about any object,
|
* Verify that we can safely inquire about about any object,
|
||||||
|
@ -5216,7 +5207,7 @@ ztest_run(ztest_shared_t *zs)
|
||||||
}
|
}
|
||||||
zs->zs_enospc_count = 0;
|
zs->zs_enospc_count = 0;
|
||||||
|
|
||||||
tid = umem_zalloc(zopt_threads * sizeof (kthread_t *), UMEM_NOFAIL);
|
tid = umem_zalloc(zopt_threads * sizeof (kt_did_t), UMEM_NOFAIL);
|
||||||
|
|
||||||
if (zopt_verbose >= 4)
|
if (zopt_verbose >= 4)
|
||||||
(void) printf("starting main threads...\n");
|
(void) printf("starting main threads...\n");
|
||||||
|
@ -5225,11 +5216,14 @@ ztest_run(ztest_shared_t *zs)
|
||||||
* Kick off all the tests that run in parallel.
|
* Kick off all the tests that run in parallel.
|
||||||
*/
|
*/
|
||||||
for (t = 0; t < zopt_threads; t++) {
|
for (t = 0; t < zopt_threads; t++) {
|
||||||
|
kthread_t *thread;
|
||||||
|
|
||||||
if (t < zopt_datasets && ztest_dataset_open(zs, t) != 0)
|
if (t < zopt_datasets && ztest_dataset_open(zs, t) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VERIFY3P(tid[t] = thread_create(NULL, 0, ztest_thread,
|
VERIFY3P(thread = thread_create(NULL, 0, ztest_thread,
|
||||||
(void *)(uintptr_t)t, TS_RUN, NULL, 0, 0), !=, NULL);
|
(void *)(uintptr_t)t, TS_RUN, NULL, 0, 0), !=, NULL);
|
||||||
|
tid[t] = thread->t_tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5237,7 +5231,7 @@ ztest_run(ztest_shared_t *zs)
|
||||||
* so we don't close datasets while threads are still using them.
|
* so we don't close datasets while threads are still using them.
|
||||||
*/
|
*/
|
||||||
for (t = zopt_threads - 1; t >= 0; t--) {
|
for (t = zopt_threads - 1; t >= 0; t--) {
|
||||||
thread_join(tid[t]->t_tid);
|
thread_join(tid[t]);
|
||||||
if (t < zopt_datasets)
|
if (t < zopt_datasets)
|
||||||
ztest_dataset_close(zs, t);
|
ztest_dataset_close(zs, t);
|
||||||
}
|
}
|
||||||
|
@ -5247,7 +5241,7 @@ ztest_run(ztest_shared_t *zs)
|
||||||
zs->zs_alloc = metaslab_class_get_alloc(spa_normal_class(spa));
|
zs->zs_alloc = metaslab_class_get_alloc(spa_normal_class(spa));
|
||||||
zs->zs_space = metaslab_class_get_space(spa_normal_class(spa));
|
zs->zs_space = metaslab_class_get_space(spa_normal_class(spa));
|
||||||
|
|
||||||
umem_free(tid, zopt_threads * sizeof (kthread_t *));
|
umem_free(tid, zopt_threads * sizeof (kt_did_t));
|
||||||
|
|
||||||
/* Kill the resume thread */
|
/* Kill the resume thread */
|
||||||
ztest_exiting = B_TRUE;
|
ztest_exiting = B_TRUE;
|
||||||
|
|
|
@ -24,7 +24,7 @@ if test "$zfs_ac_debug" = yes; then
|
||||||
[Define to 1 to enable debug tracing])
|
[Define to 1 to enable debug tracing])
|
||||||
KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG "
|
KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG "
|
||||||
HOSTCFLAGS="${HOSTCFLAGS} -DDEBUG "
|
HOSTCFLAGS="${HOSTCFLAGS} -DDEBUG "
|
||||||
USERDEBUG="-DDEBUG"
|
USERDEBUG="-DDEBUG -fstack-check"
|
||||||
else
|
else
|
||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
AC_DEFINE([NDEBUG], [1],
|
AC_DEFINE([NDEBUG], [1],
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
include $(top_srcdir)/config/Rules.am
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
AM_CFLAGS += -Wframe-larger-than=1024
|
||||||
|
|
||||||
SUBDIRS = include
|
SUBDIRS = include
|
||||||
DEFAULT_INCLUDES += \
|
DEFAULT_INCLUDES += \
|
||||||
-I${top_srcdir}/lib/libzpool/include \
|
-I${top_srcdir}/lib/libzpool/include \
|
||||||
|
|
|
@ -203,6 +203,7 @@ _NOTE(CONSTCOND) } while (0)
|
||||||
/*
|
/*
|
||||||
* Threads
|
* Threads
|
||||||
*/
|
*/
|
||||||
|
#define TS_MAGIC 0x72f158ab4261e538ull
|
||||||
#define TS_RUN 0x00000002
|
#define TS_RUN 0x00000002
|
||||||
#ifdef _linux_
|
#ifdef _linux_
|
||||||
#define STACK_SIZE 8192 /* Linux x86 and amd64 */
|
#define STACK_SIZE 8192 /* Linux x86 and amd64 */
|
||||||
|
@ -227,7 +228,6 @@ typedef struct kthread {
|
||||||
void * t_arg;
|
void * t_arg;
|
||||||
} kthread_t;
|
} kthread_t;
|
||||||
|
|
||||||
/* XXX tsd_create()/tsd_destroy() missing */
|
|
||||||
#define tsd_get(key) pthread_getspecific(key)
|
#define tsd_get(key) pthread_getspecific(key)
|
||||||
#define tsd_set(key, val) pthread_setspecific(key, val)
|
#define tsd_set(key, val) pthread_setspecific(key, val)
|
||||||
#define curthread zk_thread_current()
|
#define curthread zk_thread_current()
|
||||||
|
|
|
@ -191,13 +191,16 @@ zk_thread_exit(void)
|
||||||
pthread_mutex_unlock(&kthread_lock);
|
pthread_mutex_unlock(&kthread_lock);
|
||||||
|
|
||||||
pthread_cond_broadcast(&kthread_cond);
|
pthread_cond_broadcast(&kthread_cond);
|
||||||
pthread_exit(NULL);
|
pthread_exit((void *)TS_MAGIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
zk_thread_join(kt_did_t tid)
|
zk_thread_join(kt_did_t tid)
|
||||||
{
|
{
|
||||||
pthread_join((pthread_t)tid, NULL);
|
void *ret;
|
||||||
|
|
||||||
|
pthread_join((pthread_t)tid, &ret);
|
||||||
|
VERIFY3P(ret, ==, (void *)TS_MAGIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -507,10 +510,12 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
|
||||||
int fd;
|
int fd;
|
||||||
vnode_t *vp;
|
vnode_t *vp;
|
||||||
int old_umask;
|
int old_umask;
|
||||||
char realpath[MAXPATHLEN];
|
char *realpath;
|
||||||
struct stat64 st;
|
struct stat64 st;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
realpath = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're accessing a real disk from userland, we need to use
|
* If we're accessing a real disk from userland, we need to use
|
||||||
* the character interface to avoid caching. This is particularly
|
* the character interface to avoid caching. This is particularly
|
||||||
|
@ -524,11 +529,16 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
|
||||||
if (strncmp(path, "/dev/", 5) == 0) {
|
if (strncmp(path, "/dev/", 5) == 0) {
|
||||||
char *dsk;
|
char *dsk;
|
||||||
fd = open64(path, O_RDONLY);
|
fd = open64(path, O_RDONLY);
|
||||||
if (fd == -1)
|
if (fd == -1) {
|
||||||
return (errno);
|
err = errno;
|
||||||
|
free(realpath);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
if (fstat64(fd, &st) == -1) {
|
if (fstat64(fd, &st) == -1) {
|
||||||
|
err = errno;
|
||||||
close(fd);
|
close(fd);
|
||||||
return (errno);
|
free(realpath);
|
||||||
|
return (err);
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
(void) sprintf(realpath, "%s", path);
|
(void) sprintf(realpath, "%s", path);
|
||||||
|
@ -538,8 +548,11 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
|
||||||
dsk + 1);
|
dsk + 1);
|
||||||
} else {
|
} else {
|
||||||
(void) sprintf(realpath, "%s", path);
|
(void) sprintf(realpath, "%s", path);
|
||||||
if (!(flags & FCREAT) && stat64(realpath, &st) == -1)
|
if (!(flags & FCREAT) && stat64(realpath, &st) == -1) {
|
||||||
return (errno);
|
err = errno;
|
||||||
|
free(realpath);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & FCREAT)
|
if (flags & FCREAT)
|
||||||
|
@ -550,6 +563,7 @@ vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
|
||||||
* FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR.
|
* FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR.
|
||||||
*/
|
*/
|
||||||
fd = open64(realpath, flags - FREAD, mode);
|
fd = open64(realpath, flags - FREAD, mode);
|
||||||
|
free(realpath);
|
||||||
|
|
||||||
if (flags & FCREAT)
|
if (flags & FCREAT)
|
||||||
(void) umask(old_umask);
|
(void) umask(old_umask);
|
||||||
|
|
|
@ -356,46 +356,54 @@ static int
|
||||||
traverse_impl(spa_t *spa, uint64_t objset, blkptr_t *rootbp,
|
traverse_impl(spa_t *spa, uint64_t objset, blkptr_t *rootbp,
|
||||||
uint64_t txg_start, int flags, blkptr_cb_t func, void *arg)
|
uint64_t txg_start, int flags, blkptr_cb_t func, void *arg)
|
||||||
{
|
{
|
||||||
struct traverse_data td;
|
struct traverse_data *td;
|
||||||
struct prefetch_data pd;
|
struct prefetch_data *pd;
|
||||||
zbookmark_t czb;
|
zbookmark_t *czb;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
td.td_spa = spa;
|
td = kmem_alloc(sizeof(struct traverse_data), KM_SLEEP);
|
||||||
td.td_objset = objset;
|
pd = kmem_alloc(sizeof(struct prefetch_data), KM_SLEEP);
|
||||||
td.td_rootbp = rootbp;
|
czb = kmem_alloc(sizeof(zbookmark_t), KM_SLEEP);
|
||||||
td.td_min_txg = txg_start;
|
|
||||||
td.td_func = func;
|
|
||||||
td.td_arg = arg;
|
|
||||||
td.td_pfd = &pd;
|
|
||||||
td.td_flags = flags;
|
|
||||||
|
|
||||||
pd.pd_blks_max = 100;
|
td->td_spa = spa;
|
||||||
pd.pd_blks_fetched = 0;
|
td->td_objset = objset;
|
||||||
pd.pd_flags = flags;
|
td->td_rootbp = rootbp;
|
||||||
pd.pd_cancel = B_FALSE;
|
td->td_min_txg = txg_start;
|
||||||
pd.pd_exited = B_FALSE;
|
td->td_func = func;
|
||||||
mutex_init(&pd.pd_mtx, NULL, MUTEX_DEFAULT, NULL);
|
td->td_arg = arg;
|
||||||
cv_init(&pd.pd_cv, NULL, CV_DEFAULT, NULL);
|
td->td_pfd = pd;
|
||||||
|
td->td_flags = flags;
|
||||||
|
|
||||||
|
pd->pd_blks_max = 100;
|
||||||
|
pd->pd_blks_fetched = 0;
|
||||||
|
pd->pd_flags = flags;
|
||||||
|
pd->pd_cancel = B_FALSE;
|
||||||
|
pd->pd_exited = B_FALSE;
|
||||||
|
mutex_init(&pd->pd_mtx, NULL, MUTEX_DEFAULT, NULL);
|
||||||
|
cv_init(&pd->pd_cv, NULL, CV_DEFAULT, NULL);
|
||||||
|
|
||||||
if (!(flags & TRAVERSE_PREFETCH) ||
|
if (!(flags & TRAVERSE_PREFETCH) ||
|
||||||
0 == taskq_dispatch(system_taskq, traverse_prefetch_thread,
|
0 == taskq_dispatch(system_taskq, traverse_prefetch_thread,
|
||||||
&td, TQ_NOQUEUE))
|
td, TQ_NOQUEUE))
|
||||||
pd.pd_exited = B_TRUE;
|
pd->pd_exited = B_TRUE;
|
||||||
|
|
||||||
SET_BOOKMARK(&czb, objset,
|
SET_BOOKMARK(czb, objset,
|
||||||
ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
|
ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
|
||||||
err = traverse_visitbp(&td, NULL, NULL, rootbp, &czb);
|
err = traverse_visitbp(td, NULL, NULL, rootbp, czb);
|
||||||
|
|
||||||
mutex_enter(&pd.pd_mtx);
|
mutex_enter(&pd->pd_mtx);
|
||||||
pd.pd_cancel = B_TRUE;
|
pd->pd_cancel = B_TRUE;
|
||||||
cv_broadcast(&pd.pd_cv);
|
cv_broadcast(&pd->pd_cv);
|
||||||
while (!pd.pd_exited)
|
while (!pd->pd_exited)
|
||||||
cv_wait(&pd.pd_cv, &pd.pd_mtx);
|
cv_wait(&pd->pd_cv, &pd->pd_mtx);
|
||||||
mutex_exit(&pd.pd_mtx);
|
mutex_exit(&pd->pd_mtx);
|
||||||
|
|
||||||
mutex_destroy(&pd.pd_mtx);
|
mutex_destroy(&pd->pd_mtx);
|
||||||
cv_destroy(&pd.pd_cv);
|
cv_destroy(&pd->pd_cv);
|
||||||
|
|
||||||
|
kmem_free(czb, sizeof(zbookmark_t));
|
||||||
|
kmem_free(pd, sizeof(struct prefetch_data));
|
||||||
|
kmem_free(td, sizeof(struct traverse_data));
|
||||||
|
|
||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1038,7 +1038,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||||
dsl_dir_t *dd;
|
dsl_dir_t *dd;
|
||||||
uint64_t obj;
|
uint64_t obj;
|
||||||
struct dsl_ds_destroyarg dsda = { 0 };
|
struct dsl_ds_destroyarg dsda = { 0 };
|
||||||
dsl_dataset_t dummy_ds = { 0 };
|
dsl_dataset_t *dummy_ds;
|
||||||
|
|
||||||
dsda.ds = ds;
|
dsda.ds = ds;
|
||||||
|
|
||||||
|
@ -1058,8 +1058,9 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||||
}
|
}
|
||||||
|
|
||||||
dd = ds->ds_dir;
|
dd = ds->ds_dir;
|
||||||
dummy_ds.ds_dir = dd;
|
dummy_ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP);
|
||||||
dummy_ds.ds_object = ds->ds_object;
|
dummy_ds->ds_dir = dd;
|
||||||
|
dummy_ds->ds_object = ds->ds_object;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for errors and mark this ds as inconsistent, in
|
* Check for errors and mark this ds as inconsistent, in
|
||||||
|
@ -1068,11 +1069,11 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||||
err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check,
|
err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check,
|
||||||
dsl_dataset_destroy_begin_sync, ds, NULL, 0);
|
dsl_dataset_destroy_begin_sync, ds, NULL, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out_free;
|
||||||
|
|
||||||
err = dmu_objset_from_ds(ds, &os);
|
err = dmu_objset_from_ds(ds, &os);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out_free;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remove the objects in open context, so that we won't
|
* remove the objects in open context, so that we won't
|
||||||
|
@ -1108,14 +1109,14 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != ESRCH)
|
if (err != ESRCH)
|
||||||
goto out;
|
goto out_free;
|
||||||
|
|
||||||
rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
|
rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER);
|
||||||
err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd);
|
err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd);
|
||||||
rw_exit(&dd->dd_pool->dp_config_rwlock);
|
rw_exit(&dd->dd_pool->dp_config_rwlock);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out_free;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Blow away the dsl_dir + head dataset.
|
* Blow away the dsl_dir + head dataset.
|
||||||
|
@ -1131,7 +1132,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||||
err = dsl_dataset_origin_rm_prep(&dsda, tag);
|
err = dsl_dataset_origin_rm_prep(&dsda, tag);
|
||||||
if (err) {
|
if (err) {
|
||||||
dsl_dir_close(dd, FTAG);
|
dsl_dir_close(dd, FTAG);
|
||||||
goto out;
|
goto out_free;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1139,7 +1140,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||||
dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
|
dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
|
||||||
dsl_dataset_destroy_sync, &dsda, tag, 0);
|
dsl_dataset_destroy_sync, &dsda, tag, 0);
|
||||||
dsl_sync_task_create(dstg, dsl_dir_destroy_check,
|
dsl_sync_task_create(dstg, dsl_dir_destroy_check,
|
||||||
dsl_dir_destroy_sync, &dummy_ds, FTAG, 0);
|
dsl_dir_destroy_sync, dummy_ds, FTAG, 0);
|
||||||
err = dsl_sync_task_group_wait(dstg);
|
err = dsl_sync_task_group_wait(dstg);
|
||||||
dsl_sync_task_group_destroy(dstg);
|
dsl_sync_task_group_destroy(dstg);
|
||||||
|
|
||||||
|
@ -1162,6 +1163,9 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||||
/* if it is successful, dsl_dir_destroy_sync will close the dd */
|
/* if it is successful, dsl_dir_destroy_sync will close the dd */
|
||||||
if (err)
|
if (err)
|
||||||
dsl_dir_close(dd, FTAG);
|
dsl_dir_close(dd, FTAG);
|
||||||
|
|
||||||
|
out_free:
|
||||||
|
kmem_free(dummy_ds, sizeof (dsl_dataset_t));
|
||||||
out:
|
out:
|
||||||
dsl_dataset_disown(ds, tag);
|
dsl_dataset_disown(ds, tag);
|
||||||
return (err);
|
return (err);
|
||||||
|
|
Loading…
Reference in New Issue