Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Turn rtlx upside down. o Coding style o Race condition on open o Switch to dynamic major o Header file cleanup Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

+105 -120
+93 -104
arch/mips/kernel/rtlx.c
··· 20 20 #include <linux/module.h> 21 21 #include <linux/fs.h> 22 22 #include <linux/init.h> 23 - #include <asm/uaccess.h> 24 - #include <linux/slab.h> 25 - #include <linux/list.h> 26 - #include <linux/vmalloc.h> 27 - #include <linux/elf.h> 28 - #include <linux/seq_file.h> 29 - #include <linux/syscalls.h> 30 - #include <linux/moduleloader.h> 31 - #include <linux/interrupt.h> 32 23 #include <linux/poll.h> 33 24 #include <linux/sched.h> 34 25 #include <linux/wait.h> 35 26 #include <asm/mipsmtregs.h> 36 - #include <asm/cacheflush.h> 37 - #include <asm/atomic.h> 27 + #include <asm/bitops.h> 38 28 #include <asm/cpu.h> 39 29 #include <asm/processor.h> 40 - #include <asm/system.h> 41 30 #include <asm/rtlx.h> 31 + #include <asm/uaccess.h> 42 32 43 - #define RTLX_MAJOR 64 44 33 #define RTLX_TARG_VPE 1 45 34 46 - struct rtlx_info *rtlx; 35 + static struct rtlx_info *rtlx; 47 36 static int major; 48 37 static char module_name[] = "rtlx"; 49 - static inline int spacefree(int read, int write, int size); 38 + static struct irqaction irq; 39 + static int irq_num; 40 + 41 + static inline int spacefree(int read, int write, int size) 42 + { 43 + if (read == write) { 44 + /* 45 + * never fill the buffer completely, so indexes are always 46 + * equal if empty and only empty, or !equal if data available 47 + */ 48 + return size - 1; 49 + } 50 + 51 + return ((read + size - write) % size) - 1; 52 + } 50 53 51 54 static struct chan_waitqueues { 52 55 wait_queue_head_t rt_queue; 53 56 wait_queue_head_t lx_queue; 54 57 } channel_wqs[RTLX_CHANNELS]; 55 - 56 - static struct irqaction irq; 57 - static int irq_num; 58 58 59 59 extern void *vpe_get_shared(int index); 60 60 ··· 63 63 do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs); 64 64 } 65 65 66 - irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs) 66 + static irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs) 67 67 { 68 - irqreturn_t r = IRQ_HANDLED; 69 68 int i; 70 69 71 70 for (i = 0; i < RTLX_CHANNELS; i++) { ··· 74 75 wake_up_interruptible(&channel_wqs[i].lx_queue); 75 76 } 76 77 77 - return r; 78 - } 79 - 80 - void dump_rtlx(void) 81 - { 82 - int i; 83 - 84 - printk("id 0x%lx state %d\n", rtlx->id, rtlx->state); 85 - 86 - for (i = 0; i < RTLX_CHANNELS; i++) { 87 - struct rtlx_channel *chan = &rtlx->channel[i]; 88 - 89 - printk(" rt_state %d lx_state %d buffer_size %d\n", 90 - chan->rt_state, chan->lx_state, chan->buffer_size); 91 - 92 - printk(" rt_read %d rt_write %d\n", 93 - chan->rt_read, chan->rt_write); 94 - 95 - printk(" lx_read %d lx_write %d\n", 96 - chan->lx_read, chan->lx_write); 97 - 98 - printk(" rt_buffer <%s>\n", chan->rt_buffer); 99 - printk(" lx_buffer <%s>\n", chan->lx_buffer); 100 - } 78 + return IRQ_HANDLED; 101 79 } 102 80 103 81 /* call when we have the address of the shared structure from the SP side. */ ··· 84 108 85 109 if (rtlxi->id != RTLX_ID) { 86 110 printk(KERN_WARNING "no valid RTLX id at 0x%p\n", rtlxi); 87 - return (-ENOEXEC); 111 + return -ENOEXEC; 88 112 } 89 113 90 114 /* initialise the wait queues */ ··· 96 120 /* set up for interrupt handling */ 97 121 memset(&irq, 0, sizeof(struct irqaction)); 98 122 99 - if (cpu_has_vint) { 123 + if (cpu_has_vint) 100 124 set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch); 101 - } 102 125 103 126 irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ; 104 127 irq.handler = rtlx_interrupt; ··· 107 132 setup_irq(irq_num, &irq); 108 133 109 134 rtlx = rtlxi; 110 - return (0); 135 + 136 + return 0; 111 137 } 112 138 113 139 /* only allow one open process at a time to open each channel */ ··· 123 147 if (rtlx == NULL) { 124 148 struct rtlx_info **p; 125 149 if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { 126 - printk(" vpe_get_shared is NULL. Has an SP program been loaded?\n"); 127 - return (-EFAULT); 150 + printk(KERN_ERR "vpe_get_shared is NULL. " 151 + "Has an SP program been loaded?\n"); 152 + return -EFAULT; 128 153 } 129 154 130 155 if (*p == NULL) { 131 - printk(" vpe_shared %p %p\n", p, *p); 132 - return (-EFAULT); 156 + printk(KERN_ERR "vpe_shared %p %p\n", p, *p); 157 + return -EFAULT; 133 158 } 134 159 135 160 if ((ret = rtlx_init(*p)) < 0) 136 - return (ret); 161 + return ret; 137 162 } 138 163 139 164 chan = &rtlx->channel[minor]; 140 165 141 - /* already open? */ 142 - if (chan->lx_state == RTLX_STATE_OPENED) 143 - return (-EBUSY); 166 + if (test_and_set_bit(RTLX_STATE_OPENED, &chan->lx_state)) 167 + return -EBUSY; 144 168 145 - chan->lx_state = RTLX_STATE_OPENED; 146 - return (0); 169 + return 0; 147 170 } 148 171 149 172 static int rtlx_release(struct inode *inode, struct file *filp) 150 173 { 151 - int minor; 174 + int minor = MINOR(inode->i_rdev); 152 175 153 - minor = MINOR(inode->i_rdev); 154 - rtlx->channel[minor].lx_state = RTLX_STATE_UNUSED; 155 - return (0); 176 + clear_bit(RTLX_STATE_OPENED, &rtlx->channel[minor].lx_state); 177 + smp_mb__after_clear_bit(); 178 + 179 + return 0; 156 180 } 157 181 158 182 static unsigned int rtlx_poll(struct file *file, poll_table * wait) ··· 175 199 if (spacefree(chan->rt_read, chan->rt_write, chan->buffer_size)) 176 200 mask |= POLLOUT | POLLWRNORM; 177 201 178 - return (mask); 202 + return mask; 179 203 } 180 204 181 205 static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count, 182 206 loff_t * ppos) 183 207 { 208 + unsigned long failed; 184 209 size_t fl = 0L; 185 210 int minor; 186 211 struct rtlx_channel *lx; ··· 193 216 /* data available? */ 194 217 if (lx->lx_write == lx->lx_read) { 195 218 if (file->f_flags & O_NONBLOCK) 196 - return (0); // -EAGAIN makes cat whinge 219 + return 0; /* -EAGAIN makes cat whinge */ 197 220 198 221 /* go to sleep */ 199 222 add_wait_queue(&channel_wqs[minor].lx_queue, &wait); ··· 209 232 } 210 233 211 234 /* find out how much in total */ 212 - count = min( count, 213 - (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size); 235 + count = min(count, 236 + (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size); 214 237 215 238 /* then how much from the read pointer onwards */ 216 - fl = min( count, (size_t)lx->buffer_size - lx->lx_read); 239 + fl = min(count, (size_t)lx->buffer_size - lx->lx_read); 217 240 218 - copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl); 241 + failed = copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl); 242 + if (failed) { 243 + count = fl - failed; 244 + goto out; 245 + } 219 246 220 247 /* and if there is anything left at the beginning of the buffer */ 221 - if ( count - fl ) 222 - copy_to_user (buffer + fl, lx->lx_buffer, count - fl); 248 + if (count - fl) { 249 + failed = copy_to_user (buffer + fl, lx->lx_buffer, count - fl); 250 + if (failed) { 251 + count -= failed; 252 + goto out; 253 + } 254 + } 223 255 256 + out: 224 257 /* update the index */ 225 258 lx->lx_read += count; 226 259 lx->lx_read %= lx->buffer_size; 227 260 228 - return (count); 229 - } 230 - 231 - static inline int spacefree(int read, int write, int size) 232 - { 233 - if (read == write) { 234 - /* never fill the buffer completely, so indexes are always equal if empty 235 - and only empty, or !equal if data available */ 236 - return (size - 1); 237 - } 238 - 239 - return ((read + size - write) % size) - 1; 261 + return count; 240 262 } 241 263 242 264 static ssize_t rtlx_write(struct file *file, const char __user * buffer, 243 265 size_t count, loff_t * ppos) 244 266 { 267 + unsigned long failed; 245 268 int minor; 246 269 struct rtlx_channel *rt; 247 270 size_t fl; ··· 254 277 if (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) { 255 278 256 279 if (file->f_flags & O_NONBLOCK) 257 - return (-EAGAIN); 280 + return -EAGAIN; 258 281 259 282 add_wait_queue(&channel_wqs[minor].rt_queue, &wait); 260 283 set_current_state(TASK_INTERRUPTIBLE); ··· 267 290 } 268 291 269 292 /* total number of bytes to copy */ 270 - count = min( count, (size_t)spacefree(rt->rt_read, rt->rt_write, rt->buffer_size) ); 293 + count = min(count, (size_t)spacefree(rt->rt_read, rt->rt_write, rt->buffer_size) ); 271 294 272 295 /* first bit from write pointer to the end of the buffer, or count */ 273 296 fl = min(count, (size_t) rt->buffer_size - rt->rt_write); 274 297 275 - copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl); 298 + failed = copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl); 299 + if (failed) { 300 + count = fl - failed; 301 + goto out; 302 + } 276 303 277 304 /* if there's any left copy to the beginning of the buffer */ 278 - if( count - fl ) 279 - copy_from_user(rt->rt_buffer, buffer + fl, count - fl); 305 + if (count - fl) { 306 + failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl); 307 + if (failed) { 308 + count -= failed; 309 + goto out; 310 + } 311 + } 280 312 313 + out: 281 314 rt->rt_write += count; 282 315 rt->rt_write %= rt->buffer_size; 283 316 284 - return(count); 317 + return count; 285 318 } 286 319 287 320 static struct file_operations rtlx_fops = { 288 - .owner = THIS_MODULE, 289 - .open = rtlx_open, 290 - .release = rtlx_release, 291 - .write = rtlx_write, 292 - .read = rtlx_read, 293 - .poll = rtlx_poll 321 + .owner = THIS_MODULE, 322 + .open = rtlx_open, 323 + .release = rtlx_release, 324 + .write = rtlx_write, 325 + .read = rtlx_read, 326 + .poll = rtlx_poll 294 327 }; 295 328 296 - static int rtlx_module_init(void) 329 + static char register_chrdev_failed[] __initdata = 330 + KERN_ERR "rtlx_module_init: unable to register device\n"; 331 + 332 + static int __init rtlx_module_init(void) 297 333 { 298 - if ((major = register_chrdev(RTLX_MAJOR, module_name, &rtlx_fops)) < 0) { 299 - printk("rtlx_module_init: unable to register device\n"); 300 - return (-EBUSY); 334 + major = register_chrdev(0, module_name, &rtlx_fops); 335 + if (major < 0) { 336 + printk(register_chrdev_failed); 337 + return major; 301 338 } 302 339 303 - if (major == 0) 304 - major = RTLX_MAJOR; 305 - 306 - return (0); 340 + return 0; 307 341 } 308 342 309 - static void rtlx_module_exit(void) 343 + static void __exit rtlx_module_exit(void) 310 344 { 311 345 unregister_chrdev(major, module_name); 312 346 } 313 347 314 348 module_init(rtlx_module_init); 315 349 module_exit(rtlx_module_exit); 350 + 316 351 MODULE_DESCRIPTION("MIPS RTLX"); 317 - MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc"); 352 + MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc."); 318 353 MODULE_LICENSE("GPL");
+12 -16
include/asm-mips/rtlx.h
··· 16 16 #define RTLX_ID (RTLX_xID | RTLX_VERSION) 17 17 #define RTLX_CHANNELS 8 18 18 19 - enum rtlx_state { 20 - RTLX_STATE_UNUSED = 0, 21 - RTLX_STATE_INITIALISED, 22 - RTLX_STATE_REMOTE_READY, 23 - RTLX_STATE_OPENED 24 - }; 25 - 26 19 #define RTLX_BUFFER_SIZE 1024 20 + 21 + /* 22 + * lx_state bits 23 + */ 24 + #define RTLX_STATE_OPENED 1UL 25 + 27 26 /* each channel supports read and write. 28 27 linux (vpe0) reads lx_buffer and writes rt_buffer 29 28 SP (vpe1) reads rt_buffer and writes lx_buffer 30 29 */ 31 - typedef struct rtlx_channel { 32 - enum rtlx_state rt_state; 33 - enum rtlx_state lx_state; 30 + struct rtlx_channel { 31 + unsigned long lx_state; 34 32 35 33 int buffer_size; 36 34 ··· 41 43 42 44 void *queues; 43 45 44 - } rtlx_channel_t; 46 + }; 45 47 46 - typedef struct rtlx_info { 48 + struct rtlx_info { 47 49 unsigned long id; 48 - enum rtlx_state state; 49 50 50 51 struct rtlx_channel channel[RTLX_CHANNELS]; 52 + }; 51 53 52 - } rtlx_info_t; 53 - 54 - #endif 54 + #endif /* _RTLX_H_ */