diff options
author | Richard Yao <[email protected]> | 2023-03-16 17:27:49 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2023-03-16 14:27:49 -0700 |
commit | fa468025859f4d73ee74ece7f2f8c13ad6e5aa73 (patch) | |
tree | 73fc137b14926fd5991d4509271d209f99bf15c8 /module | |
parent | 60cfd3bbc22cd51a2e7e9c8341d9909cdb5dac85 (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.c | 5 |
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; } |