Message ID | 20240909091851.1165742-8-link@vivo.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | udmabuf bug fix and some improvements | expand |
Hi Huan, > Subject: [PATCH v6 7/7] udmabuf: reuse folio array when pin folios > > When invoke memfd_pin_folios, we need offer an array to save each folio > which we pinned. > > The currently way is dynamic alloc an array, get folios, save into *current > udmabuf and then free. > > If the size is tiny(alloc from slab) is ok due to slab can cache it. > Or, just PCP order can cover, also ok. A casual reader may not know what is PCP. Please mention what it stands for and how it is relevant here. > > But if size is huge, need fallback into vmalloc, then, not well, due to > each page need alloc, and map into vmalloc area. Too heavy. I think it would be better if the above two lines are rewritten to more clearly describe why or how fallback to vmalloc adversely affects performance. Thanks, Vivek > > Now that we need to iter each udmabuf item, then pin it's range folios, > we can reuse the maximum size range's folios array. > > Signed-off-by: Huan Yang <link@vivo.com> > Acked-by: Vivek Kasireddy <vivek.kasireddy@intel.com> > --- > drivers/dma-buf/udmabuf.c | 36 +++++++++++++++++++++--------------- > 1 file changed, 21 insertions(+), 15 deletions(-) > > diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c > index 0e405a589ca2..9fc5d22d54ae 100644 > --- a/drivers/dma-buf/udmabuf.c > +++ b/drivers/dma-buf/udmabuf.c > @@ -341,28 +341,20 @@ static int export_udmabuf(struct udmabuf *ubuf, > } > > static long udmabuf_pin_folios(struct udmabuf *ubuf, struct file *memfd, > - loff_t start, loff_t size) > + loff_t start, loff_t size, struct folio **folios) > { > pgoff_t nr_pinned = ubuf->nr_pinned; > pgoff_t upgcnt = ubuf->pagecount; > - struct folio **folios = NULL; > u32 cur_folio, cur_pgcnt; > pgoff_t pgoff, pgcnt; > long nr_folios; > - long ret = 0; > loff_t end; > > pgcnt = size >> PAGE_SHIFT; > - folios = kvmalloc_array(pgcnt, sizeof(*folios), GFP_KERNEL); > - if (!folios) > - return -ENOMEM; > - > end = start + (pgcnt << PAGE_SHIFT) - 1; > nr_folios = memfd_pin_folios(memfd, start, end, folios, pgcnt, > &pgoff); > - if (nr_folios <= 0) { > - ret = nr_folios ? nr_folios : -EINVAL; > - goto end; > - } > + if (nr_folios <= 0) > + return nr_folios ? nr_folios : -EINVAL; > > cur_pgcnt = 0; > for (cur_folio = 0; cur_folio < nr_folios; ++cur_folio) { > @@ -391,14 +383,15 @@ static long udmabuf_pin_folios(struct udmabuf > *ubuf, struct file *memfd, > end: > ubuf->pagecount = upgcnt; > ubuf->nr_pinned = nr_pinned; > - kvfree(folios); > - return ret; > + return 0; > } > > static long udmabuf_create(struct miscdevice *device, > struct udmabuf_create_list *head, > struct udmabuf_create_item *list) > { > + unsigned long max_nr_folios = 0; > + struct folio **folios = NULL; > pgoff_t pgcnt = 0, pglimit; > struct udmabuf *ubuf; > long ret = -EINVAL; > @@ -410,14 +403,19 @@ static long udmabuf_create(struct miscdevice > *device, > > pglimit = (size_limit_mb * 1024 * 1024) >> PAGE_SHIFT; > for (i = 0; i < head->count; i++) { > + pgoff_t subpgcnt; > + > if (!PAGE_ALIGNED(list[i].offset)) > goto err_noinit; > if (!PAGE_ALIGNED(list[i].size)) > goto err_noinit; > > - pgcnt += list[i].size >> PAGE_SHIFT; > + subpgcnt = list[i].size >> PAGE_SHIFT; > + pgcnt += subpgcnt; > if (pgcnt > pglimit) > goto err_noinit; > + > + max_nr_folios = max_t(unsigned long, subpgcnt, > max_nr_folios); > } > > if (!pgcnt) > @@ -427,6 +425,12 @@ static long udmabuf_create(struct miscdevice > *device, > if (ret) > goto err; > > + folios = kvmalloc_array(max_nr_folios, sizeof(*folios), GFP_KERNEL); > + if (!folios) { > + ret = -ENOMEM; > + goto err; > + } > + > for (i = 0; i < head->count; i++) { > struct file *memfd = fget(list[i].memfd); > > @@ -442,7 +446,7 @@ static long udmabuf_create(struct miscdevice > *device, > } > > ret = udmabuf_pin_folios(ubuf, memfd, list[i].offset, > - list[i].size); > + list[i].size, folios); > fput(memfd); > if (ret) > goto err; > @@ -453,12 +457,14 @@ static long udmabuf_create(struct miscdevice > *device, > if (ret < 0) > goto err; > > + kvfree(folios); > return ret; > > err: > deinit_udmabuf(ubuf); > err_noinit: > kfree(ubuf); > + kvfree(folios); > return ret; > } > > -- > 2.45.2
diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c index 0e405a589ca2..9fc5d22d54ae 100644 --- a/drivers/dma-buf/udmabuf.c +++ b/drivers/dma-buf/udmabuf.c @@ -341,28 +341,20 @@ static int export_udmabuf(struct udmabuf *ubuf, } static long udmabuf_pin_folios(struct udmabuf *ubuf, struct file *memfd, - loff_t start, loff_t size) + loff_t start, loff_t size, struct folio **folios) { pgoff_t nr_pinned = ubuf->nr_pinned; pgoff_t upgcnt = ubuf->pagecount; - struct folio **folios = NULL; u32 cur_folio, cur_pgcnt; pgoff_t pgoff, pgcnt; long nr_folios; - long ret = 0; loff_t end; pgcnt = size >> PAGE_SHIFT; - folios = kvmalloc_array(pgcnt, sizeof(*folios), GFP_KERNEL); - if (!folios) - return -ENOMEM; - end = start + (pgcnt << PAGE_SHIFT) - 1; nr_folios = memfd_pin_folios(memfd, start, end, folios, pgcnt, &pgoff); - if (nr_folios <= 0) { - ret = nr_folios ? nr_folios : -EINVAL; - goto end; - } + if (nr_folios <= 0) + return nr_folios ? nr_folios : -EINVAL; cur_pgcnt = 0; for (cur_folio = 0; cur_folio < nr_folios; ++cur_folio) { @@ -391,14 +383,15 @@ static long udmabuf_pin_folios(struct udmabuf *ubuf, struct file *memfd, end: ubuf->pagecount = upgcnt; ubuf->nr_pinned = nr_pinned; - kvfree(folios); - return ret; + return 0; } static long udmabuf_create(struct miscdevice *device, struct udmabuf_create_list *head, struct udmabuf_create_item *list) { + unsigned long max_nr_folios = 0; + struct folio **folios = NULL; pgoff_t pgcnt = 0, pglimit; struct udmabuf *ubuf; long ret = -EINVAL; @@ -410,14 +403,19 @@ static long udmabuf_create(struct miscdevice *device, pglimit = (size_limit_mb * 1024 * 1024) >> PAGE_SHIFT; for (i = 0; i < head->count; i++) { + pgoff_t subpgcnt; + if (!PAGE_ALIGNED(list[i].offset)) goto err_noinit; if (!PAGE_ALIGNED(list[i].size)) goto err_noinit; - pgcnt += list[i].size >> PAGE_SHIFT; + subpgcnt = list[i].size >> PAGE_SHIFT; + pgcnt += subpgcnt; if (pgcnt > pglimit) goto err_noinit; + + max_nr_folios = max_t(unsigned long, subpgcnt, max_nr_folios); } if (!pgcnt) @@ -427,6 +425,12 @@ static long udmabuf_create(struct miscdevice *device, if (ret) goto err; + folios = kvmalloc_array(max_nr_folios, sizeof(*folios), GFP_KERNEL); + if (!folios) { + ret = -ENOMEM; + goto err; + } + for (i = 0; i < head->count; i++) { struct file *memfd = fget(list[i].memfd); @@ -442,7 +446,7 @@ static long udmabuf_create(struct miscdevice *device, } ret = udmabuf_pin_folios(ubuf, memfd, list[i].offset, - list[i].size); + list[i].size, folios); fput(memfd); if (ret) goto err; @@ -453,12 +457,14 @@ static long udmabuf_create(struct miscdevice *device, if (ret < 0) goto err; + kvfree(folios); return ret; err: deinit_udmabuf(ubuf); err_noinit: kfree(ubuf); + kvfree(folios); return ret; }