[PATCH 01/50] staging: comedi: prepare for new struct comedi_kcmd

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The `struct comedi_cmd` type includes a `chanlist` pointer tagged as
`__user` (and also an unused `data` pointer tagged as `__user`).  The
`COMEDI_CMD` and `COMEDI_CMDTEST` ioctls treat their argument as a
pointer to this type, where the `chanlist` pointer point to a channel
list in user space.  The same type is used elsewhere in comedi (mostly
in the low-level drivers) but in this case the `chanlist` pointer points
to a channel list in kernel space.  This results in various "sparse"
warnings about differing address spaces being used.

We can declare a `struct comedi_kcmd` type identical to `struct
comedi_cmd` except that the `chanlist` (and unused `data`) pointer
points to kernel memory.  Prepare for this change by temporarily
defining a macro `comedi_kcmd` that expands to `comedi_cmd` and change
the interface between the comedi core and the low-level drivers to use
`struct comedi_kcmd` instead of `struct comedi_cmd`.  While were at it,
rename some variables in `do_cmd_ioctl()` and `do_cmdtest_ioctl()` to
avoid confusing user-space stuff with kernel-space stuff, and copy the
user-space `chanlist` separately from the whole of the `struct
comedi_cmd` to avoid some "sparse" warnings after `struct comedi_kcmd`
has been declared properly later.

Once the low-level drivers have been updated, the `struct comedi_kcmd`
type can be defined for real.  Once that is done, a bunch of sparse
warnings involving the `chanllist` pointer in this type will be
eliminated.

Signed-off-by: Ian Abbott <abbotti@xxxxxxxxx>
---
 drivers/staging/comedi/comedi_fops.c | 83 +++++++++++++++++-------------------
 drivers/staging/comedi/comedidev.h   |  9 +++-
 2 files changed, 46 insertions(+), 46 deletions(-)

diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 00d8d1f..7d18325 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1133,35 +1133,34 @@ static void comedi_set_subdevice_runflags(struct comedi_subdevice *s,
 static int do_cmd_ioctl(struct comedi_device *dev,
 			struct comedi_cmd __user *cmd, void *file)
 {
-	struct comedi_cmd user_cmd;
+	struct comedi_kcmd kcmd;
 	struct comedi_subdevice *s;
 	struct comedi_async *async;
 	int ret = 0;
-	unsigned int __user *chanlist_saver = NULL;
+	unsigned int __user *uchanlist = NULL;
 
-	if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) {
+	if (copy_from_user(&kcmd, cmd, sizeof(struct comedi_kcmd)) ||
+	    __get_user(uchanlist, &cmd->chanlist)) {
 		DPRINTK("bad cmd address\n");
 		return -EFAULT;
 	}
-	/* save user's chanlist pointer so it can be restored later */
-	chanlist_saver = user_cmd.chanlist;
 
-	if (user_cmd.subdev >= dev->n_subdevices) {
-		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
+	if (kcmd.subdev >= dev->n_subdevices) {
+		DPRINTK("%d no such subdevice\n", kcmd.subdev);
 		return -ENODEV;
 	}
 
-	s = &dev->subdevices[user_cmd.subdev];
+	s = &dev->subdevices[kcmd.subdev];
 	async = s->async;
 
 	if (s->type == COMEDI_SUBD_UNUSED) {
-		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
+		DPRINTK("%d not valid subdevice\n", kcmd.subdev);
 		return -EIO;
 	}
 
 	if (!s->do_cmd || !s->do_cmdtest || !s->async) {
 		DPRINTK("subdevice %i does not support commands\n",
-			user_cmd.subdev);
+			kcmd.subdev);
 		return -EIO;
 	}
 
@@ -1179,23 +1178,23 @@ static int do_cmd_ioctl(struct comedi_device *dev,
 	s->busy = file;
 
 	/* make sure channel/gain list isn't too long */
-	if (user_cmd.chanlist_len > s->len_chanlist) {
+	if (kcmd.chanlist_len > s->len_chanlist) {
 		DPRINTK("channel/gain list too long %u > %d\n",
-			user_cmd.chanlist_len, s->len_chanlist);
+			kcmd.chanlist_len, s->len_chanlist);
 		ret = -EINVAL;
 		goto cleanup;
 	}
 
 	/* make sure channel/gain list isn't too short */
-	if (user_cmd.chanlist_len < 1) {
+	if (kcmd.chanlist_len < 1) {
 		DPRINTK("channel/gain list too short %u < 1\n",
-			user_cmd.chanlist_len);
+			kcmd.chanlist_len);
 		ret = -EINVAL;
 		goto cleanup;
 	}
 
 	kfree(async->cmd.chanlist);
-	async->cmd = user_cmd;
+	async->cmd = kcmd;
 	async->cmd.data = NULL;
 	/* load channel/gain list */
 	async->cmd.chanlist =
@@ -1206,7 +1205,7 @@ static int do_cmd_ioctl(struct comedi_device *dev,
 		goto cleanup;
 	}
 
-	if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist,
+	if (copy_from_user(async->cmd.chanlist, uchanlist,
 			   async->cmd.chanlist_len * sizeof(int))) {
 		DPRINTK("fault reading chanlist\n");
 		ret = -EFAULT;
@@ -1226,11 +1225,10 @@ static int do_cmd_ioctl(struct comedi_device *dev,
 
 	if (async->cmd.flags & TRIG_BOGUS || ret) {
 		DPRINTK("test returned %d\n", ret);
-		user_cmd = async->cmd;
-		/* restore chanlist pointer before copying back */
-		user_cmd.chanlist = chanlist_saver;
-		user_cmd.data = NULL;
-		if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) {
+		kcmd = async->cmd;
+		kcmd.data = NULL;
+		if (copy_to_user(cmd, &kcmd, sizeof(struct comedi_cmd)) ||
+		    __put_user(uchanlist, &cmd->chanlist)) {
 			DPRINTK("fault writing cmd\n");
 			ret = -EFAULT;
 			goto cleanup;
@@ -1283,77 +1281,74 @@ cleanup:
 static int do_cmdtest_ioctl(struct comedi_device *dev,
 			    struct comedi_cmd __user *arg, void *file)
 {
-	struct comedi_cmd user_cmd;
+	struct comedi_kcmd kcmd;
 	struct comedi_subdevice *s;
 	int ret = 0;
 	unsigned int *chanlist = NULL;
-	unsigned int __user *chanlist_saver = NULL;
+	unsigned int __user *uchanlist = NULL;
 
-	if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) {
+	if (copy_from_user(&kcmd, arg, sizeof(struct comedi_kcmd)) ||
+	    __get_user(uchanlist, &arg->chanlist)) {
 		DPRINTK("bad cmd address\n");
 		return -EFAULT;
 	}
-	/* save user's chanlist pointer so it can be restored later */
-	chanlist_saver = user_cmd.chanlist;
 
-	if (user_cmd.subdev >= dev->n_subdevices) {
-		DPRINTK("%d no such subdevice\n", user_cmd.subdev);
+	if (kcmd.subdev >= dev->n_subdevices) {
+		DPRINTK("%d no such subdevice\n", kcmd.subdev);
 		return -ENODEV;
 	}
 
-	s = &dev->subdevices[user_cmd.subdev];
+	s = &dev->subdevices[kcmd.subdev];
 	if (s->type == COMEDI_SUBD_UNUSED) {
-		DPRINTK("%d not valid subdevice\n", user_cmd.subdev);
+		DPRINTK("%d not valid subdevice\n", kcmd.subdev);
 		return -EIO;
 	}
 
 	if (!s->do_cmd || !s->do_cmdtest) {
 		DPRINTK("subdevice %i does not support commands\n",
-			user_cmd.subdev);
+			kcmd.subdev);
 		return -EIO;
 	}
 
 	/* make sure channel/gain list isn't too long */
-	if (user_cmd.chanlist_len > s->len_chanlist) {
+	if (kcmd.chanlist_len > s->len_chanlist) {
 		DPRINTK("channel/gain list too long %d > %d\n",
-			user_cmd.chanlist_len, s->len_chanlist);
+			kcmd.chanlist_len, s->len_chanlist);
 		ret = -EINVAL;
 		goto cleanup;
 	}
 
 	/* load channel/gain list */
-	if (user_cmd.chanlist) {
+	if (uchanlist) {
 		chanlist =
-		    kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL);
+		    kmalloc(kcmd.chanlist_len * sizeof(int), GFP_KERNEL);
 		if (!chanlist) {
 			DPRINTK("allocation failed\n");
 			ret = -ENOMEM;
 			goto cleanup;
 		}
 
-		if (copy_from_user(chanlist, user_cmd.chanlist,
-				   user_cmd.chanlist_len * sizeof(int))) {
+		if (copy_from_user(chanlist, uchanlist,
+				   kcmd.chanlist_len * sizeof(int))) {
 			DPRINTK("fault reading chanlist\n");
 			ret = -EFAULT;
 			goto cleanup;
 		}
 
 		/* make sure each element in channel/gain list is valid */
-		ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist);
+		ret = comedi_check_chanlist(s, kcmd.chanlist_len, chanlist);
 		if (ret < 0) {
 			DPRINTK("bad chanlist\n");
 			goto cleanup;
 		}
 
-		user_cmd.chanlist = chanlist;
+		kcmd.chanlist = chanlist;
 	}
 
-	ret = s->do_cmdtest(dev, s, &user_cmd);
+	ret = s->do_cmdtest(dev, s, &kcmd);
 
-	/* restore chanlist pointer before copying back */
-	user_cmd.chanlist = chanlist_saver;
-
-	if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) {
+	if (copy_to_user(arg, &kcmd, sizeof(struct comedi_cmd)) ||
+	    __put_user(uchanlist, &arg->chanlist)) {
 		DPRINTK("bad cmd address\n");
 		ret = -EFAULT;
 		goto cleanup;
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index cb67a5c..708bba6 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -62,6 +62,11 @@
 #define COMEDI_NUM_BOARD_MINORS 0x30
 #define COMEDI_FIRST_SUBDEVICE_MINOR COMEDI_NUM_BOARD_MINORS
 
+/* Define kernel versions of some ioctl user API structures. */
+/* FIXME: use macros for now.  Define proper structures once the kernel
+ * level code has been changed to use the kernel versions of the structures. */
+#define comedi_kcmd comedi_cmd
+
 struct comedi_subdevice {
 	struct comedi_device *device;
 	int type;
@@ -104,7 +109,7 @@ struct comedi_subdevice {
 
 	int (*do_cmd) (struct comedi_device *, struct comedi_subdevice *);
 	int (*do_cmdtest) (struct comedi_device *, struct comedi_subdevice *,
-			   struct comedi_cmd *);
+			   struct comedi_kcmd *);
 	int (*poll) (struct comedi_device *, struct comedi_subdevice *);
 	int (*cancel) (struct comedi_device *, struct comedi_subdevice *);
 	/* int (*do_lock)(struct comedi_device *, struct comedi_subdevice *); */
@@ -168,7 +173,7 @@ struct comedi_async {
 
 	unsigned int events;	/* events that have occurred */
 
-	struct comedi_cmd cmd;
+	struct comedi_kcmd cmd;
 
 	wait_queue_head_t wait_head;
 
-- 
1.7.12

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel


[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux