mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-25 11:47:43 +03:00
OpenZFS 7431 - ZFS Channel Programs
Authored by: Chris Williamson <chris.williamson@delphix.com> Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: John Kennedy <john.kennedy@delphix.com> Reviewed by: Dan Kimmel <dan.kimmel@delphix.com> Approved by: Garrett D'Amore <garrett@damore.org> Ported-by: Don Brady <don.brady@delphix.com> Ported-by: John Kennedy <john.kennedy@delphix.com> OpenZFS-issue: https://www.illumos.org/issues/7431 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/dfc11533 Porting Notes: * The CLI long option arguments for '-t' and '-m' don't parse on linux * Switched from kmem_alloc to vmem_alloc in zcp_lua_alloc * Lua implementation is built as its own module (zlua.ko) * Lua headers consumed directly by zfs code moved to 'include/sys/lua/' * There is no native setjmp/longjump available in stock Linux kernel. Brought over implementations from illumos and FreeBSD * The get_temporary_prop() was adapted due to VFS platform differences * Use of inline functions in lua parser to reduce stack usage per C call * Skip some ZFS Test Suite ZCP tests on sparc64 to avoid stack overflow
This commit is contained in:
committed by
Brian Behlendorf
parent
8824a7f133
commit
d99a015343
+400
-103
@@ -1681,7 +1681,6 @@ dsl_dataset_snapshot_tmp(const char *fsname, const char *snapname,
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
|
||||
{
|
||||
@@ -1749,29 +1748,16 @@ dsl_dataset_sync_done(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
dmu_buf_rele(ds->ds_dbuf, ds);
|
||||
}
|
||||
|
||||
static void
|
||||
get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
int
|
||||
get_clones_stat_impl(dsl_dataset_t *ds, nvlist_t *val)
|
||||
{
|
||||
uint64_t count = 0;
|
||||
objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
|
||||
zap_cursor_t zc;
|
||||
zap_attribute_t za;
|
||||
nvlist_t *propval = fnvlist_alloc();
|
||||
nvlist_t *val;
|
||||
|
||||
ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
|
||||
|
||||
/*
|
||||
* We use nvlist_alloc() instead of fnvlist_alloc() because the
|
||||
* latter would allocate the list with NV_UNIQUE_NAME flag.
|
||||
* As a result, every time a clone name is appended to the list
|
||||
* it would be (linearly) searched for for a duplicate name.
|
||||
* We already know that all clone names must be unique and we
|
||||
* want avoid the quadratic complexity of double-checking that
|
||||
* because we can have a large number of clones.
|
||||
*/
|
||||
VERIFY0(nvlist_alloc(&val, 0, KM_SLEEP));
|
||||
|
||||
/*
|
||||
* There may be missing entries in ds_next_clones_obj
|
||||
* due to a bug in a previous version of the code.
|
||||
@@ -1781,8 +1767,9 @@ get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
VERIFY0(zap_count(mos, dsl_dataset_phys(ds)->ds_next_clones_obj,
|
||||
&count));
|
||||
}
|
||||
if (count != dsl_dataset_phys(ds)->ds_num_children - 1)
|
||||
goto fail;
|
||||
if (count != dsl_dataset_phys(ds)->ds_num_children - 1) {
|
||||
return (ENOENT);
|
||||
}
|
||||
for (zap_cursor_init(&zc, mos,
|
||||
dsl_dataset_phys(ds)->ds_next_clones_obj);
|
||||
zap_cursor_retrieve(&zc, &za) == 0;
|
||||
@@ -1796,15 +1783,42 @@ get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
dsl_dataset_rele(clone, FTAG);
|
||||
}
|
||||
zap_cursor_fini(&zc);
|
||||
fnvlist_add_nvlist(propval, ZPROP_VALUE, val);
|
||||
fnvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES), propval);
|
||||
fail:
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
{
|
||||
nvlist_t *propval = fnvlist_alloc();
|
||||
nvlist_t *val;
|
||||
|
||||
/*
|
||||
* We use nvlist_alloc() instead of fnvlist_alloc() because the
|
||||
* latter would allocate the list with NV_UNIQUE_NAME flag.
|
||||
* As a result, every time a clone name is appended to the list
|
||||
* it would be (linearly) searched for for a duplicate name.
|
||||
* We already know that all clone names must be unique and we
|
||||
* want avoid the quadratic complexity of double-checking that
|
||||
* because we can have a large number of clones.
|
||||
*/
|
||||
VERIFY0(nvlist_alloc(&val, 0, KM_SLEEP));
|
||||
|
||||
if (get_clones_stat_impl(ds, val) == 0) {
|
||||
fnvlist_add_nvlist(propval, ZPROP_VALUE, val);
|
||||
fnvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES),
|
||||
propval);
|
||||
}
|
||||
|
||||
nvlist_free(val);
|
||||
nvlist_free(propval);
|
||||
}
|
||||
|
||||
static void
|
||||
get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
/*
|
||||
* Returns a string that represents the receive resume stats token. It should
|
||||
* be freed with strfree().
|
||||
*/
|
||||
char *
|
||||
get_receive_resume_stats_impl(dsl_dataset_t *ds)
|
||||
{
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
|
||||
@@ -1876,86 +1890,361 @@ get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
ZFS_SEND_RESUME_TOKEN_VERSION,
|
||||
(longlong_t)cksum.zc_word[0],
|
||||
(longlong_t)packed_size, str);
|
||||
dsl_prop_nvlist_add_string(nv,
|
||||
ZFS_PROP_RECEIVE_RESUME_TOKEN, propval);
|
||||
kmem_free(packed, packed_size);
|
||||
kmem_free(str, compressed_size * 2 + 1);
|
||||
kmem_free(compressed, packed_size);
|
||||
strfree(propval);
|
||||
return (propval);
|
||||
}
|
||||
return (strdup(""));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a string that represents the receive resume stats token of the
|
||||
* dataset's child. It should be freed with strfree().
|
||||
*/
|
||||
char *
|
||||
get_child_receive_stats(dsl_dataset_t *ds)
|
||||
{
|
||||
char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
|
||||
dsl_dataset_t *recv_ds;
|
||||
dsl_dataset_name(ds, recvname);
|
||||
if (strlcat(recvname, "/", sizeof (recvname)) <
|
||||
sizeof (recvname) &&
|
||||
strlcat(recvname, recv_clone_name, sizeof (recvname)) <
|
||||
sizeof (recvname) &&
|
||||
dsl_dataset_hold(ds->ds_dir->dd_pool, recvname, FTAG,
|
||||
&recv_ds) == 0) {
|
||||
char *propval = get_receive_resume_stats_impl(recv_ds);
|
||||
dsl_dataset_rele(recv_ds, FTAG);
|
||||
return (propval);
|
||||
}
|
||||
return (strdup(""));
|
||||
}
|
||||
|
||||
static void
|
||||
get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
{
|
||||
char *propval = get_receive_resume_stats_impl(ds);
|
||||
if (strcmp(propval, "") != 0) {
|
||||
dsl_prop_nvlist_add_string(nv,
|
||||
ZFS_PROP_RECEIVE_RESUME_TOKEN, propval);
|
||||
} else {
|
||||
char *childval = get_child_receive_stats(ds);
|
||||
if (strcmp(childval, "") != 0) {
|
||||
dsl_prop_nvlist_add_string(nv,
|
||||
ZFS_PROP_RECEIVE_RESUME_TOKEN, childval);
|
||||
}
|
||||
strfree(childval);
|
||||
}
|
||||
strfree(propval);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_refratio(dsl_dataset_t *ds)
|
||||
{
|
||||
uint64_t ratio = dsl_dataset_phys(ds)->ds_compressed_bytes == 0 ? 100 :
|
||||
(dsl_dataset_phys(ds)->ds_uncompressed_bytes * 100 /
|
||||
dsl_dataset_phys(ds)->ds_compressed_bytes);
|
||||
return (ratio);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_logicalreferenced(dsl_dataset_t *ds)
|
||||
{
|
||||
return (dsl_dataset_phys(ds)->ds_uncompressed_bytes);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_compressratio(dsl_dataset_t *ds)
|
||||
{
|
||||
if (ds->ds_is_snapshot) {
|
||||
return (dsl_get_refratio(ds));
|
||||
} else {
|
||||
dsl_dir_t *dd = ds->ds_dir;
|
||||
mutex_enter(&dd->dd_lock);
|
||||
uint64_t val = dsl_dir_get_compressratio(dd);
|
||||
mutex_exit(&dd->dd_lock);
|
||||
return (val);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_used(dsl_dataset_t *ds)
|
||||
{
|
||||
if (ds->ds_is_snapshot) {
|
||||
return (dsl_dataset_phys(ds)->ds_unique_bytes);
|
||||
} else {
|
||||
dsl_dir_t *dd = ds->ds_dir;
|
||||
mutex_enter(&dd->dd_lock);
|
||||
uint64_t val = dsl_dir_get_used(dd);
|
||||
mutex_exit(&dd->dd_lock);
|
||||
return (val);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_creation(dsl_dataset_t *ds)
|
||||
{
|
||||
return (dsl_dataset_phys(ds)->ds_creation_time);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_creationtxg(dsl_dataset_t *ds)
|
||||
{
|
||||
return (dsl_dataset_phys(ds)->ds_creation_txg);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_refquota(dsl_dataset_t *ds)
|
||||
{
|
||||
return (ds->ds_quota);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_refreservation(dsl_dataset_t *ds)
|
||||
{
|
||||
return (ds->ds_reserved);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_guid(dsl_dataset_t *ds)
|
||||
{
|
||||
return (dsl_dataset_phys(ds)->ds_guid);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_unique(dsl_dataset_t *ds)
|
||||
{
|
||||
return (dsl_dataset_phys(ds)->ds_unique_bytes);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_objsetid(dsl_dataset_t *ds)
|
||||
{
|
||||
return (ds->ds_object);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_userrefs(dsl_dataset_t *ds)
|
||||
{
|
||||
return (ds->ds_userrefs);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_defer_destroy(dsl_dataset_t *ds)
|
||||
{
|
||||
return (DS_IS_DEFER_DESTROY(ds) ? 1 : 0);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_referenced(dsl_dataset_t *ds)
|
||||
{
|
||||
return (dsl_dataset_phys(ds)->ds_referenced_bytes);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_numclones(dsl_dataset_t *ds)
|
||||
{
|
||||
ASSERT(ds->ds_is_snapshot);
|
||||
return (dsl_dataset_phys(ds)->ds_num_children - 1);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_inconsistent(dsl_dataset_t *ds)
|
||||
{
|
||||
return ((dsl_dataset_phys(ds)->ds_flags & DS_FLAG_INCONSISTENT) ?
|
||||
1 : 0);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
dsl_get_available(dsl_dataset_t *ds)
|
||||
{
|
||||
uint64_t refdbytes = dsl_get_referenced(ds);
|
||||
uint64_t availbytes = dsl_dir_space_available(ds->ds_dir,
|
||||
NULL, 0, TRUE);
|
||||
if (ds->ds_reserved > dsl_dataset_phys(ds)->ds_unique_bytes) {
|
||||
availbytes +=
|
||||
ds->ds_reserved - dsl_dataset_phys(ds)->ds_unique_bytes;
|
||||
}
|
||||
if (ds->ds_quota != 0) {
|
||||
/*
|
||||
* Adjust available bytes according to refquota
|
||||
*/
|
||||
if (refdbytes < ds->ds_quota) {
|
||||
availbytes = MIN(availbytes,
|
||||
ds->ds_quota - refdbytes);
|
||||
} else {
|
||||
availbytes = 0;
|
||||
}
|
||||
}
|
||||
return (availbytes);
|
||||
}
|
||||
|
||||
int
|
||||
dsl_get_written(dsl_dataset_t *ds, uint64_t *written)
|
||||
{
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
dsl_dataset_t *prev;
|
||||
int err = dsl_dataset_hold_obj(dp,
|
||||
dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &prev);
|
||||
if (err == 0) {
|
||||
uint64_t comp, uncomp;
|
||||
err = dsl_dataset_space_written(prev, ds, written,
|
||||
&comp, &uncomp);
|
||||
dsl_dataset_rele(prev, FTAG);
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* 'snap' should be a buffer of size ZFS_MAX_DATASET_NAME_LEN.
|
||||
*/
|
||||
int
|
||||
dsl_get_prev_snap(dsl_dataset_t *ds, char *snap)
|
||||
{
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
if (ds->ds_prev != NULL && ds->ds_prev != dp->dp_origin_snap) {
|
||||
dsl_dataset_name(ds->ds_prev, snap);
|
||||
return (0);
|
||||
} else {
|
||||
return (ENOENT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the mountpoint property and source for the given dataset in the value
|
||||
* and source buffers. The value buffer must be at least as large as MAXPATHLEN
|
||||
* and the source buffer as least as large a ZFS_MAX_DATASET_NAME_LEN.
|
||||
* Returns 0 on success and an error on failure.
|
||||
*/
|
||||
int
|
||||
dsl_get_mountpoint(dsl_dataset_t *ds, const char *dsname, char *value,
|
||||
char *source)
|
||||
{
|
||||
int error;
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
|
||||
/* Retrieve the mountpoint value stored in the zap opbject */
|
||||
error = dsl_prop_get_ds(ds, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), 1,
|
||||
ZAP_MAXVALUELEN, value, source);
|
||||
if (error != 0) {
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the dsname and source to find the full mountpoint string.
|
||||
* Can be skipped for 'legacy' or 'none'.
|
||||
*/
|
||||
if (value[0] == '/') {
|
||||
char *buf = kmem_alloc(ZAP_MAXVALUELEN, KM_SLEEP);
|
||||
char *root = buf;
|
||||
const char *relpath;
|
||||
|
||||
/*
|
||||
* If we inherit the mountpoint, even from a dataset
|
||||
* with a received value, the source will be the path of
|
||||
* the dataset we inherit from. If source is
|
||||
* ZPROP_SOURCE_VAL_RECVD, the received value is not
|
||||
* inherited.
|
||||
*/
|
||||
if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) {
|
||||
relpath = "";
|
||||
} else {
|
||||
ASSERT0(strncmp(dsname, source, strlen(source)));
|
||||
relpath = dsname + strlen(source);
|
||||
if (relpath[0] == '/')
|
||||
relpath++;
|
||||
}
|
||||
|
||||
spa_altroot(dp->dp_spa, root, ZAP_MAXVALUELEN);
|
||||
|
||||
/*
|
||||
* Special case an alternate root of '/'. This will
|
||||
* avoid having multiple leading slashes in the
|
||||
* mountpoint path.
|
||||
*/
|
||||
if (strcmp(root, "/") == 0)
|
||||
root++;
|
||||
|
||||
/*
|
||||
* If the mountpoint is '/' then skip over this
|
||||
* if we are obtaining either an alternate root or
|
||||
* an inherited mountpoint.
|
||||
*/
|
||||
char *mnt = value;
|
||||
if (value[1] == '\0' && (root[0] != '\0' ||
|
||||
relpath[0] != '\0'))
|
||||
mnt = value + 1;
|
||||
|
||||
if (relpath[0] == '\0') {
|
||||
(void) snprintf(value, ZAP_MAXVALUELEN, "%s%s",
|
||||
root, mnt);
|
||||
} else {
|
||||
(void) snprintf(value, ZAP_MAXVALUELEN, "%s%s%s%s",
|
||||
root, mnt, relpath[0] == '@' ? "" : "/",
|
||||
relpath);
|
||||
}
|
||||
kmem_free(buf, ZAP_MAXVALUELEN);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
{
|
||||
int err;
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
uint64_t refd, avail, uobjs, aobjs, ratio;
|
||||
|
||||
ASSERT(dsl_pool_config_held(dp));
|
||||
|
||||
ratio = dsl_dataset_phys(ds)->ds_compressed_bytes == 0 ? 100 :
|
||||
(dsl_dataset_phys(ds)->ds_uncompressed_bytes * 100 /
|
||||
dsl_dataset_phys(ds)->ds_compressed_bytes);
|
||||
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio);
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO,
|
||||
dsl_get_refratio(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_LOGICALREFERENCED,
|
||||
dsl_dataset_phys(ds)->ds_uncompressed_bytes);
|
||||
dsl_get_logicalreferenced(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO,
|
||||
dsl_get_compressratio(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
|
||||
dsl_get_used(ds));
|
||||
|
||||
if (ds->ds_is_snapshot) {
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio);
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
|
||||
dsl_dataset_phys(ds)->ds_unique_bytes);
|
||||
get_clones_stat(ds, nv);
|
||||
} else {
|
||||
if (ds->ds_prev != NULL && ds->ds_prev != dp->dp_origin_snap) {
|
||||
char buf[ZFS_MAX_DATASET_NAME_LEN];
|
||||
dsl_dataset_name(ds->ds_prev, buf);
|
||||
dsl_prop_nvlist_add_string(nv, ZFS_PROP_PREV_SNAP, buf);
|
||||
}
|
||||
|
||||
char buf[ZFS_MAX_DATASET_NAME_LEN];
|
||||
if (dsl_get_prev_snap(ds, buf) == 0)
|
||||
dsl_prop_nvlist_add_string(nv, ZFS_PROP_PREV_SNAP,
|
||||
buf);
|
||||
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);
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd);
|
||||
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE,
|
||||
dsl_get_available(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED,
|
||||
dsl_get_referenced(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION,
|
||||
dsl_dataset_phys(ds)->ds_creation_time);
|
||||
dsl_get_creation(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG,
|
||||
dsl_dataset_phys(ds)->ds_creation_txg);
|
||||
dsl_get_creationtxg(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA,
|
||||
ds->ds_quota);
|
||||
dsl_get_refquota(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION,
|
||||
ds->ds_reserved);
|
||||
dsl_get_refreservation(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID,
|
||||
dsl_dataset_phys(ds)->ds_guid);
|
||||
dsl_get_guid(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_UNIQUE,
|
||||
dsl_dataset_phys(ds)->ds_unique_bytes);
|
||||
dsl_get_unique(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID,
|
||||
ds->ds_object);
|
||||
dsl_get_objsetid(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS,
|
||||
ds->ds_userrefs);
|
||||
dsl_get_userrefs(ds));
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY,
|
||||
DS_IS_DEFER_DESTROY(ds) ? 1 : 0);
|
||||
dsl_get_defer_destroy(ds));
|
||||
dsl_dataset_crypt_stats(ds, nv);
|
||||
|
||||
if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
|
||||
uint64_t written, comp, uncomp;
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
dsl_dataset_t *prev;
|
||||
|
||||
err = dsl_dataset_hold_obj(dp,
|
||||
dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &prev);
|
||||
if (err == 0) {
|
||||
err = dsl_dataset_space_written(prev, ds, &written,
|
||||
&comp, &uncomp);
|
||||
dsl_dataset_rele(prev, FTAG);
|
||||
if (err == 0) {
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN,
|
||||
written);
|
||||
}
|
||||
uint64_t written;
|
||||
if (dsl_get_written(ds, &written) == 0) {
|
||||
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN,
|
||||
written);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1989,30 +2278,22 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
void
|
||||
dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat)
|
||||
{
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
ASSERTV(dsl_pool_t *dp = ds->ds_dir->dd_pool);
|
||||
ASSERT(dsl_pool_config_held(dp));
|
||||
|
||||
stat->dds_creation_txg = dsl_dataset_phys(ds)->ds_creation_txg;
|
||||
stat->dds_inconsistent =
|
||||
dsl_dataset_phys(ds)->ds_flags & DS_FLAG_INCONSISTENT;
|
||||
stat->dds_guid = dsl_dataset_phys(ds)->ds_guid;
|
||||
stat->dds_creation_txg = dsl_get_creationtxg(ds);
|
||||
stat->dds_inconsistent = dsl_get_inconsistent(ds);
|
||||
stat->dds_guid = dsl_get_guid(ds);
|
||||
stat->dds_origin[0] = '\0';
|
||||
if (ds->ds_is_snapshot) {
|
||||
stat->dds_is_snapshot = B_TRUE;
|
||||
stat->dds_num_clones =
|
||||
dsl_dataset_phys(ds)->ds_num_children - 1;
|
||||
stat->dds_num_clones = dsl_get_numclones(ds);
|
||||
} else {
|
||||
stat->dds_is_snapshot = B_FALSE;
|
||||
stat->dds_num_clones = 0;
|
||||
|
||||
if (dsl_dir_is_clone(ds->ds_dir)) {
|
||||
dsl_dataset_t *ods;
|
||||
|
||||
VERIFY0(dsl_dataset_hold_obj(dp,
|
||||
dsl_dir_phys(ds->ds_dir)->dd_origin_obj,
|
||||
FTAG, &ods));
|
||||
dsl_dataset_name(ods, stat->dds_origin);
|
||||
dsl_dataset_rele(ods, FTAG);
|
||||
dsl_dir_get_origin(ds->ds_dir, stat->dds_origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2422,22 +2703,12 @@ struct promotenode {
|
||||
dsl_dataset_t *ds;
|
||||
};
|
||||
|
||||
typedef struct dsl_dataset_promote_arg {
|
||||
const char *ddpa_clonename;
|
||||
dsl_dataset_t *ddpa_clone;
|
||||
list_t shared_snaps, origin_snaps, clone_snaps;
|
||||
dsl_dataset_t *origin_origin; /* origin of the origin */
|
||||
uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap;
|
||||
char *err_ds;
|
||||
cred_t *cr;
|
||||
} dsl_dataset_promote_arg_t;
|
||||
|
||||
static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep);
|
||||
static int promote_hold(dsl_dataset_promote_arg_t *ddpa, dsl_pool_t *dp,
|
||||
void *tag);
|
||||
static void promote_rele(dsl_dataset_promote_arg_t *ddpa, void *tag);
|
||||
|
||||
static int
|
||||
int
|
||||
dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_promote_arg_t *ddpa = arg;
|
||||
@@ -2449,14 +2720,19 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
|
||||
uint64_t unused;
|
||||
uint64_t ss_mv_cnt;
|
||||
size_t max_snap_len;
|
||||
boolean_t conflicting_snaps;
|
||||
|
||||
err = promote_hold(ddpa, dp, FTAG);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
hds = ddpa->ddpa_clone;
|
||||
snap = list_head(&ddpa->shared_snaps);
|
||||
origin_ds = snap->ds;
|
||||
max_snap_len = MAXNAMELEN - strlen(ddpa->ddpa_clonename) - 1;
|
||||
|
||||
snap = list_head(&ddpa->origin_snaps);
|
||||
|
||||
if (dsl_dataset_phys(hds)->ds_flags & DS_FLAG_NOPROMOTE) {
|
||||
promote_rele(ddpa, FTAG);
|
||||
return (SET_ERROR(EXDEV));
|
||||
@@ -2511,6 +2787,7 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
|
||||
* Note however, if we stop before we reach the ORIGIN we get:
|
||||
* uN + kN + kN-1 + ... + kM - uM-1
|
||||
*/
|
||||
conflicting_snaps = B_FALSE;
|
||||
ss_mv_cnt = 0;
|
||||
ddpa->used = dsl_dataset_phys(origin_ds)->ds_referenced_bytes;
|
||||
ddpa->comp = dsl_dataset_phys(origin_ds)->ds_compressed_bytes;
|
||||
@@ -2539,12 +2816,12 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
|
||||
}
|
||||
err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val);
|
||||
if (err == 0) {
|
||||
(void) strcpy(ddpa->err_ds, snap->ds->ds_snapname);
|
||||
err = SET_ERROR(EEXIST);
|
||||
fnvlist_add_boolean(ddpa->err_ds,
|
||||
snap->ds->ds_snapname);
|
||||
conflicting_snaps = B_TRUE;
|
||||
} else if (err != ENOENT) {
|
||||
goto out;
|
||||
}
|
||||
if (err != ENOENT)
|
||||
goto out;
|
||||
|
||||
/* The very first snapshot does not have a deadlist */
|
||||
if (dsl_dataset_phys(ds)->ds_prev_snap_obj == 0)
|
||||
@@ -2557,6 +2834,15 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
|
||||
ddpa->uncomp += dluncomp;
|
||||
}
|
||||
|
||||
/*
|
||||
* In order to return the full list of conflicting snapshots, we check
|
||||
* whether there was a conflict after traversing all of them.
|
||||
*/
|
||||
if (conflicting_snaps) {
|
||||
err = SET_ERROR(EEXIST);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are a clone of a clone then we never reached ORIGIN,
|
||||
* so we need to subtract out the clone origin's used space.
|
||||
@@ -2623,7 +2909,7 @@ out:
|
||||
return (err);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
dsl_dataset_promote_sync(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
dsl_dataset_promote_arg_t *ddpa = arg;
|
||||
@@ -2950,6 +3236,7 @@ dsl_dataset_promote(const char *name, char *conflsnap)
|
||||
dsl_dataset_promote_arg_t ddpa = { 0 };
|
||||
uint64_t numsnaps;
|
||||
int error;
|
||||
nvpair_t *snap_pair;
|
||||
objset_t *os;
|
||||
|
||||
/*
|
||||
@@ -2967,12 +3254,22 @@ dsl_dataset_promote(const char *name, char *conflsnap)
|
||||
return (error);
|
||||
|
||||
ddpa.ddpa_clonename = name;
|
||||
ddpa.err_ds = conflsnap;
|
||||
ddpa.err_ds = fnvlist_alloc();
|
||||
ddpa.cr = CRED();
|
||||
|
||||
return (dsl_sync_task(name, dsl_dataset_promote_check,
|
||||
error = dsl_sync_task(name, dsl_dataset_promote_check,
|
||||
dsl_dataset_promote_sync, &ddpa,
|
||||
2 + numsnaps, ZFS_SPACE_CHECK_RESERVED));
|
||||
2 + numsnaps, ZFS_SPACE_CHECK_RESERVED);
|
||||
|
||||
/*
|
||||
* Return the first conflicting snapshot found.
|
||||
*/
|
||||
snap_pair = nvlist_next_nvpair(ddpa.err_ds, NULL);
|
||||
if (snap_pair != NULL && conflsnap != NULL)
|
||||
(void) strcpy(conflsnap, nvpair_name(snap_pair));
|
||||
|
||||
fnvlist_free(ddpa.err_ds);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
Reference in New Issue
Block a user