Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 771d3feb authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull DRM compat ioctl handling updates from Al Viro:
 "This kills the double-copies in there and tons of field-by-field
  copyin/copyout.

  Several dead ioctls put to rest, while we are at it - the native
  counterparts had been gone for a decade, so we can bloody well fail
  early on the compat side. No point rearranging the 32bit structure
  into 64bit one (and back) only to be told "piss off, I don't know that
  ioctl" by the native code..."

* 'work.drm' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (29 commits)
  Fix trivial misannotations
  mga: switch compat ioctls to drm_ioctl_kernel()
  radeon: take out dead compat ioctls
  drm compat: ia64 is not biarch
  drm_compat_ioctl(): tidy up a bit
  switch compat_drm_mapbufs() to drm_ioctl_kernel()
  switch compat_drm_rmmap() to drm_ioctl_kernel()
  switch compat_drm_mode_addfb2() to drm_ioctl_kernel()
  switch compat_drm_wait_vblank() to drm_ioctl_kernel()
  switch compat_drm_update_draw()
  compat_drm: switch sg ioctls
  compat_drm: switch AGP compat ioctls to drm_ioctl_kernel()
  switch compat_drm_dma() to drm_ioctl_kernel()
  switch compat_drm_resctx() to drm_ioctl_kernel()
  switch compat_drm_getsareactx() to drm_ioctl_kernel()
  switch compat_drm_setsareactx() to drm_ioctl_kernel()
  switch compat_drm_freebufs() to drm_ioctl_kernel()
  switch compat_drm_markbufs() to drm_ioctl_kernel()
  switch compat_drm_addmap() to drm_ioctl_kernel()
  switch compat_drm_getstats() to drm_ioctl_kernel()
  ...
parents 2074006d b87b786b
Loading
Loading
Loading
Loading
+65 −51
Original line number Original line Diff line number Diff line
@@ -1258,11 +1258,11 @@ int drm_legacy_addbufs(struct drm_device *dev, void *data,
 * lock, preventing of allocating more buffers after this call. Information
 * lock, preventing of allocating more buffers after this call. Information
 * about each requested buffer is then copied into user space.
 * about each requested buffer is then copied into user space.
 */
 */
int drm_legacy_infobufs(struct drm_device *dev, void *data,
int __drm_legacy_infobufs(struct drm_device *dev,
			struct drm_file *file_priv)
			void *data, int *p,
			int (*f)(void *, int, struct drm_buf_entry *))
{
{
	struct drm_device_dma *dma = dev->dma;
	struct drm_device_dma *dma = dev->dma;
	struct drm_buf_info *request = data;
	int i;
	int i;
	int count;
	int count;


@@ -1290,26 +1290,12 @@ int drm_legacy_infobufs(struct drm_device *dev, void *data,


	DRM_DEBUG("count = %d\n", count);
	DRM_DEBUG("count = %d\n", count);


	if (request->count >= count) {
	if (*p >= count) {
		for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
		for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
			if (dma->bufs[i].buf_count) {
				struct drm_buf_desc __user *to =
				    &request->list[count];
			struct drm_buf_entry *from = &dma->bufs[i];
			struct drm_buf_entry *from = &dma->bufs[i];
				if (copy_to_user(&to->count,
			if (from->buf_count) {
						 &from->buf_count,
				if (f(data, count, from) < 0)
						 sizeof(from->buf_count)) ||
				    copy_to_user(&to->size,
						 &from->buf_size,
						 sizeof(from->buf_size)) ||
				    copy_to_user(&to->low_mark,
						 &from->low_mark,
						 sizeof(from->low_mark)) ||
				    copy_to_user(&to->high_mark,
						 &from->high_mark,
						 sizeof(from->high_mark)))
					return -EFAULT;
					return -EFAULT;

				DRM_DEBUG("%d %d %d %d %d\n",
				DRM_DEBUG("%d %d %d %d %d\n",
					  i,
					  i,
					  dma->bufs[i].buf_count,
					  dma->bufs[i].buf_count,
@@ -1320,11 +1306,29 @@ int drm_legacy_infobufs(struct drm_device *dev, void *data,
			}
			}
		}
		}
	}
	}
	request->count = count;
	*p = count;


	return 0;
	return 0;
}
}


static int copy_one_buf(void *data, int count, struct drm_buf_entry *from)
{
	struct drm_buf_info *request = data;
	struct drm_buf_desc __user *to = &request->list[count];
	struct drm_buf_desc v = {.count = from->buf_count,
				 .size = from->buf_size,
				 .low_mark = from->low_mark,
				 .high_mark = from->high_mark};
	return copy_to_user(to, &v, offsetof(struct drm_buf_desc, flags));
}

int drm_legacy_infobufs(struct drm_device *dev, void *data,
			struct drm_file *file_priv)
{
	struct drm_buf_info *request = data;
	return __drm_legacy_infobufs(dev, data, &request->count, copy_one_buf);
}

/**
/**
 * Specifies a low and high water mark for buffer allocation
 * Specifies a low and high water mark for buffer allocation
 *
 *
@@ -1439,15 +1443,15 @@ int drm_legacy_freebufs(struct drm_device *dev, void *data,
 * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls
 * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls
 * drm_mmap_dma().
 * drm_mmap_dma().
 */
 */
int drm_legacy_mapbufs(struct drm_device *dev, void *data,
int __drm_legacy_mapbufs(struct drm_device *dev, void *data, int *p,
			 void __user **v,
			 int (*f)(void *, int, unsigned long,
				  struct drm_buf *),
		         struct drm_file *file_priv)
		         struct drm_file *file_priv)
{
{
	struct drm_device_dma *dma = dev->dma;
	struct drm_device_dma *dma = dev->dma;
	int retcode = 0;
	int retcode = 0;
	const int zero = 0;
	unsigned long virtual;
	unsigned long virtual;
	unsigned long address;
	struct drm_buf_map *request = data;
	int i;
	int i;


	if (!drm_core_check_feature(dev, DRIVER_LEGACY))
	if (!drm_core_check_feature(dev, DRIVER_LEGACY))
@@ -1467,7 +1471,7 @@ int drm_legacy_mapbufs(struct drm_device *dev, void *data,
	dev->buf_use++;		/* Can't allocate more after this call */
	dev->buf_use++;		/* Can't allocate more after this call */
	spin_unlock(&dev->buf_lock);
	spin_unlock(&dev->buf_lock);


	if (request->count >= dma->buf_count) {
	if (*p >= dma->buf_count) {
		if ((dev->agp && (dma->flags & _DRM_DMA_USE_AGP))
		if ((dev->agp && (dma->flags & _DRM_DMA_USE_AGP))
		    || (drm_core_check_feature(dev, DRIVER_SG)
		    || (drm_core_check_feature(dev, DRIVER_SG)
			&& (dma->flags & _DRM_DMA_USE_SG))) {
			&& (dma->flags & _DRM_DMA_USE_SG))) {
@@ -1492,41 +1496,51 @@ int drm_legacy_mapbufs(struct drm_device *dev, void *data,
			retcode = (signed long)virtual;
			retcode = (signed long)virtual;
			goto done;
			goto done;
		}
		}
		request->virtual = (void __user *)virtual;
		*v = (void __user *)virtual;


		for (i = 0; i < dma->buf_count; i++) {
		for (i = 0; i < dma->buf_count; i++) {
			if (copy_to_user(&request->list[i].idx,
			if (f(data, i, virtual, dma->buflist[i]) < 0) {
					 &dma->buflist[i]->idx,
					 sizeof(request->list[0].idx))) {
				retcode = -EFAULT;
				goto done;
			}
			if (copy_to_user(&request->list[i].total,
					 &dma->buflist[i]->total,
					 sizeof(request->list[0].total))) {
				retcode = -EFAULT;
				goto done;
			}
			if (copy_to_user(&request->list[i].used,
					 &zero, sizeof(zero))) {
				retcode = -EFAULT;
				goto done;
			}
			address = virtual + dma->buflist[i]->offset;	/* *** */
			if (copy_to_user(&request->list[i].address,
					 &address, sizeof(address))) {
				retcode = -EFAULT;
				retcode = -EFAULT;
				goto done;
				goto done;
			}
			}
		}
		}
	}
	}
      done:
      done:
	request->count = dma->buf_count;
	*p = dma->buf_count;
	DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode);
	DRM_DEBUG("%d buffers, retcode = %d\n", *p, retcode);


	return retcode;
	return retcode;
}
}


static int map_one_buf(void *data, int idx, unsigned long virtual,
			struct drm_buf *buf)
{
	struct drm_buf_map *request = data;
	unsigned long address = virtual + buf->offset;	/* *** */

	if (copy_to_user(&request->list[idx].idx, &buf->idx,
			 sizeof(request->list[0].idx)))
		return -EFAULT;
	if (copy_to_user(&request->list[idx].total, &buf->total,
			 sizeof(request->list[0].total)))
		return -EFAULT;
	if (clear_user(&request->list[idx].used, sizeof(int)))
		return -EFAULT;
	if (copy_to_user(&request->list[idx].address, &address,
			 sizeof(address)))
		return -EFAULT;
	return 0;
}

int drm_legacy_mapbufs(struct drm_device *dev, void *data,
		       struct drm_file *file_priv)
{
	struct drm_buf_map *request = data;
	return __drm_legacy_mapbufs(dev, data, &request->count,
				    &request->virtual, map_one_buf,
				    file_priv);
}

int drm_legacy_dma_ioctl(struct drm_device *dev, void *data,
int drm_legacy_dma_ioctl(struct drm_device *dev, void *data,
		  struct drm_file *file_priv)
		  struct drm_file *file_priv)
{
{
+3 −0
Original line number Original line Diff line number Diff line
@@ -143,3 +143,6 @@ static inline int drm_debugfs_crtc_crc_add(struct drm_crtc *crtc)
	return 0;
	return 0;
}
}
#endif
#endif
drm_ioctl_t drm_version;
drm_ioctl_t drm_getunique;
drm_ioctl_t drm_getclient;
+290 −460

File changed.

Preview size limit exceeded, changes collapsed.

+31 −17
Original line number Original line Diff line number Diff line
@@ -107,7 +107,7 @@
 *
 *
 * Copies the bus id from drm_device::unique into user space.
 * Copies the bus id from drm_device::unique into user space.
 */
 */
static int drm_getunique(struct drm_device *dev, void *data,
int drm_getunique(struct drm_device *dev, void *data,
		  struct drm_file *file_priv)
		  struct drm_file *file_priv)
{
{
	struct drm_unique *u = data;
	struct drm_unique *u = data;
@@ -172,7 +172,7 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
 * Searches for the client with the specified index and copies its information
 * Searches for the client with the specified index and copies its information
 * into userspace
 * into userspace
 */
 */
static int drm_getclient(struct drm_device *dev, void *data,
int drm_getclient(struct drm_device *dev, void *data,
		  struct drm_file *file_priv)
		  struct drm_file *file_priv)
{
{
	struct drm_client *client = data;
	struct drm_client *client = data;
@@ -461,7 +461,7 @@ static int drm_copy_field(char __user *buf, size_t *buf_len, const char *value)
 *
 *
 * Fills in the version information in \p arg.
 * Fills in the version information in \p arg.
 */
 */
static int drm_version(struct drm_device *dev, void *data,
int drm_version(struct drm_device *dev, void *data,
		       struct drm_file *file_priv)
		       struct drm_file *file_priv)
{
{
	struct drm_version *version = data;
	struct drm_version *version = data;
@@ -694,6 +694,33 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
 * structure.
 * structure.
 */
 */


long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata,
		      u32 flags)
{
	struct drm_file *file_priv = file->private_data;
	struct drm_device *dev = file_priv->minor->dev;
	int retcode;

	if (drm_device_is_unplugged(dev))
		return -ENODEV;

	retcode = drm_ioctl_permit(flags, file_priv);
	if (unlikely(retcode))
		return retcode;

	/* Enforce sane locking for modern driver ioctls. */
	if (!drm_core_check_feature(dev, DRIVER_LEGACY) ||
	    (flags & DRM_UNLOCKED))
		retcode = func(dev, kdata, file_priv);
	else {
		mutex_lock(&drm_global_mutex);
		retcode = func(dev, kdata, file_priv);
		mutex_unlock(&drm_global_mutex);
	}
	return retcode;
}
EXPORT_SYMBOL(drm_ioctl_kernel);

/**
/**
 * drm_ioctl - ioctl callback implementation for DRM drivers
 * drm_ioctl - ioctl callback implementation for DRM drivers
 * @filp: file this ioctl is called on
 * @filp: file this ioctl is called on
@@ -762,10 +789,6 @@ long drm_ioctl(struct file *filp,
		goto err_i1;
		goto err_i1;
	}
	}


	retcode = drm_ioctl_permit(ioctl->flags, file_priv);
	if (unlikely(retcode))
		goto err_i1;

	if (ksize <= sizeof(stack_kdata)) {
	if (ksize <= sizeof(stack_kdata)) {
		kdata = stack_kdata;
		kdata = stack_kdata;
	} else {
	} else {
@@ -784,16 +807,7 @@ long drm_ioctl(struct file *filp,
	if (ksize > in_size)
	if (ksize > in_size)
		memset(kdata + in_size, 0, ksize - in_size);
		memset(kdata + in_size, 0, ksize - in_size);


	/* Enforce sane locking for modern driver ioctls. */
	retcode = drm_ioctl_kernel(filp, func, kdata, ioctl->flags);
	if (!drm_core_check_feature(dev, DRIVER_LEGACY) ||
	    (ioctl->flags & DRM_UNLOCKED))
		retcode = func(dev, kdata, file_priv);
	else {
		mutex_lock(&drm_global_mutex);
		retcode = func(dev, kdata, file_priv);
		mutex_unlock(&drm_global_mutex);
	}

	if (copy_to_user((void __user *)arg, kdata, out_size) != 0)
	if (copy_to_user((void __user *)arg, kdata, out_size) != 0)
		retcode = -EFAULT;
		retcode = -EFAULT;


+7 −0
Original line number Original line Diff line number Diff line
@@ -74,6 +74,13 @@ int drm_legacy_freebufs(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_mapbufs(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_mapbufs(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_dma_ioctl(struct drm_device *d, void *v, struct drm_file *f);
int drm_legacy_dma_ioctl(struct drm_device *d, void *v, struct drm_file *f);


int __drm_legacy_infobufs(struct drm_device *, void *, int *,
			  int (*)(void *, int, struct drm_buf_entry *));
int __drm_legacy_mapbufs(struct drm_device *, void *, int *,
			  void __user **,
			  int (*)(void *, int, unsigned long, struct drm_buf *),
			  struct drm_file *);

#ifdef CONFIG_DRM_VM
#ifdef CONFIG_DRM_VM
void drm_legacy_vma_flush(struct drm_device *d);
void drm_legacy_vma_flush(struct drm_device *d);
#else
#else
Loading