@@ -291,9 +291,6 @@ static int check_memfd_seals(struct file *memfd)
291291{
292292 int seals ;
293293
294- if (!memfd )
295- return - EBADFD ;
296-
297294 if (!shmem_file (memfd ) && !is_file_hugepages (memfd ))
298295 return - EBADFD ;
299296
@@ -328,17 +325,68 @@ static int export_udmabuf(struct udmabuf *ubuf,
328325 return dma_buf_fd (buf , flags );
329326}
330327
328+ static long udmabuf_pin_folios (struct udmabuf * ubuf , struct file * memfd ,
329+ loff_t start , loff_t size )
330+ {
331+ pgoff_t pgoff , pgcnt , upgcnt = ubuf -> pagecount ;
332+ struct folio * * folios = NULL ;
333+ u32 cur_folio , cur_pgcnt ;
334+ long nr_folios ;
335+ long ret = 0 ;
336+ loff_t end ;
337+
338+ pgcnt = size >> PAGE_SHIFT ;
339+ folios = kvmalloc_array (pgcnt , sizeof (* folios ), GFP_KERNEL );
340+ if (!folios )
341+ return - ENOMEM ;
342+
343+ end = start + (pgcnt << PAGE_SHIFT ) - 1 ;
344+ nr_folios = memfd_pin_folios (memfd , start , end , folios , pgcnt , & pgoff );
345+ if (nr_folios <= 0 ) {
346+ ret = nr_folios ? nr_folios : - EINVAL ;
347+ goto end ;
348+ }
349+
350+ cur_pgcnt = 0 ;
351+ for (cur_folio = 0 ; cur_folio < nr_folios ; ++ cur_folio ) {
352+ pgoff_t subpgoff = pgoff ;
353+ size_t fsize = folio_size (folios [cur_folio ]);
354+
355+ ret = add_to_unpin_list (& ubuf -> unpin_list , folios [cur_folio ]);
356+ if (ret < 0 )
357+ goto end ;
358+
359+ for (; subpgoff < fsize ; subpgoff += PAGE_SIZE ) {
360+ ubuf -> folios [upgcnt ] = folios [cur_folio ];
361+ ubuf -> offsets [upgcnt ] = subpgoff ;
362+ ++ upgcnt ;
363+
364+ if (++ cur_pgcnt >= pgcnt )
365+ goto end ;
366+ }
367+
368+ /**
369+ * In a given range, only the first subpage of the first folio
370+ * has an offset, that is returned by memfd_pin_folios().
371+ * The first subpages of other folios (in the range) have an
372+ * offset of 0.
373+ */
374+ pgoff = 0 ;
375+ }
376+ end :
377+ ubuf -> pagecount = upgcnt ;
378+ kvfree (folios );
379+ return ret ;
380+ }
381+
331382static long udmabuf_create (struct miscdevice * device ,
332383 struct udmabuf_create_list * head ,
333384 struct udmabuf_create_item * list )
334385{
335- pgoff_t pgoff , pgcnt , pglimit , pgbuf = 0 ;
336- long nr_folios , ret = - EINVAL ;
337- struct file * memfd = NULL ;
338- struct folio * * folios ;
386+ pgoff_t pgcnt = 0 , pglimit ;
339387 struct udmabuf * ubuf ;
340- u32 i , j , k , flags ;
341- loff_t end ;
388+ long ret = - EINVAL ;
389+ u32 i , flags ;
342390
343391 ubuf = kzalloc (sizeof (* ubuf ), GFP_KERNEL );
344392 if (!ubuf )
@@ -347,81 +395,50 @@ static long udmabuf_create(struct miscdevice *device,
347395 INIT_LIST_HEAD (& ubuf -> unpin_list );
348396 pglimit = (size_limit_mb * 1024 * 1024 ) >> PAGE_SHIFT ;
349397 for (i = 0 ; i < head -> count ; i ++ ) {
350- if (!IS_ALIGNED (list [i ].offset , PAGE_SIZE ))
398+ if (!PAGE_ALIGNED (list [i ].offset ))
351399 goto err ;
352- if (!IS_ALIGNED (list [i ].size , PAGE_SIZE ))
400+ if (!PAGE_ALIGNED (list [i ].size ))
353401 goto err ;
354- ubuf -> pagecount += list [i ].size >> PAGE_SHIFT ;
355- if (ubuf -> pagecount > pglimit )
402+
403+ pgcnt += list [i ].size >> PAGE_SHIFT ;
404+ if (pgcnt > pglimit )
356405 goto err ;
357406 }
358407
359- if (!ubuf -> pagecount )
408+ if (!pgcnt )
360409 goto err ;
361410
362- ubuf -> folios = kvmalloc_array (ubuf -> pagecount , sizeof (* ubuf -> folios ),
363- GFP_KERNEL );
411+ ubuf -> folios = kvmalloc_array (pgcnt , sizeof (* ubuf -> folios ), GFP_KERNEL );
364412 if (!ubuf -> folios ) {
365413 ret = - ENOMEM ;
366414 goto err ;
367415 }
368- ubuf -> offsets = kvcalloc ( ubuf -> pagecount , sizeof ( * ubuf -> offsets ),
369- GFP_KERNEL );
416+
417+ ubuf -> offsets = kvcalloc ( pgcnt , sizeof ( * ubuf -> offsets ), GFP_KERNEL );
370418 if (!ubuf -> offsets ) {
371419 ret = - ENOMEM ;
372420 goto err ;
373421 }
374422
375- pgbuf = 0 ;
376423 for (i = 0 ; i < head -> count ; i ++ ) {
377- memfd = fget (list [i ].memfd );
378- ret = check_memfd_seals (memfd );
379- if (ret < 0 )
380- goto err ;
424+ struct file * memfd = fget (list [i ].memfd );
381425
382- pgcnt = list [i ].size >> PAGE_SHIFT ;
383- folios = kvmalloc_array (pgcnt , sizeof (* folios ), GFP_KERNEL );
384- if (!folios ) {
385- ret = - ENOMEM ;
426+ if (!memfd ) {
427+ ret = - EBADFD ;
386428 goto err ;
387429 }
388430
389- end = list [i ].offset + (pgcnt << PAGE_SHIFT ) - 1 ;
390- ret = memfd_pin_folios (memfd , list [i ].offset , end ,
391- folios , pgcnt , & pgoff );
392- if (ret <= 0 ) {
393- kvfree (folios );
394- if (!ret )
395- ret = - EINVAL ;
431+ ret = check_memfd_seals (memfd );
432+ if (ret < 0 ) {
433+ fput (memfd );
396434 goto err ;
397435 }
398436
399- nr_folios = ret ;
400- pgoff >>= PAGE_SHIFT ;
401- for (j = 0 , k = 0 ; j < pgcnt ; j ++ ) {
402- ubuf -> folios [pgbuf ] = folios [k ];
403- ubuf -> offsets [pgbuf ] = pgoff << PAGE_SHIFT ;
404-
405- if (j == 0 || ubuf -> folios [pgbuf - 1 ] != folios [k ]) {
406- ret = add_to_unpin_list (& ubuf -> unpin_list ,
407- folios [k ]);
408- if (ret < 0 ) {
409- kfree (folios );
410- goto err ;
411- }
412- }
413-
414- pgbuf ++ ;
415- if (++ pgoff == folio_nr_pages (folios [k ])) {
416- pgoff = 0 ;
417- if (++ k == nr_folios )
418- break ;
419- }
420- }
421-
422- kvfree (folios );
437+ ret = udmabuf_pin_folios (ubuf , memfd , list [i ].offset ,
438+ list [i ].size );
423439 fput (memfd );
424- memfd = NULL ;
440+ if (ret )
441+ goto err ;
425442 }
426443
427444 flags = head -> flags & UDMABUF_FLAGS_CLOEXEC ? O_CLOEXEC : 0 ;
@@ -432,8 +449,6 @@ static long udmabuf_create(struct miscdevice *device,
432449 return ret ;
433450
434451err :
435- if (memfd )
436- fput (memfd );
437452 unpin_all_folios (& ubuf -> unpin_list );
438453 kvfree (ubuf -> offsets );
439454 kvfree (ubuf -> folios );
0 commit comments