From 67e2cccec6d230165345fdf6c0fe4c8761f9d1ba Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 22 Feb 2007 14:19:48 +0000 Subject: [MIPS] RTLX: Handle signals when sleeping. Signed-off-by: Ralf Baechle --- arch/mips/kernel/rtlx.c | 122 +++++++++++++++++------------------------------- 1 file changed, 42 insertions(+), 80 deletions(-) (limited to 'arch/mips/kernel/rtlx.c') diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index d92c48e0d7a6..766db51ab69e 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -146,9 +146,9 @@ static void stopping(int vpe) int rtlx_open(int index, int can_sleep) { - int ret; - struct rtlx_channel *chan; volatile struct rtlx_info **p; + struct rtlx_channel *chan; + int ret = 0; if (index >= RTLX_CHANNELS) { printk(KERN_DEBUG "rtlx_open index out of range\n"); @@ -165,65 +165,37 @@ int rtlx_open(int index, int can_sleep) if (rtlx == NULL) { if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { if (can_sleep) { - DECLARE_WAITQUEUE(wait, current); - - /* go to sleep */ - add_wait_queue(&channel_wqs[index].lx_queue, &wait); + int ret = 0; - set_current_state(TASK_INTERRUPTIBLE); - while ((p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&channel_wqs[index].lx_queue, &wait); - - /* back running */ + __wait_event_interruptible(channel_wqs[index].lx_queue, + (p = vpe_get_shared(RTLX_TARG_VPE)), + ret); + if (ret) + goto out_fail; } else { printk( KERN_DEBUG "No SP program loaded, and device " "opened with O_NONBLOCK\n"); channel_wqs[index].in_open = 0; - return -ENOSYS; + ret = -ENOSYS; + goto out_fail; } } if (*p == NULL) { if (can_sleep) { - DECLARE_WAITQUEUE(wait, current); - - /* go to sleep */ - add_wait_queue(&channel_wqs[index].lx_queue, &wait); + int ret = 0; - set_current_state(TASK_INTERRUPTIBLE); - while (*p == NULL) { - schedule(); - - /* reset task state to interruptable otherwise - we'll whizz round here like a very fast loopy - thing. schedule() appears to return with state - set to TASK_RUNNING. - - If the loaded SP program, for whatever reason, - doesn't set up the shared structure *p will never - become true. So whoever connected to either /dev/rt? - or if it was kspd, will then take up rather a lot of - processor cycles. - */ - - set_current_state(TASK_INTERRUPTIBLE); - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&channel_wqs[index].lx_queue, &wait); - - /* back running */ - } - else { + __wait_event_interruptible(channel_wqs[index].lx_queue, + *p != NULL, + ret); + if (ret) + goto out_fail; + } else { printk(" *vpe_get_shared is NULL. " "Has an SP program been loaded?\n"); channel_wqs[index].in_open = 0; - return -ENOSYS; + ret = -ENOSYS; + goto out_fail; } } @@ -231,10 +203,11 @@ int rtlx_open(int index, int can_sleep) printk(KERN_WARNING "vpe_get_shared returned an invalid pointer " "maybe an error code %d\n", (int)*p); channel_wqs[index].in_open = 0; - return -ENOSYS; + ret = -ENOSYS; + goto out_fail; } - if ((ret = rtlx_init(*p)) < 0) { + if ((ret = rtlx_init(*p)) < 0) { channel_wqs[index].in_open = 0; return ret; } @@ -250,6 +223,11 @@ int rtlx_open(int index, int can_sleep) chan->lx_state = RTLX_STATE_OPENED; channel_wqs[index].in_open = 0; return 0; + +out_fail: + channel_wqs[index].in_open--; + + return ret; } int rtlx_release(int index) @@ -270,30 +248,17 @@ unsigned int rtlx_read_poll(int index, int can_sleep) /* data available to read? */ if (chan->lx_read == chan->lx_write) { if (can_sleep) { - DECLARE_WAITQUEUE(wait, current); + int ret = 0; - /* go to sleep */ - add_wait_queue(&channel_wqs[index].lx_queue, &wait); + __wait_event_interruptible(channel_wqs[index].lx_queue, + chan->lx_read != chan->lx_write || sp_stopping, + ret); + if (ret) + return ret; - set_current_state(TASK_INTERRUPTIBLE); - while (chan->lx_read == chan->lx_write) { - schedule(); - - set_current_state(TASK_INTERRUPTIBLE); - - if (sp_stopping) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&channel_wqs[index].lx_queue, &wait); - return 0; - } - } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&channel_wqs[index].lx_queue, &wait); - - /* back running */ - } - else + if (sp_stopping) + return 0; + } else return 0; } @@ -454,25 +419,22 @@ static ssize_t file_write(struct file *file, const char __user * buffer, { int minor; struct rtlx_channel *rt; - DECLARE_WAITQUEUE(wait, current); minor = iminor(file->f_path.dentry->d_inode); rt = &rtlx->channel[minor]; /* any space left... */ if (!rtlx_write_poll(minor)) { + int ret = 0; if (file->f_flags & O_NONBLOCK) return -EAGAIN; - add_wait_queue(&channel_wqs[minor].rt_queue, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - while (!rtlx_write_poll(minor)) - schedule(); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&channel_wqs[minor].rt_queue, &wait); + __wait_event_interruptible(channel_wqs[minor].rt_queue, + rtlx_write_poll(minor), + ret); + if (ret) + return ret; } return rtlx_write(minor, (void *)buffer, count, 1); -- cgit From c4c4018b04f9b7993e3800dc1f391ac8947764a5 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 23 Feb 2007 13:40:45 +0000 Subject: [MIPS] RTLX, VPE: Make open actually atomic. Signed-off-by: Ralf Baechle --- arch/mips/kernel/rtlx.c | 44 ++++++++++++++++++++------------------------ arch/mips/kernel/vpe.c | 7 +++---- 2 files changed, 23 insertions(+), 28 deletions(-) (limited to 'arch/mips/kernel/rtlx.c') diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 766db51ab69e..7a8683ab6fde 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -53,7 +53,7 @@ static char module_name[] = "rtlx"; static struct chan_waitqueues { wait_queue_head_t rt_queue; wait_queue_head_t lx_queue; - int in_open; + atomic_t in_open; } channel_wqs[RTLX_CHANNELS]; static struct irqaction irq; @@ -148,6 +148,7 @@ int rtlx_open(int index, int can_sleep) { volatile struct rtlx_info **p; struct rtlx_channel *chan; + enum rtlx_state state; int ret = 0; if (index >= RTLX_CHANNELS) { @@ -155,13 +156,13 @@ int rtlx_open(int index, int can_sleep) return -ENOSYS; } - if (channel_wqs[index].in_open) { - printk(KERN_DEBUG "rtlx_open channel %d already opened\n", index); - return -EBUSY; + if (atomic_inc_return(&channel_wqs[index].in_open) > 1) { + printk(KERN_DEBUG "rtlx_open channel %d already opened\n", + index); + ret = -EBUSY; + goto out_fail; } - channel_wqs[index].in_open++; - if (rtlx == NULL) { if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { if (can_sleep) { @@ -173,9 +174,8 @@ int rtlx_open(int index, int can_sleep) if (ret) goto out_fail; } else { - printk( KERN_DEBUG "No SP program loaded, and device " + printk(KERN_DEBUG "No SP program loaded, and device " "opened with O_NONBLOCK\n"); - channel_wqs[index].in_open = 0; ret = -ENOSYS; goto out_fail; } @@ -193,7 +193,6 @@ int rtlx_open(int index, int can_sleep) } else { printk(" *vpe_get_shared is NULL. " "Has an SP program been loaded?\n"); - channel_wqs[index].in_open = 0; ret = -ENOSYS; goto out_fail; } @@ -202,31 +201,28 @@ int rtlx_open(int index, int can_sleep) if ((unsigned int)*p < KSEG0) { printk(KERN_WARNING "vpe_get_shared returned an invalid pointer " "maybe an error code %d\n", (int)*p); - channel_wqs[index].in_open = 0; ret = -ENOSYS; goto out_fail; } - if ((ret = rtlx_init(*p)) < 0) { - channel_wqs[index].in_open = 0; - return ret; - } + if ((ret = rtlx_init(*p)) < 0) + goto out_ret; } chan = &rtlx->channel[index]; - if (chan->lx_state == RTLX_STATE_OPENED) { - channel_wqs[index].in_open = 0; - return -EBUSY; - } - - chan->lx_state = RTLX_STATE_OPENED; - channel_wqs[index].in_open = 0; - return 0; + state = xchg(&chan->lx_state, RTLX_STATE_OPENED); + if (state == RTLX_STATE_OPENED) { + ret = -EBUSY; + goto out_fail; + } out_fail: - channel_wqs[index].in_open--; + smp_mb(); + atomic_dec(&channel_wqs[index].in_open); + smp_mb(); +out_ret: return ret; } @@ -475,7 +471,7 @@ static int rtlx_module_init(void) for (i = 0; i < RTLX_CHANNELS; i++) { init_waitqueue_head(&channel_wqs[i].rt_queue); init_waitqueue_head(&channel_wqs[i].lx_queue); - channel_wqs[i].in_open = 0; + atomic_set(&channel_wqs[i].in_open, 0); dev = device_create(mt_class, NULL, MKDEV(major, i), "%s%d", module_name, i); diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 9aca871a307f..c9ee9d2d5856 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -1079,6 +1079,7 @@ static int getcwd(char *buff, int size) static int vpe_open(struct inode *inode, struct file *filp) { int minor, ret; + enum vpe_state state; struct vpe *v; struct vpe_notifications *not; @@ -1093,7 +1094,8 @@ static int vpe_open(struct inode *inode, struct file *filp) return -ENODEV; } - if (v->state != VPE_STATE_UNUSED) { + state = xchg(&v->state, VPE_STATE_INUSE); + if (state != VPE_STATE_UNUSED) { dvpe(); printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); @@ -1108,9 +1110,6 @@ static int vpe_open(struct inode *inode, struct file *filp) cleanup_tc(get_tc(minor)); } - // allocate it so when we get write ops we know it's expected. - v->state = VPE_STATE_INUSE; - /* this of-course trashes what was there before... */ v->pbuffer = vmalloc(P_SIZE); v->plen = P_SIZE; -- cgit From 3dac2561e2ed8d75a8bb682c25a32b271298ff49 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 23 Feb 2007 14:12:32 +0000 Subject: [MIPS] RTLX: Delete multiple definition of ret shaddowing each other. Signed-off-by: Ralf Baechle --- arch/mips/kernel/rtlx.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'arch/mips/kernel/rtlx.c') diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 7a8683ab6fde..e14ae09eda2b 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -166,8 +166,6 @@ int rtlx_open(int index, int can_sleep) if (rtlx == NULL) { if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { if (can_sleep) { - int ret = 0; - __wait_event_interruptible(channel_wqs[index].lx_queue, (p = vpe_get_shared(RTLX_TARG_VPE)), ret); @@ -183,8 +181,6 @@ int rtlx_open(int index, int can_sleep) if (*p == NULL) { if (can_sleep) { - int ret = 0; - __wait_event_interruptible(channel_wqs[index].lx_queue, *p != NULL, ret); -- cgit From 9e34682026572f07328208f7d2b2c611d2001844 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 15 Mar 2007 17:08:28 +0000 Subject: [MIPS] RTLX: Don't use volatile; it's fragile. Signed-off-by: Ralf Baechle --- arch/mips/kernel/rtlx.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'arch/mips/kernel/rtlx.c') diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index e14ae09eda2b..16d3fdecf3ea 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -146,7 +146,7 @@ static void stopping(int vpe) int rtlx_open(int index, int can_sleep) { - volatile struct rtlx_info **p; + struct rtlx_info **p; struct rtlx_channel *chan; enum rtlx_state state; int ret = 0; @@ -179,13 +179,24 @@ int rtlx_open(int index, int can_sleep) } } + smp_rmb(); if (*p == NULL) { if (can_sleep) { - __wait_event_interruptible(channel_wqs[index].lx_queue, - *p != NULL, - ret); - if (ret) + DEFINE_WAIT(wait); + + for (;;) { + prepare_to_wait(&channel_wqs[index].lx_queue, &wait, TASK_INTERRUPTIBLE); + smp_rmb(); + if (*p != NULL) + break; + if (!signal_pending(current)) { + schedule(); + continue; + } + ret = -ERESTARTSYS; goto out_fail; + } + finish_wait(&channel_wqs[index].lx_queue, &wait); } else { printk(" *vpe_get_shared is NULL. " "Has an SP program been loaded?\n"); -- cgit From 61dcc6f4d9ed5db71f4f0be9026bdd09f1a7dc06 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 15 Mar 2007 17:10:16 +0000 Subject: [MIPS] RTLX: Harden against compiler reordering and optimization. RTLX communication is based on lock-free shared memory buffers. It happened to be working by luck so far but relies on the optimizer doing certain optimizations but no reordering. Fixed by inserting proper barriers in rtlx_read and rtlx_write, and careful pointer dereferencing. Signed-off-by: Ralf Baechle --- arch/mips/kernel/rtlx.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) (limited to 'arch/mips/kernel/rtlx.c') diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 16d3fdecf3ea..0441c7c1e44c 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -306,7 +306,7 @@ static inline void copy_from(void *dst, void *src, size_t count, int user) ssize_t rtlx_read(int index, void *buff, size_t count, int user) { - size_t fl = 0L; + size_t lx_write, fl = 0L; struct rtlx_channel *lx; if (rtlx == NULL) @@ -314,23 +314,26 @@ ssize_t rtlx_read(int index, void *buff, size_t count, int user) lx = &rtlx->channel[index]; + smp_rmb(); + lx_write = lx->lx_write; + /* find out how much in total */ count = min(count, - (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) + (size_t)(lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size); /* then how much from the read pointer onwards */ - fl = min( count, (size_t)lx->buffer_size - lx->lx_read); + fl = min(count, (size_t)lx->buffer_size - lx->lx_read); - copy_to(buff, &lx->lx_buffer[lx->lx_read], fl, user); + copy_to(buff, lx->lx_buffer + lx->lx_read, fl, user); /* 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); + if (count - fl) + copy_to(buff + fl, lx->lx_buffer, count - fl, user); - /* update the index */ - lx->lx_read += count; - lx->lx_read %= lx->buffer_size; + smp_wmb(); + lx->lx_read = (lx->lx_read + count) % lx->buffer_size; + smp_wmb(); return count; } @@ -338,6 +341,7 @@ ssize_t rtlx_read(int index, void *buff, size_t count, int user) ssize_t rtlx_write(int index, void *buffer, size_t count, int user) { struct rtlx_channel *rt; + size_t rt_read; size_t fl; if (rtlx == NULL) @@ -345,24 +349,27 @@ ssize_t rtlx_write(int index, void *buffer, size_t count, int user) rt = &rtlx->channel[index]; + smp_rmb(); + rt_read = rt->rt_read; + /* total number of bytes to copy */ count = min(count, - (size_t)write_spacefree(rt->rt_read, rt->rt_write, - rt->buffer_size)); + (size_t)write_spacefree(rt_read, rt->rt_write, rt->buffer_size)); /* 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); + copy_from(rt->rt_buffer + rt->rt_write, buffer, fl, user); /* 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) + copy_from(rt->rt_buffer, buffer + fl, count - fl, user); - rt->rt_write += count; - rt->rt_write %= rt->buffer_size; + smp_wmb(); + rt->rt_write = (rt->rt_write + count) % rt->buffer_size; + smp_wmb(); - return(count); + return count; } -- cgit From bc4809e939b91c9642f1ddaea732e2d432ee6af6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 15 Mar 2007 17:13:47 +0000 Subject: [MIPS] RTLX: Protect rtlx_{read,write} with mutex. Signed-off-by: Ralf Baechle --- arch/mips/kernel/rtlx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch/mips/kernel/rtlx.c') diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 0441c7c1e44c..745649e15adc 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -54,6 +54,7 @@ static struct chan_waitqueues { wait_queue_head_t rt_queue; wait_queue_head_t lx_queue; atomic_t in_open; + struct mutex mutex; } channel_wqs[RTLX_CHANNELS]; static struct irqaction irq; @@ -314,6 +315,7 @@ ssize_t rtlx_read(int index, void *buff, size_t count, int user) lx = &rtlx->channel[index]; + mutex_lock(&channel_wqs[index].mutex); smp_rmb(); lx_write = lx->lx_write; @@ -334,6 +336,7 @@ ssize_t rtlx_read(int index, void *buff, size_t count, int user) smp_wmb(); lx->lx_read = (lx->lx_read + count) % lx->buffer_size; smp_wmb(); + mutex_unlock(&channel_wqs[index].mutex); return count; } @@ -349,6 +352,7 @@ ssize_t rtlx_write(int index, void *buffer, size_t count, int user) rt = &rtlx->channel[index]; + mutex_lock(&channel_wqs[index].mutex); smp_rmb(); rt_read = rt->rt_read; @@ -368,6 +372,7 @@ ssize_t rtlx_write(int index, void *buffer, size_t count, int user) smp_wmb(); rt->rt_write = (rt->rt_write + count) % rt->buffer_size; smp_wmb(); + mutex_unlock(&channel_wqs[index].mutex); return count; } @@ -486,6 +491,7 @@ static int rtlx_module_init(void) init_waitqueue_head(&channel_wqs[i].rt_queue); init_waitqueue_head(&channel_wqs[i].lx_queue); atomic_set(&channel_wqs[i].in_open, 0); + mutex_init(&channel_wqs[i].mutex); dev = device_create(mt_class, NULL, MKDEV(major, i), "%s%d", module_name, i); -- cgit From 46230aa6ea1671690e3e5efa2a961fc0745fe9b5 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 16 Mar 2007 12:16:27 +0000 Subject: [MIPS] RTLX: Handle copy_*_user return values. Signed-off-by: Ralf Baechle --- arch/mips/kernel/kspd.c | 18 ++++++++++++++---- arch/mips/kernel/rtlx.c | 46 +++++++++++++++++++++------------------------- include/asm-mips/rtlx.h | 4 ++-- 3 files changed, 37 insertions(+), 31 deletions(-) (limited to 'arch/mips/kernel/rtlx.c') diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c index 241ee7a2906e..29eadd404fa5 100644 --- a/arch/mips/kernel/kspd.c +++ b/arch/mips/kernel/kspd.c @@ -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"); } diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 745649e15adc..e6e3047151a6 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -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 = { diff --git a/include/asm-mips/rtlx.h b/include/asm-mips/rtlx.h index 59162f74a798..65778c890a62 100644 --- a/include/asm-mips/rtlx.h +++ b/include/asm-mips/rtlx.h @@ -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); -- cgit From 7f5a7716dc0b380fd3c85ca5a5841969555feaa7 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 25 Apr 2007 15:08:57 +0100 Subject: [MIPS] Fix AP/SP to work in the reality of modern kernels. Signed-off-by: Ralf Baechle --- arch/mips/kernel/kspd.c | 5 +---- arch/mips/kernel/rtlx.c | 7 ++++--- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'arch/mips/kernel/rtlx.c') diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c index 29eadd404fa5..c6580018c94b 100644 --- a/arch/mips/kernel/kspd.c +++ b/arch/mips/kernel/kspd.c @@ -17,6 +17,7 @@ */ #include #include +#include #include #include #include @@ -198,7 +199,6 @@ void sp_work_handle_request(void) int cmd; char *vcwd; - mm_segment_t old_fs; int size; ret.retval = -1; @@ -241,8 +241,6 @@ void sp_work_handle_request(void) if ((ret.retval = sp_syscall(__NR_gettimeofday, (int)&tv, (int)&tz, 0,0)) == 0) ret.retval = tv.tv_sec; - - ret.errno = errno; break; case MTSP_SYSCALL_EXIT: @@ -279,7 +277,6 @@ void sp_work_handle_request(void) if (cmd >= 0) { ret.retval = sp_syscall(cmd, generic.arg0, generic.arg1, generic.arg2, generic.arg3); - ret.errno = errno; } else printk(KERN_WARNING "KSPD: Unknown SP syscall number %d\n", sc.cmd); diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index e6e3047151a6..bfc8ca168f83 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -289,7 +289,7 @@ unsigned int rtlx_write_poll(int index) return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size); } -ssize_t rtlx_read(int index, void __user *buff, size_t count, int user) +ssize_t rtlx_read(int index, void __user *buff, size_t count) { size_t lx_write, fl = 0L; struct rtlx_channel *lx; @@ -331,9 +331,10 @@ out: return count; } -ssize_t rtlx_write(int index, const void __user *buffer, size_t count, int user) +ssize_t rtlx_write(int index, const void __user *buffer, size_t count) { struct rtlx_channel *rt; + unsigned long failed; size_t rt_read; size_t fl; @@ -363,7 +364,7 @@ ssize_t rtlx_write(int index, const void __user *buffer, size_t count, int user) } out: - count -= cailed; + count -= failed; smp_wmb(); rt->rt_write = (rt->rt_write + count) % rt->buffer_size; -- cgit