summaryrefslogtreecommitdiffstats
path: root/include/sys/dnode.h
diff options
context:
space:
mode:
authorGvozden Neskovic <[email protected]>2016-08-31 10:12:08 +0200
committerBrian Behlendorf <[email protected]>2016-09-29 15:55:41 -0700
commit031d7c2fe6afaa78943bd0a563b91fc84ace42d7 (patch)
treee30c20bc233c680f997e8b11948988c7e97f1c83 /include/sys/dnode.h
parent0b78aeae927833de580e140375a15ea5ea9d924a (diff)
fix: Shift exponent too large
Undefined operation is reported by running ztest (or zloop) compiled with GCC UndefinedBehaviorSanitizer. Error only happens on top level of dnode indirection with large enough offset values. Logically, left shift operation would work, but bit shift semantics in C, and limitation of uint64_t, do not produce desired result. Issue #5059, #4883 Signed-off-by: Gvozden Neskovic <[email protected]>
Diffstat (limited to 'include/sys/dnode.h')
-rw-r--r--include/sys/dnode.h5
1 files changed, 2 insertions, 3 deletions
diff --git a/include/sys/dnode.h b/include/sys/dnode.h
index 7b4d7b9d3..fe36e5989 100644
--- a/include/sys/dnode.h
+++ b/include/sys/dnode.h
@@ -104,9 +104,8 @@ extern "C" {
#define DNODES_PER_LEVEL_SHIFT (DN_MAX_INDBLKSHIFT - SPA_BLKPTRSHIFT)
#define DNODES_PER_LEVEL (1ULL << DNODES_PER_LEVEL_SHIFT)
-/* The +2 here is a cheesy way to round up */
-#define DN_MAX_LEVELS (2 + ((DN_MAX_OFFSET_SHIFT - SPA_MINBLOCKSHIFT) / \
- (DN_MIN_INDBLKSHIFT - SPA_BLKPTRSHIFT)))
+#define DN_MAX_LEVELS (DIV_ROUND_UP(DN_MAX_OFFSET_SHIFT - SPA_MINBLOCKSHIFT, \
+ DN_MIN_INDBLKSHIFT - SPA_BLKPTRSHIFT) + 1)
#define DN_BONUS(dnp) ((void*)((dnp)->dn_bonus + \
(((dnp)->dn_nblkptr - 1) * sizeof (blkptr_t))))