Commit e913a8cd authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'topic/iomem-mmap-vs-gup-2021-02-22' of git://anongit.freedesktop.org/drm/drm

Pull follow_pfn() updates from Daniel Vetter:
 "Fixes around VM_FPNMAP and follow_pfn:

   - replace mm/frame_vector.c by get_user_pages in misc/habana and
     drm/exynos drivers, then move that into media as it's sole user

   - close race in generic_access_phys

   - s390 pci ioctl fix of this series landed in 5.11 already

   - properly revoke iomem mappings (/dev/mem, pci files)"

* tag 'topic/iomem-mmap-vs-gup-2021-02-22' of git://anongit.freedesktop.org/drm/drm:
  PCI: Revoke mappings like devmem
  PCI: Also set up legacy files only after sysfs init
  sysfs: Support zapping of binary attr mmaps
  resource: Move devmem revoke code to resource framework
  /dev/mem: Only set filp->f_mapping
  PCI: Obey iomem restrictions for procfs mmap
  mm: Close race in generic_access_phys
  media: videobuf2: Move frame_vector into media subsystem
  mm/frame-vector: Use FOLL_LONGTERM
  misc/habana: Use FOLL_LONGTERM for userptr
  misc/habana: Stop using frame_vector helpers
  drm/exynos: Use FOLL_LONGTERM for g2d cmdlists
  drm/exynos: Stop using frame_vector helpers
parents 4b5f9254 636b21b5
Loading
Loading
Loading
Loading
+1 −85
Original line number Diff line number Diff line
@@ -31,9 +31,6 @@
#include <linux/uio.h>
#include <linux/uaccess.h>
#include <linux/security.h>
#include <linux/pseudo_fs.h>
#include <uapi/linux/magic.h>
#include <linux/mount.h>

#ifdef CONFIG_IA64
# include <linux/efi.h>
@@ -829,42 +826,6 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig)
	return ret;
}

static struct inode *devmem_inode;

#ifdef CONFIG_IO_STRICT_DEVMEM
void revoke_devmem(struct resource *res)
{
	/* pairs with smp_store_release() in devmem_init_inode() */
	struct inode *inode = smp_load_acquire(&devmem_inode);

	/*
	 * Check that the initialization has completed. Losing the race
	 * is ok because it means drivers are claiming resources before
	 * the fs_initcall level of init and prevent /dev/mem from
	 * establishing mappings.
	 */
	if (!inode)
		return;

	/*
	 * The expectation is that the driver has successfully marked
	 * the resource busy by this point, so devmem_is_allowed()
	 * should start returning false, however for performance this
	 * does not iterate the entire resource range.
	 */
	if (devmem_is_allowed(PHYS_PFN(res->start)) &&
	    devmem_is_allowed(PHYS_PFN(res->end))) {
		/*
		 * *cringe* iomem=relaxed says "go ahead, what's the
		 * worst that can happen?"
		 */
		return;
	}

	unmap_mapping_range(inode->i_mapping, res->start, resource_size(res), 1);
}
#endif

static int open_port(struct inode *inode, struct file *filp)
{
	int rc;
@@ -884,8 +845,7 @@ static int open_port(struct inode *inode, struct file *filp)
	 * revocations when drivers want to take over a /dev/mem mapped
	 * range.
	 */
	inode->i_mapping = devmem_inode->i_mapping;
	filp->f_mapping = inode->i_mapping;
	filp->f_mapping = iomem_get_mapping();

	return 0;
}
@@ -1017,48 +977,6 @@ static char *mem_devnode(struct device *dev, umode_t *mode)

static struct class *mem_class;

static int devmem_fs_init_fs_context(struct fs_context *fc)
{
	return init_pseudo(fc, DEVMEM_MAGIC) ? 0 : -ENOMEM;
}

static struct file_system_type devmem_fs_type = {
	.name		= "devmem",
	.owner		= THIS_MODULE,
	.init_fs_context = devmem_fs_init_fs_context,
	.kill_sb	= kill_anon_super,
};

static int devmem_init_inode(void)
{
	static struct vfsmount *devmem_vfs_mount;
	static int devmem_fs_cnt;
	struct inode *inode;
	int rc;

	rc = simple_pin_fs(&devmem_fs_type, &devmem_vfs_mount, &devmem_fs_cnt);
	if (rc < 0) {
		pr_err("Cannot mount /dev/mem pseudo filesystem: %d\n", rc);
		return rc;
	}

	inode = alloc_anon_inode(devmem_vfs_mount->mnt_sb);
	if (IS_ERR(inode)) {
		rc = PTR_ERR(inode);
		pr_err("Cannot allocate inode for /dev/mem: %d\n", rc);
		simple_release_fs(&devmem_vfs_mount, &devmem_fs_cnt);
		return rc;
	}

	/*
	 * Publish /dev/mem initialized.
	 * Pairs with smp_load_acquire() in revoke_devmem().
	 */
	smp_store_release(&devmem_inode, inode);

	return 0;
}

static int __init chr_dev_init(void)
{
	int minor;
@@ -1080,8 +998,6 @@ static int __init chr_dev_init(void)
		 */
		if ((minor == DEVPORT_MINOR) && !arch_has_dev_port())
			continue;
		if ((minor == DEVMEM_MINOR) && devmem_init_inode() != 0)
			continue;

		device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
			      NULL, devlist[minor].name);
+0 −1
Original line number Diff line number Diff line
@@ -89,7 +89,6 @@ comment "Sub-drivers"
config DRM_EXYNOS_G2D
	bool "G2D"
	depends on VIDEO_SAMSUNG_S5P_G2D=n || COMPILE_TEST
	select FRAME_VECTOR
	help
	  Choose this option if you want to use Exynos G2D for DRM.

+21 −27
Original line number Diff line number Diff line
@@ -205,7 +205,8 @@ struct g2d_cmdlist_userptr {
	dma_addr_t		dma_addr;
	unsigned long		userptr;
	unsigned long		size;
	struct frame_vector	*vec;
	struct page		**pages;
	unsigned int		npages;
	struct sg_table		*sgt;
	atomic_t		refcount;
	bool			in_pool;
@@ -378,7 +379,6 @@ static void g2d_userptr_put_dma_addr(struct g2d_data *g2d,
					bool force)
{
	struct g2d_cmdlist_userptr *g2d_userptr = obj;
	struct page **pages;

	if (!obj)
		return;
@@ -398,15 +398,9 @@ static void g2d_userptr_put_dma_addr(struct g2d_data *g2d,
	dma_unmap_sgtable(to_dma_dev(g2d->drm_dev), g2d_userptr->sgt,
			  DMA_BIDIRECTIONAL, 0);

	pages = frame_vector_pages(g2d_userptr->vec);
	if (!IS_ERR(pages)) {
		int i;

		for (i = 0; i < frame_vector_count(g2d_userptr->vec); i++)
			set_page_dirty_lock(pages[i]);
	}
	put_vaddr_frames(g2d_userptr->vec);
	frame_vector_destroy(g2d_userptr->vec);
	unpin_user_pages_dirty_lock(g2d_userptr->pages, g2d_userptr->npages,
				    true);
	kvfree(g2d_userptr->pages);

	if (!g2d_userptr->out_of_list)
		list_del_init(&g2d_userptr->list);
@@ -474,35 +468,35 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d,
	offset = userptr & ~PAGE_MASK;
	end = PAGE_ALIGN(userptr + size);
	npages = (end - start) >> PAGE_SHIFT;
	g2d_userptr->vec = frame_vector_create(npages);
	if (!g2d_userptr->vec) {
	g2d_userptr->pages = kvmalloc_array(npages, sizeof(*g2d_userptr->pages),
					    GFP_KERNEL);
	if (!g2d_userptr->pages) {
		ret = -ENOMEM;
		goto err_free;
	}

	ret = get_vaddr_frames(start, npages, FOLL_FORCE | FOLL_WRITE,
		g2d_userptr->vec);
	ret = pin_user_pages_fast(start, npages,
				  FOLL_FORCE | FOLL_WRITE | FOLL_LONGTERM,
				  g2d_userptr->pages);
	if (ret != npages) {
		DRM_DEV_ERROR(g2d->dev,
			      "failed to get user pages from userptr.\n");
		if (ret < 0)
			goto err_destroy_framevec;
		ret = -EFAULT;
		goto err_put_framevec;
	}
	if (frame_vector_to_pages(g2d_userptr->vec) < 0) {
			goto err_destroy_pages;
		npages = ret;
		ret = -EFAULT;
		goto err_put_framevec;
		goto err_unpin_pages;
	}
	g2d_userptr->npages = npages;

	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
	if (!sgt) {
		ret = -ENOMEM;
		goto err_put_framevec;
		goto err_unpin_pages;
	}

	ret = sg_alloc_table_from_pages(sgt,
					frame_vector_pages(g2d_userptr->vec),
					g2d_userptr->pages,
					npages, offset, size, GFP_KERNEL);
	if (ret < 0) {
		DRM_DEV_ERROR(g2d->dev, "failed to get sgt from pages.\n");
@@ -538,11 +532,11 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct g2d_data *g2d,
err_free_sgt:
	kfree(sgt);

err_put_framevec:
	put_vaddr_frames(g2d_userptr->vec);
err_unpin_pages:
	unpin_user_pages(g2d_userptr->pages, npages);

err_destroy_framevec:
	frame_vector_destroy(g2d_userptr->vec);
err_destroy_pages:
	kvfree(g2d_userptr->pages);

err_free:
	kfree(g2d_userptr);
+0 −1
Original line number Diff line number Diff line
@@ -9,7 +9,6 @@ config VIDEOBUF2_V4L2

config VIDEOBUF2_MEMOPS
	tristate
	select FRAME_VECTOR

config VIDEOBUF2_DMA_CONTIG
	tristate
+1 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0
videobuf2-common-objs := videobuf2-core.o
videobuf2-common-objs += frame_vector.o

ifeq ($(CONFIG_TRACEPOINTS),y)
  videobuf2-common-objs += vb2-trace.o
Loading