mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
2882 implement libzfs_core 2883 changing "canmount" property to "on" should not always remount dataset 2900 "zfs snapshot" should be able to create multiple, arbitrary snapshots at once Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Chris Siden <christopher.siden@delphix.com> Reviewed by: Garrett D'Amore <garrett@damore.org> Reviewed by: Bill Pijewski <wdp@joyent.com> Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com> Approved by: Eric Schrock <Eric.Schrock@delphix.com> References: https://www.illumos.org/issues/2882 https://www.illumos.org/issues/2883 https://www.illumos.org/issues/2900 illumos/illumos-gate@4445fffbbb Ported-by: Tim Chase <tim@chase2k.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #1293 Porting notes: WARNING: This patch changes the user/kernel ABI. That means that the zfs/zpool utilities built from master are NOT compatible with the 0.6.2 kernel modules. Ensure you load the matching kernel modules from master after updating the utilities. Otherwise the zfs/zpool commands will be unable to interact with your pool and you will see errors similar to the following: $ zpool list failed to read pool configuration: bad address no pools available $ zfs list no datasets available Add zvol minor device creation to the new zfs_snapshot_nvl function. Remove the logging of the "release" operation in dsl_dataset_user_release_sync(). The logging caused a null dereference because ds->ds_dir is zeroed in dsl_dataset_destroy_sync() and the logging functions try to get the ds name via the dsl_dataset_name() function. I've got no idea why this particular code would have worked in Illumos. This code has subsequently been completely reworked in Illumos commit 3b2aab1 (3464 zfs synctask code needs restructuring). Squash some "may be used uninitialized" warning/erorrs. Fix some printf format warnings for %lld and %llu. Apply a few spa_writeable() changes that were made to Illumos in illumos/illumos-gate.git@cd1c8b8 as part of the 3112, 3113, 3114 and 3115 fixes. Add a missing call to fnvlist_free(nvl) in log_internal() that was added in Illumos to fix issue 3085 but couldn't be ported to ZoL at the time (zfsonlinux/zfs@9e11c73) because it depended on future work.
This commit is contained in:
committed by
Brian Behlendorf
parent
0c28fb4808
commit
6f1ffb0665
@@ -501,6 +501,7 @@ EXPORT_SYMBOL(fnvlist_alloc);
|
||||
EXPORT_SYMBOL(fnvlist_free);
|
||||
EXPORT_SYMBOL(fnvlist_size);
|
||||
EXPORT_SYMBOL(fnvlist_pack);
|
||||
EXPORT_SYMBOL(fnvlist_pack_free);
|
||||
EXPORT_SYMBOL(fnvlist_unpack);
|
||||
EXPORT_SYMBOL(fnvlist_dup);
|
||||
EXPORT_SYMBOL(fnvlist_merge);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -157,7 +158,11 @@ zfs_spa_version_map(int zpl_version)
|
||||
return (version);
|
||||
}
|
||||
|
||||
const char *zfs_history_event_names[LOG_END] = {
|
||||
/*
|
||||
* This is the table of legacy internal event names; it should not be modified.
|
||||
* The internal events are now stored in the history log as strings.
|
||||
*/
|
||||
const char *zfs_history_event_names[ZFS_NUM_LEGACY_HISTORY_EVENTS] = {
|
||||
"invalid event",
|
||||
"pool create",
|
||||
"vdev add",
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common routines used by zfs and zpool property management.
|
||||
@@ -129,7 +132,8 @@ zprop_register_hidden(int prop, const char *name, zprop_type_t type,
|
||||
zprop_attr_t attr, int objset_types, const char *colname)
|
||||
{
|
||||
zprop_register_impl(prop, name, type, 0, NULL, attr,
|
||||
objset_types, NULL, colname, B_FALSE, B_FALSE, NULL);
|
||||
objset_types, NULL, colname,
|
||||
type == PROP_TYPE_NUMBER, B_FALSE, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+188
-128
@@ -21,6 +21,7 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/* Portions Copyright 2010 Robert Milkowski */
|
||||
@@ -525,9 +526,10 @@ dmu_objset_evict_dbufs(objset_t *os)
|
||||
void
|
||||
dmu_objset_evict(objset_t *os)
|
||||
{
|
||||
dsl_dataset_t *ds = os->os_dsl_dataset;
|
||||
int t;
|
||||
|
||||
dsl_dataset_t *ds = os->os_dsl_dataset;
|
||||
|
||||
for (t = 0; t < TXG_SIZE; t++)
|
||||
ASSERT(!dmu_objset_is_dirty(os, t));
|
||||
|
||||
@@ -698,30 +700,33 @@ dmu_objset_create_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
spa_t *spa = dd->dd_pool->dp_spa;
|
||||
struct oscarg *oa = arg2;
|
||||
uint64_t obj;
|
||||
dsl_dataset_t *ds;
|
||||
blkptr_t *bp;
|
||||
|
||||
ASSERT(dmu_tx_is_syncing(tx));
|
||||
|
||||
obj = dsl_dataset_create_sync(dd, oa->lastname,
|
||||
oa->clone_origin, oa->flags, oa->cr, tx);
|
||||
|
||||
if (oa->clone_origin == NULL) {
|
||||
dsl_pool_t *dp = dd->dd_pool;
|
||||
dsl_dataset_t *ds;
|
||||
blkptr_t *bp;
|
||||
objset_t *os;
|
||||
|
||||
VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, obj, FTAG, &ds));
|
||||
bp = dsl_dataset_get_blkptr(ds);
|
||||
ASSERT(BP_IS_HOLE(bp));
|
||||
|
||||
os = dmu_objset_create_impl(spa, ds, bp, oa->type, tx);
|
||||
VERIFY3U(0, ==, dsl_dataset_hold_obj(dd->dd_pool, obj, FTAG, &ds));
|
||||
bp = dsl_dataset_get_blkptr(ds);
|
||||
if (BP_IS_HOLE(bp)) {
|
||||
objset_t *os =
|
||||
dmu_objset_create_impl(spa, ds, bp, oa->type, tx);
|
||||
|
||||
if (oa->userfunc)
|
||||
oa->userfunc(os, oa->userarg, oa->cr, tx);
|
||||
dsl_dataset_rele(ds, FTAG);
|
||||
}
|
||||
|
||||
spa_history_log_internal(LOG_DS_CREATE, spa, tx, "dataset = %llu", obj);
|
||||
if (oa->clone_origin == NULL) {
|
||||
spa_history_log_internal_ds(ds, "create", tx, "");
|
||||
} else {
|
||||
char namebuf[MAXNAMELEN];
|
||||
dsl_dataset_name(oa->clone_origin, namebuf);
|
||||
spa_history_log_internal_ds(ds, "clone", tx,
|
||||
"origin=%s (%llu)", namebuf, oa->clone_origin->ds_object);
|
||||
}
|
||||
dsl_dataset_rele(ds, FTAG);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -798,34 +803,40 @@ dmu_objset_destroy(const char *name, boolean_t defer)
|
||||
return (error);
|
||||
}
|
||||
|
||||
struct snaparg {
|
||||
dsl_sync_task_group_t *dstg;
|
||||
char *snapname;
|
||||
char *htag;
|
||||
char failed[MAXPATHLEN];
|
||||
boolean_t recursive;
|
||||
boolean_t needsuspend;
|
||||
boolean_t temporary;
|
||||
nvlist_t *props;
|
||||
struct dsl_ds_holdarg *ha; /* only needed in the temporary case */
|
||||
dsl_dataset_t *newds;
|
||||
};
|
||||
typedef struct snapallarg {
|
||||
dsl_sync_task_group_t *saa_dstg;
|
||||
boolean_t saa_needsuspend;
|
||||
nvlist_t *saa_props;
|
||||
|
||||
/* the following are used only if 'temporary' is set: */
|
||||
boolean_t saa_temporary;
|
||||
const char *saa_htag;
|
||||
struct dsl_ds_holdarg *saa_ha;
|
||||
dsl_dataset_t *saa_newds;
|
||||
} snapallarg_t;
|
||||
|
||||
typedef struct snaponearg {
|
||||
const char *soa_longname; /* long snap name */
|
||||
const char *soa_snapname; /* short snap name */
|
||||
snapallarg_t *soa_saa;
|
||||
} snaponearg_t;
|
||||
|
||||
static int
|
||||
snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
{
|
||||
objset_t *os = arg1;
|
||||
struct snaparg *sn = arg2;
|
||||
snaponearg_t *soa = arg2;
|
||||
snapallarg_t *saa = soa->soa_saa;
|
||||
int error;
|
||||
|
||||
/* The props have already been checked by zfs_check_userprops(). */
|
||||
|
||||
error = dsl_dataset_snapshot_check(os->os_dsl_dataset,
|
||||
sn->snapname, tx);
|
||||
soa->soa_snapname, tx);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
if (sn->temporary) {
|
||||
if (saa->saa_temporary) {
|
||||
/*
|
||||
* Ideally we would just call
|
||||
* dsl_dataset_user_hold_check() and
|
||||
@@ -843,12 +854,13 @@ snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
* Not checking number of tags because the tag will be
|
||||
* unique, as it will be the only tag.
|
||||
*/
|
||||
if (strlen(sn->htag) + MAX_TAG_PREFIX_LEN >= MAXNAMELEN)
|
||||
if (strlen(saa->saa_htag) + MAX_TAG_PREFIX_LEN >= MAXNAMELEN)
|
||||
return (E2BIG);
|
||||
|
||||
sn->ha = kmem_alloc(sizeof(struct dsl_ds_holdarg), KM_PUSHPAGE);
|
||||
sn->ha->temphold = B_TRUE;
|
||||
sn->ha->htag = sn->htag;
|
||||
saa->saa_ha = kmem_alloc(sizeof (struct dsl_ds_holdarg),
|
||||
KM_PUSHPAGE);
|
||||
saa->saa_ha->temphold = B_TRUE;
|
||||
saa->saa_ha->htag = saa->saa_htag;
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
@@ -858,24 +870,25 @@ snapshot_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
{
|
||||
objset_t *os = arg1;
|
||||
dsl_dataset_t *ds = os->os_dsl_dataset;
|
||||
struct snaparg *sn = arg2;
|
||||
snaponearg_t *soa = arg2;
|
||||
snapallarg_t *saa = soa->soa_saa;
|
||||
|
||||
dsl_dataset_snapshot_sync(ds, sn->snapname, tx);
|
||||
dsl_dataset_snapshot_sync(ds, soa->soa_snapname, tx);
|
||||
|
||||
if (sn->props) {
|
||||
if (saa->saa_props != NULL) {
|
||||
dsl_props_arg_t pa;
|
||||
pa.pa_props = sn->props;
|
||||
pa.pa_props = saa->saa_props;
|
||||
pa.pa_source = ZPROP_SRC_LOCAL;
|
||||
dsl_props_set_sync(ds->ds_prev, &pa, tx);
|
||||
}
|
||||
|
||||
if (sn->temporary) {
|
||||
if (saa->saa_temporary) {
|
||||
struct dsl_ds_destroyarg da;
|
||||
|
||||
dsl_dataset_user_hold_sync(ds->ds_prev, sn->ha, tx);
|
||||
kmem_free(sn->ha, sizeof (struct dsl_ds_holdarg));
|
||||
sn->ha = NULL;
|
||||
sn->newds = ds->ds_prev;
|
||||
dsl_dataset_user_hold_sync(ds->ds_prev, saa->saa_ha, tx);
|
||||
kmem_free(saa->saa_ha, sizeof (struct dsl_ds_holdarg));
|
||||
saa->saa_ha = NULL;
|
||||
saa->saa_newds = ds->ds_prev;
|
||||
|
||||
da.ds = ds->ds_prev;
|
||||
da.defer = B_TRUE;
|
||||
@@ -884,135 +897,182 @@ snapshot_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
}
|
||||
|
||||
static int
|
||||
dmu_objset_snapshot_one(const char *name, void *arg)
|
||||
snapshot_one_impl(const char *snapname, void *arg)
|
||||
{
|
||||
struct snaparg *sn = arg;
|
||||
char *fsname;
|
||||
snapallarg_t *saa = arg;
|
||||
snaponearg_t *soa;
|
||||
objset_t *os;
|
||||
int err;
|
||||
char *cp;
|
||||
|
||||
/*
|
||||
* If the objset starts with a '%', then ignore it unless it was
|
||||
* explicitly named (ie, not recursive). These hidden datasets
|
||||
* are always inconsistent, and by not opening them here, we can
|
||||
* avoid a race with dsl_dir_destroy_check().
|
||||
*/
|
||||
cp = strrchr(name, '/');
|
||||
if (cp && cp[1] == '%' && sn->recursive)
|
||||
return (0);
|
||||
fsname = kmem_zalloc(MAXPATHLEN, KM_PUSHPAGE);
|
||||
(void) strlcpy(fsname, snapname, MAXPATHLEN);
|
||||
strchr(fsname, '@')[0] = '\0';
|
||||
|
||||
(void) strcpy(sn->failed, name);
|
||||
|
||||
/*
|
||||
* Check permissions if we are doing a recursive snapshot. The
|
||||
* permission checks for the starting dataset have already been
|
||||
* performed in zfs_secpolicy_snapshot()
|
||||
*/
|
||||
if (sn->recursive && (err = zfs_secpolicy_snapshot_perms(name, CRED())))
|
||||
return (err);
|
||||
|
||||
err = dmu_objset_hold(name, sn, &os);
|
||||
err = dmu_objset_hold(fsname, saa, &os);
|
||||
kmem_free(fsname, MAXPATHLEN);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
/*
|
||||
* If the objset is in an inconsistent state (eg, in the process
|
||||
* of being destroyed), don't snapshot it. As with %hidden
|
||||
* datasets, we return EBUSY if this name was explicitly
|
||||
* requested (ie, not recursive), and otherwise ignore it.
|
||||
* of being destroyed), don't snapshot it.
|
||||
*/
|
||||
if (os->os_dsl_dataset->ds_phys->ds_flags & DS_FLAG_INCONSISTENT) {
|
||||
dmu_objset_rele(os, sn);
|
||||
return (sn->recursive ? 0 : EBUSY);
|
||||
dmu_objset_rele(os, saa);
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
if (sn->needsuspend) {
|
||||
if (saa->saa_needsuspend) {
|
||||
err = zil_suspend(dmu_objset_zil(os));
|
||||
if (err) {
|
||||
dmu_objset_rele(os, sn);
|
||||
dmu_objset_rele(os, saa);
|
||||
return (err);
|
||||
}
|
||||
}
|
||||
dsl_sync_task_create(sn->dstg, snapshot_check, snapshot_sync,
|
||||
os, sn, 3);
|
||||
|
||||
soa = kmem_zalloc(sizeof (*soa), KM_PUSHPAGE);
|
||||
soa->soa_saa = saa;
|
||||
soa->soa_longname = snapname;
|
||||
soa->soa_snapname = strchr(snapname, '@') + 1;
|
||||
|
||||
dsl_sync_task_create(saa->saa_dstg, snapshot_check, snapshot_sync,
|
||||
os, soa, 3);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The snapshots must all be in the same pool.
|
||||
*/
|
||||
int
|
||||
dmu_objset_snapshot(char *fsname, char *snapname, char *tag,
|
||||
nvlist_t *props, boolean_t recursive, boolean_t temporary, int cleanup_fd)
|
||||
dmu_objset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
|
||||
{
|
||||
dsl_sync_task_t *dst;
|
||||
struct snaparg *sn;
|
||||
snapallarg_t saa = { 0 };
|
||||
spa_t *spa;
|
||||
int rv = 0;
|
||||
int err;
|
||||
nvpair_t *pair;
|
||||
|
||||
pair = nvlist_next_nvpair(snaps, NULL);
|
||||
if (pair == NULL)
|
||||
return (0);
|
||||
|
||||
err = spa_open(nvpair_name(pair), &spa, FTAG);
|
||||
if (err)
|
||||
return (err);
|
||||
saa.saa_dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
|
||||
saa.saa_props = props;
|
||||
saa.saa_needsuspend = (spa_version(spa) < SPA_VERSION_FAST_SNAP);
|
||||
|
||||
for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
|
||||
pair = nvlist_next_nvpair(snaps, pair)) {
|
||||
err = snapshot_one_impl(nvpair_name(pair), &saa);
|
||||
if (err != 0) {
|
||||
if (errors != NULL) {
|
||||
fnvlist_add_int32(errors,
|
||||
nvpair_name(pair), err);
|
||||
}
|
||||
rv = err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If any call to snapshot_one_impl() failed, don't execute the
|
||||
* sync task. The error handling code below will clean up the
|
||||
* snaponearg_t from any successful calls to
|
||||
* snapshot_one_impl().
|
||||
*/
|
||||
if (rv == 0)
|
||||
err = dsl_sync_task_group_wait(saa.saa_dstg);
|
||||
if (err != 0)
|
||||
rv = err;
|
||||
|
||||
for (dst = list_head(&saa.saa_dstg->dstg_tasks); dst;
|
||||
dst = list_next(&saa.saa_dstg->dstg_tasks, dst)) {
|
||||
objset_t *os = dst->dst_arg1;
|
||||
snaponearg_t *soa = dst->dst_arg2;
|
||||
if (dst->dst_err != 0) {
|
||||
if (errors != NULL) {
|
||||
fnvlist_add_int32(errors,
|
||||
soa->soa_longname, dst->dst_err);
|
||||
}
|
||||
rv = dst->dst_err;
|
||||
}
|
||||
|
||||
if (saa.saa_needsuspend)
|
||||
zil_resume(dmu_objset_zil(os));
|
||||
dmu_objset_rele(os, &saa);
|
||||
kmem_free(soa, sizeof (*soa));
|
||||
}
|
||||
|
||||
dsl_sync_task_group_destroy(saa.saa_dstg);
|
||||
spa_close(spa, FTAG);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
int
|
||||
dmu_objset_snapshot_one(const char *fsname, const char *snapname)
|
||||
{
|
||||
int err;
|
||||
char *longsnap = kmem_asprintf("%s@%s", fsname, snapname);
|
||||
nvlist_t *snaps = fnvlist_alloc();
|
||||
|
||||
fnvlist_add_boolean(snaps, longsnap);
|
||||
err = dmu_objset_snapshot(snaps, NULL, NULL);
|
||||
fnvlist_free(snaps);
|
||||
strfree(longsnap);
|
||||
return (err);
|
||||
}
|
||||
|
||||
int
|
||||
dmu_objset_snapshot_tmp(const char *snapname, const char *tag, int cleanup_fd)
|
||||
{
|
||||
dsl_sync_task_t *dst;
|
||||
snapallarg_t saa = { 0 };
|
||||
spa_t *spa;
|
||||
minor_t minor;
|
||||
int err;
|
||||
|
||||
sn = kmem_alloc(sizeof (struct snaparg), KM_SLEEP);
|
||||
(void) strcpy(sn->failed, fsname);
|
||||
err = spa_open(snapname, &spa, FTAG);
|
||||
if (err)
|
||||
return (err);
|
||||
saa.saa_dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
|
||||
saa.saa_htag = tag;
|
||||
saa.saa_needsuspend = (spa_version(spa) < SPA_VERSION_FAST_SNAP);
|
||||
saa.saa_temporary = B_TRUE;
|
||||
|
||||
err = spa_open(fsname, &spa, FTAG);
|
||||
if (err) {
|
||||
kmem_free(sn, sizeof (struct snaparg));
|
||||
if (cleanup_fd < 0) {
|
||||
spa_close(spa, FTAG);
|
||||
return (EINVAL);
|
||||
}
|
||||
if ((err = zfs_onexit_fd_hold(cleanup_fd, &minor)) != 0) {
|
||||
spa_close(spa, FTAG);
|
||||
return (err);
|
||||
}
|
||||
|
||||
if (temporary) {
|
||||
if (cleanup_fd < 0) {
|
||||
spa_close(spa, FTAG);
|
||||
return (EINVAL);
|
||||
}
|
||||
if ((err = zfs_onexit_fd_hold(cleanup_fd, &minor)) != 0) {
|
||||
spa_close(spa, FTAG);
|
||||
return (err);
|
||||
}
|
||||
}
|
||||
|
||||
sn->dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
|
||||
sn->snapname = snapname;
|
||||
sn->htag = tag;
|
||||
sn->props = props;
|
||||
sn->recursive = recursive;
|
||||
sn->needsuspend = (spa_version(spa) < SPA_VERSION_FAST_SNAP);
|
||||
sn->temporary = temporary;
|
||||
sn->ha = NULL;
|
||||
sn->newds = NULL;
|
||||
|
||||
if (recursive) {
|
||||
err = dmu_objset_find(fsname,
|
||||
dmu_objset_snapshot_one, sn, DS_FIND_CHILDREN);
|
||||
} else {
|
||||
err = dmu_objset_snapshot_one(fsname, sn);
|
||||
}
|
||||
err = snapshot_one_impl(snapname, &saa);
|
||||
|
||||
if (err == 0)
|
||||
err = dsl_sync_task_group_wait(sn->dstg);
|
||||
err = dsl_sync_task_group_wait(saa.saa_dstg);
|
||||
|
||||
for (dst = list_head(&sn->dstg->dstg_tasks); dst;
|
||||
dst = list_next(&sn->dstg->dstg_tasks, dst)) {
|
||||
for (dst = list_head(&saa.saa_dstg->dstg_tasks); dst;
|
||||
dst = list_next(&saa.saa_dstg->dstg_tasks, dst)) {
|
||||
objset_t *os = dst->dst_arg1;
|
||||
dsl_dataset_t *ds = os->os_dsl_dataset;
|
||||
if (dst->dst_err) {
|
||||
dsl_dataset_name(ds, sn->failed);
|
||||
} else if (temporary) {
|
||||
dsl_register_onexit_hold_cleanup(sn->newds, tag, minor);
|
||||
}
|
||||
if (sn->needsuspend)
|
||||
dsl_register_onexit_hold_cleanup(saa.saa_newds, tag, minor);
|
||||
if (saa.saa_needsuspend)
|
||||
zil_resume(dmu_objset_zil(os));
|
||||
dmu_objset_rele(os, sn);
|
||||
dmu_objset_rele(os, &saa);
|
||||
}
|
||||
|
||||
if (err)
|
||||
(void) strcpy(fsname, sn->failed);
|
||||
if (temporary)
|
||||
zfs_onexit_fd_rele(cleanup_fd);
|
||||
dsl_sync_task_group_destroy(sn->dstg);
|
||||
zfs_onexit_fd_rele(cleanup_fd);
|
||||
dsl_sync_task_group_destroy(saa.saa_dstg);
|
||||
spa_close(spa, FTAG);
|
||||
kmem_free(sn, sizeof (struct snaparg));
|
||||
return (err);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dmu_objset_sync_dnodes(list_t *list, list_t *newlist, dmu_tx_t *tx)
|
||||
{
|
||||
@@ -1159,7 +1219,7 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx)
|
||||
dmu_objset_sync_dnodes(&os->os_dirty_dnodes[txgoff], newlist, tx);
|
||||
|
||||
list = &DMU_META_DNODE(os)->dn_dirty_records[txgoff];
|
||||
while ((dr = list_head(list)) != NULL) {
|
||||
while ((dr = list_head(list))) {
|
||||
ASSERT(dr->dr_dbuf->db_level == 0);
|
||||
list_remove(list, dr);
|
||||
if (dr->dr_zio)
|
||||
@@ -1219,7 +1279,7 @@ dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx)
|
||||
|
||||
ASSERT(list_head(list) == NULL || dmu_objset_userused_enabled(os));
|
||||
|
||||
while ((dn = list_head(list)) != NULL) {
|
||||
while ((dn = list_head(list))) {
|
||||
int flags;
|
||||
ASSERT(!DMU_OBJECT_IS_SPECIAL(dn->dn_object));
|
||||
ASSERT(dn->dn_phys->dn_type == DMU_OT_NONE ||
|
||||
|
||||
+56
-54
@@ -416,9 +416,48 @@ backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if 'earlier' is an earlier snapshot in 'later's timeline.
|
||||
* For example, they could both be snapshots of the same filesystem, and
|
||||
* 'earlier' is before 'later'. Or 'earlier' could be the origin of
|
||||
* 'later's filesystem. Or 'earlier' could be an older snapshot in the origin's
|
||||
* filesystem. Or 'earlier' could be the origin's origin.
|
||||
*/
|
||||
static boolean_t
|
||||
is_before(dsl_dataset_t *later, dsl_dataset_t *earlier)
|
||||
{
|
||||
dsl_pool_t *dp = later->ds_dir->dd_pool;
|
||||
int error;
|
||||
boolean_t ret;
|
||||
dsl_dataset_t *origin;
|
||||
|
||||
if (earlier->ds_phys->ds_creation_txg >=
|
||||
later->ds_phys->ds_creation_txg)
|
||||
return (B_FALSE);
|
||||
|
||||
if (later->ds_dir == earlier->ds_dir)
|
||||
return (B_TRUE);
|
||||
if (!dsl_dir_is_clone(later->ds_dir))
|
||||
return (B_FALSE);
|
||||
|
||||
rw_enter(&dp->dp_config_rwlock, RW_READER);
|
||||
if (later->ds_dir->dd_phys->dd_origin_obj == earlier->ds_object) {
|
||||
rw_exit(&dp->dp_config_rwlock);
|
||||
return (B_TRUE);
|
||||
}
|
||||
error = dsl_dataset_hold_obj(dp,
|
||||
later->ds_dir->dd_phys->dd_origin_obj, FTAG, &origin);
|
||||
rw_exit(&dp->dp_config_rwlock);
|
||||
if (error != 0)
|
||||
return (B_FALSE);
|
||||
ret = is_before(origin, earlier);
|
||||
dsl_dataset_rele(origin, FTAG);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
dmu_send(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
|
||||
int outfd, vnode_t *vp, offset_t *off)
|
||||
dmu_send(objset_t *tosnap, objset_t *fromsnap, int outfd, vnode_t *vp,
|
||||
offset_t *off)
|
||||
{
|
||||
dsl_dataset_t *ds = tosnap->os_dsl_dataset;
|
||||
dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL;
|
||||
@@ -431,30 +470,13 @@ dmu_send(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
|
||||
if (ds->ds_phys->ds_next_snap_obj == 0)
|
||||
return (EINVAL);
|
||||
|
||||
/* fromsnap must be an earlier snapshot from the same fs as tosnap */
|
||||
if (fromds && (ds->ds_dir != fromds->ds_dir ||
|
||||
fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg))
|
||||
/*
|
||||
* fromsnap must be an earlier snapshot from the same fs as tosnap,
|
||||
* or the origin's fs.
|
||||
*/
|
||||
if (fromds != NULL && !is_before(ds, fromds))
|
||||
return (EXDEV);
|
||||
|
||||
if (fromorigin) {
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
|
||||
if (fromsnap)
|
||||
return (EINVAL);
|
||||
|
||||
if (dsl_dir_is_clone(ds->ds_dir)) {
|
||||
rw_enter(&dp->dp_config_rwlock, RW_READER);
|
||||
err = dsl_dataset_hold_obj(dp,
|
||||
ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds);
|
||||
rw_exit(&dp->dp_config_rwlock);
|
||||
if (err)
|
||||
return (err);
|
||||
} else {
|
||||
fromorigin = B_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
|
||||
drr->drr_type = DRR_BEGIN;
|
||||
drr->drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
|
||||
@@ -479,7 +501,7 @@ dmu_send(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
|
||||
drr->drr_u.drr_begin.drr_creation_time =
|
||||
ds->ds_phys->ds_creation_time;
|
||||
drr->drr_u.drr_begin.drr_type = tosnap->os_phys->os_type;
|
||||
if (fromorigin)
|
||||
if (fromds != NULL && ds->ds_dir != fromds->ds_dir)
|
||||
drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE;
|
||||
drr->drr_u.drr_begin.drr_toguid = ds->ds_phys->ds_guid;
|
||||
if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET)
|
||||
@@ -491,8 +513,6 @@ dmu_send(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
|
||||
|
||||
if (fromds)
|
||||
fromtxg = fromds->ds_phys->ds_creation_txg;
|
||||
if (fromorigin)
|
||||
dsl_dataset_rele(fromds, FTAG);
|
||||
|
||||
dsp = kmem_zalloc(sizeof (dmu_sendarg_t), KM_SLEEP);
|
||||
|
||||
@@ -550,8 +570,7 @@ out:
|
||||
}
|
||||
|
||||
int
|
||||
dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
|
||||
uint64_t *sizep)
|
||||
dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, uint64_t *sizep)
|
||||
{
|
||||
dsl_dataset_t *ds = tosnap->os_dsl_dataset;
|
||||
dsl_dataset_t *fromds = fromsnap ? fromsnap->os_dsl_dataset : NULL;
|
||||
@@ -563,27 +582,13 @@ dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
|
||||
if (ds->ds_phys->ds_next_snap_obj == 0)
|
||||
return (EINVAL);
|
||||
|
||||
/* fromsnap must be an earlier snapshot from the same fs as tosnap */
|
||||
if (fromds && (ds->ds_dir != fromds->ds_dir ||
|
||||
fromds->ds_phys->ds_creation_txg >= ds->ds_phys->ds_creation_txg))
|
||||
/*
|
||||
* fromsnap must be an earlier snapshot from the same fs as tosnap,
|
||||
* or the origin's fs.
|
||||
*/
|
||||
if (fromds != NULL && !is_before(ds, fromds))
|
||||
return (EXDEV);
|
||||
|
||||
if (fromorigin) {
|
||||
if (fromsnap)
|
||||
return (EINVAL);
|
||||
|
||||
if (dsl_dir_is_clone(ds->ds_dir)) {
|
||||
rw_enter(&dp->dp_config_rwlock, RW_READER);
|
||||
err = dsl_dataset_hold_obj(dp,
|
||||
ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &fromds);
|
||||
rw_exit(&dp->dp_config_rwlock);
|
||||
if (err)
|
||||
return (err);
|
||||
} else {
|
||||
fromorigin = B_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get uncompressed size estimate of changed data. */
|
||||
if (fromds == NULL) {
|
||||
size = ds->ds_phys->ds_uncompressed_bytes;
|
||||
@@ -591,8 +596,6 @@ dmu_send_estimate(objset_t *tosnap, objset_t *fromsnap, boolean_t fromorigin,
|
||||
uint64_t used, comp;
|
||||
err = dsl_dataset_space_written(fromds, ds,
|
||||
&used, &comp, &size);
|
||||
if (fromorigin)
|
||||
dsl_dataset_rele(fromds, FTAG);
|
||||
if (err)
|
||||
return (err);
|
||||
}
|
||||
@@ -690,8 +693,7 @@ recv_new_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
rbsa->ds, &rbsa->ds->ds_phys->ds_bp, rbsa->type, tx);
|
||||
}
|
||||
|
||||
spa_history_log_internal(LOG_DS_REPLAY_FULL_SYNC,
|
||||
dd->dd_pool->dp_spa, tx, "dataset = %lld", dsobj);
|
||||
spa_history_log_internal_ds(rbsa->ds, "receive new", tx, "");
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
@@ -792,8 +794,7 @@ recv_existing_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
|
||||
rbsa->ds = cds;
|
||||
|
||||
spa_history_log_internal(LOG_DS_REPLAY_INC_SYNC,
|
||||
dp->dp_spa, tx, "dataset = %lld", dsobj);
|
||||
spa_history_log_internal_ds(cds, "receive over existing", tx, "");
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
@@ -1604,6 +1605,7 @@ recv_end_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
|
||||
dmu_buf_will_dirty(ds->ds_dbuf, tx);
|
||||
ds->ds_phys->ds_flags &= ~DS_FLAG_INCONSISTENT;
|
||||
spa_history_log_internal_ds(ds, "finished receiving", tx, "");
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ dmu_tx_create_dd(dsl_dir_t *dd)
|
||||
{
|
||||
dmu_tx_t *tx = kmem_zalloc(sizeof (dmu_tx_t), KM_PUSHPAGE);
|
||||
tx->tx_dir = dd;
|
||||
if (dd)
|
||||
if (dd != NULL)
|
||||
tx->tx_pool = dd->dd_pool;
|
||||
list_create(&tx->tx_holds, sizeof (dmu_tx_hold_t),
|
||||
offsetof(dmu_tx_hold_t, txh_node));
|
||||
|
||||
+68
-77
@@ -907,7 +907,8 @@ dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname,
|
||||
* The snapshots must all be in the same pool.
|
||||
*/
|
||||
int
|
||||
dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, char *failed)
|
||||
dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer,
|
||||
nvlist_t *errlist)
|
||||
{
|
||||
int err;
|
||||
dsl_sync_task_t *dst;
|
||||
@@ -942,7 +943,7 @@ dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, char *failed)
|
||||
} else if (err == ENOENT) {
|
||||
err = 0;
|
||||
} else {
|
||||
(void) strcpy(failed, nvpair_name(pair));
|
||||
fnvlist_add_int32(errlist, nvpair_name(pair), err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -956,10 +957,12 @@ dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, char *failed)
|
||||
dsl_dataset_t *ds = dsda->ds;
|
||||
|
||||
/*
|
||||
* Return the file system name that triggered the error
|
||||
* Return the snapshots that triggered the error.
|
||||
*/
|
||||
if (dst->dst_err) {
|
||||
dsl_dataset_name(ds, failed);
|
||||
if (dst->dst_err != 0) {
|
||||
char name[ZFS_MAXNAMELEN];
|
||||
dsl_dataset_name(ds, name);
|
||||
fnvlist_add_int32(errlist, name, dst->dst_err);
|
||||
}
|
||||
ASSERT3P(dsda->rm_origin, ==, NULL);
|
||||
dsl_dataset_disown(ds, dstg);
|
||||
@@ -1038,7 +1041,6 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||
dsl_dir_t *dd;
|
||||
uint64_t obj;
|
||||
struct dsl_ds_destroyarg dsda = { 0 };
|
||||
dsl_dataset_t *dummy_ds;
|
||||
|
||||
dsda.ds = ds;
|
||||
|
||||
@@ -1058,9 +1060,6 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||
}
|
||||
|
||||
dd = ds->ds_dir;
|
||||
dummy_ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP);
|
||||
dummy_ds->ds_dir = dd;
|
||||
dummy_ds->ds_object = ds->ds_object;
|
||||
|
||||
if (!spa_feature_is_enabled(dsl_dataset_get_spa(ds),
|
||||
&spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) {
|
||||
@@ -1072,11 +1071,11 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||
dsl_dataset_destroy_begin_check,
|
||||
dsl_dataset_destroy_begin_sync, ds, NULL, 0);
|
||||
if (err)
|
||||
goto out_free;
|
||||
goto out;
|
||||
|
||||
err = dmu_objset_from_ds(ds, &os);
|
||||
if (err)
|
||||
goto out_free;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Remove all objects while in the open context so that
|
||||
@@ -1091,7 +1090,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||
(void) dmu_free_object(os, obj);
|
||||
}
|
||||
if (err != ESRCH)
|
||||
goto out_free;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Sync out all in-flight IO.
|
||||
@@ -1118,7 +1117,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||
rw_exit(&dd->dd_pool->dp_config_rwlock);
|
||||
|
||||
if (err)
|
||||
goto out_free;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Blow away the dsl_dir + head dataset.
|
||||
@@ -1134,7 +1133,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||
err = dsl_dataset_origin_rm_prep(&dsda, tag);
|
||||
if (err) {
|
||||
dsl_dir_close(dd, FTAG);
|
||||
goto out_free;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1142,7 +1141,7 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||
dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
|
||||
dsl_dataset_destroy_sync, &dsda, tag, 0);
|
||||
dsl_sync_task_create(dstg, dsl_dir_destroy_check,
|
||||
dsl_dir_destroy_sync, dummy_ds, FTAG, 0);
|
||||
dsl_dir_destroy_sync, dd, FTAG, 0);
|
||||
err = dsl_sync_task_group_wait(dstg);
|
||||
dsl_sync_task_group_destroy(dstg);
|
||||
|
||||
@@ -1166,8 +1165,6 @@ dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer)
|
||||
if (err)
|
||||
dsl_dir_close(dd, FTAG);
|
||||
|
||||
out_free:
|
||||
kmem_free(dummy_ds, sizeof (dsl_dataset_t));
|
||||
out:
|
||||
dsl_dataset_disown(ds, tag);
|
||||
return (err);
|
||||
@@ -1333,14 +1330,12 @@ static void
|
||||
dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_t *ds = arg1;
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
|
||||
/* Mark it as inconsistent on-disk, in case we crash */
|
||||
dmu_buf_will_dirty(ds->ds_dbuf, tx);
|
||||
ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
|
||||
|
||||
spa_history_log_internal(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx,
|
||||
"dataset = %llu", ds->ds_object);
|
||||
spa_history_log_internal_ds(ds, "destroy begin", tx, "");
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1665,9 +1660,13 @@ dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx)
|
||||
ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS);
|
||||
dmu_buf_will_dirty(ds->ds_dbuf, tx);
|
||||
ds->ds_phys->ds_flags |= DS_FLAG_DEFER_DESTROY;
|
||||
spa_history_log_internal_ds(ds, "defer_destroy", tx, "");
|
||||
return;
|
||||
}
|
||||
|
||||
/* We need to log before removing it from the namespace. */
|
||||
spa_history_log_internal_ds(ds, "destroy", tx, "");
|
||||
|
||||
/* signal any waiters that this dataset is going away */
|
||||
mutex_enter(&ds->ds_lock);
|
||||
ds->ds_owner = dsl_reaper;
|
||||
@@ -1965,8 +1964,6 @@ dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx)
|
||||
dsl_dataset_rele(ds_prev, FTAG);
|
||||
|
||||
spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx);
|
||||
spa_history_log_internal(LOG_DS_DESTROY, dp->dp_spa, tx,
|
||||
"dataset = %llu", ds->ds_object);
|
||||
|
||||
if (ds->ds_phys->ds_next_clones_obj != 0) {
|
||||
ASSERTV(uint64_t count);
|
||||
@@ -2014,7 +2011,7 @@ dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
return (ENOSPC);
|
||||
|
||||
/*
|
||||
* Propogate any reserved space for this snapshot to other
|
||||
* Propagate any reserved space for this snapshot to other
|
||||
* snapshot checks in this sync group.
|
||||
*/
|
||||
if (asize > 0)
|
||||
@@ -2024,10 +2021,9 @@ dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
}
|
||||
|
||||
int
|
||||
dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
dsl_dataset_snapshot_check(dsl_dataset_t *ds, const char *snapname,
|
||||
dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_t *ds = arg1;
|
||||
const char *snapname = arg2;
|
||||
int err;
|
||||
uint64_t value;
|
||||
|
||||
@@ -2039,7 +2035,7 @@ dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
return (EAGAIN);
|
||||
|
||||
/*
|
||||
* Check for conflicting name snapshot name.
|
||||
* Check for conflicting snapshot name.
|
||||
*/
|
||||
err = dsl_dataset_snap_lookup(ds, snapname, &value);
|
||||
if (err == 0)
|
||||
@@ -2063,10 +2059,9 @@ dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
}
|
||||
|
||||
void
|
||||
dsl_dataset_snapshot_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
dsl_dataset_snapshot_sync(dsl_dataset_t *ds, const char *snapname,
|
||||
dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_t *ds = arg1;
|
||||
const char *snapname = arg2;
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
dmu_buf_t *dbuf;
|
||||
dsl_dataset_phys_t *dsphys;
|
||||
@@ -2172,8 +2167,7 @@ dsl_dataset_snapshot_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
|
||||
dsl_dir_snap_cmtime_update(ds->ds_dir);
|
||||
|
||||
spa_history_log_internal(LOG_DS_SNAPSHOT, dp->dp_spa, tx,
|
||||
"dataset = %llu", dsobj);
|
||||
spa_history_log_internal_ds(ds->ds_prev, "snapshot", tx, "");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2259,7 +2253,20 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
{
|
||||
uint64_t refd, avail, uobjs, aobjs, ratio;
|
||||
|
||||
dsl_dir_stats(ds->ds_dir, nv);
|
||||
ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 :
|
||||
(ds->ds_phys->ds_uncompressed_bytes * 100 /
|
||||
ds->ds_phys->ds_compressed_bytes);
|
||||
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio);
|
||||
|
||||
if (dsl_dataset_is_snapshot(ds)) {
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio);
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
|
||||
ds->ds_phys->ds_unique_bytes);
|
||||
get_clones_stat(ds, nv);
|
||||
} else {
|
||||
dsl_dir_stats(ds->ds_dir, nv);
|
||||
}
|
||||
|
||||
dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs);
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail);
|
||||
@@ -2305,22 +2312,6 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
}
|
||||
}
|
||||
|
||||
ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 :
|
||||
(ds->ds_phys->ds_uncompressed_bytes * 100 /
|
||||
ds->ds_phys->ds_compressed_bytes);
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio);
|
||||
|
||||
if (ds->ds_phys->ds_next_snap_obj) {
|
||||
/*
|
||||
* This is a snapshot; override the dd's space used with
|
||||
* our unique space and compression ratio.
|
||||
*/
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
|
||||
ds->ds_phys->ds_unique_bytes);
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio);
|
||||
|
||||
get_clones_stat(ds, nv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2329,27 +2320,25 @@ dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat)
|
||||
stat->dds_creation_txg = ds->ds_phys->ds_creation_txg;
|
||||
stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT;
|
||||
stat->dds_guid = ds->ds_phys->ds_guid;
|
||||
if (ds->ds_phys->ds_next_snap_obj) {
|
||||
stat->dds_origin[0] = '\0';
|
||||
if (dsl_dataset_is_snapshot(ds)) {
|
||||
stat->dds_is_snapshot = B_TRUE;
|
||||
stat->dds_num_clones = ds->ds_phys->ds_num_children - 1;
|
||||
} else {
|
||||
stat->dds_is_snapshot = B_FALSE;
|
||||
stat->dds_num_clones = 0;
|
||||
}
|
||||
|
||||
/* clone origin is really a dsl_dir thing... */
|
||||
rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
|
||||
if (dsl_dir_is_clone(ds->ds_dir)) {
|
||||
dsl_dataset_t *ods;
|
||||
rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
|
||||
if (dsl_dir_is_clone(ds->ds_dir)) {
|
||||
dsl_dataset_t *ods;
|
||||
|
||||
VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool,
|
||||
ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods));
|
||||
dsl_dataset_name(ods, stat->dds_origin);
|
||||
dsl_dataset_drop_ref(ods, FTAG);
|
||||
} else {
|
||||
stat->dds_origin[0] = '\0';
|
||||
VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool,
|
||||
ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods));
|
||||
dsl_dataset_name(ods, stat->dds_origin);
|
||||
dsl_dataset_drop_ref(ods, FTAG);
|
||||
}
|
||||
rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
|
||||
}
|
||||
rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@@ -2466,8 +2455,8 @@ dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
ds->ds_snapname, 8, 1, &ds->ds_object, tx);
|
||||
ASSERT0(err);
|
||||
|
||||
spa_history_log_internal(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx,
|
||||
"dataset = %llu", ds->ds_object);
|
||||
spa_history_log_internal_ds(ds, "rename", tx,
|
||||
"-> @%s", newsnapname);
|
||||
dsl_dataset_rele(hds, FTAG);
|
||||
}
|
||||
|
||||
@@ -2946,8 +2935,7 @@ dsl_dataset_promote_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
origin_ds->ds_phys->ds_unique_bytes = pa->unique;
|
||||
|
||||
/* log history record */
|
||||
spa_history_log_internal(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx,
|
||||
"dataset = %llu", hds->ds_object);
|
||||
spa_history_log_internal_ds(hds, "promote", tx, "");
|
||||
|
||||
dsl_dir_close(odd, FTAG);
|
||||
}
|
||||
@@ -3306,6 +3294,9 @@ dsl_dataset_clone_swap_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
csa->ohds->ds_phys->ds_deadlist_obj);
|
||||
|
||||
dsl_scan_ds_clone_swapped(csa->ohds, csa->cds, tx);
|
||||
|
||||
spa_history_log_internal_ds(csa->cds, "clone swap", tx,
|
||||
"parent=%s", csa->ohds->ds_dir->dd_myname);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3463,6 +3454,9 @@ dsl_dataset_set_quota_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
if (ds->ds_quota != effective_value) {
|
||||
dmu_buf_will_dirty(ds->ds_dbuf, tx);
|
||||
ds->ds_quota = effective_value;
|
||||
|
||||
spa_history_log_internal_ds(ds, "set refquota", tx,
|
||||
"refquota=%lld", (longlong_t)ds->ds_quota);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3566,6 +3560,9 @@ dsl_dataset_set_reservation_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
|
||||
dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx);
|
||||
mutex_exit(&ds->ds_dir->dd_lock);
|
||||
|
||||
spa_history_log_internal_ds(ds, "set refreservation", tx,
|
||||
"refreservation=%lld", (longlong_t)effective_value);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -3631,7 +3628,7 @@ dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_t *ds = arg1;
|
||||
struct dsl_ds_holdarg *ha = arg2;
|
||||
char *htag = ha->htag;
|
||||
const char *htag = ha->htag;
|
||||
objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
|
||||
int error = 0;
|
||||
|
||||
@@ -3665,7 +3662,7 @@ dsl_dataset_user_hold_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_t *ds = arg1;
|
||||
struct dsl_ds_holdarg *ha = arg2;
|
||||
char *htag = ha->htag;
|
||||
const char *htag = ha->htag;
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
objset_t *mos = dp->dp_meta_objset;
|
||||
uint64_t now = gethrestime_sec();
|
||||
@@ -3693,9 +3690,9 @@ dsl_dataset_user_hold_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
htag, &now, tx));
|
||||
}
|
||||
|
||||
spa_history_log_internal(LOG_DS_USER_HOLD,
|
||||
dp->dp_spa, tx, "<%s> temp = %d dataset = %llu", htag,
|
||||
(int)ha->temphold, ds->ds_object);
|
||||
spa_history_log_internal_ds(ds, "hold", tx,
|
||||
"tag = %s temp = %d holds now = %llu",
|
||||
htag, (int)ha->temphold, ds->ds_userrefs);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3902,7 +3899,6 @@ dsl_dataset_user_release_sync(void *arg1, void *tag, dmu_tx_t *tx)
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
objset_t *mos = dp->dp_meta_objset;
|
||||
uint64_t zapobj;
|
||||
uint64_t dsobj = ds->ds_object;
|
||||
uint64_t refs;
|
||||
int error;
|
||||
|
||||
@@ -3914,11 +3910,6 @@ dsl_dataset_user_release_sync(void *arg1, void *tag, dmu_tx_t *tx)
|
||||
VERIFY(error == 0 || error == ENOENT);
|
||||
zapobj = ds->ds_phys->ds_userrefs_obj;
|
||||
VERIFY(0 == zap_remove(mos, zapobj, ra->htag, tx));
|
||||
|
||||
spa_history_log_internal(LOG_DS_USER_RELEASE,
|
||||
dp->dp_spa, tx, "<%s> %lld dataset = %llu",
|
||||
ra->htag, (longlong_t)refs, dsobj);
|
||||
|
||||
if (ds->ds_userrefs == 0 && ds->ds_phys->ds_num_children == 1 &&
|
||||
DS_IS_DEFER_DESTROY(ds)) {
|
||||
struct dsl_ds_destroyarg dsda = {0};
|
||||
|
||||
+10
-18
@@ -181,10 +181,8 @@ dsl_deleg_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
|
||||
VERIFY(zap_update(mos, jumpobj,
|
||||
perm, 8, 1, &n, tx) == 0);
|
||||
spa_history_log_internal(LOG_DS_PERM_UPDATE,
|
||||
dd->dd_pool->dp_spa, tx,
|
||||
"%s %s dataset = %llu", whokey, perm,
|
||||
dd->dd_phys->dd_head_dataset_obj);
|
||||
spa_history_log_internal_dd(dd, "permission update", tx,
|
||||
"%s %s", whokey, perm);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,10 +211,8 @@ dsl_deleg_unset_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
(void) zap_remove(mos, zapobj, whokey, tx);
|
||||
VERIFY(0 == zap_destroy(mos, jumpobj, tx));
|
||||
}
|
||||
spa_history_log_internal(LOG_DS_PERM_WHO_REMOVE,
|
||||
dd->dd_pool->dp_spa, tx,
|
||||
"%s dataset = %llu", whokey,
|
||||
dd->dd_phys->dd_head_dataset_obj);
|
||||
spa_history_log_internal_dd(dd, "permission who remove",
|
||||
tx, "%s", whokey);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -234,10 +230,8 @@ dsl_deleg_unset_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
VERIFY(0 == zap_destroy(mos,
|
||||
jumpobj, tx));
|
||||
}
|
||||
spa_history_log_internal(LOG_DS_PERM_REMOVE,
|
||||
dd->dd_pool->dp_spa, tx,
|
||||
"%s %s dataset = %llu", whokey, perm,
|
||||
dd->dd_phys->dd_head_dataset_obj);
|
||||
spa_history_log_internal_dd(dd, "permission remove", tx,
|
||||
"%s %s", whokey, perm);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -533,12 +527,10 @@ dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if user has requested permission. If descendent is set, must have
|
||||
* descendent perms.
|
||||
* Check if user has requested permission.
|
||||
*/
|
||||
int
|
||||
dsl_deleg_access_impl(dsl_dataset_t *ds, boolean_t descendent, const char *perm,
|
||||
cred_t *cr)
|
||||
dsl_deleg_access_impl(dsl_dataset_t *ds, const char *perm, cred_t *cr)
|
||||
{
|
||||
dsl_dir_t *dd;
|
||||
dsl_pool_t *dp;
|
||||
@@ -559,7 +551,7 @@ dsl_deleg_access_impl(dsl_dataset_t *ds, boolean_t descendent, const char *perm,
|
||||
SPA_VERSION_DELEGATED_PERMS)
|
||||
return (EPERM);
|
||||
|
||||
if (dsl_dataset_is_snapshot(ds) || descendent) {
|
||||
if (dsl_dataset_is_snapshot(ds)) {
|
||||
/*
|
||||
* Snapshots are treated as descendents only,
|
||||
* local permissions do not apply.
|
||||
@@ -652,7 +644,7 @@ dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
error = dsl_deleg_access_impl(ds, B_FALSE, perm, cr);
|
||||
error = dsl_deleg_access_impl(ds, perm, cr);
|
||||
dsl_dataset_rele(ds, FTAG);
|
||||
|
||||
return (error);
|
||||
|
||||
+39
-28
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/dmu.h>
|
||||
@@ -39,8 +40,8 @@
|
||||
#include "zfs_namecheck.h"
|
||||
|
||||
static uint64_t dsl_dir_space_towrite(dsl_dir_t *dd);
|
||||
static void dsl_dir_set_reservation_sync(void *arg1, void *arg2, dmu_tx_t *tx);
|
||||
|
||||
static void dsl_dir_set_reservation_sync_impl(dsl_dir_t *dd,
|
||||
uint64_t value, dmu_tx_t *tx);
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
@@ -449,8 +450,7 @@ dsl_dir_create_sync(dsl_pool_t *dp, dsl_dir_t *pds, const char *name,
|
||||
int
|
||||
dsl_dir_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_t *ds = arg1;
|
||||
dsl_dir_t *dd = ds->ds_dir;
|
||||
dsl_dir_t *dd = arg1;
|
||||
dsl_pool_t *dp = dd->dd_pool;
|
||||
objset_t *mos = dp->dp_meta_objset;
|
||||
int err;
|
||||
@@ -481,24 +481,19 @@ dsl_dir_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
void
|
||||
dsl_dir_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_t *ds = arg1;
|
||||
dsl_dir_t *dd = ds->ds_dir;
|
||||
dsl_dir_t *dd = arg1;
|
||||
objset_t *mos = dd->dd_pool->dp_meta_objset;
|
||||
dsl_prop_setarg_t psa;
|
||||
uint64_t value = 0;
|
||||
uint64_t obj;
|
||||
dd_used_t t;
|
||||
|
||||
ASSERT(RW_WRITE_HELD(&dd->dd_pool->dp_config_rwlock));
|
||||
ASSERT(dd->dd_phys->dd_head_dataset_obj == 0);
|
||||
|
||||
/* Remove our reservation. */
|
||||
dsl_prop_setarg_init_uint64(&psa, "reservation",
|
||||
(ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED),
|
||||
&value);
|
||||
psa.psa_effective_value = 0; /* predict default value */
|
||||
|
||||
dsl_dir_set_reservation_sync(ds, &psa, tx);
|
||||
/*
|
||||
* Remove our reservation. The impl() routine avoids setting the
|
||||
* actual property, which would require the (already destroyed) ds.
|
||||
*/
|
||||
dsl_dir_set_reservation_sync_impl(dd, 0, tx);
|
||||
|
||||
ASSERT0(dd->dd_phys->dd_used_bytes);
|
||||
ASSERT0(dd->dd_phys->dd_reserved);
|
||||
@@ -1062,6 +1057,9 @@ dsl_dir_set_quota_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
mutex_enter(&dd->dd_lock);
|
||||
dd->dd_phys->dd_quota = effective_value;
|
||||
mutex_exit(&dd->dd_lock);
|
||||
|
||||
spa_history_log_internal_dd(dd, "set quota", tx,
|
||||
"quota=%lld", (longlong_t)effective_value);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -1148,25 +1146,17 @@ dsl_dir_set_reservation_check(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
}
|
||||
|
||||
static void
|
||||
dsl_dir_set_reservation_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
dsl_dir_set_reservation_sync_impl(dsl_dir_t *dd, uint64_t value, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_t *ds = arg1;
|
||||
dsl_dir_t *dd = ds->ds_dir;
|
||||
dsl_prop_setarg_t *psa = arg2;
|
||||
uint64_t effective_value = psa->psa_effective_value;
|
||||
uint64_t used;
|
||||
int64_t delta;
|
||||
|
||||
dsl_prop_set_sync(ds, psa, tx);
|
||||
DSL_PROP_CHECK_PREDICTION(dd, psa);
|
||||
|
||||
dmu_buf_will_dirty(dd->dd_dbuf, tx);
|
||||
|
||||
mutex_enter(&dd->dd_lock);
|
||||
used = dd->dd_phys->dd_used_bytes;
|
||||
delta = MAX(used, effective_value) -
|
||||
MAX(used, dd->dd_phys->dd_reserved);
|
||||
dd->dd_phys->dd_reserved = effective_value;
|
||||
delta = MAX(used, value) - MAX(used, dd->dd_phys->dd_reserved);
|
||||
dd->dd_phys->dd_reserved = value;
|
||||
|
||||
if (dd->dd_parent != NULL) {
|
||||
/* Roll up this additional usage into our ancestors */
|
||||
@@ -1176,6 +1166,23 @@ dsl_dir_set_reservation_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
mutex_exit(&dd->dd_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
dsl_dir_set_reservation_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_t *ds = arg1;
|
||||
dsl_dir_t *dd = ds->ds_dir;
|
||||
dsl_prop_setarg_t *psa = arg2;
|
||||
uint64_t value = psa->psa_effective_value;
|
||||
|
||||
dsl_prop_set_sync(ds, psa, tx);
|
||||
DSL_PROP_CHECK_PREDICTION(dd, psa);
|
||||
|
||||
dsl_dir_set_reservation_sync_impl(dd, value, tx);
|
||||
|
||||
spa_history_log_internal_dd(dd, "set reservation", tx,
|
||||
"reservation=%lld", (longlong_t)value);
|
||||
}
|
||||
|
||||
int
|
||||
dsl_dir_set_reservation(const char *ddname, zprop_source_t source,
|
||||
uint64_t reservation)
|
||||
@@ -1294,9 +1301,15 @@ dsl_dir_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
dsl_pool_t *dp = dd->dd_pool;
|
||||
objset_t *mos = dp->dp_meta_objset;
|
||||
int err;
|
||||
char namebuf[MAXNAMELEN];
|
||||
|
||||
ASSERT(dmu_buf_refcount(dd->dd_dbuf) <= 2);
|
||||
|
||||
/* Log this before we change the name. */
|
||||
dsl_dir_name(ra->newparent, namebuf);
|
||||
spa_history_log_internal_dd(dd, "rename", tx,
|
||||
"-> %s/%s", namebuf, ra->mynewname);
|
||||
|
||||
if (ra->newparent != dd->dd_parent) {
|
||||
dsl_dir_diduse_space(dd->dd_parent, DD_USED_CHILD,
|
||||
-dd->dd_phys->dd_used_bytes,
|
||||
@@ -1336,8 +1349,6 @@ dsl_dir_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
dd->dd_myname, 8, 1, &dd->dd_object, tx);
|
||||
ASSERT0(err);
|
||||
|
||||
spa_history_log_internal(LOG_DS_RENAME, dd->dd_pool->dp_spa,
|
||||
tx, "dataset = %llu", dd->dd_phys->dd_head_dataset_obj);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
+4
-23
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
@@ -704,11 +705,9 @@ dsl_prop_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
}
|
||||
}
|
||||
|
||||
spa_history_log_internal((source == ZPROP_SRC_NONE ||
|
||||
source == ZPROP_SRC_INHERITED) ? LOG_DS_INHERIT :
|
||||
LOG_DS_PROPSET, ds->ds_dir->dd_pool->dp_spa, tx,
|
||||
"%s=%s dataset = %llu", propname,
|
||||
(valstr == NULL ? "" : valstr), ds->ds_object);
|
||||
spa_history_log_internal_ds(ds, (source == ZPROP_SRC_NONE ||
|
||||
source == ZPROP_SRC_INHERITED) ? "inherit" : "set", tx,
|
||||
"%s=%s", propname, (valstr == NULL ? "" : valstr));
|
||||
|
||||
if (tbuf != NULL)
|
||||
kmem_free(tbuf, ZAP_MAXVALUELEN);
|
||||
@@ -757,24 +756,6 @@ dsl_props_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dsl_dir_prop_set_uint64_sync(dsl_dir_t *dd, const char *name, uint64_t val,
|
||||
dmu_tx_t *tx)
|
||||
{
|
||||
objset_t *mos = dd->dd_pool->dp_meta_objset;
|
||||
uint64_t zapobj = dd->dd_phys->dd_props_zapobj;
|
||||
|
||||
ASSERT(dmu_tx_is_syncing(tx));
|
||||
|
||||
VERIFY(0 == zap_update(mos, zapobj, name, sizeof (val), 1, &val, tx));
|
||||
|
||||
dsl_prop_changed_notify(dd->dd_pool, dd->dd_object, name, val, TRUE);
|
||||
|
||||
spa_history_log_internal(LOG_DS_PROPSET, dd->dd_pool->dp_spa, tx,
|
||||
"%s=%llu dataset = %llu", name, (u_longlong_t)val,
|
||||
dd->dd_phys->dd_head_dataset_obj);
|
||||
}
|
||||
|
||||
int
|
||||
dsl_prop_set(const char *dsname, const char *propname, zprop_source_t source,
|
||||
int intsz, int numints, const void *buf)
|
||||
|
||||
@@ -224,7 +224,7 @@ dsl_scan_setup_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
|
||||
dsl_scan_sync_state(scn, tx);
|
||||
|
||||
spa_history_log_internal(LOG_POOL_SCAN, spa, tx,
|
||||
spa_history_log_internal(spa, "scan setup", tx,
|
||||
"func=%u mintxg=%llu maxtxg=%llu",
|
||||
*funcp, scn->scn_phys.scn_min_txg, scn->scn_phys.scn_max_txg);
|
||||
}
|
||||
@@ -273,7 +273,7 @@ dsl_scan_done(dsl_scan_t *scn, boolean_t complete, dmu_tx_t *tx)
|
||||
else
|
||||
scn->scn_phys.scn_state = DSS_CANCELED;
|
||||
|
||||
spa_history_log_internal(LOG_POOL_SCAN_DONE, spa, tx,
|
||||
spa_history_log_internal(spa, "scan done", tx,
|
||||
"complete=%u", complete);
|
||||
|
||||
if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) {
|
||||
|
||||
+12
-11
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/dmu.h>
|
||||
@@ -85,17 +86,17 @@ top:
|
||||
|
||||
/* Do a preliminary error check. */
|
||||
dstg->dstg_err = 0;
|
||||
#ifdef ZFS_DEBUG
|
||||
/*
|
||||
* Only check half the time, otherwise, the sync-context
|
||||
* check will almost never fail.
|
||||
*/
|
||||
if (spa_get_random(2) == 0)
|
||||
goto skip;
|
||||
#endif
|
||||
rw_enter(&dstg->dstg_pool->dp_config_rwlock, RW_READER);
|
||||
for (dst = list_head(&dstg->dstg_tasks); dst;
|
||||
dst = list_next(&dstg->dstg_tasks, dst)) {
|
||||
#ifdef ZFS_DEBUG
|
||||
/*
|
||||
* Only check half the time, otherwise, the sync-context
|
||||
* check will almost never fail.
|
||||
*/
|
||||
if (spa_get_random(2) == 0)
|
||||
continue;
|
||||
#endif
|
||||
dst->dst_err =
|
||||
dst->dst_checkfunc(dst->dst_arg1, dst->dst_arg2, tx);
|
||||
if (dst->dst_err)
|
||||
@@ -107,6 +108,9 @@ top:
|
||||
dmu_tx_commit(tx);
|
||||
return (dstg->dstg_err);
|
||||
}
|
||||
#ifdef ZFS_DEBUG
|
||||
skip:
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We don't generally have many sync tasks, so pay the price of
|
||||
@@ -230,9 +234,6 @@ dsl_sync_task_do_nowait(dsl_pool_t *dp,
|
||||
{
|
||||
dsl_sync_task_group_t *dstg;
|
||||
|
||||
if (!spa_writeable(dp->dp_spa))
|
||||
return;
|
||||
|
||||
dstg = dsl_sync_task_group_create(dp);
|
||||
dsl_sync_task_create(dstg, checkfunc, syncfunc,
|
||||
arg1, arg2, blocks_modified);
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/refcount.h>
|
||||
#include <sys/rrwlock.h>
|
||||
@@ -262,3 +265,13 @@ rrw_held(rrwlock_t *rrl, krw_t rw)
|
||||
|
||||
return (held);
|
||||
}
|
||||
|
||||
void
|
||||
rrw_tsd_destroy(void *arg)
|
||||
{
|
||||
rrw_node_t *rn = arg;
|
||||
if (rn != NULL) {
|
||||
panic("thread %p terminating with rrw lock %p held",
|
||||
(void *)curthread, (void *)rn->rn_rrl);
|
||||
}
|
||||
}
|
||||
|
||||
+28
-26
@@ -731,8 +731,8 @@ spa_change_guid_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
vdev_config_dirty(rvd);
|
||||
spa_config_exit(spa, SCL_STATE, FTAG);
|
||||
|
||||
spa_history_log_internal(LOG_POOL_GUID_CHANGE, spa, tx,
|
||||
"old=%lld new=%lld", oldguid, *newguid);
|
||||
spa_history_log_internal(spa, "guid change", tx, "old=%llu new=%llu",
|
||||
oldguid, *newguid);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2715,6 +2715,12 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config,
|
||||
vdev_resilver_needed(rvd, NULL, NULL))
|
||||
spa_async_request(spa, SPA_ASYNC_RESILVER);
|
||||
|
||||
/*
|
||||
* Log the fact that we booted up (so that we can detect if
|
||||
* we rebooted in the middle of an operation).
|
||||
*/
|
||||
spa_history_log_version(spa, "open");
|
||||
|
||||
/*
|
||||
* Delete any inconsistent datasets.
|
||||
*/
|
||||
@@ -3399,7 +3405,7 @@ spa_l2cache_drop(spa_t *spa)
|
||||
*/
|
||||
int
|
||||
spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
|
||||
const char *history_str, nvlist_t *zplprops)
|
||||
nvlist_t *zplprops)
|
||||
{
|
||||
spa_t *spa;
|
||||
char *altroot = NULL;
|
||||
@@ -3620,9 +3626,7 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
|
||||
|
||||
spa_config_sync(spa, B_FALSE, B_TRUE);
|
||||
|
||||
if (version >= SPA_VERSION_ZPOOL_HISTORY && history_str != NULL)
|
||||
(void) spa_history_log(spa, history_str, LOG_CMD_POOL_CREATE);
|
||||
spa_history_log_version(spa, LOG_POOL_CREATE);
|
||||
spa_history_log_version(spa, "create");
|
||||
|
||||
spa->spa_minref = refcount_count(&spa->spa_refcount);
|
||||
|
||||
@@ -3824,7 +3828,6 @@ spa_import_rootpool(char *devpath, char *devid)
|
||||
}
|
||||
|
||||
error = 0;
|
||||
spa_history_log_version(spa, LOG_POOL_IMPORT);
|
||||
out:
|
||||
spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
|
||||
vdev_free(rvd);
|
||||
@@ -3886,7 +3889,7 @@ spa_import(const char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags)
|
||||
spa_config_sync(spa, B_FALSE, B_TRUE);
|
||||
|
||||
mutex_exit(&spa_namespace_lock);
|
||||
spa_history_log_version(spa, LOG_POOL_IMPORT);
|
||||
spa_history_log_version(spa, "import");
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -4017,7 +4020,7 @@ spa_import(const char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags)
|
||||
spa_async_request(spa, SPA_ASYNC_AUTOEXPAND);
|
||||
|
||||
mutex_exit(&spa_namespace_lock);
|
||||
spa_history_log_version(spa, LOG_POOL_IMPORT);
|
||||
spa_history_log_version(spa, "import");
|
||||
|
||||
#ifdef _KERNEL
|
||||
zvol_create_minors(pool);
|
||||
@@ -4560,7 +4563,7 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing)
|
||||
*/
|
||||
(void) spa_vdev_exit(spa, newrootvd, dtl_max_txg, 0);
|
||||
|
||||
spa_history_log_internal(LOG_POOL_VDEV_ATTACH, spa, NULL,
|
||||
spa_history_log_internal(spa, "vdev attach", NULL,
|
||||
"%s vdev=%s %s vdev=%s",
|
||||
replacing && newvd_isspare ? "spare in" :
|
||||
replacing ? "replace" : "attach", newvdpath,
|
||||
@@ -4778,7 +4781,7 @@ spa_vdev_detach(spa_t *spa, uint64_t guid, uint64_t pguid, int replace_done)
|
||||
|
||||
error = spa_vdev_exit(spa, vd, txg, 0);
|
||||
|
||||
spa_history_log_internal(LOG_POOL_VDEV_DETACH, spa, NULL,
|
||||
spa_history_log_internal(spa, "detach", NULL,
|
||||
"vdev=%s", vdpath);
|
||||
spa_strfree(vdpath);
|
||||
|
||||
@@ -5047,9 +5050,8 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
|
||||
if (vml[c] != NULL) {
|
||||
vdev_split(vml[c]);
|
||||
if (error == 0)
|
||||
spa_history_log_internal(LOG_POOL_VDEV_DETACH,
|
||||
spa, tx, "vdev=%s",
|
||||
vml[c]->vdev_path);
|
||||
spa_history_log_internal(spa, "detach", tx,
|
||||
"vdev=%s", vml[c]->vdev_path);
|
||||
vdev_free(vml[c]);
|
||||
}
|
||||
}
|
||||
@@ -5064,8 +5066,8 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
|
||||
zio_handle_panic_injection(spa, FTAG, 3);
|
||||
|
||||
/* split is complete; log a history record */
|
||||
spa_history_log_internal(LOG_POOL_SPLIT, newspa, NULL,
|
||||
"split new pool %s from pool %s", newname, spa_name(spa));
|
||||
spa_history_log_internal(newspa, "split", NULL,
|
||||
"from pool %s", spa_name(spa));
|
||||
|
||||
kmem_free(vml, children * sizeof (vdev_t *));
|
||||
|
||||
@@ -5647,8 +5649,7 @@ spa_async_thread(spa_t *spa)
|
||||
* then log an internal history event.
|
||||
*/
|
||||
if (new_space != old_space) {
|
||||
spa_history_log_internal(LOG_POOL_VDEV_ONLINE,
|
||||
spa, NULL,
|
||||
spa_history_log_internal(spa, "vdev online", NULL,
|
||||
"pool '%s' size: %llu(+%llu)",
|
||||
spa_name(spa), new_space, new_space - old_space);
|
||||
}
|
||||
@@ -5892,6 +5893,7 @@ spa_sync_version(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
|
||||
spa->spa_uberblock.ub_version = version;
|
||||
vdev_config_dirty(spa->spa_root_vdev);
|
||||
spa_history_log_internal(spa, "set", tx, "version=%lld", version);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5927,6 +5929,8 @@ spa_sync_props(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
VERIFY3U(0, ==, zfeature_lookup_name(fname, &feature));
|
||||
|
||||
spa_feature_enable(spa, feature, tx);
|
||||
spa_history_log_internal(spa, "set", tx,
|
||||
"%s=enabled", nvpair_name(elem));
|
||||
break;
|
||||
|
||||
case ZPOOL_PROP_VERSION:
|
||||
@@ -5966,6 +5970,8 @@ spa_sync_props(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
*/
|
||||
if (tx->tx_txg != TXG_INITIAL)
|
||||
vdev_config_dirty(spa->spa_root_vdev);
|
||||
spa_history_log_internal(spa, "set", tx,
|
||||
"%s=%s", nvpair_name(elem), strval);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
@@ -5988,7 +5994,8 @@ spa_sync_props(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
VERIFY(zap_update(mos,
|
||||
spa->spa_pool_props_object, propname,
|
||||
1, strlen(strval) + 1, strval, tx) == 0);
|
||||
|
||||
spa_history_log_internal(spa, "set", tx,
|
||||
"%s=%s", nvpair_name(elem), strval);
|
||||
} else if (nvpair_type(elem) == DATA_TYPE_UINT64) {
|
||||
VERIFY(nvpair_value_uint64(elem, &intval) == 0);
|
||||
|
||||
@@ -6000,6 +6007,8 @@ spa_sync_props(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
VERIFY(zap_update(mos,
|
||||
spa->spa_pool_props_object, propname,
|
||||
8, 1, &intval, tx) == 0);
|
||||
spa_history_log_internal(spa, "set", tx,
|
||||
"%s=%lld", nvpair_name(elem), intval);
|
||||
} else {
|
||||
ASSERT(0); /* not allowed */
|
||||
}
|
||||
@@ -6028,13 +6037,6 @@ spa_sync_props(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
}
|
||||
}
|
||||
|
||||
/* log internal history if this is not a zpool create */
|
||||
if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY &&
|
||||
tx->tx_txg != TXG_INITIAL) {
|
||||
spa_history_log_internal(LOG_POOL_PROPSET,
|
||||
spa, tx, "%s %lld %s",
|
||||
nvpair_name(elem), intval, spa_name(spa));
|
||||
}
|
||||
}
|
||||
|
||||
mutex_exit(&spa->spa_props_lock);
|
||||
|
||||
+140
-88
@@ -21,7 +21,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011 by Delphix. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/spa.h>
|
||||
@@ -30,9 +30,12 @@
|
||||
#include <sys/dsl_synctask.h>
|
||||
#include <sys/dmu_tx.h>
|
||||
#include <sys/dmu_objset.h>
|
||||
#include <sys/dsl_dataset.h>
|
||||
#include <sys/dsl_dir.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/cmn_err.h>
|
||||
#include <sys/sunddi.h>
|
||||
#include <sys/cred.h>
|
||||
#include "zfs_comutil.h"
|
||||
#ifdef _KERNEL
|
||||
#include <sys/zone.h>
|
||||
@@ -185,7 +188,7 @@ spa_history_zone(void)
|
||||
return (curproc->p_zone->zone_name);
|
||||
#endif
|
||||
#else
|
||||
return ("global");
|
||||
return (NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -197,14 +200,12 @@ static void
|
||||
spa_history_log_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
{
|
||||
spa_t *spa = arg1;
|
||||
history_arg_t *hap = arg2;
|
||||
const char *history_str = hap->ha_history_str;
|
||||
nvlist_t *nvl = arg2;
|
||||
objset_t *mos = spa->spa_meta_objset;
|
||||
dmu_buf_t *dbp;
|
||||
spa_history_phys_t *shpp;
|
||||
size_t reclen;
|
||||
uint64_t le_len;
|
||||
nvlist_t *nvrecord;
|
||||
char *record_packed = NULL;
|
||||
int ret;
|
||||
|
||||
@@ -234,46 +235,36 @@ spa_history_log_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
}
|
||||
#endif
|
||||
|
||||
VERIFY(nvlist_alloc(&nvrecord, NV_UNIQUE_NAME, KM_PUSHPAGE) == 0);
|
||||
VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_TIME,
|
||||
gethrestime_sec()) == 0);
|
||||
VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_WHO, hap->ha_uid) == 0);
|
||||
if (hap->ha_zone != NULL)
|
||||
VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_ZONE,
|
||||
hap->ha_zone) == 0);
|
||||
fnvlist_add_uint64(nvl, ZPOOL_HIST_TIME, gethrestime_sec());
|
||||
#ifdef _KERNEL
|
||||
VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_HOST,
|
||||
utsname.nodename) == 0);
|
||||
fnvlist_add_string(nvl, ZPOOL_HIST_HOST, utsname.nodename);
|
||||
#endif
|
||||
if (hap->ha_log_type == LOG_CMD_POOL_CREATE ||
|
||||
hap->ha_log_type == LOG_CMD_NORMAL) {
|
||||
VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_CMD,
|
||||
history_str) == 0);
|
||||
|
||||
zfs_dbgmsg("command: %s", history_str);
|
||||
} else {
|
||||
VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_INT_EVENT,
|
||||
hap->ha_event) == 0);
|
||||
VERIFY(nvlist_add_uint64(nvrecord, ZPOOL_HIST_TXG,
|
||||
tx->tx_txg) == 0);
|
||||
VERIFY(nvlist_add_string(nvrecord, ZPOOL_HIST_INT_STR,
|
||||
history_str) == 0);
|
||||
|
||||
zfs_dbgmsg("internal %s pool:%s txg:%llu %s",
|
||||
zfs_history_event_names[hap->ha_event], spa_name(spa),
|
||||
(longlong_t)tx->tx_txg, history_str);
|
||||
|
||||
if (nvlist_exists(nvl, ZPOOL_HIST_CMD)) {
|
||||
zfs_dbgmsg("command: %s",
|
||||
fnvlist_lookup_string(nvl, ZPOOL_HIST_CMD));
|
||||
} else if (nvlist_exists(nvl, ZPOOL_HIST_INT_NAME)) {
|
||||
if (nvlist_exists(nvl, ZPOOL_HIST_DSNAME)) {
|
||||
zfs_dbgmsg("txg %lld %s %s (id %llu) %s",
|
||||
fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG),
|
||||
fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME),
|
||||
fnvlist_lookup_string(nvl, ZPOOL_HIST_DSNAME),
|
||||
fnvlist_lookup_uint64(nvl, ZPOOL_HIST_DSID),
|
||||
fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR));
|
||||
} else {
|
||||
zfs_dbgmsg("txg %lld %s %s",
|
||||
fnvlist_lookup_uint64(nvl, ZPOOL_HIST_TXG),
|
||||
fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_NAME),
|
||||
fnvlist_lookup_string(nvl, ZPOOL_HIST_INT_STR));
|
||||
}
|
||||
} else if (nvlist_exists(nvl, ZPOOL_HIST_IOCTL)) {
|
||||
zfs_dbgmsg("ioctl %s",
|
||||
fnvlist_lookup_string(nvl, ZPOOL_HIST_IOCTL));
|
||||
}
|
||||
|
||||
VERIFY(nvlist_size(nvrecord, &reclen, NV_ENCODE_XDR) == 0);
|
||||
record_packed = kmem_alloc(reclen, KM_PUSHPAGE);
|
||||
|
||||
VERIFY(nvlist_pack(nvrecord, &record_packed, &reclen,
|
||||
NV_ENCODE_XDR, KM_PUSHPAGE) == 0);
|
||||
VERIFY3U(nvlist_pack(nvl, &record_packed, &reclen, NV_ENCODE_NATIVE,
|
||||
KM_PUSHPAGE), ==, 0);
|
||||
|
||||
mutex_enter(&spa->spa_history_lock);
|
||||
if (hap->ha_log_type == LOG_CMD_POOL_CREATE)
|
||||
VERIFY(shpp->sh_eof == shpp->sh_pool_create_len);
|
||||
|
||||
/* write out the packed length as little endian */
|
||||
le_len = LE_64((uint64_t)reclen);
|
||||
@@ -281,33 +272,44 @@ spa_history_log_sync(void *arg1, void *arg2, dmu_tx_t *tx)
|
||||
if (!ret)
|
||||
ret = spa_history_write(spa, record_packed, reclen, shpp, tx);
|
||||
|
||||
if (!ret && hap->ha_log_type == LOG_CMD_POOL_CREATE) {
|
||||
shpp->sh_pool_create_len += sizeof (le_len) + reclen;
|
||||
shpp->sh_bof = shpp->sh_pool_create_len;
|
||||
/* The first command is the create, which we keep forever */
|
||||
if (ret == 0 && shpp->sh_pool_create_len == 0 &&
|
||||
nvlist_exists(nvl, ZPOOL_HIST_CMD)) {
|
||||
shpp->sh_pool_create_len = shpp->sh_bof = shpp->sh_eof;
|
||||
}
|
||||
|
||||
mutex_exit(&spa->spa_history_lock);
|
||||
nvlist_free(nvrecord);
|
||||
kmem_free(record_packed, reclen);
|
||||
fnvlist_pack_free(record_packed, reclen);
|
||||
dmu_buf_rele(dbp, FTAG);
|
||||
|
||||
strfree(hap->ha_history_str);
|
||||
if (hap->ha_zone != NULL)
|
||||
strfree(hap->ha_zone);
|
||||
kmem_free(hap, sizeof (history_arg_t));
|
||||
fnvlist_free(nvl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out a history event.
|
||||
*/
|
||||
int
|
||||
spa_history_log(spa_t *spa, const char *history_str, history_log_type_t what)
|
||||
spa_history_log(spa_t *spa, const char *msg)
|
||||
{
|
||||
int err;
|
||||
nvlist_t *nvl;
|
||||
|
||||
VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_PUSHPAGE));
|
||||
|
||||
fnvlist_add_string(nvl, ZPOOL_HIST_CMD, msg);
|
||||
err = spa_history_log_nvl(spa, nvl);
|
||||
fnvlist_free(nvl);
|
||||
return (err);
|
||||
}
|
||||
|
||||
int
|
||||
spa_history_log_nvl(spa_t *spa, nvlist_t *nvl)
|
||||
{
|
||||
history_arg_t *ha;
|
||||
int err = 0;
|
||||
dmu_tx_t *tx;
|
||||
nvlist_t *nvarg;
|
||||
|
||||
ASSERT(what != LOG_INTERNAL);
|
||||
if (spa_version(spa) < SPA_VERSION_ZPOOL_HISTORY || !spa_writeable(spa))
|
||||
return (EINVAL);
|
||||
|
||||
tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir);
|
||||
err = dmu_tx_assign(tx, TXG_WAIT);
|
||||
@@ -316,19 +318,21 @@ spa_history_log(spa_t *spa, const char *history_str, history_log_type_t what)
|
||||
return (err);
|
||||
}
|
||||
|
||||
ha = kmem_alloc(sizeof (history_arg_t), KM_PUSHPAGE);
|
||||
ha->ha_history_str = strdup(history_str);
|
||||
ha->ha_zone = strdup(spa_history_zone());
|
||||
ha->ha_log_type = what;
|
||||
ha->ha_uid = crgetuid(CRED());
|
||||
VERIFY0(nvlist_dup(nvl, &nvarg, KM_PUSHPAGE));
|
||||
if (spa_history_zone() != NULL) {
|
||||
fnvlist_add_string(nvarg, ZPOOL_HIST_ZONE,
|
||||
spa_history_zone());
|
||||
}
|
||||
fnvlist_add_uint64(nvarg, ZPOOL_HIST_WHO, crgetruid(CRED()));
|
||||
|
||||
/* Kick this off asynchronously; errors are ignored. */
|
||||
dsl_sync_task_do_nowait(spa_get_dsl(spa), NULL,
|
||||
spa_history_log_sync, spa, ha, 0, tx);
|
||||
spa_history_log_sync, spa, nvarg, 0, tx);
|
||||
dmu_tx_commit(tx);
|
||||
|
||||
/* spa_history_log_sync will free ha and strings */
|
||||
/* spa_history_log_sync will free nvl */
|
||||
return (err);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -345,7 +349,7 @@ spa_history_get(spa_t *spa, uint64_t *offp, uint64_t *len, char *buf)
|
||||
int err;
|
||||
|
||||
/*
|
||||
* If the command history doesn't exist (older pool),
|
||||
* If the command history doesn't exist (older pool),
|
||||
* that's ok, just return ENOENT.
|
||||
*/
|
||||
if (!spa->spa_history)
|
||||
@@ -428,44 +432,54 @@ spa_history_get(spa_t *spa, uint64_t *offp, uint64_t *len, char *buf)
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* The nvlist will be consumed by this call.
|
||||
*/
|
||||
static void
|
||||
log_internal(history_internal_events_t event, spa_t *spa,
|
||||
log_internal(nvlist_t *nvl, const char *operation, spa_t *spa,
|
||||
dmu_tx_t *tx, const char *fmt, va_list adx)
|
||||
{
|
||||
history_arg_t *ha;
|
||||
va_list adx_copy;
|
||||
char *msg;
|
||||
va_list adx1;
|
||||
|
||||
/*
|
||||
* If this is part of creating a pool, not everything is
|
||||
* initialized yet, so don't bother logging the internal events.
|
||||
* Likewise if the pool is not writeable.
|
||||
*/
|
||||
if (tx->tx_txg == TXG_INITIAL)
|
||||
if (tx->tx_txg == TXG_INITIAL || !spa_writeable(spa)) {
|
||||
fnvlist_free(nvl);
|
||||
return;
|
||||
}
|
||||
|
||||
ha = kmem_alloc(sizeof (history_arg_t), KM_PUSHPAGE);
|
||||
va_copy(adx_copy, adx);
|
||||
ha->ha_history_str = kmem_vasprintf(fmt, adx_copy);
|
||||
va_end(adx_copy);
|
||||
ha->ha_log_type = LOG_INTERNAL;
|
||||
ha->ha_event = event;
|
||||
ha->ha_zone = NULL;
|
||||
ha->ha_uid = 0;
|
||||
va_copy(adx1, adx);
|
||||
msg = kmem_alloc(vsnprintf(NULL, 0, fmt, adx1) + 1, KM_PUSHPAGE);
|
||||
va_end(adx1);
|
||||
va_copy(adx1, adx);
|
||||
(void) vsprintf(msg, fmt, adx1);
|
||||
va_end(adx1);
|
||||
fnvlist_add_string(nvl, ZPOOL_HIST_INT_STR, msg);
|
||||
strfree(msg);
|
||||
|
||||
fnvlist_add_string(nvl, ZPOOL_HIST_INT_NAME, operation);
|
||||
fnvlist_add_uint64(nvl, ZPOOL_HIST_TXG, tx->tx_txg);
|
||||
|
||||
if (dmu_tx_is_syncing(tx)) {
|
||||
spa_history_log_sync(spa, ha, tx);
|
||||
spa_history_log_sync(spa, nvl, tx);
|
||||
} else {
|
||||
dsl_sync_task_do_nowait(spa_get_dsl(spa), NULL,
|
||||
spa_history_log_sync, spa, ha, 0, tx);
|
||||
spa_history_log_sync, spa, nvl, 0, tx);
|
||||
}
|
||||
/* spa_history_log_sync() will free ha and strings */
|
||||
/* spa_history_log_sync() will free nvl */
|
||||
}
|
||||
|
||||
void
|
||||
spa_history_log_internal(history_internal_events_t event, spa_t *spa,
|
||||
spa_history_log_internal(spa_t *spa, const char *operation,
|
||||
dmu_tx_t *tx, const char *fmt, ...)
|
||||
{
|
||||
dmu_tx_t *htx = tx;
|
||||
va_list adx;
|
||||
nvlist_t *nvl;
|
||||
|
||||
/* create a tx if we didn't get one */
|
||||
if (tx == NULL) {
|
||||
@@ -477,7 +491,8 @@ spa_history_log_internal(history_internal_events_t event, spa_t *spa,
|
||||
}
|
||||
|
||||
va_start(adx, fmt);
|
||||
log_internal(event, spa, htx, fmt, adx);
|
||||
VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_PUSHPAGE));
|
||||
log_internal(nvl, operation, spa, htx, fmt, adx);
|
||||
va_end(adx);
|
||||
|
||||
/* if we didn't get a tx from the caller, commit the one we made */
|
||||
@@ -486,21 +501,58 @@ spa_history_log_internal(history_internal_events_t event, spa_t *spa,
|
||||
}
|
||||
|
||||
void
|
||||
spa_history_log_version(spa_t *spa, history_internal_events_t event)
|
||||
spa_history_log_internal_ds(dsl_dataset_t *ds, const char *operation,
|
||||
dmu_tx_t *tx, const char *fmt, ...)
|
||||
{
|
||||
va_list adx;
|
||||
char namebuf[MAXNAMELEN];
|
||||
nvlist_t *nvl;
|
||||
|
||||
ASSERT(tx != NULL);
|
||||
|
||||
dsl_dataset_name(ds, namebuf);
|
||||
VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_PUSHPAGE));
|
||||
fnvlist_add_string(nvl, ZPOOL_HIST_DSNAME, namebuf);
|
||||
fnvlist_add_uint64(nvl, ZPOOL_HIST_DSID, ds->ds_object);
|
||||
|
||||
va_start(adx, fmt);
|
||||
log_internal(nvl, operation, dsl_dataset_get_spa(ds), tx, fmt, adx);
|
||||
va_end(adx);
|
||||
}
|
||||
|
||||
void
|
||||
spa_history_log_internal_dd(dsl_dir_t *dd, const char *operation,
|
||||
dmu_tx_t *tx, const char *fmt, ...)
|
||||
{
|
||||
va_list adx;
|
||||
char namebuf[MAXNAMELEN];
|
||||
nvlist_t *nvl;
|
||||
|
||||
ASSERT(tx != NULL);
|
||||
|
||||
dsl_dir_name(dd, namebuf);
|
||||
VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_PUSHPAGE));
|
||||
fnvlist_add_string(nvl, ZPOOL_HIST_DSNAME, namebuf);
|
||||
fnvlist_add_uint64(nvl, ZPOOL_HIST_DSID,
|
||||
dd->dd_phys->dd_head_dataset_obj);
|
||||
|
||||
va_start(adx, fmt);
|
||||
log_internal(nvl, operation, dd->dd_pool->dp_spa, tx, fmt, adx);
|
||||
va_end(adx);
|
||||
}
|
||||
|
||||
void
|
||||
spa_history_log_version(spa_t *spa, const char *operation)
|
||||
{
|
||||
#ifdef _KERNEL
|
||||
uint64_t current_vers = spa_version(spa);
|
||||
|
||||
if (current_vers >= SPA_VERSION_ZPOOL_HISTORY) {
|
||||
spa_history_log_internal(event, spa, NULL,
|
||||
"pool spa %llu; zfs spa %llu; zpl %d; uts %s %s %s %s",
|
||||
(u_longlong_t)current_vers, SPA_VERSION, ZPL_VERSION,
|
||||
utsname.nodename, utsname.release, utsname.version,
|
||||
utsname.machine);
|
||||
}
|
||||
cmn_err(CE_CONT, "!%s version %llu pool %s using %llu",
|
||||
event == LOG_POOL_IMPORT ? "imported" :
|
||||
event == LOG_POOL_CREATE ? "created" : "accessed",
|
||||
spa_history_log_internal(spa, operation, NULL,
|
||||
"pool version %llu; software version %llu/%d; uts %s %s %s %s",
|
||||
(u_longlong_t)current_vers, SPA_VERSION, ZPL_VERSION,
|
||||
utsname.nodename, utsname.release, utsname.version,
|
||||
utsname.machine);
|
||||
cmn_err(CE_CONT, "!%s version %llu pool %s using %llu", operation,
|
||||
(u_longlong_t)current_vers, spa_name(spa), SPA_VERSION);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -632,8 +632,7 @@ zfsctl_snapdir_mkdir(struct inode *dip, char *dirname, vattr_t *vap,
|
||||
goto out;
|
||||
|
||||
if (error == 0) {
|
||||
error = dmu_objset_snapshot(dsname, dirname,
|
||||
NULL, NULL, B_FALSE, B_FALSE, -1);
|
||||
error = dmu_objset_snapshot_one(dsname, dirname);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
|
||||
+1111
-523
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||
*/
|
||||
|
||||
/* Portions Copyright 2010 Robert Milkowski */
|
||||
@@ -1550,9 +1551,8 @@ zfs_set_version(zfs_sb_t *zsb, uint64_t newvers)
|
||||
sa_register_update_callback(os, zfs_sa_upgrade);
|
||||
}
|
||||
|
||||
spa_history_log_internal(LOG_DS_UPGRADE,
|
||||
dmu_objset_spa(os), tx, "oldver=%llu newver=%llu dataset = %llu",
|
||||
zsb->z_version, newvers, dmu_objset_id(os));
|
||||
spa_history_log_internal_ds(dmu_objset_ds(os), "upgrade", tx,
|
||||
"from %llu to %llu", zsb->z_version, newvers);
|
||||
|
||||
dmu_tx_commit(tx);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user