diff options
author | delphij <delphij@FreeBSD.org> | 2014-10-23 01:47:09 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2014-10-23 01:47:09 +0000 |
commit | 29bd84c81d3e415f9d73677a04733b8d318f657b (patch) | |
tree | 5b5c6771a339904801ec2295db65394350bae9a9 /sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c | |
parent | 7b171ea87602a17ebabc9fbbc823d2cfc32fb352 (diff) | |
download | FreeBSD-src-29bd84c81d3e415f9d73677a04733b8d318f657b.zip FreeBSD-src-29bd84c81d3e415f9d73677a04733b8d318f657b.tar.gz |
MFC r272810: FV r272804:
Refactor the code and stop restore_object from creating two transactions.
Illumos issue:
3693 restore_object uses at least two transactions to restore an object
Diffstat (limited to 'sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c')
-rw-r--r-- | sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c | 75 |
1 files changed, 53 insertions, 22 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c index 314e73c..1a0cab5 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_send.c @@ -24,6 +24,7 @@ * Copyright (c) 2011, 2014 by Delphix. All rights reserved. * Copyright (c) 2014, Joyent, Inc. All rights reserved. * Copyright (c) 2012, Martin Matuska <mm@FreeBSD.org>. All rights reserved. + * Copyright 2014 HybridCluster. All rights reserved. */ #include <sys/dmu.h> @@ -1392,12 +1393,25 @@ backup_byteswap(dmu_replay_record_t *drr) #undef DO32 } +static inline uint8_t +deduce_nblkptr(dmu_object_type_t bonus_type, uint64_t bonus_size) +{ + if (bonus_type == DMU_OT_SA) { + return (1); + } else { + return (1 + + ((DN_MAX_BONUSLEN - bonus_size) >> SPA_BLKPTRSHIFT)); + } +} + static int restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) { - int err; + dmu_object_info_t doi; dmu_tx_t *tx; void *data = NULL; + uint64_t object; + int err; if (drro->drr_type == DMU_OT_NONE || !DMU_OT_IS_VALID(drro->drr_type) || @@ -1411,10 +1425,11 @@ restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) return (SET_ERROR(EINVAL)); } - err = dmu_object_info(os, drro->drr_object, NULL); + err = dmu_object_info(os, drro->drr_object, &doi); if (err != 0 && err != ENOENT) return (SET_ERROR(EINVAL)); + object = err == 0 ? drro->drr_object : DMU_NEW_OBJECT; if (drro->drr_bonuslen) { data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8), NULL); @@ -1422,37 +1437,53 @@ restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro) return (ra->err); } - if (err == ENOENT) { - /* currently free, want to be allocated */ - tx = dmu_tx_create(os); - dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT); - err = dmu_tx_assign(tx, TXG_WAIT); - if (err != 0) { - dmu_tx_abort(tx); - return (err); + /* + * If we are losing blkptrs or changing the block size this must + * be a new file instance. We must clear out the previous file + * contents before we can change this type of metadata in the dnode. + */ + if (err == 0) { + int nblkptr; + + nblkptr = deduce_nblkptr(drro->drr_bonustype, + drro->drr_bonuslen); + + if (drro->drr_blksz != doi.doi_data_block_size || + nblkptr < doi.doi_nblkptr) { + err = dmu_free_long_range(os, drro->drr_object, + 0, DMU_OBJECT_END); + if (err != 0) + return (SET_ERROR(EINVAL)); } + } + + tx = dmu_tx_create(os); + dmu_tx_hold_bonus(tx, object); + err = dmu_tx_assign(tx, TXG_WAIT); + if (err != 0) { + dmu_tx_abort(tx); + return (err); + } + + if (object == DMU_NEW_OBJECT) { + /* currently free, want to be allocated */ err = dmu_object_claim(os, drro->drr_object, drro->drr_type, drro->drr_blksz, drro->drr_bonustype, drro->drr_bonuslen, tx); - dmu_tx_commit(tx); - } else { - /* currently allocated, want to be allocated */ + } else if (drro->drr_type != doi.doi_type || + drro->drr_blksz != doi.doi_data_block_size || + drro->drr_bonustype != doi.doi_bonus_type || + drro->drr_bonuslen != doi.doi_bonus_size) { + /* currently allocated, but with different properties */ err = dmu_object_reclaim(os, drro->drr_object, drro->drr_type, drro->drr_blksz, - drro->drr_bonustype, drro->drr_bonuslen); + drro->drr_bonustype, drro->drr_bonuslen, tx); } if (err != 0) { + dmu_tx_commit(tx); return (SET_ERROR(EINVAL)); } - tx = dmu_tx_create(os); - dmu_tx_hold_bonus(tx, drro->drr_object); - err = dmu_tx_assign(tx, TXG_WAIT); - if (err != 0) { - dmu_tx_abort(tx); - return (err); - } - dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksumtype, tx); dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx); |