diff options
author | loli10K <[email protected]> | 2019-09-24 21:01:37 +0200 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2019-09-24 12:01:37 -0700 |
commit | d359e99c38f66732d42278c32d52cfcf1839aa4f (patch) | |
tree | 7206eb4767afe1f831c67f20cb7e77061e5176f8 /module/zfs/dmu_diff.c | |
parent | 73d7820bba26dd61085cb6dd8348ebf0bb41b951 (diff) |
diff_cb() does not handle large dnodes
Trying to 'zfs diff' a snapshot with large dnodes will incorrectly try
to access its interior slots when dnodesize > sizeof(dnode_phys_t).
This is normally not an issue because the interior slots are
zero-filled, which report_dnode() handles calling
report_free_dnode_range(). However this is not the case for encrypted
large dnodes or filesystem using many SA based xattrs where the extra
data past the legacy dnode size boundary is interpreted as a
dnode_phys_t.
Reviewed-by: Brian Behlendorf <[email protected]>
Reviewed-by: Tom Caputi <[email protected]>
Reviewed-by: Ryan Moeller <[email protected]>
Signed-off-by: loli10K <[email protected]>
Closes #7678
Closes #8931
Closes #9343
Diffstat (limited to 'module/zfs/dmu_diff.c')
-rw-r--r-- | module/zfs/dmu_diff.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/module/zfs/dmu_diff.c b/module/zfs/dmu_diff.c index 180f90f94..c40ed57f2 100644 --- a/module/zfs/dmu_diff.c +++ b/module/zfs/dmu_diff.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2019, loli10K <[email protected]>. All rights reserved. */ #include <sys/dmu.h> @@ -131,7 +132,7 @@ diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, dnode_phys_t *blk; arc_buf_t *abuf; arc_flags_t aflags = ARC_FLAG_WAIT; - int blksz = BP_GET_LSIZE(bp); + int epb = BP_GET_LSIZE(bp) >> DNODE_SHIFT; int zio_flags = ZIO_FLAG_CANFAIL; int i; @@ -143,7 +144,7 @@ diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, return (SET_ERROR(EIO)); blk = abuf->b_data; - for (i = 0; i < blksz >> DNODE_SHIFT; i++) { + for (i = 0; i < epb; i += blk[i].dn_extra_slots + 1) { uint64_t dnobj = (zb->zb_blkid << (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i; err = report_dnode(da, dnobj, blk+i); |