diff mbox series

Add kv_to_page()

Message ID 20190121003944.GA26866@bombadil.infradead.org (mailing list archive)
State New, archived
Headers show
Series Add kv_to_page() | expand

Commit Message

Matthew Wilcox (Oracle) Jan. 21, 2019, 12:39 a.m. UTC
We currently have 12 places in the kernel which call either
vmalloc_to_page() or virt_to_page() or even kmap_to_page() depending on
the type of memory passed to them.  This is clearly useful functionality
we should provide in the kernel core so add kv_to_page() and convert
these users.

Signed-off-by: Matthew Wilcox <willy@infradead.org>

---
 drivers/fpga/fpga-mgr.c                  |    5 +----
 drivers/gpu/drm/ttm/ttm_page_alloc_dma.c |    5 +----
 drivers/md/bcache/util.c                 |    5 +----
 drivers/md/dm-writecache.c               |   17 ++---------------
 drivers/misc/mic/scif/scif_rma.c         |   26 ++++----------------------
 drivers/spi/spi.c                        |    5 +----
 drivers/uio/uio.c                        |    5 +----
 drivers/virt/vboxguest/vboxguest_utils.c |   10 +---------
 fs/xfs/xfs_buf.c                         |   13 +------------
 include/linux/mm.h                       |    2 ++
 mm/util.c                                |   12 ++++++++++++
 net/9p/trans_virtio.c                    |    5 +----
 net/ceph/crypto.c                        |    6 +-----
 net/packet/af_packet.c                   |   31 ++++++++++++-------------------
 14 files changed, 41 insertions(+), 106 deletions(-)

Comments

Mike Rapoport Jan. 21, 2019, 9:37 a.m. UTC | #1
On Sun, Jan 20, 2019 at 04:39:44PM -0800, Matthew Wilcox wrote:
> 
> We currently have 12 places in the kernel which call either
> vmalloc_to_page() or virt_to_page() or even kmap_to_page() depending on
> the type of memory passed to them.  This is clearly useful functionality
> we should provide in the kernel core so add kv_to_page() and convert
> these users.
> 
> Signed-off-by: Matthew Wilcox <willy@infradead.org>
> 
> ---
>  drivers/fpga/fpga-mgr.c                  |    5 +----
>  drivers/gpu/drm/ttm/ttm_page_alloc_dma.c |    5 +----
>  drivers/md/bcache/util.c                 |    5 +----
>  drivers/md/dm-writecache.c               |   17 ++---------------
>  drivers/misc/mic/scif/scif_rma.c         |   26 ++++----------------------
>  drivers/spi/spi.c                        |    5 +----
>  drivers/uio/uio.c                        |    5 +----
>  drivers/virt/vboxguest/vboxguest_utils.c |   10 +---------
>  fs/xfs/xfs_buf.c                         |   13 +------------
>  include/linux/mm.h                       |    2 ++
>  mm/util.c                                |   12 ++++++++++++
>  net/9p/trans_virtio.c                    |    5 +----
>  net/ceph/crypto.c                        |    6 +-----
>  net/packet/af_packet.c                   |   31 ++++++++++++-------------------
>  14 files changed, 41 insertions(+), 106 deletions(-)
> 
> diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
> index c3866816456a..a39b2461a3d1 100644
> --- a/drivers/fpga/fpga-mgr.c
> +++ b/drivers/fpga/fpga-mgr.c
> @@ -275,10 +275,7 @@ static int fpga_mgr_buf_load(struct fpga_manager *mgr,
> 
>  	p = buf - offset_in_page(buf);
>  	for (index = 0; index < nr_pages; index++) {
> -		if (is_vmalloc_addr(p))
> -			pages[index] = vmalloc_to_page(p);
> -		else
> -			pages[index] = kmap_to_page((void *)p);
> +		pages[index] = kv_to_page(p);
>  		if (!pages[index]) {
>  			kfree(pages);
>  			return -EFAULT;
> diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
> index d594f7520b7b..46326de4d9fe 100644
> --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
> +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
> @@ -308,10 +308,7 @@ static struct dma_page *__ttm_dma_alloc_page(struct dma_pool *pool)
>  	vaddr = dma_alloc_attrs(pool->dev, pool->size, &d_page->dma,
>  				pool->gfp_flags, attrs);
>  	if (vaddr) {
> -		if (is_vmalloc_addr(vaddr))
> -			d_page->p = vmalloc_to_page(vaddr);
> -		else
> -			d_page->p = virt_to_page(vaddr);
> +		d_page->p = kv_to_page(vaddr);
>  		d_page->vaddr = (unsigned long)vaddr;
>  		if (pool->type & IS_HUGE)
>  			d_page->vaddr |= VADDR_FLAG_HUGE_POOL;
> diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c
> index 20eddeac1531..2609ba9f27b6 100644
> --- a/drivers/md/bcache/util.c
> +++ b/drivers/md/bcache/util.c
> @@ -244,10 +244,7 @@ void bch_bio_map(struct bio *bio, void *base)
>  start:		bv->bv_len	= min_t(size_t, PAGE_SIZE - bv->bv_offset,
>  					size);
>  		if (base) {
> -			bv->bv_page = is_vmalloc_addr(base)
> -				? vmalloc_to_page(base)
> -				: virt_to_page(base);
> -
> +			bv->bv_page = kv_to_page(base);
>  			base += bv->bv_len;
>  		}
> 
> diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c
> index 2b8cee35e4d5..50ae919d66b9 100644
> --- a/drivers/md/dm-writecache.c
> +++ b/drivers/md/dm-writecache.c
> @@ -318,19 +318,6 @@ static void persistent_memory_release(struct dm_writecache *wc)
>  		vunmap(wc->memory_map - ((size_t)wc->start_sector << SECTOR_SHIFT));
>  }
> 
> -static struct page *persistent_memory_page(void *addr)
> -{
> -	if (is_vmalloc_addr(addr))
> -		return vmalloc_to_page(addr);
> -	else
> -		return virt_to_page(addr);
> -}
> -
> -static unsigned persistent_memory_page_offset(void *addr)
> -{
> -	return (unsigned long)addr & (PAGE_SIZE - 1);
> -}
> -
>  static void persistent_memory_flush_cache(void *ptr, size_t size)
>  {
>  	if (is_vmalloc_addr(ptr))
> @@ -1439,8 +1426,8 @@ static bool wc_add_block(struct writeback_struct *wb, struct wc_entry *e, gfp_t
>  	void *address = memory_data(wc, e);
> 
>  	persistent_memory_flush_cache(address, block_size);
> -	return bio_add_page(&wb->bio, persistent_memory_page(address),
> -			    block_size, persistent_memory_page_offset(address)) != 0;
> +	return bio_add_page(&wb->bio, kv_to_page(address), block_size,
> +			offset_in_page(address)) != 0;

This would be less eye hurting with 

	struct page *page = kv_to_page(address);
	unsigned offset = offset_in_page(address);

defined.

>  }
> 
>  struct writeback_list {
> diff --git a/drivers/misc/mic/scif/scif_rma.c b/drivers/misc/mic/scif/scif_rma.c
> index 749321eb91ae..ee38b346985c 100644
> --- a/drivers/misc/mic/scif/scif_rma.c
> +++ b/drivers/misc/mic/scif/scif_rma.c
> @@ -370,7 +370,6 @@ static int scif_create_remote_lookup(struct scif_dev *remote_dev,
>  {
>  	int i, j, err = 0;
>  	int nr_pages = window->nr_pages;
> -	bool vmalloc_dma_phys, vmalloc_num_pages;
> 
>  	might_sleep();
>  	/* Map window */
> @@ -403,23 +402,14 @@ static int scif_create_remote_lookup(struct scif_dev *remote_dev,
>  		goto error_window;
>  	}
> 
> -	vmalloc_dma_phys = is_vmalloc_addr(&window->dma_addr[0]);
> -	vmalloc_num_pages = is_vmalloc_addr(&window->num_pages[0]);
> -
>  	/* Now map each of the pages containing physical addresses */
>  	for (i = 0, j = 0; i < nr_pages; i += SCIF_NR_ADDR_IN_PAGE, j++) {
>  		err = scif_map_page(&window->dma_addr_lookup.lookup[j],
> -				    vmalloc_dma_phys ?
> -				    vmalloc_to_page(&window->dma_addr[i]) :
> -				    virt_to_page(&window->dma_addr[i]),
> -				    remote_dev);
> +				kv_to_page(&window->dma_addr[i]), remote_dev);
>  		if (err)
>  			goto error_window;
>  		err = scif_map_page(&window->num_pages_lookup.lookup[j],
> -				    vmalloc_num_pages ?
> -				    vmalloc_to_page(&window->num_pages[i]) :
> -				    virt_to_page(&window->num_pages[i]),
> -				    remote_dev);
> +				kv_to_page(&window->num_pages[i]), remote_dev);

I'd add a temporary variable here.

>  		if (err)
>  			goto error_window;
>  	}
> @@ -1327,7 +1317,6 @@ int __scif_pin_pages(void *addr, size_t len, int *out_prot,
>  {
>  	struct scif_pinned_pages *pinned_pages;
>  	int nr_pages, err = 0, i;
> -	bool vmalloc_addr = false;
>  	bool try_upgrade = false;
>  	int prot = *out_prot;
>  	int ulimit = 0;
> @@ -1358,16 +1347,9 @@ int __scif_pin_pages(void *addr, size_t len, int *out_prot,
>  		return -ENOMEM;
> 
>  	if (map_flags & SCIF_MAP_KERNEL) {
> -		if (is_vmalloc_addr(addr))
> -			vmalloc_addr = true;
> -
>  		for (i = 0; i < nr_pages; i++) {
> -			if (vmalloc_addr)
> -				pinned_pages->pages[i] =
> -					vmalloc_to_page(addr + (i * PAGE_SIZE));
> -			else
> -				pinned_pages->pages[i] =
> -					virt_to_page(addr + (i * PAGE_SIZE));
> +			pinned_pages->pages[i] =
> +				kv_to_page(addr + (i * PAGE_SIZE));
>  		}
>  		pinned_pages->nr_pages = nr_pages;
>  		pinned_pages->map_flags = SCIF_MAP_KERNEL;
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index 9a7def7c3237..1382cc18e7db 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -833,10 +833,7 @@ int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
>  			min = min_t(size_t, desc_len,
>  				    min_t(size_t, len,
>  					  PAGE_SIZE - offset_in_page(buf)));
> -			if (vmalloced_buf)
> -				vm_page = vmalloc_to_page(buf);
> -			else
> -				vm_page = kmap_to_page(buf);
> +			vm_page = kv_to_page(buf);
>  			if (!vm_page) {
>  				sg_free_table(sgt);
>  				return -ENOMEM;
> diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
> index 131342280b46..6de5ffa506c0 100644
> --- a/drivers/uio/uio.c
> +++ b/drivers/uio/uio.c
> @@ -692,10 +692,7 @@ static vm_fault_t uio_vma_fault(struct vm_fault *vmf)
>  	offset = (vmf->pgoff - mi) << PAGE_SHIFT;
> 
>  	addr = (void *)(unsigned long)idev->info->mem[mi].addr + offset;
> -	if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
> -		page = virt_to_page(addr);
> -	else
> -		page = vmalloc_to_page(addr);
> +	page = kv_to_page(addr);
>  	get_page(page);
>  	vmf->page = page;
> 
> diff --git a/drivers/virt/vboxguest/vboxguest_utils.c b/drivers/virt/vboxguest/vboxguest_utils.c
> index bf4474214b4d..4999b17210c9 100644
> --- a/drivers/virt/vboxguest/vboxguest_utils.c
> +++ b/drivers/virt/vboxguest/vboxguest_utils.c
> @@ -326,8 +326,6 @@ static void hgcm_call_init_linaddr(struct vmmdev_hgcm_call *call,
>  	enum vmmdev_hgcm_function_parameter_type type, u32 *off_extra)
>  {
>  	struct vmmdev_hgcm_pagelist *dst_pg_lst;
> -	struct page *page;
> -	bool is_vmalloc;
>  	u32 i, page_count;
> 
>  	dst_parm->type = type;
> @@ -340,7 +338,6 @@ static void hgcm_call_init_linaddr(struct vmmdev_hgcm_call *call,
> 
>  	dst_pg_lst = (void *)call + *off_extra;
>  	page_count = hgcm_call_buf_size_in_pages(buf, len);
> -	is_vmalloc = is_vmalloc_addr(buf);
> 
>  	dst_parm->type = VMMDEV_HGCM_PARM_TYPE_PAGELIST;
>  	dst_parm->u.page_list.size = len;
> @@ -350,12 +347,7 @@ static void hgcm_call_init_linaddr(struct vmmdev_hgcm_call *call,
>  	dst_pg_lst->page_count = page_count;
> 
>  	for (i = 0; i < page_count; i++) {
> -		if (is_vmalloc)
> -			page = vmalloc_to_page(buf);
> -		else
> -			page = virt_to_page(buf);
> -
> -		dst_pg_lst->pages[i] = page_to_phys(page);
> +		dst_pg_lst->pages[i] = page_to_phys(kv_to_page(buf));
>  		buf += PAGE_SIZE;
>  	}
> 
> diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
> index b21ea2ba768d..b84ecd2a012d 100644
> --- a/fs/xfs/xfs_buf.c
> +++ b/fs/xfs/xfs_buf.c
> @@ -922,17 +922,6 @@ xfs_buf_set_empty(
>  	bp->b_maps[0].bm_len = bp->b_length;
>  }
> 
> -static inline struct page *
> -mem_to_page(
> -	void			*addr)
> -{
> -	if ((!is_vmalloc_addr(addr))) {
> -		return virt_to_page(addr);
> -	} else {
> -		return vmalloc_to_page(addr);
> -	}
> -}
> -
>  int
>  xfs_buf_associate_memory(
>  	xfs_buf_t		*bp,
> @@ -965,7 +954,7 @@ xfs_buf_associate_memory(
>  	bp->b_offset = offset;
> 
>  	for (i = 0; i < bp->b_page_count; i++) {
> -		bp->b_pages[i] = mem_to_page((void *)pageaddr);
> +		bp->b_pages[i] = kv_to_page((void *)pageaddr);
>  		pageaddr += PAGE_SIZE;
>  	}
> 
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index c6a5aabc7f85..5056fe66f259 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -691,6 +691,8 @@ static inline struct page *virt_to_head_page(const void *x)
>  	return compound_head(page);
>  }
> 
> +struct page *kv_to_page(const void *addr);
> +
>  void __put_page(struct page *page);
> 
>  void put_pages_list(struct list_head *pages);
> diff --git a/mm/util.c b/mm/util.c
> index 4df23d64aac7..a7ddfbe04a15 100644
> --- a/mm/util.c
> +++ b/mm/util.c
> @@ -446,6 +446,18 @@ void kvfree(const void *addr)
>  }
>  EXPORT_SYMBOL(kvfree);
> 
> +/**
> + * kv_to_page() - Return the struct page for a virtual address
> + * @addr: Virtual address

I know adding 'Return:' here is redundant, but without it there will be
warning in 'make V=1 htmldocs'.

> + */
> +struct page *kv_to_page(const void *addr)
> +{
> +	if (is_vmalloc_addr(addr))
> +		return vmalloc_to_page(addr);
> +	return kmap_to_page((void *)addr);
> +}
> +EXPORT_SYMBOL(kv_to_page);
> +
>  static inline void *__page_rmapping(struct page *page)
>  {
>  	unsigned long mapping;
> diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
> index b1d39cabf125..2afdf6f3418b 100644
> --- a/net/9p/trans_virtio.c
> +++ b/net/9p/trans_virtio.c
> @@ -377,10 +377,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
>  		*need_drop = 0;
>  		p -= (*offs = offset_in_page(p));
>  		for (index = 0; index < nr_pages; index++) {
> -			if (is_vmalloc_addr(p))
> -				(*pages)[index] = vmalloc_to_page(p);
> -			else
> -				(*pages)[index] = kmap_to_page(p);
> +			(*pages)[index] = kv_to_page(p);
>  			p += PAGE_SIZE;
>  		}
>  		return len;
> diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c
> index 5d6724cee38f..4e13e88dd38c 100644
> --- a/net/ceph/crypto.c
> +++ b/net/ceph/crypto.c
> @@ -191,11 +191,7 @@ static int setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg,
>  		struct page *page;
>  		unsigned int len = min(chunk_len - off, buf_len);
> 
> -		if (is_vmalloc)
> -			page = vmalloc_to_page(buf);
> -		else
> -			page = virt_to_page(buf);
> -
> +		page = kv_to_page(buf);
>  		sg_set_page(sg, page, len, off);
> 
>  		off = 0;
> diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
> index a74650e98f42..c87ea1c09882 100644
> --- a/net/packet/af_packet.c
> +++ b/net/packet/af_packet.c
> @@ -359,13 +359,6 @@ static void unregister_prot_hook(struct sock *sk, bool sync)
>  		__unregister_prot_hook(sk, sync);
>  }
> 
> -static inline struct page * __pure pgv_to_page(void *addr)
> -{
> -	if (is_vmalloc_addr(addr))
> -		return vmalloc_to_page(addr);
> -	return virt_to_page(addr);
> -}
> -
>  static void __packet_set_status(struct packet_sock *po, void *frame, int status)
>  {
>  	union tpacket_uhdr h;
> @@ -374,15 +367,15 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status)
>  	switch (po->tp_version) {
>  	case TPACKET_V1:
>  		h.h1->tp_status = status;
> -		flush_dcache_page(pgv_to_page(&h.h1->tp_status));
> +		flush_dcache_page(kv_to_page(&h.h1->tp_status));
>  		break;
>  	case TPACKET_V2:
>  		h.h2->tp_status = status;
> -		flush_dcache_page(pgv_to_page(&h.h2->tp_status));
> +		flush_dcache_page(kv_to_page(&h.h2->tp_status));
>  		break;
>  	case TPACKET_V3:
>  		h.h3->tp_status = status;
> -		flush_dcache_page(pgv_to_page(&h.h3->tp_status));
> +		flush_dcache_page(kv_to_page(&h.h3->tp_status));
>  		break;
>  	default:
>  		WARN(1, "TPACKET version not supported.\n");
> @@ -401,13 +394,13 @@ static int __packet_get_status(struct packet_sock *po, void *frame)
>  	h.raw = frame;
>  	switch (po->tp_version) {
>  	case TPACKET_V1:
> -		flush_dcache_page(pgv_to_page(&h.h1->tp_status));
> +		flush_dcache_page(kv_to_page(&h.h1->tp_status));
>  		return h.h1->tp_status;
>  	case TPACKET_V2:
> -		flush_dcache_page(pgv_to_page(&h.h2->tp_status));
> +		flush_dcache_page(kv_to_page(&h.h2->tp_status));
>  		return h.h2->tp_status;
>  	case TPACKET_V3:
> -		flush_dcache_page(pgv_to_page(&h.h3->tp_status));
> +		flush_dcache_page(kv_to_page(&h.h3->tp_status));
>  		return h.h3->tp_status;
>  	default:
>  		WARN(1, "TPACKET version not supported.\n");
> @@ -462,7 +455,7 @@ static __u32 __packet_set_timestamp(struct packet_sock *po, void *frame,
>  	}
> 
>  	/* one flush is safe, as both fields always lie on the same cacheline */
> -	flush_dcache_page(pgv_to_page(&h.h1->tp_sec));
> +	flush_dcache_page(kv_to_page(&h.h1->tp_sec));
>  	smp_wmb();
> 
>  	return ts_status;
> @@ -728,7 +721,7 @@ static void prb_flush_block(struct tpacket_kbdq_core *pkc1,
> 
>  	end = (u8 *)PAGE_ALIGN((unsigned long)pkc1->pkblk_end);
>  	for (; start < end; start += PAGE_SIZE)
> -		flush_dcache_page(pgv_to_page(start));
> +		flush_dcache_page(kv_to_page(start));
> 
>  	smp_wmb();
>  #endif
> @@ -741,7 +734,7 @@ static void prb_flush_block(struct tpacket_kbdq_core *pkc1,
> 
>  #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1
>  	start = (u8 *)pbd1;
> -	flush_dcache_page(pgv_to_page(start));
> +	flush_dcache_page(kv_to_page(start));
> 
>  	smp_wmb();
>  #endif
> @@ -2352,7 +2345,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
>  					macoff + snaplen);
> 
>  		for (start = h.raw; start < end; start += PAGE_SIZE)
> -			flush_dcache_page(pgv_to_page(start));
> +			flush_dcache_page(kv_to_page(start));
>  	}
>  	smp_wmb();
>  #endif
> @@ -2508,7 +2501,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
>  			return -EFAULT;
>  		}
> 
> -		page = pgv_to_page(data);
> +		page = kv_to_page(data);
>  		data += len;
>  		flush_dcache_page(page);
>  		get_page(page);
> @@ -4423,7 +4416,7 @@ static int packet_mmap(struct file *file, struct socket *sock,
>  			int pg_num;
> 
>  			for (pg_num = 0; pg_num < rb->pg_vec_pages; pg_num++) {
> -				page = pgv_to_page(kaddr);
> +				page = kv_to_page(kaddr);
>  				err = vm_insert_page(vma, start, page);
>  				if (unlikely(err))
>  					goto out;
>
Christoph Hellwig Jan. 21, 2019, 3:02 p.m. UTC | #2
> > diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
> > index d594f7520b7b..46326de4d9fe 100644
> > --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
> > +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
> > @@ -308,10 +308,7 @@ static struct dma_page *__ttm_dma_alloc_page(struct dma_pool *pool)
> >  	vaddr = dma_alloc_attrs(pool->dev, pool->size, &d_page->dma,
> >  				pool->gfp_flags, attrs);
> >  	if (vaddr) {
> > -		if (is_vmalloc_addr(vaddr))
> > -			d_page->p = vmalloc_to_page(vaddr);
> > -		else
> > -			d_page->p = virt_to_page(vaddr);
> > +		d_page->p = kv_to_page(vaddr);
> >  		d_page->vaddr = (unsigned long)vaddr;

This code doesn't need cosmetic cleanup but a real fix.  Calling
either vmalloc_to_page OR virt_to_page on the return value of
dma_alloc_* is not allowed, an will break for many of the
implementations.

> > +++ b/drivers/md/bcache/util.c
> > @@ -244,10 +244,7 @@ void bch_bio_map(struct bio *bio, void *base)
> >  start:		bv->bv_len	= min_t(size_t, PAGE_SIZE - bv->bv_offset,
> >  					size);
> >  		if (base) {
> > -			bv->bv_page = is_vmalloc_addr(base)
> > -				? vmalloc_to_page(base)
> > -				: virt_to_page(base);
> > -
> > +			bv->bv_page = kv_to_page(base);
> >  			base += bv->bv_len;
> >  		}

This one also is broken, although not quite as badly.  Anyone using
vmalloc-like memory for bios need to call invalidate_kernel_vmap_range /
flush_kernel_vmap_range to maintain cache coherency for VIVT caches.

It seems this odd bcache API just makes it way to easy to miss that.

> > @@ -403,23 +402,14 @@ static int scif_create_remote_lookup(struct scif_dev *remote_dev,
> >  		goto error_window;
> >  	}
> > 
> > -	vmalloc_dma_phys = is_vmalloc_addr(&window->dma_addr[0]);
> > -	vmalloc_num_pages = is_vmalloc_addr(&window->num_pages[0]);
> > -
> >  	/* Now map each of the pages containing physical addresses */
> >  	for (i = 0, j = 0; i < nr_pages; i += SCIF_NR_ADDR_IN_PAGE, j++) {
> >  		err = scif_map_page(&window->dma_addr_lookup.lookup[j],
> > -				    vmalloc_dma_phys ?
> > -				    vmalloc_to_page(&window->dma_addr[i]) :
> > -				    virt_to_page(&window->dma_addr[i]),
> > -				    remote_dev);
> > +				kv_to_page(&window->dma_addr[i]), remote_dev);

Similar issue here.  We can't just DMA map pages returned from
vmalloc_to_page without very explicit cache maintainance.

> >  		pinned_pages->map_flags = SCIF_MAP_KERNEL;
> > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> > index 9a7def7c3237..1382cc18e7db 100644
> > --- a/drivers/spi/spi.c
> > +++ b/drivers/spi/spi.c
> > @@ -833,10 +833,7 @@ int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
> >  			min = min_t(size_t, desc_len,
> >  				    min_t(size_t, len,
> >  					  PAGE_SIZE - offset_in_page(buf)));
> > -			if (vmalloced_buf)
> > -				vm_page = vmalloc_to_page(buf);
> > -			else
> > -				vm_page = kmap_to_page(buf);
> > +			vm_page = kv_to_page(buf);

Same issue here again :(

> > diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c
> > index 5d6724cee38f..4e13e88dd38c 100644
> > --- a/net/ceph/crypto.c
> > +++ b/net/ceph/crypto.c
> > @@ -191,11 +191,7 @@ static int setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg,
> >  		struct page *page;
> >  		unsigned int len = min(chunk_len - off, buf_len);
> > 
> > -		if (is_vmalloc)
> > -			page = vmalloc_to_page(buf);
> > -		else
> > -			page = virt_to_page(buf);
> > -
> > +		page = kv_to_page(buf);
> >  		sg_set_page(sg, page, len, off);

Another issue of the same kind.

> > 
> > -static inline struct page * __pure pgv_to_page(void *addr)
> > -{
> > -	if (is_vmalloc_addr(addr))
> > -		return vmalloc_to_page(addr);
> > -	return virt_to_page(addr);
> > -}

This one plays really odd flush_dcache_page games, which looks like
a workaround for the above proper APIs.
diff mbox series

Patch

diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
index c3866816456a..a39b2461a3d1 100644
--- a/drivers/fpga/fpga-mgr.c
+++ b/drivers/fpga/fpga-mgr.c
@@ -275,10 +275,7 @@  static int fpga_mgr_buf_load(struct fpga_manager *mgr,
 
 	p = buf - offset_in_page(buf);
 	for (index = 0; index < nr_pages; index++) {
-		if (is_vmalloc_addr(p))
-			pages[index] = vmalloc_to_page(p);
-		else
-			pages[index] = kmap_to_page((void *)p);
+		pages[index] = kv_to_page(p);
 		if (!pages[index]) {
 			kfree(pages);
 			return -EFAULT;
diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
index d594f7520b7b..46326de4d9fe 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
@@ -308,10 +308,7 @@  static struct dma_page *__ttm_dma_alloc_page(struct dma_pool *pool)
 	vaddr = dma_alloc_attrs(pool->dev, pool->size, &d_page->dma,
 				pool->gfp_flags, attrs);
 	if (vaddr) {
-		if (is_vmalloc_addr(vaddr))
-			d_page->p = vmalloc_to_page(vaddr);
-		else
-			d_page->p = virt_to_page(vaddr);
+		d_page->p = kv_to_page(vaddr);
 		d_page->vaddr = (unsigned long)vaddr;
 		if (pool->type & IS_HUGE)
 			d_page->vaddr |= VADDR_FLAG_HUGE_POOL;
diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c
index 20eddeac1531..2609ba9f27b6 100644
--- a/drivers/md/bcache/util.c
+++ b/drivers/md/bcache/util.c
@@ -244,10 +244,7 @@  void bch_bio_map(struct bio *bio, void *base)
 start:		bv->bv_len	= min_t(size_t, PAGE_SIZE - bv->bv_offset,
 					size);
 		if (base) {
-			bv->bv_page = is_vmalloc_addr(base)
-				? vmalloc_to_page(base)
-				: virt_to_page(base);
-
+			bv->bv_page = kv_to_page(base);
 			base += bv->bv_len;
 		}
 
diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c
index 2b8cee35e4d5..50ae919d66b9 100644
--- a/drivers/md/dm-writecache.c
+++ b/drivers/md/dm-writecache.c
@@ -318,19 +318,6 @@  static void persistent_memory_release(struct dm_writecache *wc)
 		vunmap(wc->memory_map - ((size_t)wc->start_sector << SECTOR_SHIFT));
 }
 
-static struct page *persistent_memory_page(void *addr)
-{
-	if (is_vmalloc_addr(addr))
-		return vmalloc_to_page(addr);
-	else
-		return virt_to_page(addr);
-}
-
-static unsigned persistent_memory_page_offset(void *addr)
-{
-	return (unsigned long)addr & (PAGE_SIZE - 1);
-}
-
 static void persistent_memory_flush_cache(void *ptr, size_t size)
 {
 	if (is_vmalloc_addr(ptr))
@@ -1439,8 +1426,8 @@  static bool wc_add_block(struct writeback_struct *wb, struct wc_entry *e, gfp_t
 	void *address = memory_data(wc, e);
 
 	persistent_memory_flush_cache(address, block_size);
-	return bio_add_page(&wb->bio, persistent_memory_page(address),
-			    block_size, persistent_memory_page_offset(address)) != 0;
+	return bio_add_page(&wb->bio, kv_to_page(address), block_size,
+			offset_in_page(address)) != 0;
 }
 
 struct writeback_list {
diff --git a/drivers/misc/mic/scif/scif_rma.c b/drivers/misc/mic/scif/scif_rma.c
index 749321eb91ae..ee38b346985c 100644
--- a/drivers/misc/mic/scif/scif_rma.c
+++ b/drivers/misc/mic/scif/scif_rma.c
@@ -370,7 +370,6 @@  static int scif_create_remote_lookup(struct scif_dev *remote_dev,
 {
 	int i, j, err = 0;
 	int nr_pages = window->nr_pages;
-	bool vmalloc_dma_phys, vmalloc_num_pages;
 
 	might_sleep();
 	/* Map window */
@@ -403,23 +402,14 @@  static int scif_create_remote_lookup(struct scif_dev *remote_dev,
 		goto error_window;
 	}
 
-	vmalloc_dma_phys = is_vmalloc_addr(&window->dma_addr[0]);
-	vmalloc_num_pages = is_vmalloc_addr(&window->num_pages[0]);
-
 	/* Now map each of the pages containing physical addresses */
 	for (i = 0, j = 0; i < nr_pages; i += SCIF_NR_ADDR_IN_PAGE, j++) {
 		err = scif_map_page(&window->dma_addr_lookup.lookup[j],
-				    vmalloc_dma_phys ?
-				    vmalloc_to_page(&window->dma_addr[i]) :
-				    virt_to_page(&window->dma_addr[i]),
-				    remote_dev);
+				kv_to_page(&window->dma_addr[i]), remote_dev);
 		if (err)
 			goto error_window;
 		err = scif_map_page(&window->num_pages_lookup.lookup[j],
-				    vmalloc_num_pages ?
-				    vmalloc_to_page(&window->num_pages[i]) :
-				    virt_to_page(&window->num_pages[i]),
-				    remote_dev);
+				kv_to_page(&window->num_pages[i]), remote_dev);
 		if (err)
 			goto error_window;
 	}
@@ -1327,7 +1317,6 @@  int __scif_pin_pages(void *addr, size_t len, int *out_prot,
 {
 	struct scif_pinned_pages *pinned_pages;
 	int nr_pages, err = 0, i;
-	bool vmalloc_addr = false;
 	bool try_upgrade = false;
 	int prot = *out_prot;
 	int ulimit = 0;
@@ -1358,16 +1347,9 @@  int __scif_pin_pages(void *addr, size_t len, int *out_prot,
 		return -ENOMEM;
 
 	if (map_flags & SCIF_MAP_KERNEL) {
-		if (is_vmalloc_addr(addr))
-			vmalloc_addr = true;
-
 		for (i = 0; i < nr_pages; i++) {
-			if (vmalloc_addr)
-				pinned_pages->pages[i] =
-					vmalloc_to_page(addr + (i * PAGE_SIZE));
-			else
-				pinned_pages->pages[i] =
-					virt_to_page(addr + (i * PAGE_SIZE));
+			pinned_pages->pages[i] =
+				kv_to_page(addr + (i * PAGE_SIZE));
 		}
 		pinned_pages->nr_pages = nr_pages;
 		pinned_pages->map_flags = SCIF_MAP_KERNEL;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 9a7def7c3237..1382cc18e7db 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -833,10 +833,7 @@  int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
 			min = min_t(size_t, desc_len,
 				    min_t(size_t, len,
 					  PAGE_SIZE - offset_in_page(buf)));
-			if (vmalloced_buf)
-				vm_page = vmalloc_to_page(buf);
-			else
-				vm_page = kmap_to_page(buf);
+			vm_page = kv_to_page(buf);
 			if (!vm_page) {
 				sg_free_table(sgt);
 				return -ENOMEM;
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 131342280b46..6de5ffa506c0 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -692,10 +692,7 @@  static vm_fault_t uio_vma_fault(struct vm_fault *vmf)
 	offset = (vmf->pgoff - mi) << PAGE_SHIFT;
 
 	addr = (void *)(unsigned long)idev->info->mem[mi].addr + offset;
-	if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
-		page = virt_to_page(addr);
-	else
-		page = vmalloc_to_page(addr);
+	page = kv_to_page(addr);
 	get_page(page);
 	vmf->page = page;
 
diff --git a/drivers/virt/vboxguest/vboxguest_utils.c b/drivers/virt/vboxguest/vboxguest_utils.c
index bf4474214b4d..4999b17210c9 100644
--- a/drivers/virt/vboxguest/vboxguest_utils.c
+++ b/drivers/virt/vboxguest/vboxguest_utils.c
@@ -326,8 +326,6 @@  static void hgcm_call_init_linaddr(struct vmmdev_hgcm_call *call,
 	enum vmmdev_hgcm_function_parameter_type type, u32 *off_extra)
 {
 	struct vmmdev_hgcm_pagelist *dst_pg_lst;
-	struct page *page;
-	bool is_vmalloc;
 	u32 i, page_count;
 
 	dst_parm->type = type;
@@ -340,7 +338,6 @@  static void hgcm_call_init_linaddr(struct vmmdev_hgcm_call *call,
 
 	dst_pg_lst = (void *)call + *off_extra;
 	page_count = hgcm_call_buf_size_in_pages(buf, len);
-	is_vmalloc = is_vmalloc_addr(buf);
 
 	dst_parm->type = VMMDEV_HGCM_PARM_TYPE_PAGELIST;
 	dst_parm->u.page_list.size = len;
@@ -350,12 +347,7 @@  static void hgcm_call_init_linaddr(struct vmmdev_hgcm_call *call,
 	dst_pg_lst->page_count = page_count;
 
 	for (i = 0; i < page_count; i++) {
-		if (is_vmalloc)
-			page = vmalloc_to_page(buf);
-		else
-			page = virt_to_page(buf);
-
-		dst_pg_lst->pages[i] = page_to_phys(page);
+		dst_pg_lst->pages[i] = page_to_phys(kv_to_page(buf));
 		buf += PAGE_SIZE;
 	}
 
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index b21ea2ba768d..b84ecd2a012d 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -922,17 +922,6 @@  xfs_buf_set_empty(
 	bp->b_maps[0].bm_len = bp->b_length;
 }
 
-static inline struct page *
-mem_to_page(
-	void			*addr)
-{
-	if ((!is_vmalloc_addr(addr))) {
-		return virt_to_page(addr);
-	} else {
-		return vmalloc_to_page(addr);
-	}
-}
-
 int
 xfs_buf_associate_memory(
 	xfs_buf_t		*bp,
@@ -965,7 +954,7 @@  xfs_buf_associate_memory(
 	bp->b_offset = offset;
 
 	for (i = 0; i < bp->b_page_count; i++) {
-		bp->b_pages[i] = mem_to_page((void *)pageaddr);
+		bp->b_pages[i] = kv_to_page((void *)pageaddr);
 		pageaddr += PAGE_SIZE;
 	}
 
diff --git a/include/linux/mm.h b/include/linux/mm.h
index c6a5aabc7f85..5056fe66f259 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -691,6 +691,8 @@  static inline struct page *virt_to_head_page(const void *x)
 	return compound_head(page);
 }
 
+struct page *kv_to_page(const void *addr);
+
 void __put_page(struct page *page);
 
 void put_pages_list(struct list_head *pages);
diff --git a/mm/util.c b/mm/util.c
index 4df23d64aac7..a7ddfbe04a15 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -446,6 +446,18 @@  void kvfree(const void *addr)
 }
 EXPORT_SYMBOL(kvfree);
 
+/**
+ * kv_to_page() - Return the struct page for a virtual address
+ * @addr: Virtual address
+ */
+struct page *kv_to_page(const void *addr)
+{
+	if (is_vmalloc_addr(addr))
+		return vmalloc_to_page(addr);
+	return kmap_to_page((void *)addr);
+}
+EXPORT_SYMBOL(kv_to_page);
+
 static inline void *__page_rmapping(struct page *page)
 {
 	unsigned long mapping;
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index b1d39cabf125..2afdf6f3418b 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -377,10 +377,7 @@  static int p9_get_mapped_pages(struct virtio_chan *chan,
 		*need_drop = 0;
 		p -= (*offs = offset_in_page(p));
 		for (index = 0; index < nr_pages; index++) {
-			if (is_vmalloc_addr(p))
-				(*pages)[index] = vmalloc_to_page(p);
-			else
-				(*pages)[index] = kmap_to_page(p);
+			(*pages)[index] = kv_to_page(p);
 			p += PAGE_SIZE;
 		}
 		return len;
diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c
index 5d6724cee38f..4e13e88dd38c 100644
--- a/net/ceph/crypto.c
+++ b/net/ceph/crypto.c
@@ -191,11 +191,7 @@  static int setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg,
 		struct page *page;
 		unsigned int len = min(chunk_len - off, buf_len);
 
-		if (is_vmalloc)
-			page = vmalloc_to_page(buf);
-		else
-			page = virt_to_page(buf);
-
+		page = kv_to_page(buf);
 		sg_set_page(sg, page, len, off);
 
 		off = 0;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index a74650e98f42..c87ea1c09882 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -359,13 +359,6 @@  static void unregister_prot_hook(struct sock *sk, bool sync)
 		__unregister_prot_hook(sk, sync);
 }
 
-static inline struct page * __pure pgv_to_page(void *addr)
-{
-	if (is_vmalloc_addr(addr))
-		return vmalloc_to_page(addr);
-	return virt_to_page(addr);
-}
-
 static void __packet_set_status(struct packet_sock *po, void *frame, int status)
 {
 	union tpacket_uhdr h;
@@ -374,15 +367,15 @@  static void __packet_set_status(struct packet_sock *po, void *frame, int status)
 	switch (po->tp_version) {
 	case TPACKET_V1:
 		h.h1->tp_status = status;
-		flush_dcache_page(pgv_to_page(&h.h1->tp_status));
+		flush_dcache_page(kv_to_page(&h.h1->tp_status));
 		break;
 	case TPACKET_V2:
 		h.h2->tp_status = status;
-		flush_dcache_page(pgv_to_page(&h.h2->tp_status));
+		flush_dcache_page(kv_to_page(&h.h2->tp_status));
 		break;
 	case TPACKET_V3:
 		h.h3->tp_status = status;
-		flush_dcache_page(pgv_to_page(&h.h3->tp_status));
+		flush_dcache_page(kv_to_page(&h.h3->tp_status));
 		break;
 	default:
 		WARN(1, "TPACKET version not supported.\n");
@@ -401,13 +394,13 @@  static int __packet_get_status(struct packet_sock *po, void *frame)
 	h.raw = frame;
 	switch (po->tp_version) {
 	case TPACKET_V1:
-		flush_dcache_page(pgv_to_page(&h.h1->tp_status));
+		flush_dcache_page(kv_to_page(&h.h1->tp_status));
 		return h.h1->tp_status;
 	case TPACKET_V2:
-		flush_dcache_page(pgv_to_page(&h.h2->tp_status));
+		flush_dcache_page(kv_to_page(&h.h2->tp_status));
 		return h.h2->tp_status;
 	case TPACKET_V3:
-		flush_dcache_page(pgv_to_page(&h.h3->tp_status));
+		flush_dcache_page(kv_to_page(&h.h3->tp_status));
 		return h.h3->tp_status;
 	default:
 		WARN(1, "TPACKET version not supported.\n");
@@ -462,7 +455,7 @@  static __u32 __packet_set_timestamp(struct packet_sock *po, void *frame,
 	}
 
 	/* one flush is safe, as both fields always lie on the same cacheline */
-	flush_dcache_page(pgv_to_page(&h.h1->tp_sec));
+	flush_dcache_page(kv_to_page(&h.h1->tp_sec));
 	smp_wmb();
 
 	return ts_status;
@@ -728,7 +721,7 @@  static void prb_flush_block(struct tpacket_kbdq_core *pkc1,
 
 	end = (u8 *)PAGE_ALIGN((unsigned long)pkc1->pkblk_end);
 	for (; start < end; start += PAGE_SIZE)
-		flush_dcache_page(pgv_to_page(start));
+		flush_dcache_page(kv_to_page(start));
 
 	smp_wmb();
 #endif
@@ -741,7 +734,7 @@  static void prb_flush_block(struct tpacket_kbdq_core *pkc1,
 
 #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1
 	start = (u8 *)pbd1;
-	flush_dcache_page(pgv_to_page(start));
+	flush_dcache_page(kv_to_page(start));
 
 	smp_wmb();
 #endif
@@ -2352,7 +2345,7 @@  static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
 					macoff + snaplen);
 
 		for (start = h.raw; start < end; start += PAGE_SIZE)
-			flush_dcache_page(pgv_to_page(start));
+			flush_dcache_page(kv_to_page(start));
 	}
 	smp_wmb();
 #endif
@@ -2508,7 +2501,7 @@  static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
 			return -EFAULT;
 		}
 
-		page = pgv_to_page(data);
+		page = kv_to_page(data);
 		data += len;
 		flush_dcache_page(page);
 		get_page(page);
@@ -4423,7 +4416,7 @@  static int packet_mmap(struct file *file, struct socket *sock,
 			int pg_num;
 
 			for (pg_num = 0; pg_num < rb->pg_vec_pages; pg_num++) {
-				page = pgv_to_page(kaddr);
+				page = kv_to_page(kaddr);
 				err = vm_insert_page(vma, start, page);
 				if (unlikely(err))
 					goto out;