@@ -2727,18 +2727,42 @@ dnode_next_offset(dnode_t *dn, int flags, uint64_t *offset,
27272727 }
27282728
27292729 if (lvl > 0 ) {
2730- uint64_t n = blkid << epbs ;
2731- if (index > 0 || n > 0 )
2732- n += index ; /* -1 <= index <= 1<<epbs */
2733-
27342730 int span = (lvl - 1 ) * epbs + dn -> dn_datablkshift ;
2735- if (span >= 8 * sizeof (uint64_t ))
2736- * offset = 0 ;
2737- else if (flags & DNODE_FIND_BACKWARDS )
2738- /* traversing backwards; position at block end */
2731+ uint64_t n ;
2732+
2733+ /*
2734+ * Calculate the range of L0 offsets for blkid n at lvl - 1.
2735+ * Forward search: Return the first offset in the range or
2736+ * the initial offset, whichever is larger.
2737+ * Backward search: Return the last offset (inclusive) or the
2738+ * initial offset, whichever is smaller.
2739+ */
2740+ n = (blkid << epbs ) + index ; /* -1 <= index <= (1<<epbs) */
2741+ if (index < 0 && blkid == 0 ) {
2742+ * offset = 0 ; /* Not found searching backwards */
2743+ } else if (span >= 8 * sizeof (uint64_t ) ||
2744+ (n >> (8 * sizeof (* offset ) - span )) != 0 ) {
2745+ /*
2746+ * Overflow cases:
2747+ * n == 0: range starts at 0 and ends beyond UINT64_MAX
2748+ * n > 0: range starts (and ends) beyond UINT64_MAX
2749+ *
2750+ * This leaves *offset unchanged in two cases:
2751+ * 1. Searching forward, n == 0: the range starts at 0
2752+ * which is always <= any initial offset.
2753+ * 2. Searching backward, any n: the range ends beyond
2754+ * UINT64_MAX which is always >= any initial offset.
2755+ *
2756+ * Searching forward, n > 0: the range start overflows,
2757+ * so clamp *offset to UINT64_MAX upon return.
2758+ */
2759+ if (n > 0 && !(flags & DNODE_FIND_BACKWARDS ))
2760+ * offset = UINT64_MAX ; /* Forward overflow */
2761+ } else if (flags & DNODE_FIND_BACKWARDS ) {
27392762 * offset = MIN (* offset , ((n + 1 ) << span ) - 1 );
2740- else
2763+ } else {
27412764 * offset = MAX (* offset , n << span );
2765+ }
27422766 } else {
27432767 * offset = (blkid << dn -> dn_datablkshift ) +
27442768 (index << DNODE_SHIFT ); /* 0 <= index <= blkfill */
0 commit comments