From: Bernard Metzler Date: Mon, 11 May 2026 14:11:49 +0000 (+0200) Subject: RDMA/siw: use kzalloc_flex X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c6207055617a7f463c4aac92d704d21081103b94;p=thirdparty%2Fkernel%2Flinux.git RDMA/siw: use kzalloc_flex Simplify umem allocation by using flexible array member. Add __counted_by to get extra runtime analysis. Suggested-by: Rosen Penev Signed-off-by: Bernard Metzler Link: https://patch.msgid.link/20260511141149.52362-1-bernard.metzler@linux.dev Signed-off-by: Leon Romanovsky --- diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h index f5fd71717b807..dbc998248b1e9 100644 --- a/drivers/infiniband/sw/siw/siw.h +++ b/drivers/infiniband/sw/siw/siw.h @@ -119,9 +119,10 @@ struct siw_page_chunk { struct siw_umem { struct ib_umem *base_mem; - struct siw_page_chunk *page_chunk; - int num_pages; + unsigned int num_pages; + unsigned int num_chunks; u64 fp_addr; /* First page base address */ + struct siw_page_chunk page_chunk[] __counted_by(num_chunks); }; struct siw_pble { diff --git a/drivers/infiniband/sw/siw/siw_mem.c b/drivers/infiniband/sw/siw/siw_mem.c index 98c802b3ed723..4df792ebe02fa 100644 --- a/drivers/infiniband/sw/siw/siw_mem.c +++ b/drivers/infiniband/sw/siw/siw_mem.c @@ -41,16 +41,14 @@ struct siw_mem *siw_mem_id2obj(struct siw_device *sdev, int stag_index) void siw_umem_release(struct siw_umem *umem) { - int i, num_pages = umem->num_pages; + unsigned int i, num_chunks = umem->num_chunks; if (umem->base_mem) ib_umem_release(umem->base_mem); - for (i = 0; num_pages > 0; i++) { + for (i = 0; i < num_chunks; i++) kfree(umem->page_chunk[i].plist); - num_pages -= PAGES_PER_CHUNK; - } - kfree(umem->page_chunk); + kfree(umem); } @@ -188,7 +186,7 @@ int siw_check_mem(struct ib_pd *pd, struct siw_mem *mem, u64 addr, * lookup is being done and mem is not released it check fails. */ int siw_check_sge(struct ib_pd *pd, struct siw_sge *sge, struct siw_mem *mem[], - enum ib_access_flags perms, u32 off, int len) + enum ib_access_flags perms, u32 off, u32 len) { struct siw_device *sdev = to_siw_dev(pd->device); struct siw_mem *new = NULL; @@ -338,25 +336,20 @@ struct siw_umem *siw_umem_get(struct ib_device *base_dev, u64 start, struct sg_page_iter sg_iter; struct sg_table *sgt; u64 first_page_va; - int num_pages, num_chunks, i, rv = 0; + unsigned int num_pages, num_chunks, i; + int rv = 0; if (!len) return ERR_PTR(-EINVAL); first_page_va = start & PAGE_MASK; num_pages = PAGE_ALIGN(start + len - first_page_va) >> PAGE_SHIFT; - num_chunks = (num_pages >> CHUNK_SHIFT) + 1; + num_chunks = ((num_pages - 1) >> CHUNK_SHIFT) + 1; - umem = kzalloc_obj(*umem); + umem = kzalloc_flex(*umem, page_chunk, num_chunks); if (!umem) return ERR_PTR(-ENOMEM); - umem->page_chunk = - kzalloc_objs(struct siw_page_chunk, num_chunks); - if (!umem->page_chunk) { - rv = -ENOMEM; - goto err_out; - } base_mem = ib_umem_get(base_dev, start, len, rights); if (IS_ERR(base_mem)) { rv = PTR_ERR(base_mem); @@ -365,33 +358,40 @@ struct siw_umem *siw_umem_get(struct ib_device *base_dev, u64 start, } umem->fp_addr = first_page_va; umem->base_mem = base_mem; + umem->num_pages = num_pages; + umem->num_chunks = num_chunks; sgt = &base_mem->sgt_append.sgt; __sg_page_iter_start(&sg_iter, sgt->sgl, sgt->orig_nents, 0); - if (!__sg_page_iter_next(&sg_iter)) { - rv = -EINVAL; - goto err_out; - } - for (i = 0; num_pages > 0; i++) { - int nents = min_t(int, num_pages, PAGES_PER_CHUNK); - struct page **plist = - kzalloc_objs(struct page *, nents); + for (i = 0; i < num_chunks; i++) { + struct page **plist; + unsigned int pix, nents = min(num_pages, PAGES_PER_CHUNK); + plist = kzalloc_objs(struct page *, nents); if (!plist) { rv = -ENOMEM; goto err_out; } umem->page_chunk[i].plist = plist; - while (nents--) { - *plist = sg_page_iter_page(&sg_iter); - umem->num_pages++; - num_pages--; - plist++; + + for (pix = 0; pix < nents; pix++) { if (!__sg_page_iter_next(&sg_iter)) break; + plist[pix] = sg_page_iter_page(&sg_iter); + num_pages--; } } + + if (num_pages) { + /* + * Unexpected size of sg list provided by ib_umem_get() + */ + siw_dbg(base_dev, "Short SG list, missing %u pages\n", + num_pages); + rv = -EINVAL; + goto err_out; + } return umem; err_out: siw_umem_release(umem); diff --git a/drivers/infiniband/sw/siw/siw_mem.h b/drivers/infiniband/sw/siw/siw_mem.h index 8e769d30e2acd..e4f3a5a4f81df 100644 --- a/drivers/infiniband/sw/siw/siw_mem.h +++ b/drivers/infiniband/sw/siw/siw_mem.h @@ -17,7 +17,7 @@ int siw_check_mem(struct ib_pd *pd, struct siw_mem *mem, u64 addr, enum ib_access_flags perms, int len); int siw_check_sge(struct ib_pd *pd, struct siw_sge *sge, struct siw_mem *mem[], enum ib_access_flags perms, - u32 off, int len); + u32 off, u32 len); void siw_wqe_put_mem(struct siw_wqe *wqe, enum siw_opcode op); int siw_mr_add_mem(struct siw_mr *mr, struct ib_pd *pd, void *mem_obj, u64 start, u64 len, int rights); @@ -45,7 +45,6 @@ static inline void siw_unref_mem_sgl(struct siw_mem **mem, unsigned int num_sge) #define CHUNK_SHIFT 9 /* sets number of pages per chunk */ #define PAGES_PER_CHUNK (_AC(1, UL) << CHUNK_SHIFT) #define CHUNK_MASK (~(PAGES_PER_CHUNK - 1)) -#define PAGE_CHUNK_SIZE (PAGES_PER_CHUNK * sizeof(struct page *)) /* * siw_get_upage() @@ -61,7 +60,7 @@ static inline struct page *siw_get_upage(struct siw_umem *umem, u64 addr) chunk_idx = page_idx >> CHUNK_SHIFT, page_in_chunk = page_idx & ~CHUNK_MASK; - if (likely(page_idx < umem->num_pages)) + if (page_idx < umem->num_pages) return umem->page_chunk[chunk_idx].plist[page_in_chunk]; return NULL;