1/* 2 * usema.c: software semaphore driver (see IRIX's usema(7M)) 3 * written 1997 Mike Shaver (shaver@neon.ingenia.ca) 4 * 1997 Miguel de Icaza (miguel@kernel.org) 5 * 6 * This file contains the implementation of /dev/usemaclone, 7 * the devices used by IRIX's us* semaphore routines. 8 * 9 * /dev/usemaclone is used to create a new semaphore device, and then 10 * the semaphore is manipulated via ioctls. 11 * 12 * At least for the zero-contention case, lock set and unset as well 13 * as semaphore P and V are done in userland, which makes things a 14 * little bit better. I suspect that the ioctls are used to register 15 * the process as blocking, etc. 16 * 17 * Much inspiration and structure stolen from Miguel's shmiq work. 18 * 19 * For more information: 20 * usema(7m), usinit(3p), usnewsema(3p) 21 * /usr/include/sys/usioctl.h 22 * 23 */ 24#include <linux/fs.h> 25#include <linux/miscdevice.h> 26#include <linux/sched.h> 27#include <linux/file.h> 28#include <linux/major.h> 29#include <linux/poll.h> 30#include <linux/string.h> 31#include <linux/dcache.h> 32#include <linux/mm.h> 33#include <linux/module.h> 34#include <linux/slab.h> 35#include <linux/smp_lock.h> 36#include "usema.h" 37 38#include <asm/usioctl.h> 39#include <asm/mman.h> 40#include <asm/uaccess.h> 41 42struct irix_usema { 43 struct file *filp; 44 wait_queue_head_t proc_list; 45}; 46 47 48static int 49sgi_usema_attach (usattach_t * attach, struct irix_usema *usema) 50{ 51 int newfd; 52 newfd = get_unused_fd(); 53 if (newfd < 0) 54 return newfd; 55 56 get_file(usema->filp); 57 fd_install(newfd, usema->filp); 58 /* Is that it? */ 59 printk("UIOCATTACHSEMA: new usema fd is %d", newfd); 60 return newfd; 61} 62 63static int 64sgi_usemaclone_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 65 unsigned long arg) 66{ 67 struct irix_usema *usema = file->private_data; 68 int retval; 69 70 printk("[%s:%d] wants ioctl 0x%xd (arg 0x%lx)", 71 current->comm, current->pid, cmd, arg); 72 73 switch(cmd) { 74 case UIOCATTACHSEMA: { 75 /* They pass us information about the semaphore to 76 which they wish to be attached, and we create&return 77 a new fd corresponding to the appropriate semaphore. 78 */ 79 usattach_t *attach = (usattach_t *)arg; 80 retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t)); 81 if (retval) { 82 printk("[%s:%d] sgi_usema_ioctl(UIOCATTACHSEMA): " 83 "verify_area failure", 84 current->comm, current->pid); 85 return retval; 86 } 87 if (usema == 0) 88 return -EINVAL; 89 90 printk("UIOCATTACHSEMA: attaching usema %p to process %d\n", 91 usema, current->pid); 92 return sgi_usema_attach(attach, usema); 93 break; 94 } 95 case UIOCABLOCK: 96 case UIOCNOIBLOCK: 97 case UIOCBLOCK: { 98 /* Block this process on the semaphore */ 99 usattach_t *attach = (usattach_t *)arg; 100 101 retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t)); 102 if (retval) { 103 printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): " 104 "verify_area failure", 105 current->comm, current->pid); 106 return retval; 107 } 108 printk("UIOC*BLOCK: putting process %d to sleep on usema %p", 109 current->pid, usema); 110 if (cmd == UIOCNOIBLOCK) 111 interruptible_sleep_on(&usema->proc_list); 112 else 113 sleep_on(&usema->proc_list); 114 return 0; 115 } 116 case UIOCAUNBLOCK: 117 case UIOCUNBLOCK: { 118 /* Wake up all process waiting on this semaphore */ 119 usattach_t *attach = (usattach_t *)arg; 120 121 retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t)); 122 if (retval) { 123 printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): " 124 "verify_area failure", 125 current->comm, current->pid); 126 return retval; 127 } 128 129 printk("[%s:%d] releasing usema %p", 130 current->comm, current->pid, usema); 131 wake_up(&usema->proc_list); 132 return 0; 133 } 134 } 135 return -ENOSYS; 136} 137 138static unsigned int 139sgi_usemaclone_poll(struct file *filp, poll_table *wait) 140{ 141 struct irix_usema *usema = filp->private_data; 142 143 printk("[%s:%d] wants to poll usema %p", 144 current->comm, current->pid, usema); 145 146 return 0; 147} 148 149static int 150sgi_usemaclone_open(struct inode *inode, struct file *filp) 151{ 152 struct irix_usema *usema; 153 154 usema = kmalloc (sizeof (struct irix_usema), GFP_KERNEL); 155 if (!usema) 156 return -ENOMEM; 157 158 usema->filp = filp; 159 init_waitqueue_head(&usema->proc_list); 160 filp->private_data = usema; 161 162 return 0; 163} 164 165struct file_operations sgi_usemaclone_fops = { 166 .poll = sgi_usemaclone_poll, 167 .ioctl = sgi_usemaclone_ioctl, 168 .open = sgi_usemaclone_open, 169}; 170 171static struct miscdevice dev_usemaclone = { 172 .minor = SGI_USEMACLONE, 173 .name = "usemaclone", 174 .fops = &sgi_usemaclone_fops, 175}; 176 177void 178usema_init(void) 179{ 180 printk(KERN_INFO "usemaclone misc device registered (minor: %d)\n", 181 SGI_USEMACLONE); 182 misc_register(&dev_usemaclone); 183} 184 185EXPORT_SYMBOL(usema_init); 186