@@ -441,6 +441,7 @@ zfs_unmark_page(struct page *page)
441
441
}
442
442
#endif /* HAVE_ZERO_PAGE_GPL_ONLY || !_LP64 */
443
443
444
+ #if !defined(HAVE_PIN_USER_PAGES_UNLOCKED )
444
445
static void
445
446
zfs_uio_dio_check_for_zero_page (zfs_uio_t * uio )
446
447
{
@@ -472,6 +473,7 @@ zfs_uio_dio_check_for_zero_page(zfs_uio_t *uio)
472
473
}
473
474
}
474
475
}
476
+ #endif
475
477
476
478
void
477
479
zfs_uio_free_dio_pages (zfs_uio_t * uio , zfs_uio_rw_t rw )
@@ -480,6 +482,9 @@ zfs_uio_free_dio_pages(zfs_uio_t *uio, zfs_uio_rw_t rw)
480
482
ASSERT (uio -> uio_extflg & UIO_DIRECT );
481
483
ASSERT3P (uio -> uio_dio .pages , != , NULL );
482
484
485
+ #if defined(HAVE_PIN_USER_PAGES_UNLOCKED )
486
+ unpin_user_pages (uio -> uio_dio .pages , uio -> uio_dio .npages );
487
+ #else
483
488
for (long i = 0 ; i < uio -> uio_dio .npages ; i ++ ) {
484
489
struct page * p = uio -> uio_dio .pages [i ];
485
490
@@ -491,51 +496,114 @@ zfs_uio_free_dio_pages(zfs_uio_t *uio, zfs_uio_rw_t rw)
491
496
492
497
put_page (p );
493
498
}
494
-
499
+ #endif
495
500
vmem_free (uio -> uio_dio .pages ,
496
501
uio -> uio_dio .npages * sizeof (struct page * ));
497
502
}
498
503
504
+ #if defined(HAVE_PIN_USER_PAGES_UNLOCKED )
499
505
static int
500
- zfs_uio_get_dio_pages_iov_iter (zfs_uio_t * uio , zfs_uio_rw_t rw )
506
+ zfs_uio_pin_user_pages (zfs_uio_t * uio , zfs_uio_rw_t rw )
501
507
{
508
+ long res ;
502
509
size_t skip = uio -> uio_skip ;
510
+ size_t len = uio -> uio_resid - skip ;
511
+ unsigned int gup_flags = 0 ;
512
+ unsigned long addr ;
513
+ unsigned long nr_pages ;
514
+
515
+ /*
516
+ * Kernel 6.2 introduced the FOLL_PCI_P2PDMA flag. This flag could
517
+ * possibly be used here in the future to allow for P2P operations with
518
+ * user pages.
519
+ */
520
+ if (rw == UIO_READ )
521
+ gup_flags = FOLL_WRITE ;
522
+
523
+ if (len == 0 )
524
+ return (0 );
525
+
526
+ #if defined(HAVE_ITER_IS_UBUF )
527
+ if (iter_is_ubuf (uio -> uio_iter )) {
528
+ nr_pages = DIV_ROUND_UP (len , PAGE_SIZE );
529
+ addr = (unsigned long )uio -> uio_iter -> ubuf + skip ;
530
+ res = pin_user_pages_unlocked (addr , nr_pages ,
531
+ & uio -> uio_dio .pages [uio -> uio_dio .npages ], gup_flags );
532
+ if (res < 0 ) {
533
+ return (SET_ERROR (- res ));
534
+ } else if (len != (res * PAGE_SIZE )) {
535
+ uio -> uio_dio .npages += res ;
536
+ return (SET_ERROR (EFAULT ));
537
+ }
538
+ uio -> uio_dio .npages += res ;
539
+ return (0 );
540
+ }
541
+ #endif
542
+ const struct iovec * iovp = zfs_uio_iter_iov (uio -> uio_iter );
543
+ for (int i = 0 ; i < uio -> uio_iovcnt ; i ++ ) {
544
+ size_t amt = iovp -> iov_len - skip ;
545
+ if (amt == 0 ) {
546
+ iovp ++ ;
547
+ skip = 0 ;
548
+ continue ;
549
+ }
550
+
551
+ addr = (unsigned long )iovp -> iov_base + skip ;
552
+ nr_pages = DIV_ROUND_UP (amt , PAGE_SIZE );
553
+ res = pin_user_pages_unlocked (addr , nr_pages ,
554
+ & uio -> uio_dio .pages [uio -> uio_dio .npages ], gup_flags );
555
+ if (res < 0 ) {
556
+ return (SET_ERROR (- res ));
557
+ } else if (amt != (res * PAGE_SIZE )) {
558
+ uio -> uio_dio .npages += res ;
559
+ return (SET_ERROR (EFAULT ));
560
+ }
561
+
562
+ len -= amt ;
563
+ uio -> uio_dio .npages += res ;
564
+ skip = 0 ;
565
+ iovp ++ ;
566
+ };
567
+
568
+ ASSERT0 (len );
569
+
570
+ return (0 );
571
+ }
572
+
573
+ #else
574
+ static int
575
+ zfs_uio_get_dio_pages_iov_iter (zfs_uio_t * uio , zfs_uio_rw_t rw )
576
+ {
577
+ size_t start ;
503
578
size_t wanted = uio -> uio_resid - uio -> uio_skip ;
504
579
ssize_t rollback = 0 ;
505
580
ssize_t cnt ;
506
581
unsigned maxpages = DIV_ROUND_UP (wanted , PAGE_SIZE );
507
582
508
583
while (wanted ) {
509
- #if defined(HAVE_IOV_ITER_GET_PAGES2 )
510
- cnt = iov_iter_get_pages2 (uio -> uio_iter ,
511
- & uio -> uio_dio .pages [uio -> uio_dio .npages ],
512
- wanted , maxpages , & skip );
513
- #else
514
584
cnt = iov_iter_get_pages (uio -> uio_iter ,
515
585
& uio -> uio_dio .pages [uio -> uio_dio .npages ],
516
- wanted , maxpages , & skip );
517
- #endif
586
+ wanted , maxpages , & start );
518
587
if (cnt < 0 ) {
519
588
iov_iter_revert (uio -> uio_iter , rollback );
520
589
return (SET_ERROR (- cnt ));
521
590
}
591
+ /*
592
+ * All Direct I/O operations must be page aligned.
593
+ */
594
+ ASSERT (IS_P2ALIGNED (start , PAGE_SIZE ));
522
595
uio -> uio_dio .npages += DIV_ROUND_UP (cnt , PAGE_SIZE );
523
596
rollback += cnt ;
524
597
wanted -= cnt ;
525
- skip = 0 ;
526
- #if !defined(HAVE_IOV_ITER_GET_PAGES2 )
527
- /*
528
- * iov_iter_get_pages2() advances the iov_iter on success.
529
- */
530
598
iov_iter_advance (uio -> uio_iter , cnt );
531
- #endif
532
599
533
600
}
534
601
ASSERT3U (rollback , = = , uio -> uio_resid - uio -> uio_skip );
535
602
iov_iter_revert (uio -> uio_iter , rollback );
536
603
537
604
return (0 );
538
605
}
606
+ #endif /* HAVE_PIN_USER_PAGES_UNLOCKED */
539
607
540
608
/*
541
609
* This function pins user pages. In the event that the user pages were not
@@ -552,25 +620,34 @@ zfs_uio_get_dio_pages_alloc(zfs_uio_t *uio, zfs_uio_rw_t rw)
552
620
553
621
if (uio -> uio_segflg == UIO_ITER ) {
554
622
uio -> uio_dio .pages = vmem_alloc (size , KM_SLEEP );
623
+ #if defined(HAVE_PIN_USER_PAGES_UNLOCKED )
624
+ error = zfs_uio_pin_user_pages (uio , rw );
625
+ #else
555
626
error = zfs_uio_get_dio_pages_iov_iter (uio , rw );
627
+ #endif
556
628
} else {
557
629
return (SET_ERROR (EOPNOTSUPP ));
558
630
}
559
631
560
632
ASSERT3S (uio -> uio_dio .npages , >=, 0 );
561
633
562
634
if (error ) {
635
+ #if defined(HAVE_PIN_USER_PAGES_UNLOCKED )
636
+ unpin_user_pages (uio -> uio_dio .pages , uio -> uio_dio .npages );
637
+ #else
563
638
for (long i = 0 ; i < uio -> uio_dio .npages ; i ++ )
564
639
put_page (uio -> uio_dio .pages [i ]);
640
+ #endif
565
641
vmem_free (uio -> uio_dio .pages , size );
566
642
return (error );
567
643
} else {
568
644
ASSERT3S (uio -> uio_dio .npages , = = , npages );
569
645
}
570
646
571
- if (rw == UIO_WRITE ) {
647
+ #if !defined(HAVE_PIN_USER_PAGES_UNLOCKED )
648
+ if (rw == UIO_WRITE )
572
649
zfs_uio_dio_check_for_zero_page (uio );
573
- }
650
+ #endif
574
651
575
652
uio -> uio_extflg |= UIO_DIRECT ;
576
653
0 commit comments