From: Christopher Faulet Date: Wed, 8 Jul 2026 08:38:12 +0000 (+0200) Subject: MEDIUM: htx: Skip UNUSED blocs when getting previous,next and first blocks X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=b680af702c1700a36e792e484d692bab737890c7;p=haproxy.git MEDIUM: htx: Skip UNUSED blocs when getting previous,next and first blocks htx_get_prev_blk(), htx_get_next_blk() and htx_get_first_blk() functions were modified to automatically skip UNUSED blocks. So now, a valid block or NULL is returned. In addition, htx_remove_blk() was adapted accordingly to also skip UNUSED blocks. Thanks to this change, the loops on HTX messages could be simplified by removing test on UNUSED blocks, while it remains harmless. --- diff --git a/include/haproxy/htx.h b/include/haproxy/htx.h index 4b7b9834f..b48d87df6 100644 --- a/include/haproxy/htx.h +++ b/include/haproxy/htx.h @@ -272,16 +272,22 @@ static inline int32_t htx_get_prev(const struct htx *htx, uint32_t pos) return (pos - 1); } -/* Returns the HTX block before in the HTX message . If is the - * head, NULL returned. +/* Returns the HTX block before in the HTX message , skipping all + * UNUSED blocks. If is the head, NULL returned. */ static inline struct htx_blk *htx_get_prev_blk(const struct htx *htx, const struct htx_blk *blk) { - int32_t pos; + struct htx_blk *pblk = NULL; + int32_t pos = htx_get_blk_pos(htx, blk); - pos = htx_get_prev(htx, htx_get_blk_pos(htx, blk)); - return ((pos == -1) ? NULL : htx_get_blk(htx, pos)); + for (pos = htx_get_prev(htx, pos); pos != -1; pos = htx_get_prev(htx, pos)) { + pblk = htx_get_blk(htx, pos); + if (htx_get_blk_type(pblk) != HTX_BLK_UNUSED) + break; + pblk = NULL; + } + return pblk; } /* Returns the position of block immediately after the one pointed by . If @@ -295,18 +301,25 @@ static inline int32_t htx_get_next(const struct htx *htx, uint32_t pos) } -/* Returns the HTX block after in the HTX message . If is the - * tail, NULL returned. +/* Returns the HTX block after in the HTX message , skipping UNUSED + * blocks. If is the tail, NULL returned. */ static inline struct htx_blk *htx_get_next_blk(const struct htx *htx, const struct htx_blk *blk) { - int32_t pos; + struct htx_blk *nblk = NULL; + int32_t pos = htx_get_blk_pos(htx, blk); - pos = htx_get_next(htx, htx_get_blk_pos(htx, blk)); - return ((pos == -1) ? NULL : htx_get_blk(htx, pos)); + for (pos = htx_get_next(htx, pos); pos != -1; pos = htx_get_next(htx, pos)) { + nblk = htx_get_blk(htx, pos); + if (htx_get_blk_type(nblk) != HTX_BLK_UNUSED) + break; + nblk = NULL; + } + return nblk; } + /* Returns the position of the first block in the HTX message . -1 means * the first block is unset or the HTS is empty. */ @@ -315,15 +328,21 @@ static inline int32_t htx_get_first(const struct htx *htx) return htx->first; } -/* Returns the first HTX block in the HTX message . If unset or if is - * empty, NULL returned. +/* Returns the first HTX block in the HTX message , skipping UNUSED + * blocks. If unset or if is empty, NULL returned. */ static inline struct htx_blk *htx_get_first_blk(const struct htx *htx) { + struct htx_blk *fblk = NULL; int32_t pos; - pos = htx_get_first(htx); - return ((pos == -1) ? NULL : htx_get_blk(htx, pos)); + for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) { + fblk = htx_get_blk(htx, pos); + if (htx_get_blk_type(fblk) != HTX_BLK_UNUSED) + break; + fblk = NULL; + } + return fblk; } /* Returns the type of the first block in the HTX message . If unset or if diff --git a/src/htx.c b/src/htx.c index 3a05dc42f..fff828932 100644 --- a/src/htx.c +++ b/src/htx.c @@ -368,6 +368,7 @@ struct htx_blk *htx_add_blk(struct htx *htx, enum htx_blk_type type, uint32_t bl */ struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk) { + struct htx_blk *prevblk, *nextblk; enum htx_blk_type type; uint32_t pos, addr, sz; @@ -382,6 +383,15 @@ struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk) return NULL; } + /* Get prev and next blocks, skipping all UNUSED blocks. + * may NULL if the head is removed otherwise it must exists + * may NULL if the tail is removed otherwise it must exists + */ + prevblk = htx_get_prev_blk(htx, blk); + nextblk = htx_get_next_blk(htx, blk); + + /* There is at least 2 used blocks, so (head != tail and tail > 0) */ + type = htx_get_blk_type(blk); pos = htx_get_blk_pos(htx, blk); sz = htx_get_blksz(blk); @@ -394,26 +404,24 @@ struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk) blk->info = ((uint32_t)HTX_BLK_UNUSED << 28); } - /* There is at least 2 blocks, so tail is always > 0 */ + if (pos == htx->head) { /* move the head forward */ - htx->head++; + BUG_ON_HOT(prevblk != NULL || nextblk == NULL); + htx->head = htx_get_blk_pos(htx, nextblk); } else if (pos == htx->tail) { - /* remove the tail. this was the last inserted block so - * return NULL. */ - htx->tail--; - blk = NULL; + /* remove the tail */ + BUG_ON_HOT(prevblk == NULL || nextblk != NULL); + htx->tail = htx_get_blk_pos(htx, prevblk); goto end; } else htx->flags |= HTX_FL_FRAGMENTED; - blk = htx_get_blk(htx, pos+1); - end: if (pos == htx->first) - htx->first = (blk ? htx_get_blk_pos(htx, blk) : -1); + htx->first = (nextblk ? htx_get_blk_pos(htx, nextblk) : -1); if (htx->head == htx->tail) { /* If there is just one block in the HTX message, free space can @@ -443,7 +451,7 @@ struct htx_blk *htx_remove_blk(struct htx *htx, struct htx_blk *blk) BUG_ON((int32_t)htx->head_addr < 0); BUG_ON(htx->end_addr > htx->tail_addr); BUG_ON(htx->head_addr > htx->end_addr); - return blk; + return nextblk; } /* Looks for the HTX block containing the offset , starting at the HTX