diff options
-rw-r--r-- | include/sys/dbuf.h | 3 | ||||
-rw-r--r-- | include/sys/dnode.h | 5 | ||||
-rw-r--r-- | lib/libspl/include/sys/sysmacros.h | 3 | ||||
-rw-r--r-- | module/zfs/dbuf.c | 17 | ||||
-rw-r--r-- | module/zfs/dnode.c | 19 |
5 files changed, 38 insertions, 9 deletions
diff --git a/include/sys/dbuf.h b/include/sys/dbuf.h index bf546db6f..6262f012e 100644 --- a/include/sys/dbuf.h +++ b/include/sys/dbuf.h @@ -270,7 +270,8 @@ typedef struct dbuf_hash_table { kmutex_t hash_mutexes[DBUF_MUTEXES]; } dbuf_hash_table_t; -uint64_t dbuf_whichblock(struct dnode *di, int64_t level, uint64_t offset); +uint64_t dbuf_whichblock(const struct dnode *di, const int64_t level, + const uint64_t offset); void dbuf_create_bonus(struct dnode *dn); int dbuf_spill_set_blksz(dmu_buf_t *db, uint64_t blksz, dmu_tx_t *tx); 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)))) diff --git a/lib/libspl/include/sys/sysmacros.h b/lib/libspl/include/sys/sysmacros.h index c2525dd2a..f99b4d686 100644 --- a/lib/libspl/include/sys/sysmacros.h +++ b/lib/libspl/include/sys/sysmacros.h @@ -42,6 +42,9 @@ #ifndef ARRAY_SIZE #define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0])) #endif +#ifndef DIV_ROUND_UP +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#endif #define makedevice(maj, min) makedev(maj, min) #define _sysconf(a) sysconf(a) diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index f05190b66..e487e469f 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -918,7 +918,7 @@ dbuf_loan_arcbuf(dmu_buf_impl_t *db) * provided. */ uint64_t -dbuf_whichblock(dnode_t *dn, int64_t level, uint64_t offset) +dbuf_whichblock(const dnode_t *dn, const int64_t level, const uint64_t offset) { if (dn->dn_datablkshift != 0 && dn->dn_indblkshift != 0) { /* @@ -940,8 +940,19 @@ dbuf_whichblock(dnode_t *dn, int64_t level, uint64_t offset) * = offset >> (datablkshift + level * * (indblkshift - SPA_BLKPTRSHIFT)) */ - return (offset >> (dn->dn_datablkshift + level * - (dn->dn_indblkshift - SPA_BLKPTRSHIFT))); + + const unsigned exp = dn->dn_datablkshift + + level * (dn->dn_indblkshift - SPA_BLKPTRSHIFT); + + if (exp >= 8 * sizeof (offset)) { + /* This only happens on the highest indirection level */ + ASSERT3U(level, ==, dn->dn_nlevels - 1); + return (0); + } + + ASSERT3U(exp, <, 8 * sizeof (offset)); + + return (offset >> exp); } else { ASSERT3U(offset, <, dn->dn_datablksz); return (0); diff --git a/module/zfs/dnode.c b/module/zfs/dnode.c index a54db9511..f0b03bbba 100644 --- a/module/zfs/dnode.c +++ b/module/zfs/dnode.c @@ -1612,6 +1612,8 @@ dnode_new_blkid(dnode_t *dn, uint64_t blkid, dmu_tx_t *tx, boolean_t have_read) sz <= blkid && sz >= dn->dn_nblkptr; sz <<= epbs) new_nlevels++; + ASSERT3U(new_nlevels, <=, DN_MAX_LEVELS); + if (new_nlevels > dn->dn_nlevels) { int old_nlevels = dn->dn_nlevels; dmu_buf_impl_t *db; @@ -2073,7 +2075,14 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset, else minfill++; - *offset = *offset >> span; + if (span >= 8 * sizeof (*offset)) { + /* This only happens on the highest indirection level */ + ASSERT3U((lvl - 1), ==, dn->dn_phys->dn_nlevels - 1); + *offset = 0; + } else { + *offset = *offset >> span; + } + for (i = BF64_GET(*offset, 0, epbs); i >= 0 && i < epb; i += inc) { if (BP_GET_FILL(&bp[i]) >= minfill && @@ -2083,7 +2092,13 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset, if (inc > 0 || *offset > 0) *offset += inc; } - *offset = *offset << span; + + if (span >= 8 * sizeof (*offset)) { + *offset = start; + } else { + *offset = *offset << span; + } + if (inc < 0) { /* traversing backwards; position offset at the end */ ASSERT3U(*offset, <=, start); |