xdp_rxq_info_unreg() implicitly calls xdp_rxq_info_unreg_mem_model(). This may well be confusing to the driver authors, and lead to double free if they call xdp_rxq_info_unreg_mem_model() before xdp_rxq_info_unreg() (when mem model type == MEM_TYPE_PAGE_POOL). In fact error path of mvpp2_rxq_init() seems to currently do exactly that. The double free will result in refcount underflow in page_pool_destroy(). Make the interface a little more programmer friendly by clearing type and id so that xdp_rxq_info_unreg_mem_model() can be called multiple times.
Unified · Split
| @@ -113,8 +113,13 @@ static void mem_allocator_disconnect(void *allocator) · 112 unmodified lines | |||
| 113 | void xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info *xdp_rxq) | 113 | void xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info *xdp_rxq) |
| 114 | { | 114 | { |
| 115 | struct xdp_mem_allocator *xa; | 115 | struct xdp_mem_allocator *xa; |
| 116 | int type = xdp_rxq->mem.type; | ||
| 116 | int id = xdp_rxq->mem.id; | 117 | int id = xdp_rxq->mem.id; |
| 117 | 118 | ||
| 119 | /* Reset mem info to defaults */ | ||
| 120 | xdp_rxq->mem.id = 0; | ||
| 121 | xdp_rxq->mem.type = 0; | ||
| 122 | |||
| 118 | if (xdp_rxq->reg_state != REG_STATE_REGISTERED) { | 123 | if (xdp_rxq->reg_state != REG_STATE_REGISTERED) { |
| 119 | WARN(1, "Missing register, driver bug"); | 124 | WARN(1, "Missing register, driver bug"); |
| 120 | return; | 125 | return; |
| @@ -123,7 +128,7 @@ void xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info *xdp_rxq) · 2 unmodified lines | |||
| 123 | if (id == 0) | 128 | if (id == 0) |
| 124 | return; | 129 | return; |
| 125 | 130 | ||
| 126 | if (xdp_rxq->mem.type == MEM_TYPE_PAGE_POOL) { | 131 | if (type == MEM_TYPE_PAGE_POOL) { |
| 127 | rcu_read_lock(); | 132 | rcu_read_lock(); |
| 128 | xa = rhashtable_lookup(mem_id_ht, &id, mem_id_rht_params); | 133 | xa = rhashtable_lookup(mem_id_ht, &id, mem_id_rht_params); |
| 129 | page_pool_destroy(xa->page_pool); | 134 | page_pool_destroy(xa->page_pool); |
| @@ -144,10 +149,6 @@ void xdp_rxq_info_unreg(struct xdp_rxq_info *xdp_rxq) · 14 unmodified lines | |||
| 144 | 149 | ||
| 145 | xdp_rxq->reg_state = REG_STATE_UNREGISTERED; | 150 | xdp_rxq->reg_state = REG_STATE_UNREGISTERED; |
| 146 | xdp_rxq->dev = NULL; | 151 | xdp_rxq->dev = NULL; |
| 147 | |||
| 148 | /* Reset mem info to defaults */ | ||
| 149 | xdp_rxq->mem.id = 0; | ||
| 150 | xdp_rxq->mem.type = 0; | ||
| 151 | } | 152 | } |
| 152 | EXPORT_SYMBOL_GPL(xdp_rxq_info_unreg); | 153 | EXPORT_SYMBOL_GPL(xdp_rxq_info_unreg); |
| 153 | 154 | ||