mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-26 04:07:45 +03:00
OpenZFS 2605, 6980, 6902
2605 want to resume interrupted zfs send Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: Richard Elling <Richard.Elling@RichardElling.com> Reviewed by: Xin Li <delphij@freebsd.org> Reviewed by: Arne Jansen <sensille@gmx.net> Approved by: Dan McDonald <danmcd@omniti.com> Ported-by: kernelOfTruth <kerneloftruth@gmail.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> OpenZFS-issue: https://www.illumos.org/issues/2605 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/9c3fd12 6980 6902 causes zfs send to break due to 32-bit/64-bit struct mismatch Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Approved by: Robert Mustacchi <rm@joyent.com> Ported by: Brian Behlendorf <behlendorf1@llnl.gov> OpenZFS-issue: https://www.illumos.org/issues/6980 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/ea4a67f Porting notes: - All rsend and snapshop tests enabled and updated for Linux. - Fix misuse of input argument in traverse_visitbp(). - Fix ISO C90 warnings and errors. - Fix gcc 'missing braces around initializer' in 'struct send_thread_arg to_arg =' warning. - Replace 4 argument fletcher_4_native() with 3 argument version, this change was made in OpenZFS 4185 which has not been ported. - Part of the sections for 'zfs receive' and 'zfs send' was rewritten and reordered to approximate upstream. - Fix mktree xattr creation, 'user.' prefix required. - Minor fixes to newly enabled test cases - Long holds for volumes allowed during receive for minor registration.
This commit is contained in:
committed by
Brian Behlendorf
parent
669cf0ab29
commit
47dfff3b86
+144
-2
@@ -52,6 +52,9 @@
|
||||
#include <sys/dsl_userhold.h>
|
||||
#include <sys/dsl_bookmark.h>
|
||||
#include <sys/policy.h>
|
||||
#include <sys/dmu_send.h>
|
||||
#include <sys/zio_compress.h>
|
||||
#include <zfs_fletcher.h>
|
||||
|
||||
/*
|
||||
* The SPA supports block sizes up to 16MB. However, very large blocks
|
||||
@@ -704,6 +707,7 @@ dsl_dataset_tryown(dsl_dataset_t *ds, void *tag)
|
||||
{
|
||||
boolean_t gotit = FALSE;
|
||||
|
||||
ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
|
||||
mutex_enter(&ds->ds_lock);
|
||||
if (ds->ds_owner == NULL && !DS_IS_INCONSISTENT(ds)) {
|
||||
ds->ds_owner = tag;
|
||||
@@ -714,6 +718,16 @@ dsl_dataset_tryown(dsl_dataset_t *ds, void *tag)
|
||||
return (gotit);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
dsl_dataset_has_owner(dsl_dataset_t *ds)
|
||||
{
|
||||
boolean_t rv;
|
||||
mutex_enter(&ds->ds_lock);
|
||||
rv = (ds->ds_owner != NULL);
|
||||
mutex_exit(&ds->ds_lock);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
static void
|
||||
dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, dmu_tx_t *tx)
|
||||
{
|
||||
@@ -1615,6 +1629,21 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
|
||||
dmu_buf_will_dirty(ds->ds_dbuf, tx);
|
||||
dsl_dataset_phys(ds)->ds_fsid_guid = ds->ds_fsid_guid;
|
||||
|
||||
if (ds->ds_resume_bytes[tx->tx_txg & TXG_MASK] != 0) {
|
||||
VERIFY0(zap_update(tx->tx_pool->dp_meta_objset,
|
||||
ds->ds_object, DS_FIELD_RESUME_OBJECT, 8, 1,
|
||||
&ds->ds_resume_object[tx->tx_txg & TXG_MASK], tx));
|
||||
VERIFY0(zap_update(tx->tx_pool->dp_meta_objset,
|
||||
ds->ds_object, DS_FIELD_RESUME_OFFSET, 8, 1,
|
||||
&ds->ds_resume_offset[tx->tx_txg & TXG_MASK], tx));
|
||||
VERIFY0(zap_update(tx->tx_pool->dp_meta_objset,
|
||||
ds->ds_object, DS_FIELD_RESUME_BYTES, 8, 1,
|
||||
&ds->ds_resume_bytes[tx->tx_txg & TXG_MASK], tx));
|
||||
ds->ds_resume_object[tx->tx_txg & TXG_MASK] = 0;
|
||||
ds->ds_resume_offset[tx->tx_txg & TXG_MASK] = 0;
|
||||
ds->ds_resume_bytes[tx->tx_txg & TXG_MASK] = 0;
|
||||
}
|
||||
|
||||
dmu_objset_sync(ds->ds_objset, zio, tx);
|
||||
|
||||
for (f = 0; f < SPA_FEATURES; f++) {
|
||||
@@ -1670,6 +1699,78 @@ fail:
|
||||
nvlist_free(propval);
|
||||
}
|
||||
|
||||
static void
|
||||
get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
{
|
||||
dsl_pool_t *dp = ds->ds_dir->dd_pool;
|
||||
|
||||
if (dsl_dataset_has_resume_receive_state(ds)) {
|
||||
char *str;
|
||||
void *packed;
|
||||
uint8_t *compressed;
|
||||
uint64_t val;
|
||||
nvlist_t *token_nv = fnvlist_alloc();
|
||||
size_t packed_size, compressed_size;
|
||||
zio_cksum_t cksum;
|
||||
char *propval;
|
||||
char buf[MAXNAMELEN];
|
||||
int i;
|
||||
|
||||
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
|
||||
DS_FIELD_RESUME_FROMGUID, sizeof (val), 1, &val) == 0) {
|
||||
fnvlist_add_uint64(token_nv, "fromguid", val);
|
||||
}
|
||||
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
|
||||
DS_FIELD_RESUME_OBJECT, sizeof (val), 1, &val) == 0) {
|
||||
fnvlist_add_uint64(token_nv, "object", val);
|
||||
}
|
||||
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
|
||||
DS_FIELD_RESUME_OFFSET, sizeof (val), 1, &val) == 0) {
|
||||
fnvlist_add_uint64(token_nv, "offset", val);
|
||||
}
|
||||
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
|
||||
DS_FIELD_RESUME_BYTES, sizeof (val), 1, &val) == 0) {
|
||||
fnvlist_add_uint64(token_nv, "bytes", val);
|
||||
}
|
||||
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
|
||||
DS_FIELD_RESUME_TOGUID, sizeof (val), 1, &val) == 0) {
|
||||
fnvlist_add_uint64(token_nv, "toguid", val);
|
||||
}
|
||||
if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
|
||||
DS_FIELD_RESUME_TONAME, 1, sizeof (buf), buf) == 0) {
|
||||
fnvlist_add_string(token_nv, "toname", buf);
|
||||
}
|
||||
if (zap_contains(dp->dp_meta_objset, ds->ds_object,
|
||||
DS_FIELD_RESUME_EMBEDOK) == 0) {
|
||||
fnvlist_add_boolean(token_nv, "embedok");
|
||||
}
|
||||
packed = fnvlist_pack(token_nv, &packed_size);
|
||||
fnvlist_free(token_nv);
|
||||
compressed = kmem_alloc(packed_size, KM_SLEEP);
|
||||
|
||||
compressed_size = gzip_compress(packed, compressed,
|
||||
packed_size, packed_size, 6);
|
||||
|
||||
fletcher_4_native(compressed, compressed_size, &cksum);
|
||||
|
||||
str = kmem_alloc(compressed_size * 2 + 1, KM_SLEEP);
|
||||
for (i = 0; i < compressed_size; i++) {
|
||||
(void) sprintf(str + i * 2, "%02x", compressed[i]);
|
||||
}
|
||||
str[compressed_size * 2] = '\0';
|
||||
propval = kmem_asprintf("%u-%llx-%llx-%s",
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
{
|
||||
@@ -1743,6 +1844,29 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
|
||||
}
|
||||
}
|
||||
|
||||
if (!dsl_dataset_is_snapshot(ds)) {
|
||||
dsl_dataset_t *recv_ds;
|
||||
char recvname[ZFS_MAXNAMELEN];
|
||||
|
||||
/*
|
||||
* A failed "newfs" (e.g. full) resumable receive leaves
|
||||
* the stats set on this dataset. Check here for the prop.
|
||||
*/
|
||||
get_receive_resume_stats(ds, nv);
|
||||
|
||||
/*
|
||||
* A failed incremental resumable receive leaves the
|
||||
* stats set on our child named "%recv". Check the child
|
||||
* for the prop.
|
||||
*/
|
||||
dsl_dataset_name(ds, recvname);
|
||||
(void) strcat(recvname, "/");
|
||||
(void) strcat(recvname, recv_clone_name);
|
||||
if (dsl_dataset_hold(dp, recvname, FTAG, &recv_ds) == 0) {
|
||||
get_receive_resume_stats(recv_ds, nv);
|
||||
dsl_dataset_rele(recv_ds, FTAG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1970,7 +2094,8 @@ dsl_dataset_rename_snapshot(const char *fsname,
|
||||
* only one long hold on the dataset. We're not allowed to change anything here
|
||||
* so we don't permanently release the long hold or regular hold here. We want
|
||||
* to do this only when syncing to avoid the dataset unexpectedly going away
|
||||
* when we release the long hold.
|
||||
* when we release the long hold. Allow a long hold to exist for volumes, this
|
||||
* may occur when asynchronously registering the minor with the kernel.
|
||||
*/
|
||||
static int
|
||||
dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx)
|
||||
@@ -1985,7 +2110,7 @@ dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx)
|
||||
dsl_dataset_long_rele(ds, owner);
|
||||
}
|
||||
|
||||
held = dsl_dataset_long_held(ds);
|
||||
held = (dsl_dataset_long_held(ds) && (ds->ds_owner != zvol_tag));
|
||||
|
||||
if (owner != NULL)
|
||||
dsl_dataset_long_hold(ds, owner);
|
||||
@@ -3391,6 +3516,23 @@ dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
dmu_object_zapify(mos, ds->ds_object, DMU_OT_DSL_DATASET, tx);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
dsl_dataset_is_zapified(dsl_dataset_t *ds)
|
||||
{
|
||||
dmu_object_info_t doi;
|
||||
|
||||
dmu_object_info_from_db(ds->ds_dbuf, &doi);
|
||||
return (doi.doi_type == DMU_OTN_ZAP_METADATA);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
dsl_dataset_has_resume_receive_state(dsl_dataset_t *ds)
|
||||
{
|
||||
return (dsl_dataset_is_zapified(ds) &&
|
||||
zap_contains(ds->ds_dir->dd_pool->dp_meta_objset,
|
||||
ds->ds_object, DS_FIELD_RESUME_TOGUID) == 0);
|
||||
}
|
||||
|
||||
#if defined(_KERNEL) && defined(HAVE_SPL)
|
||||
#if defined(_LP64)
|
||||
module_param(zfs_max_recordsize, int, 0644);
|
||||
|
||||
Reference in New Issue
Block a user