Hi Huan, > Subject: [PATCH v4 4/5] udmabuf: udmabuf_create codestyle cleanup > > There are some variables in udmabuf_create that are only used inside the > loop. Therefore, there is no need to declare them outside the scope. > This patch moved it into loop. > > It is difficult to understand the loop condition of the code that adds > folio to the unpin_list. > > This patch move item folio pin and record into a single function, when > pinned success, the outer loop of this patch iterates through folios, > while the inner loop correctly sets the folio and corresponding offset > into the udmabuf starting from the offset. if reach to pgcnt or nr_folios, > end of loop. > > If item size is huge, folios may use vmalloc to get memory, which can't > cache but return into pcp(or buddy) when vfree. So, each pin may waste > some time in folios array alloc. > This patch also reuse of folios when iter create head, just use max size > of item. > > Signed-off-by: Huan Yang <link@xxxxxxxx> > --- > drivers/dma-buf/udmabuf.c | 165 +++++++++++++++++++++++--------------- > 1 file changed, 101 insertions(+), 64 deletions(-) > > diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c > index 0bbc9df36c0a..eb55bb4a5fcc 100644 > --- a/drivers/dma-buf/udmabuf.c > +++ b/drivers/dma-buf/udmabuf.c > @@ -321,17 +321,87 @@ static int export_udmabuf(struct udmabuf *ubuf, > return dma_buf_fd(buf, flags); > } > > +static int __udmabuf_pin_list_folios(struct udmabuf_create_item *item, I think the name udmabuf_pin_folios() for this function would be simple and apt. > + struct udmabuf *ubuf, > + struct folio **folios) > +{ > + struct file *memfd = NULL; > + pgoff_t pgoff, ipgcnt, upgcnt = ubuf->pagecount; > + u32 cur_folio, cur_pgcnt; > + struct folio **ubuf_folios; > + pgoff_t *ubuf_offsets; > + long nr_folios; > + loff_t end, start; > + int ret; > + > + memfd = fget(item->memfd); > + ret = check_memfd_seals(memfd); > + if (ret < 0) > + goto err; Please move the above hunk to udmabuf_create(). Lets just have pinning and processing of folios in this function. > + > + start = item->offset; > + ipgcnt = item->size >> PAGE_SHIFT; I think it would be a bit more clear to have udmabuf_create() pass start and size values directly to this function instead of item. And rename ipgcnt to something like subpgcnt or nr_subpgs. > + end = start + (ipgcnt << PAGE_SHIFT) - 1; > + > + nr_folios = memfd_pin_folios(memfd, start, end, folios, ipgcnt, > &pgoff); > + if (nr_folios <= 0) { > + kvfree(folios); Please free folios in udmabuf_create() which is where it was allocated. > + ret = nr_folios ? nr_folios : -EINVAL; > + goto err; > + } > + > + cur_pgcnt = 0; > + ubuf_folios = ubuf->folios; > + ubuf_offsets = ubuf->offsets; Please initialize these temp variables at declaration time above. No strong opinion but I am not sure if they are really helpful here. Something like upgcnt would be OK as it definitely improves readability. > + > + for (cur_folio = 0; cur_folio < nr_folios; ++cur_folio) { > + pgoff_t subpgoff = pgoff; > + long fsize = folio_size(folios[cur_folio]); The return type for folio_size() is size_t. Please use that for consistency. > + > + ret = add_to_unpin_list(&ubuf->unpin_list, folios[cur_folio]); > + if (ret < 0) { > + kfree(folios); > + goto err; > + } > + > + for (; subpgoff < fsize; subpgoff += PAGE_SIZE) { > + ubuf->folios[upgcnt] = folios[cur_folio]; > + ubuf->offsets[upgcnt] = subpgoff; > + ++upgcnt; > + > + if (++cur_pgcnt >= ipgcnt) > + goto end; > + } > + > + /** > + * Only first folio in item may start from offset, I prefer to use the term range instead of item, in this context. > + * so remain folio start from 0. > + */ > + pgoff = 0; > + } > +end: > + ubuf->pagecount = upgcnt; > + fput(memfd); > + > + return 0; > + > +err: > + ubuf->pagecount = upgcnt; > + if (memfd) > + fput(memfd); > + > + return ret; > +} > + > static long udmabuf_create(struct miscdevice *device, > struct udmabuf_create_list *head, > struct udmabuf_create_item *list) > { > - pgoff_t pgoff, pgcnt, pglimit, pgbuf = 0; > - long nr_folios, ret = -EINVAL; > - struct file *memfd = NULL; > - struct folio **folios; > + pgoff_t pgcnt = 0, pglimit, max_ipgcnt = 0; > + long ret = -EINVAL; > struct udmabuf *ubuf; > - u32 i, j, k, flags; > - loff_t end; > + struct folio **folios = NULL; > + u32 i, flags; > > ubuf = kzalloc(sizeof(*ubuf), GFP_KERNEL); > if (!ubuf) > @@ -340,82 +410,50 @@ static long udmabuf_create(struct miscdevice > *device, > INIT_LIST_HEAD(&ubuf->unpin_list); > pglimit = (size_limit_mb * 1024 * 1024) >> PAGE_SHIFT; > for (i = 0; i < head->count; i++) { > - if (!IS_ALIGNED(list[i].offset, PAGE_SIZE)) > + pgoff_t itempgcnt; > + > + if (!PAGE_ALIGNED(list[i].offset)) > goto err; > - if (!IS_ALIGNED(list[i].size, PAGE_SIZE)) > + if (!PAGE_ALIGNED(list[i].size)) > goto err; > - ubuf->pagecount += list[i].size >> PAGE_SHIFT; > - if (ubuf->pagecount > pglimit) > + > + itempgcnt = list[i].size >> PAGE_SHIFT; > + pgcnt += itempgcnt; > + > + if (pgcnt > pglimit) > goto err; > + > + max_ipgcnt = max_t(unsigned long, itempgcnt, max_ipgcnt); Is this optimization really necessary given that, in practice, the userspace provides only a few ranges? It can stay but please pull these changes into a separate patch. Thanks, Vivek > } > > - if (!ubuf->pagecount) > + if (!pgcnt) > goto err; > > - ubuf->folios = kvmalloc_array(ubuf->pagecount, sizeof(*ubuf- > >folios), > + ubuf->folios = kvmalloc_array(pgcnt, sizeof(*ubuf->folios), > GFP_KERNEL); > if (!ubuf->folios) { > ret = -ENOMEM; > goto err; > } > - ubuf->offsets = kvcalloc(ubuf->pagecount, sizeof(*ubuf->offsets), > - GFP_KERNEL); > + > + ubuf->offsets = kvcalloc(pgcnt, sizeof(*ubuf->offsets), GFP_KERNEL); > if (!ubuf->offsets) { > ret = -ENOMEM; > goto err; > } > > - pgbuf = 0; > - for (i = 0; i < head->count; i++) { > - memfd = fget(list[i].memfd); > - ret = check_memfd_seals(memfd); > - if (ret < 0) > - goto err; > - > - pgcnt = list[i].size >> PAGE_SHIFT; > - folios = kvmalloc_array(pgcnt, sizeof(*folios), GFP_KERNEL); > - if (!folios) { > - ret = -ENOMEM; > - goto err; > - } > + folios = kvmalloc_array(max_ipgcnt, sizeof(*folios), GFP_KERNEL); > + if (!folios) { > + ret = -ENOMEM; > + goto err; > + } > > - end = list[i].offset + (pgcnt << PAGE_SHIFT) - 1; > - ret = memfd_pin_folios(memfd, list[i].offset, end, > - folios, pgcnt, &pgoff); > - if (ret <= 0) { > - kvfree(folios); > - if (!ret) > - ret = -EINVAL; > + for (i = 0; i < head->count; i++) { > + ret = __udmabuf_pin_list_folios(&list[i], ubuf, folios); > + if (ret) > goto err; > - } > - > - nr_folios = ret; > - pgoff >>= PAGE_SHIFT; > - for (j = 0, k = 0; j < pgcnt; j++) { > - ubuf->folios[pgbuf] = folios[k]; > - ubuf->offsets[pgbuf] = pgoff << PAGE_SHIFT; > - > - if (j == 0 || ubuf->folios[pgbuf-1] != folios[k]) { > - ret = add_to_unpin_list(&ubuf->unpin_list, > - folios[k]); > - if (ret < 0) { > - kfree(folios); > - goto err; > - } > - } > - > - pgbuf++; > - if (++pgoff == folio_nr_pages(folios[k])) { > - pgoff = 0; > - if (++k == nr_folios) > - break; > - } > - } > - > - kvfree(folios); > - fput(memfd); > - memfd = NULL; > } > + kvfree(folios); > > flags = head->flags & UDMABUF_FLAGS_CLOEXEC ? O_CLOEXEC : 0; > ret = export_udmabuf(ubuf, device, flags); > @@ -425,9 +463,8 @@ static long udmabuf_create(struct miscdevice > *device, > return ret; > > err: > - if (memfd) > - fput(memfd); > unpin_all_folios(&ubuf->unpin_list); > + kvfree(folios); > kvfree(ubuf->offsets); > kvfree(ubuf->folios); > kfree(ubuf); > -- > 2.45.2