File: /usr/src/linux/drivers/sgi/char/usema.c

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     
42     struct irix_usema {
43     	struct file *filp;
44     	wait_queue_head_t proc_list;
45     };
46     
47     
48     static int
49     sgi_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     
63     static int
64     sgi_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     		/* XXX what is attach->us_handle for? */
93     		return sgi_usema_attach(attach, usema);
94     		break;
95     	}
96     	case UIOCABLOCK:	/* XXX make `async' */
97     	case UIOCNOIBLOCK:	/* XXX maybe? */
98     	case UIOCBLOCK: {
99     		/* Block this process on the semaphore */
100     		usattach_t *attach = (usattach_t *)arg;
101     
102     		retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
103     		if (retval) {
104     			printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): "
105     			       "verify_area failure",
106     			       current->comm, current->pid);
107     			return retval;
108     		}
109     		printk("UIOC*BLOCK: putting process %d to sleep on usema %p",
110     		       current->pid, usema);
111     		if (cmd == UIOCNOIBLOCK)
112     			interruptible_sleep_on(&usema->proc_list);
113     		else
114     			sleep_on(&usema->proc_list);
115     		return 0;
116     	}
117     	case UIOCAUNBLOCK:	/* XXX make `async' */
118     	case UIOCUNBLOCK: {
119     		/* Wake up all process waiting on this semaphore */
120     		usattach_t *attach = (usattach_t *)arg;
121     
122     		retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
123     		if (retval) {
124     			printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): "
125     			       "verify_area failure",
126     			       current->comm, current->pid);
127     			return retval;
128     		}
129     
130     		printk("[%s:%d] releasing usema %p",
131     		       current->comm, current->pid, usema);
132     		wake_up(&usema->proc_list);
133     		return 0;
134     	}
135     	}
136     	return -ENOSYS;
137     }
138     
139     static unsigned int
140     sgi_usemaclone_poll(struct file *filp, poll_table *wait)
141     {
142     	struct irix_usema *usema = filp->private_data;
143     	
144     	printk("[%s:%d] wants to poll usema %p",
145     	       current->comm, current->pid, usema);
146     	
147     	return 0;
148     }
149     
150     static int
151     sgi_usemaclone_open(struct inode *inode, struct file *filp)
152     {
153     	struct irix_usema *usema;
154     
155     	usema = kmalloc (sizeof (struct irix_usema), GFP_KERNEL);
156     	if (!usema)
157     		return -ENOMEM;
158     	
159     	usema->filp        = filp;
160     	init_waitqueue_head(&usema->proc_list);
161     	filp->private_data = usema;
162     
163     	return 0;
164     }
165     
166     struct file_operations sgi_usemaclone_fops = {
167     	poll:		sgi_usemaclone_poll,
168     	ioctl:		sgi_usemaclone_ioctl,
169     	open:		sgi_usemaclone_open,
170     };
171     
172     static struct miscdevice dev_usemaclone = {
173     	SGI_USEMACLONE, "usemaclone", &sgi_usemaclone_fops
174     };
175     
176     void
177     usema_init(void)
178     {
179     	printk("usemaclone misc device registered (minor: %d)\n",
180     	       SGI_USEMACLONE);
181     	misc_register(&dev_usemaclone);
182     }
183     
184     EXPORT_SYMBOL(usema_init);
185