@@ -338,28 +338,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) {
@@ -388,14 +380,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;
@@ -407,14 +400,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)
@@ -424,6 +422,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);
@@ -439,7 +443,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;
@@ -450,12 +454,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;
}