Skip to content

Commit 92687c7

Browse files
Steve Sistarejgunthorpe
authored andcommitted
iommufd: pfn_reader for file mappings
Extend pfn_reader_user() to pin file mappings, by calling memfd_pin_folios(). Repin at small page granularity, and fill the batch from folios. Expand folios to upages for the iopt_pages_fill() path. Link: https://patch.msgid.link/r/[email protected] Signed-off-by: Steve Sistare <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent ed9178f commit 92687c7

File tree

2 files changed

+116
-17
lines changed

2 files changed

+116
-17
lines changed

drivers/iommu/iommufd/io_pagetable.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ enum {
177177

178178
enum iopt_address_type {
179179
IOPT_ADDRESS_USER = 0,
180+
IOPT_ADDRESS_FILE = 1,
180181
};
181182

182183
/*
@@ -202,6 +203,10 @@ struct iopt_pages {
202203
enum iopt_address_type type;
203204
union {
204205
void __user *uptr; /* IOPT_ADDRESS_USER */
206+
struct { /* IOPT_ADDRESS_FILE */
207+
struct file *file;
208+
unsigned long start;
209+
};
205210
};
206211
bool writable:1;
207212
u8 account_mode;

drivers/iommu/iommufd/pages.c

Lines changed: 111 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -752,19 +752,32 @@ struct pfn_reader_user {
752752
* neither
753753
*/
754754
int locked;
755+
756+
/* The following are only valid if file != NULL. */
757+
struct file *file;
758+
struct folio **ufolios;
759+
size_t ufolios_len;
760+
unsigned long ufolios_offset;
761+
struct folio **ufolios_next;
755762
};
756763

757764
static void pfn_reader_user_init(struct pfn_reader_user *user,
758765
struct iopt_pages *pages)
759766
{
760767
user->upages = NULL;
768+
user->upages_len = 0;
761769
user->upages_start = 0;
762770
user->upages_end = 0;
763771
user->locked = -1;
764-
765772
user->gup_flags = FOLL_LONGTERM;
766773
if (pages->writable)
767774
user->gup_flags |= FOLL_WRITE;
775+
776+
user->file = (pages->type == IOPT_ADDRESS_FILE) ? pages->file : NULL;
777+
user->ufolios = NULL;
778+
user->ufolios_len = 0;
779+
user->ufolios_next = NULL;
780+
user->ufolios_offset = 0;
768781
}
769782

770783
static void pfn_reader_user_destroy(struct pfn_reader_user *user,
@@ -773,13 +786,67 @@ static void pfn_reader_user_destroy(struct pfn_reader_user *user,
773786
if (user->locked != -1) {
774787
if (user->locked)
775788
mmap_read_unlock(pages->source_mm);
776-
if (pages->source_mm != current->mm)
789+
if (!user->file && pages->source_mm != current->mm)
777790
mmput(pages->source_mm);
778791
user->locked = -1;
779792
}
780793

781794
kfree(user->upages);
782795
user->upages = NULL;
796+
kfree(user->ufolios);
797+
user->ufolios = NULL;
798+
}
799+
800+
static long pin_memfd_pages(struct pfn_reader_user *user, unsigned long start,
801+
unsigned long npages)
802+
{
803+
unsigned long i;
804+
unsigned long offset;
805+
unsigned long npages_out = 0;
806+
struct page **upages = user->upages;
807+
unsigned long end = start + (npages << PAGE_SHIFT) - 1;
808+
long nfolios = user->ufolios_len / sizeof(*user->ufolios);
809+
810+
/*
811+
* todo: memfd_pin_folios should return the last pinned offset so
812+
* we can compute npages pinned, and avoid looping over folios here
813+
* if upages == NULL.
814+
*/
815+
nfolios = memfd_pin_folios(user->file, start, end, user->ufolios,
816+
nfolios, &offset);
817+
if (nfolios <= 0)
818+
return nfolios;
819+
820+
offset >>= PAGE_SHIFT;
821+
user->ufolios_next = user->ufolios;
822+
user->ufolios_offset = offset;
823+
824+
for (i = 0; i < nfolios; i++) {
825+
struct folio *folio = user->ufolios[i];
826+
unsigned long nr = folio_nr_pages(folio);
827+
unsigned long npin = min(nr - offset, npages);
828+
829+
npages -= npin;
830+
npages_out += npin;
831+
832+
if (upages) {
833+
if (npin == 1) {
834+
*upages++ = folio_page(folio, offset);
835+
} else {
836+
int rc = folio_add_pins(folio, npin - 1);
837+
838+
if (rc)
839+
return rc;
840+
841+
while (npin--)
842+
*upages++ = folio_page(folio, offset++);
843+
}
844+
}
845+
846+
offset = 0;
847+
}
848+
849+
return npages_out;
783850
}
784851

785852
static int pfn_reader_user_pin(struct pfn_reader_user *user,
@@ -788,48 +855,60 @@ static int pfn_reader_user_pin(struct pfn_reader_user *user,
788855
unsigned long last_index)
789856
{
790857
bool remote_mm = pages->source_mm != current->mm;
791-
unsigned long npages;
858+
unsigned long npages = last_index - start_index + 1;
859+
unsigned long start;
860+
unsigned long unum;
792861
uintptr_t uptr;
793862
long rc;
794863

795864
if (IS_ENABLED(CONFIG_IOMMUFD_TEST) &&
796865
WARN_ON(last_index < start_index))
797866
return -EINVAL;
798867

799-
if (!user->upages) {
868+
if (!user->file && !user->upages) {
800869
/* All undone in pfn_reader_destroy() */
801-
user->upages_len =
802-
(last_index - start_index + 1) * sizeof(*user->upages);
870+
user->upages_len = npages * sizeof(*user->upages);
803871
user->upages = temp_kmalloc(&user->upages_len, NULL, 0);
804872
if (!user->upages)
805873
return -ENOMEM;
806874
}
807875

876+
if (user->file && !user->ufolios) {
877+
user->ufolios_len = npages * sizeof(*user->ufolios);
878+
user->ufolios = temp_kmalloc(&user->ufolios_len, NULL, 0);
879+
if (!user->ufolios)
880+
return -ENOMEM;
881+
}
882+
808883
if (user->locked == -1) {
809884
/*
810885
* The majority of usages will run the map task within the mm
811886
* providing the pages, so we can optimize into
812887
* get_user_pages_fast()
813888
*/
814-
if (remote_mm) {
889+
if (!user->file && remote_mm) {
815890
if (!mmget_not_zero(pages->source_mm))
816891
return -EFAULT;
817892
}
818893
user->locked = 0;
819894
}
820895

821-
npages = min_t(unsigned long, last_index - start_index + 1,
822-
user->upages_len / sizeof(*user->upages));
823-
896+
unum = user->file ? user->ufolios_len / sizeof(*user->ufolios) :
897+
user->upages_len / sizeof(*user->upages);
898+
npages = min_t(unsigned long, npages, unum);
824899

825900
if (iommufd_should_fail())
826901
return -EFAULT;
827902

828-
uptr = (uintptr_t)(pages->uptr + start_index * PAGE_SIZE);
829-
if (!remote_mm)
903+
if (user->file) {
904+
start = pages->start + (start_index * PAGE_SIZE);
905+
rc = pin_memfd_pages(user, start, npages);
906+
} else if (!remote_mm) {
907+
uptr = (uintptr_t)(pages->uptr + start_index * PAGE_SIZE);
830908
rc = pin_user_pages_fast(uptr, npages, user->gup_flags,
831909
user->upages);
832-
else {
910+
} else {
911+
uptr = (uintptr_t)(pages->uptr + start_index * PAGE_SIZE);
833912
if (!user->locked) {
834913
mmap_read_lock(pages->source_mm);
835914
user->locked = 1;
@@ -887,7 +966,8 @@ static int update_mm_locked_vm(struct iopt_pages *pages, unsigned long npages,
887966
mmap_read_unlock(pages->source_mm);
888967
user->locked = 0;
889968
/* If we had the lock then we also have a get */
890-
} else if ((!user || !user->upages) &&
969+
970+
} else if ((!user || (!user->upages && !user->ufolios)) &&
891971
pages->source_mm != current->mm) {
892972
if (!mmget_not_zero(pages->source_mm))
893973
return -EINVAL;
@@ -1068,8 +1148,15 @@ static int pfn_reader_fill_span(struct pfn_reader *pfns)
10681148

10691149
npages = user->upages_end - start_index;
10701150
start_index -= user->upages_start;
1071-
batch_from_pages(&pfns->batch, user->upages + start_index, npages);
1072-
return 0;
1151+
rc = 0;
1152+
1153+
if (!user->file)
1154+
batch_from_pages(&pfns->batch, user->upages + start_index,
1155+
npages);
1156+
else
1157+
rc = batch_from_folios(&pfns->batch, &user->ufolios_next,
1158+
&user->ufolios_offset, npages);
1159+
return rc;
10731160
}
10741161

10751162
static bool pfn_reader_done(struct pfn_reader *pfns)
@@ -1151,7 +1238,14 @@ static void pfn_reader_release_pins(struct pfn_reader *pfns)
11511238
unsigned long start_index = pfns->batch_end_index -
11521239
user->upages_start;
11531240

1154-
unpin_user_pages(user->upages + start_index, npages);
1241+
if (!user->file) {
1242+
unpin_user_pages(user->upages + start_index, npages);
1243+
} else {
1244+
long n = user->ufolios_len / sizeof(*user->ufolios);
1245+
1246+
unpin_folios(user->ufolios_next,
1247+
user->ufolios + n - user->ufolios_next);
1248+
}
11551249
iopt_pages_sub_npinned(pages, npages);
11561250
user->upages_end = pfns->batch_end_index;
11571251
}

0 commit comments

Comments
 (0)