Skip to content

Commit 99ff06d

Browse files
Steve Sistarejgunthorpe
authored andcommitted
iommufd: Generalize iopt_pages address
The starting address in iopt_pages is currently a __user *uptr. Generalize to allow other types of addresses. Refactor iopt_alloc_pages() and iopt_map_user_pages() into address-type specific and common functions. Link: https://patch.msgid.link/r/[email protected] Suggested-by: Nicolin Chen <[email protected]> Signed-off-by: Steve Sistare <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Reviewed-by: Nicolin Chen <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 32383c0 commit 99ff06d

File tree

3 files changed

+67
-32
lines changed

3 files changed

+67
-32
lines changed

drivers/iommu/iommufd/io_pagetable.c

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,34 @@ int iopt_map_pages(struct io_pagetable *iopt, struct list_head *pages_list,
384384
return rc;
385385
}
386386

387+
static int iopt_map_common(struct iommufd_ctx *ictx, struct io_pagetable *iopt,
388+
struct iopt_pages *pages, unsigned long *iova,
389+
unsigned long length, unsigned long start_byte,
390+
int iommu_prot, unsigned int flags)
391+
{
392+
struct iopt_pages_list elm = {};
393+
LIST_HEAD(pages_list);
394+
int rc;
395+
396+
elm.pages = pages;
397+
elm.start_byte = start_byte;
398+
if (ictx->account_mode == IOPT_PAGES_ACCOUNT_MM &&
399+
elm.pages->account_mode == IOPT_PAGES_ACCOUNT_USER)
400+
elm.pages->account_mode = IOPT_PAGES_ACCOUNT_MM;
401+
elm.length = length;
402+
list_add(&elm.next, &pages_list);
403+
404+
rc = iopt_map_pages(iopt, &pages_list, length, iova, iommu_prot, flags);
405+
if (rc) {
406+
if (elm.area)
407+
iopt_abort_area(elm.area);
408+
if (elm.pages)
409+
iopt_put_pages(elm.pages);
410+
return rc;
411+
}
412+
return 0;
413+
}
414+
387415
/**
388416
* iopt_map_user_pages() - Map a user VA to an iova in the io page table
389417
* @ictx: iommufd_ctx the iopt is part of
@@ -408,29 +436,14 @@ int iopt_map_user_pages(struct iommufd_ctx *ictx, struct io_pagetable *iopt,
408436
unsigned long length, int iommu_prot,
409437
unsigned int flags)
410438
{
411-
struct iopt_pages_list elm = {};
412-
LIST_HEAD(pages_list);
413-
int rc;
439+
struct iopt_pages *pages;
414440

415-
elm.pages = iopt_alloc_pages(uptr, length, iommu_prot & IOMMU_WRITE);
416-
if (IS_ERR(elm.pages))
417-
return PTR_ERR(elm.pages);
418-
if (ictx->account_mode == IOPT_PAGES_ACCOUNT_MM &&
419-
elm.pages->account_mode == IOPT_PAGES_ACCOUNT_USER)
420-
elm.pages->account_mode = IOPT_PAGES_ACCOUNT_MM;
421-
elm.start_byte = uptr - elm.pages->uptr;
422-
elm.length = length;
423-
list_add(&elm.next, &pages_list);
441+
pages = iopt_alloc_user_pages(uptr, length, iommu_prot & IOMMU_WRITE);
442+
if (IS_ERR(pages))
443+
return PTR_ERR(pages);
424444

425-
rc = iopt_map_pages(iopt, &pages_list, length, iova, iommu_prot, flags);
426-
if (rc) {
427-
if (elm.area)
428-
iopt_abort_area(elm.area);
429-
if (elm.pages)
430-
iopt_put_pages(elm.pages);
431-
return rc;
432-
}
433-
return 0;
445+
return iopt_map_common(ictx, iopt, pages, iova, length,
446+
uptr - pages->uptr, iommu_prot, flags);
434447
}
435448

436449
struct iova_bitmap_fn_arg {

drivers/iommu/iommufd/io_pagetable.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ enum {
175175
IOPT_PAGES_ACCOUNT_MM = 2,
176176
};
177177

178+
enum iopt_address_type {
179+
IOPT_ADDRESS_USER = 0,
180+
};
181+
178182
/*
179183
* This holds a pinned page list for multiple areas of IO address space. The
180184
* pages always originate from a linear chunk of userspace VA. Multiple
@@ -195,7 +199,10 @@ struct iopt_pages {
195199
struct task_struct *source_task;
196200
struct mm_struct *source_mm;
197201
struct user_struct *source_user;
198-
void __user *uptr;
202+
enum iopt_address_type type;
203+
union {
204+
void __user *uptr; /* IOPT_ADDRESS_USER */
205+
};
199206
bool writable:1;
200207
u8 account_mode;
201208

@@ -206,8 +213,8 @@ struct iopt_pages {
206213
struct rb_root_cached domains_itree;
207214
};
208215

209-
struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length,
210-
bool writable);
216+
struct iopt_pages *iopt_alloc_user_pages(void __user *uptr,
217+
unsigned long length, bool writable);
211218
void iopt_release_pages(struct kref *kref);
212219
static inline void iopt_put_pages(struct iopt_pages *pages)
213220
{

drivers/iommu/iommufd/pages.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,11 +1139,11 @@ static int pfn_reader_first(struct pfn_reader *pfns, struct iopt_pages *pages,
11391139
return 0;
11401140
}
11411141

1142-
struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length,
1143-
bool writable)
1142+
static struct iopt_pages *iopt_alloc_pages(unsigned long start_byte,
1143+
unsigned long length,
1144+
bool writable)
11441145
{
11451146
struct iopt_pages *pages;
1146-
unsigned long end;
11471147

11481148
/*
11491149
* The iommu API uses size_t as the length, and protect the DIV_ROUND_UP
@@ -1152,9 +1152,6 @@ struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length,
11521152
if (length > SIZE_MAX - PAGE_SIZE || length == 0)
11531153
return ERR_PTR(-EINVAL);
11541154

1155-
if (check_add_overflow((unsigned long)uptr, length, &end))
1156-
return ERR_PTR(-EOVERFLOW);
1157-
11581155
pages = kzalloc(sizeof(*pages), GFP_KERNEL_ACCOUNT);
11591156
if (!pages)
11601157
return ERR_PTR(-ENOMEM);
@@ -1164,8 +1161,7 @@ struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length,
11641161
mutex_init(&pages->mutex);
11651162
pages->source_mm = current->mm;
11661163
mmgrab(pages->source_mm);
1167-
pages->uptr = (void __user *)ALIGN_DOWN((uintptr_t)uptr, PAGE_SIZE);
1168-
pages->npages = DIV_ROUND_UP(length + (uptr - pages->uptr), PAGE_SIZE);
1164+
pages->npages = DIV_ROUND_UP(length + start_byte, PAGE_SIZE);
11691165
pages->access_itree = RB_ROOT_CACHED;
11701166
pages->domains_itree = RB_ROOT_CACHED;
11711167
pages->writable = writable;
@@ -1179,6 +1175,25 @@ struct iopt_pages *iopt_alloc_pages(void __user *uptr, unsigned long length,
11791175
return pages;
11801176
}
11811177

1178+
struct iopt_pages *iopt_alloc_user_pages(void __user *uptr,
1179+
unsigned long length, bool writable)
1180+
{
1181+
struct iopt_pages *pages;
1182+
unsigned long end;
1183+
void __user *uptr_down =
1184+
(void __user *) ALIGN_DOWN((uintptr_t)uptr, PAGE_SIZE);
1185+
1186+
if (check_add_overflow((unsigned long)uptr, length, &end))
1187+
return ERR_PTR(-EOVERFLOW);
1188+
1189+
pages = iopt_alloc_pages(uptr - uptr_down, length, writable);
1190+
if (IS_ERR(pages))
1191+
return pages;
1192+
pages->uptr = uptr_down;
1193+
pages->type = IOPT_ADDRESS_USER;
1194+
return pages;
1195+
}
1196+
11821197
void iopt_release_pages(struct kref *kref)
11831198
{
11841199
struct iopt_pages *pages = container_of(kref, struct iopt_pages, kref);

0 commit comments

Comments
 (0)