`comedi_write()` copies data from the user buffer to the acquisition
data buffer, which is cyclic, using a single call to `copy_from_user()`.
It currently avoids having to deal with wraparound of the cyclic buffer
by limiting the amount it copies (and the amount returned to the user).
Change it to deal with the wraparound using two calls to
`copy_from_user()` if necessary.

Signed-off-by: Ian Abbott <abbo...@mev.co.uk>
---
 drivers/staging/comedi/comedi_fops.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/staging/comedi/comedi_fops.c 
b/drivers/staging/comedi/comedi_fops.c
index 8c784c4..4dd4289 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -2346,6 +2346,7 @@ static ssize_t comedi_write(struct file *file, const char 
__user *buf,
        add_wait_queue(&async->wait_head, &wait);
        while (count == 0 && !retval) {
                unsigned runflags;
+               unsigned int wp, n1, n2;
 
                set_current_state(TASK_INTERRUPTIBLE);
 
@@ -2360,9 +2361,6 @@ static ssize_t comedi_write(struct file *file, const char 
__user *buf,
                /* Allocate all free buffer space. */
                comedi_buf_write_alloc(s, async->prealloc_bufsz);
                m = comedi_buf_write_n_allocated(s);
-               /* Avoid buffer wraparound. */
-               if (async->buf_write_ptr + m > async->prealloc_bufsz)
-                       m = async->prealloc_bufsz - async->buf_write_ptr;
                n = min_t(size_t, m, nbytes);
 
                if (n == 0) {
@@ -2388,8 +2386,14 @@ static ssize_t comedi_write(struct file *file, const 
char __user *buf,
                        continue;
                }
 
-               m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
-                                  buf, n);
+               wp = async->buf_write_ptr;
+               n1 = min(n, async->prealloc_bufsz - wp);
+               n2 = n - n1;
+               m = copy_from_user(async->prealloc_buf + wp, buf, n1);
+               if (m)
+                       m += n2;
+               else if (n2)
+                       m = copy_from_user(async->prealloc_buf, buf + n1, n2);
                if (m) {
                        n -= m;
                        retval = -EFAULT;
-- 
2.6.2

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

Reply via email to