Skip to content

Commit

Permalink
mm: replace get_user_pages() write/force parameters with gup_flags
Browse files Browse the repository at this point in the history
This removes the 'write' and 'force' from get_user_pages() and replaces
them with 'gup_flags' to make the use of FOLL_FORCE explicit in callers
as use of this flag can result in surprising behaviour (and hence bugs)
within the mm subsystem.

Signed-off-by: Lorenzo Stoakes <[email protected]>
Acked-by: Christian König <[email protected]>
Acked-by: Jesper Nilsson <[email protected]>
Acked-by: Michal Hocko <[email protected]>
Reviewed-by: Jan Kara <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
lorenzo-stoakes authored and torvalds committed Oct 19, 2016
1 parent 7f23b35 commit 768ae30
Show file tree
Hide file tree
Showing 22 changed files with 49 additions and 54 deletions.
4 changes: 1 addition & 3 deletions arch/cris/arch-v32/drivers/cryptocop.c
Original file line number Diff line number Diff line change
Expand Up @@ -2722,7 +2722,6 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig
err = get_user_pages((unsigned long int)(oper.indata + prev_ix),
noinpages,
0, /* read access only for in data */
0, /* no force */
inpages,
NULL);

Expand All @@ -2736,8 +2735,7 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig
if (oper.do_cipher){
err = get_user_pages((unsigned long int)oper.cipher_outdata,
nooutpages,
1, /* write access for out data */
0, /* no force */
FOLL_WRITE, /* write access for out data */
outpages,
NULL);
up_read(&current->mm->mmap_sem);
Expand Down
2 changes: 1 addition & 1 deletion arch/ia64/kernel/err_inject.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ store_virtual_to_phys(struct device *dev, struct device_attribute *attr,
u64 virt_addr=simple_strtoull(buf, NULL, 16);
int ret;

ret = get_user_pages(virt_addr, 1, VM_READ, 0, NULL, NULL);
ret = get_user_pages(virt_addr, 1, FOLL_WRITE, NULL, NULL);
if (ret<=0) {
#ifdef ERR_INJ_DEBUG
printk("Virtual address %lx is not existing.\n",virt_addr);
Expand Down
5 changes: 2 additions & 3 deletions arch/x86/mm/mpx.c
Original file line number Diff line number Diff line change
Expand Up @@ -544,10 +544,9 @@ static int mpx_resolve_fault(long __user *addr, int write)
{
long gup_ret;
int nr_pages = 1;
int force = 0;

gup_ret = get_user_pages((unsigned long)addr, nr_pages, write,
force, NULL, NULL);
gup_ret = get_user_pages((unsigned long)addr, nr_pages,
write ? FOLL_WRITE : 0, NULL, NULL);
/*
* get_user_pages() returns number of pages gotten.
* 0 means we failed to fault in and get anything,
Expand Down
7 changes: 5 additions & 2 deletions drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
Original file line number Diff line number Diff line change
Expand Up @@ -555,10 +555,13 @@ struct amdgpu_ttm_tt {
int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
{
struct amdgpu_ttm_tt *gtt = (void *)ttm;
int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
unsigned int flags = 0;
unsigned pinned = 0;
int r;

if (!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY))
flags |= FOLL_WRITE;

if (gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) {
/* check that we only use anonymous memory
to prevent problems with writeback */
Expand All @@ -581,7 +584,7 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
list_add(&guptask.list, &gtt->guptasks);
spin_unlock(&gtt->guptasklock);

r = get_user_pages(userptr, num_pages, write, 0, p, NULL);
r = get_user_pages(userptr, num_pages, flags, p, NULL);

spin_lock(&gtt->guptasklock);
list_del(&guptask.list);
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/radeon/radeon_ttm.c
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,8 @@ static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
struct page **pages = ttm->pages + pinned;

r = get_user_pages(userptr, num_pages, write, 0, pages, NULL);
r = get_user_pages(userptr, num_pages, write ? FOLL_WRITE : 0,
pages, NULL);
if (r < 0)
goto release_pages;

Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/via/via_dmablit.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
down_read(&current->mm->mmap_sem);
ret = get_user_pages((unsigned long)xfer->mem_addr,
vsg->num_pages,
(vsg->direction == DMA_FROM_DEVICE),
0, vsg->pages, NULL);
(vsg->direction == DMA_FROM_DEVICE) ? FOLL_WRITE : 0,
vsg->pages, NULL);

up_read(&current->mm->mmap_sem);
if (ret != vsg->num_pages) {
Expand Down
6 changes: 5 additions & 1 deletion drivers/infiniband/core/umem.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
unsigned long dma_attrs = 0;
struct scatterlist *sg, *sg_list_start;
int need_release = 0;
unsigned int gup_flags = FOLL_WRITE;

if (dmasync)
dma_attrs |= DMA_ATTR_WRITE_BARRIER;
Expand Down Expand Up @@ -183,14 +184,17 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
if (ret)
goto out;

if (!umem->writable)
gup_flags |= FOLL_FORCE;

need_release = 1;
sg_list_start = umem->sg_head.sgl;

while (npages) {
ret = get_user_pages(cur_base,
min_t(unsigned long, npages,
PAGE_SIZE / sizeof (struct page *)),
1, !umem->writable, page_list, vma_list);
gup_flags, page_list, vma_list);

if (ret < 0)
goto out;
Expand Down
2 changes: 1 addition & 1 deletion drivers/infiniband/hw/mthca/mthca_memfree.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
goto out;
}

ret = get_user_pages(uaddr & PAGE_MASK, 1, 1, 0, pages, NULL);
ret = get_user_pages(uaddr & PAGE_MASK, 1, FOLL_WRITE, pages, NULL);
if (ret < 0)
goto out;

Expand Down
3 changes: 2 additions & 1 deletion drivers/infiniband/hw/qib/qib_user_pages.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ static int __qib_get_user_pages(unsigned long start_page, size_t num_pages,

for (got = 0; got < num_pages; got += ret) {
ret = get_user_pages(start_page + got * PAGE_SIZE,
num_pages - got, 1, 1,
num_pages - got,
FOLL_WRITE | FOLL_FORCE,
p + got, NULL);
if (ret < 0)
goto bail_release;
Expand Down
5 changes: 4 additions & 1 deletion drivers/infiniband/hw/usnic/usnic_uiom.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
int i;
int flags;
dma_addr_t pa;
unsigned int gup_flags;

if (!can_do_mlock())
return -EPERM;
Expand All @@ -135,14 +136,16 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,

flags = IOMMU_READ | IOMMU_CACHE;
flags |= (writable) ? IOMMU_WRITE : 0;
gup_flags = FOLL_WRITE;
gup_flags |= (writable) ? 0 : FOLL_FORCE;
cur_base = addr & PAGE_MASK;
ret = 0;

while (npages) {
ret = get_user_pages(cur_base,
min_t(unsigned long, npages,
PAGE_SIZE / sizeof(struct page *)),
1, !writable, page_list, NULL);
gup_flags, page_list, NULL);

if (ret < 0)
goto out;
Expand Down
7 changes: 5 additions & 2 deletions drivers/media/v4l2-core/videobuf-dma-sg.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
{
unsigned long first, last;
int err, rw = 0;
unsigned int flags = FOLL_FORCE;

dma->direction = direction;
switch (dma->direction) {
Expand All @@ -178,12 +179,14 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
if (NULL == dma->pages)
return -ENOMEM;

if (rw == READ)
flags |= FOLL_WRITE;

dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n",
data, size, dma->nr_pages);

err = get_user_pages(data & PAGE_MASK, dma->nr_pages,
rw == READ, 1, /* force */
dma->pages, NULL);
flags, dma->pages, NULL);

if (err != dma->nr_pages) {
dma->nr_pages = (err >= 0) ? err : 0;
Expand Down
3 changes: 1 addition & 2 deletions drivers/misc/mic/scif/scif_rma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1396,8 +1396,7 @@ int __scif_pin_pages(void *addr, size_t len, int *out_prot,
pinned_pages->nr_pages = get_user_pages(
(u64)addr,
nr_pages,
!!(prot & SCIF_PROT_WRITE),
0,
(prot & SCIF_PROT_WRITE) ? FOLL_WRITE : 0,
pinned_pages->pages,
NULL);
up_write(&mm->mmap_sem);
Expand Down
2 changes: 1 addition & 1 deletion drivers/misc/sgi-gru/grufault.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma,
#else
*pageshift = PAGE_SHIFT;
#endif
if (get_user_pages(vaddr, 1, write, 0, &page, NULL) <= 0)
if (get_user_pages(vaddr, 1, write ? FOLL_WRITE : 0, &page, NULL) <= 0)
return -EFAULT;
*paddr = page_to_phys(page);
put_page(page);
Expand Down
3 changes: 2 additions & 1 deletion drivers/platform/goldfish/goldfish_pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
* much memory to the process.
*/
down_read(&current->mm->mmap_sem);
ret = get_user_pages(address, 1, !is_write, 0, &page, NULL);
ret = get_user_pages(address, 1, is_write ? 0 : FOLL_WRITE,
&page, NULL);
up_read(&current->mm->mmap_sem);
if (ret < 0)
break;
Expand Down
3 changes: 2 additions & 1 deletion drivers/rapidio/devices/rio_mport_cdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -892,7 +892,8 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode,
down_read(&current->mm->mmap_sem);
pinned = get_user_pages(
(unsigned long)xfer->loc_addr & PAGE_MASK,
nr_pages, dir == DMA_FROM_DEVICE, 0,
nr_pages,
dir == DMA_FROM_DEVICE ? FOLL_WRITE : 0,
page_list, NULL);
up_read(&current->mm->mmap_sem);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -423,8 +423,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
actual_pages = get_user_pages(task, task->mm,
(unsigned long)buf & ~(PAGE_SIZE - 1),
num_pages,
(type == PAGELIST_READ) /*Write */ ,
0 /*Force */ ,
(type == PAGELIST_READ) ? FOLL_WRITE : 0,
pages,
NULL /*vmas */);
up_read(&task->mm->mmap_sem);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1477,8 +1477,7 @@ dump_phys_mem(void *virt_addr, uint32_t num_bytes)
current->mm, /* mm */
(unsigned long)virt_addr, /* start */
num_pages, /* len */
0, /* write */
0, /* force */
0, /* gup_flags */
pages, /* pages (array of page pointers) */
NULL); /* vmas */
up_read(&current->mm->mmap_sem);
Expand Down
4 changes: 2 additions & 2 deletions drivers/virt/fsl_hypervisor.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,8 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
/* Get the physical addresses of the source buffer */
down_read(&current->mm->mmap_sem);
num_pinned = get_user_pages(param.local_vaddr - lb_offset,
num_pages, (param.source == -1) ? READ : WRITE,
0, pages, NULL);
num_pages, (param.source == -1) ? 0 : FOLL_WRITE,
pages, NULL);
up_read(&current->mm->mmap_sem);

if (num_pinned != num_pages) {
Expand Down
2 changes: 1 addition & 1 deletion include/linux/mm.h
Original file line number Diff line number Diff line change
Expand Up @@ -1279,7 +1279,7 @@ long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
int write, int force, struct page **pages,
struct vm_area_struct **vmas);
long get_user_pages(unsigned long start, unsigned long nr_pages,
int write, int force, struct page **pages,
unsigned int gup_flags, struct page **pages,
struct vm_area_struct **vmas);
long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
unsigned int gup_flags, struct page **pages, int *locked);
Expand Down
12 changes: 3 additions & 9 deletions mm/gup.c
Original file line number Diff line number Diff line change
Expand Up @@ -987,18 +987,12 @@ EXPORT_SYMBOL(get_user_pages_remote);
* obviously don't pass FOLL_REMOTE in here.
*/
long get_user_pages(unsigned long start, unsigned long nr_pages,
int write, int force, struct page **pages,
unsigned int gup_flags, struct page **pages,
struct vm_area_struct **vmas)
{
unsigned int flags = FOLL_TOUCH;

if (write)
flags |= FOLL_WRITE;
if (force)
flags |= FOLL_FORCE;

return __get_user_pages_locked(current, current->mm, start, nr_pages,
pages, vmas, NULL, false, flags);
pages, vmas, NULL, false,
gup_flags | FOLL_TOUCH);
}
EXPORT_SYMBOL(get_user_pages);

Expand Down
2 changes: 1 addition & 1 deletion mm/mempolicy.c
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ static int lookup_node(unsigned long addr)
struct page *p;
int err;

err = get_user_pages(addr & PAGE_MASK, 1, 0, 0, &p, NULL);
err = get_user_pages(addr & PAGE_MASK, 1, 0, &p, NULL);
if (err >= 0) {
err = page_to_nid(p);
put_page(p);
Expand Down
18 changes: 4 additions & 14 deletions mm/nommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,29 +160,19 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
* - don't permit access to VMAs that don't support it, such as I/O mappings
*/
long get_user_pages(unsigned long start, unsigned long nr_pages,
int write, int force, struct page **pages,
unsigned int gup_flags, struct page **pages,
struct vm_area_struct **vmas)
{
int flags = 0;

if (write)
flags |= FOLL_WRITE;
if (force)
flags |= FOLL_FORCE;

return __get_user_pages(current, current->mm, start, nr_pages, flags,
pages, vmas, NULL);
return __get_user_pages(current, current->mm, start, nr_pages,
gup_flags, pages, vmas, NULL);
}
EXPORT_SYMBOL(get_user_pages);

long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
unsigned int gup_flags, struct page **pages,
int *locked)
{
int write = gup_flags & FOLL_WRITE;
int force = gup_flags & FOLL_FORCE;

return get_user_pages(start, nr_pages, write, force, pages, NULL);
return get_user_pages(start, nr_pages, gup_flags, pages, NULL);
}
EXPORT_SYMBOL(get_user_pages_locked);

Expand Down

0 comments on commit 768ae30

Please sign in to comment.