diff options
author | Ned Bass <[email protected]> | 2017-07-25 18:52:40 -0700 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2017-07-25 18:52:40 -0700 |
commit | 73aac4aa410121ddcc08bd7fd15d987caf101584 (patch) | |
tree | d3e35cd29385670d859e6b14d78a27fda6bad11e | |
parent | 3f759c0c736d3a636614406ac0d6f9335819d6e9 (diff) |
Some additional send stream validity checking
Check in the DMU whether an object record in a send stream being
received contains an unsupported dnode slot count, and return an
error if it does. Failure to catch an unsupported dnode slot count
would result in a panic when the SPA attempts to increment the
reference count for the large_dnode feature and the pool has the
feature disabled. This is not normally an issue for a well-formed
send stream which would have the DMU_BACKUP_FEATURE_LARGE_DNODE flag
set if it contains large dnodes, so it will be rejected as
unsupported if the required feature is disabled. This change adds a
missing object record field validation.
Add missing stream feature flag checks in
dmu_recv_resume_begin_check().
Consolidate repetitive comment blocks in dmu_recv_begin_check().
Update zstreamdump to print the dnode slot count (dn_slots) for an
object record when running in verbose mode.
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: Giuseppe Di Natale <[email protected]>
Reviewed by: Matthew Ahrens <[email protected]>
Signed-off-by: Ned Bass <[email protected]>
Closes #6396
-rw-r--r-- | cmd/zstreamdump/zstreamdump.c | 6 | ||||
-rw-r--r-- | module/zfs/dmu_send.c | 26 |
2 files changed, 22 insertions, 10 deletions
diff --git a/cmd/zstreamdump/zstreamdump.c b/cmd/zstreamdump/zstreamdump.c index b2f7bfdff..2fe95dfb6 100644 --- a/cmd/zstreamdump/zstreamdump.c +++ b/cmd/zstreamdump/zstreamdump.c @@ -422,12 +422,14 @@ main(int argc, char *argv[]) } if (verbose) { (void) printf("OBJECT object = %llu type = %u " - "bonustype = %u blksz = %u bonuslen = %u\n", + "bonustype = %u blksz = %u bonuslen = %u " + "dn_slots = %u\n", (u_longlong_t)drro->drr_object, drro->drr_type, drro->drr_bonustype, drro->drr_blksz, - drro->drr_bonuslen); + drro->drr_bonuslen, + drro->drr_dn_slots); } if (drro->drr_bonuslen > 0) { (void) ssread(buf, diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c index 7162355d4..eb27b5e71 100644 --- a/module/zfs/dmu_send.c +++ b/module/zfs/dmu_send.c @@ -1428,17 +1428,12 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx) /* * The receiving code doesn't know how to translate large blocks * to smaller ones, so the pool must have the LARGE_BLOCKS - * feature enabled if the stream has LARGE_BLOCKS. + * feature enabled if the stream has LARGE_BLOCKS. Same with + * large dnodes. */ if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) && !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS)) return (SET_ERROR(ENOTSUP)); - - /* - * The receiving code doesn't know how to translate large dnodes - * to smaller ones, so the pool must have the LARGE_DNODE - * feature enabled if the stream has LARGE_DNODE. - */ if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) && !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE)) return (SET_ERROR(ENOTSUP)); @@ -1678,6 +1673,19 @@ dmu_recv_resume_begin_check(void *arg, dmu_tx_t *tx) !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) return (SET_ERROR(ENOTSUP)); + /* + * The receiving code doesn't know how to translate large blocks + * to smaller ones, so the pool must have the LARGE_BLOCKS + * feature enabled if the stream has LARGE_BLOCKS. Same with + * large dnodes. + */ + if ((featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS) && + !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS)) + return (SET_ERROR(ENOTSUP)); + if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) && + !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE)) + return (SET_ERROR(ENOTSUP)); + (void) snprintf(recvname, sizeof (recvname), "%s/%s", tofs, recv_clone_name); @@ -2121,7 +2129,9 @@ receive_object(struct receive_writer_arg *rwa, struct drr_object *drro, drro->drr_blksz < SPA_MINBLOCKSIZE || drro->drr_blksz > spa_maxblocksize(dmu_objset_spa(rwa->os)) || drro->drr_bonuslen > - DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(rwa->os)))) { + DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(rwa->os))) || + drro->drr_dn_slots > + (spa_maxdnodesize(dmu_objset_spa(rwa->os)) >> DNODE_SHIFT)) { return (SET_ERROR(EINVAL)); } |