[MIPS] RTLX: Handle copy_*_user return values.
authorRalf Baechle <ralf@linux-mips.org>
Fri, 16 Mar 2007 12:16:27 +0000 (12:16 +0000)
committerRalf Baechle <ralf@linux-mips.org>
Sat, 17 Mar 2007 01:03:29 +0000 (01:03 +0000)
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/kernel/kspd.c
arch/mips/kernel/rtlx.c
include/asm-mips/rtlx.h

index 241ee7a2906e413c6d367cf4e4d7356e68419106..29eadd404fa5fa5c9b1d787bac2335b62908b6a2 100644 (file)
@@ -191,6 +191,8 @@ void sp_work_handle_request(void)
        struct mtsp_syscall_generic generic;
        struct mtsp_syscall_ret ret;
        struct kspd_notifications *n;
+       unsigned long written;
+       mm_segment_t old_fs;
        struct timeval tv;
        struct timezone tz;
        int cmd;
@@ -201,7 +203,11 @@ void sp_work_handle_request(void)
 
        ret.retval = -1;
 
-       if (!rtlx_read(RTLX_CHANNEL_SYSIO, &sc, sizeof(struct mtsp_syscall), 0)) {
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+
+       if (!rtlx_read(RTLX_CHANNEL_SYSIO, &sc, sizeof(struct mtsp_syscall))) {
+               set_fs(old_fs);
                printk(KERN_ERR "Expected request but nothing to read\n");
                return;
        }
@@ -209,7 +215,8 @@ void sp_work_handle_request(void)
        size = sc.size;
 
        if (size) {
-               if (!rtlx_read(RTLX_CHANNEL_SYSIO, &generic, size, 0)) {
+               if (!rtlx_read(RTLX_CHANNEL_SYSIO, &generic, size)) {
+                       set_fs(old_fs);
                        printk(KERN_ERR "Expected request but nothing to read\n");
                        return;
                }
@@ -282,8 +289,11 @@ void sp_work_handle_request(void)
        if (vpe_getuid(SP_VPE))
                sp_setfsuidgid( 0, 0);
 
-       if ((rtlx_write(RTLX_CHANNEL_SYSIO, &ret, sizeof(struct mtsp_syscall_ret), 0))
-           < sizeof(struct mtsp_syscall_ret))
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+       written = rtlx_write(RTLX_CHANNEL_SYSIO, &ret, sizeof(ret));
+       set_fs(old_fs);
+       if (written < sizeof(ret))
                printk("KSPD: sp_work_handle_request failed to send to SP\n");
 }
 
index 745649e15adc96a81abe6a6c6a8307f908d3e193..e6e3047151a6715d61fa1b1875d47b9d73fdb0b9 100644 (file)
@@ -289,26 +289,11 @@ unsigned int rtlx_write_poll(int index)
        return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size);
 }
 
-static inline void copy_to(void *dst, void *src, size_t count, int user)
-{
-       if (user)
-               copy_to_user(dst, src, count);
-       else
-               memcpy(dst, src, count);
-}
-
-static inline void copy_from(void *dst, void *src, size_t count, int user)
-{
-       if (user)
-               copy_from_user(dst, src, count);
-       else
-               memcpy(dst, src, count);
-}
-
-ssize_t rtlx_read(int index, void *buff, size_t count, int user)
+ssize_t rtlx_read(int index, void __user *buff, size_t count, int user)
 {
        size_t lx_write, fl = 0L;
        struct rtlx_channel *lx;
+       unsigned long failed;
 
        if (rtlx == NULL)
                return -ENOSYS;
@@ -327,11 +312,16 @@ ssize_t rtlx_read(int index, void *buff, size_t count, int user)
        /* then how much from the read pointer onwards */
        fl = min(count, (size_t)lx->buffer_size - lx->lx_read);
 
-       copy_to(buff, lx->lx_buffer + lx->lx_read, fl, user);
+       failed = copy_to_user(buff, lx->lx_buffer + lx->lx_read, fl);
+       if (failed)
+               goto out;
 
        /* and if there is anything left at the beginning of the buffer */
        if (count - fl)
-               copy_to(buff + fl, lx->lx_buffer, count - fl, user);
+               failed = copy_to_user(buff + fl, lx->lx_buffer, count - fl);
+
+out:
+       count -= failed;
 
        smp_wmb();
        lx->lx_read = (lx->lx_read + count) % lx->buffer_size;
@@ -341,7 +331,7 @@ ssize_t rtlx_read(int index, void *buff, size_t count, int user)
        return count;
 }
 
-ssize_t rtlx_write(int index, void *buffer, size_t count, int user)
+ssize_t rtlx_write(int index, const void __user *buffer, size_t count, int user)
 {
        struct rtlx_channel *rt;
        size_t rt_read;
@@ -363,11 +353,17 @@ ssize_t rtlx_write(int index, void *buffer, size_t count, int user)
        /* first bit from write pointer to the end of the buffer, or count */
        fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
 
-       copy_from(rt->rt_buffer + rt->rt_write, buffer, fl, user);
+       failed = copy_from_user(rt->rt_buffer + rt->rt_write, buffer, fl);
+       if (failed)
+               goto out;
 
        /* if there's any left copy to the beginning of the buffer */
-       if (count - fl)
-               copy_from(rt->rt_buffer, buffer + fl, count - fl, user);
+       if (count - fl) {
+               failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl);
+       }
+
+out:
+       count -= cailed;
 
        smp_wmb();
        rt->rt_write = (rt->rt_write + count) % rt->buffer_size;
@@ -426,7 +422,7 @@ static ssize_t file_read(struct file *file, char __user * buffer, size_t count,
                return 0;       // -EAGAIN makes cat whinge
        }
 
-       return rtlx_read(minor, buffer, count, 1);
+       return rtlx_read(minor, buffer, count);
 }
 
 static ssize_t file_write(struct file *file, const char __user * buffer,
@@ -452,7 +448,7 @@ static ssize_t file_write(struct file *file, const char __user * buffer,
                        return ret;
        }
 
-       return rtlx_write(minor, (void *)buffer, count, 1);
+       return rtlx_write(minor, buffer, count);
 }
 
 static const struct file_operations rtlx_fops = {
index 59162f74a7982b98801fe903aceafe0fe08354a5..65778c890a62ef4ed3b06a673d7ce552ca616e2a 100644 (file)
@@ -23,8 +23,8 @@
 
 extern int rtlx_open(int index, int can_sleep);
 extern int rtlx_release(int index);
-extern ssize_t rtlx_read(int index, void *buff, size_t count, int user);
-extern ssize_t rtlx_write(int index, void *buffer, size_t count, int user);
+extern ssize_t rtlx_read(int index, void __user *buff, size_t count);
+extern ssize_t rtlx_write(int index, const void __user *buffer, size_t count);
 extern unsigned int rtlx_read_poll(int index, int can_sleep);
 extern unsigned int rtlx_write_poll(int index);