aboutsummaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorRichard Yao <[email protected]>2023-03-16 17:27:49 -0400
committerGitHub <[email protected]>2023-03-16 14:27:49 -0700
commitfa468025859f4d73ee74ece7f2f8c13ad6e5aa73 (patch)
tree73fc137b14926fd5991d4509271d209f99bf15c8 /module
parent60cfd3bbc22cd51a2e7e9c8341d9909cdb5dac85 (diff)
Fix possible bad bit shift in dnode_next_offset_level()
031d7c2fe6afaa78943bd0a563b91fc84ace42d7 did not handle reverse iteration, such that the original issue theoretically could still occur. Note that contrary to the claim in the ZFS disk format specification that a maximum of 6 levels are possible, 9 levels are possible with recordsize=512 and and indirect block size of 16KB. In this unusual configuration, span will be 65. The maximum size of span at 70 can be reached at recordsize=16K and an indirect blocksize of 16KB. When we are at this indirection level and are traversing backward, the minimum value is start, but we cannot calculate that with 64-bit arithmetic, so we avoid the calculation and instead rely on the earlier statement that did `*offset = start;`. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Richard Yao <[email protected]> Reported-by: Coverity (CID-1466214) Closes #14618
Diffstat (limited to 'module')
-rw-r--r--module/zfs/dnode.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/module/zfs/dnode.c b/module/zfs/dnode.c
index d334386e0..367bfaa80 100644
--- a/module/zfs/dnode.c
+++ b/module/zfs/dnode.c
@@ -2597,8 +2597,9 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset,
if (inc < 0) {
/* traversing backwards; position offset at the end */
- ASSERT3U(*offset, <=, start);
- *offset = MIN(*offset + (1ULL << span) - 1, start);
+ if (span < 8 * sizeof (*offset))
+ *offset = MIN(*offset + (1ULL << span) - 1,
+ start);
} else if (*offset < start) {
*offset = start;
}