patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / char / raw.c
1 /*
2  * linux/drivers/char/raw.c
3  *
4  * Front-end raw character devices.  These can be bound to any block
5  * devices to provide genuine Unix raw character device semantics.
6  *
7  * We reserve minor number 0 for a control interface.  ioctl()s on this
8  * device are used to bind the other minor numbers to block devices.
9  */
10
11 #include <linux/init.h>
12 #include <linux/fs.h>
13 #include <linux/devfs_fs_kernel.h>
14 #include <linux/major.h>
15 #include <linux/blkdev.h>
16 #include <linux/module.h>
17 #include <linux/raw.h>
18 #include <linux/capability.h>
19 #include <linux/uio.h>
20 #include <linux/cdev.h>
21
22 #include <asm/uaccess.h>
23
24 struct raw_device_data {
25         struct block_device *binding;
26         int inuse;
27 };
28
29 static struct raw_device_data raw_devices[MAX_RAW_MINORS];
30 static DECLARE_MUTEX(raw_mutex);
31 static struct file_operations raw_ctl_fops;          /* forward declaration */
32
33 /*
34  * Open/close code for raw IO.
35  *
36  * We just rewrite the i_mapping for the /dev/raw/rawN file descriptor to
37  * point at the blockdev's address_space and set the file handle to use
38  * O_DIRECT.
39  *
40  * Set the device's soft blocksize to the minimum possible.  This gives the
41  * finest possible alignment and has no adverse impact on performance.
42  */
43 static int raw_open(struct inode *inode, struct file *filp)
44 {
45         const int minor = iminor(inode);
46         struct block_device *bdev;
47         int err;
48
49         if (minor == 0) {       /* It is the control device */
50                 filp->f_op = &raw_ctl_fops;
51                 return 0;
52         }
53
54         down(&raw_mutex);
55
56         /*
57          * All we need to do on open is check that the device is bound.
58          */
59         bdev = raw_devices[minor].binding;
60         err = -ENODEV;
61         if (!bdev)
62                 goto out;
63         igrab(bdev->bd_inode);
64         err = blkdev_get(bdev, filp->f_mode, 0);
65         if (err)
66                 goto out;
67         err = bd_claim(bdev, raw_open);
68         if (err)
69                 goto out1;
70         err = set_blocksize(bdev, bdev_hardsect_size(bdev));
71         if (err)
72                 goto out2;
73         filp->f_flags |= O_DIRECT;
74         filp->f_mapping = bdev->bd_inode->i_mapping;
75         if (++raw_devices[minor].inuse == 1)
76                 filp->f_dentry->d_inode->i_mapping =
77                         bdev->bd_inode->i_mapping;
78         filp->private_data = bdev;
79         up(&raw_mutex);
80         return 0;
81
82 out2:
83         bd_release(bdev);
84 out1:
85         blkdev_put(bdev);
86 out:
87         up(&raw_mutex);
88         return err;
89 }
90
91 /*
92  * When the final fd which refers to this character-special node is closed, we
93  * make its ->mapping point back at its own i_data.
94  */
95 static int raw_release(struct inode *inode, struct file *filp)
96 {
97         const int minor= iminor(inode);
98         struct block_device *bdev;
99
100         down(&raw_mutex);
101         bdev = raw_devices[minor].binding;
102         if (--raw_devices[minor].inuse == 0) {
103                 /* Here  inode->i_mapping == bdev->bd_inode->i_mapping  */
104                 inode->i_mapping = &inode->i_data;
105                 inode->i_mapping->backing_dev_info = &default_backing_dev_info;
106         }
107         up(&raw_mutex);
108
109         bd_release(bdev);
110         blkdev_put(bdev);
111         return 0;
112 }
113
114 /*
115  * Forward ioctls to the underlying block device.
116  */
117 static int
118 raw_ioctl(struct inode *inode, struct file *filp,
119                   unsigned int command, unsigned long arg)
120 {
121         struct block_device *bdev = filp->private_data;
122
123         return ioctl_by_bdev(bdev, command, arg);
124 }
125
126 /*
127  * Deal with ioctls against the raw-device control interface, to bind
128  * and unbind other raw devices.
129  */
130 static int raw_ctl_ioctl(struct inode *inode, struct file *filp,
131                         unsigned int command, unsigned long arg)
132 {
133         struct raw_config_request rq;
134         struct raw_device_data *rawdev;
135         int err = 0;
136
137         switch (command) {
138         case RAW_SETBIND:
139         case RAW_GETBIND:
140
141                 /* First, find out which raw minor we want */
142
143                 if (copy_from_user(&rq, (void __user *) arg, sizeof(rq))) {
144                         err = -EFAULT;
145                         goto out;
146                 }
147
148                 if (rq.raw_minor < 0 || rq.raw_minor >= MAX_RAW_MINORS) {
149                         err = -EINVAL;
150                         goto out;
151                 }
152                 rawdev = &raw_devices[rq.raw_minor];
153
154                 if (command == RAW_SETBIND) {
155                         dev_t dev;
156
157                         /*
158                          * This is like making block devices, so demand the
159                          * same capability
160                          */
161                         if (!capable(CAP_SYS_ADMIN)) {
162                                 err = -EPERM;
163                                 goto out;
164                         }
165
166                         /*
167                          * For now, we don't need to check that the underlying
168                          * block device is present or not: we can do that when
169                          * the raw device is opened.  Just check that the
170                          * major/minor numbers make sense.
171                          */
172
173                         dev = MKDEV(rq.block_major, rq.block_minor);
174                         if ((rq.block_major == 0 && rq.block_minor != 0) ||
175                                         MAJOR(dev) != rq.block_major ||
176                                         MINOR(dev) != rq.block_minor) {
177                                 err = -EINVAL;
178                                 goto out;
179                         }
180
181                         down(&raw_mutex);
182                         if (rawdev->inuse) {
183                                 up(&raw_mutex);
184                                 err = -EBUSY;
185                                 goto out;
186                         }
187                         if (rawdev->binding) {
188                                 bdput(rawdev->binding);
189                                 module_put(THIS_MODULE);
190                         }
191                         if (rq.block_major == 0 && rq.block_minor == 0) {
192                                 /* unbind */
193                                 rawdev->binding = NULL;
194                         } else {
195                                 rawdev->binding = bdget(dev);
196                                 if (rawdev->binding == NULL)
197                                         err = -ENOMEM;
198                                 else
199                                         __module_get(THIS_MODULE);
200                         }
201                         up(&raw_mutex);
202                 } else {
203                         struct block_device *bdev;
204
205                         down(&raw_mutex);
206                         bdev = rawdev->binding;
207                         if (bdev) {
208                                 rq.block_major = MAJOR(bdev->bd_dev);
209                                 rq.block_minor = MINOR(bdev->bd_dev);
210                         } else {
211                                 rq.block_major = rq.block_minor = 0;
212                         }
213                         up(&raw_mutex);
214                         if (copy_to_user((void __user *)arg, &rq, sizeof(rq))) {
215                                 err = -EFAULT;
216                                 goto out;
217                         }
218                 }
219                 break;
220         default:
221                 err = -EINVAL;
222                 break;
223         }
224 out:
225         return err;
226 }
227
228 static ssize_t raw_file_write(struct file *file, const char __user *buf,
229                                    size_t count, loff_t *ppos)
230 {
231         struct iovec local_iov = {
232                 .iov_base = (char __user *)buf,
233                 .iov_len = count
234         };
235
236         return generic_file_write_nolock(file, &local_iov, 1, ppos);
237 }
238
239 static ssize_t raw_file_aio_write(struct kiocb *iocb, const char __user *buf,
240                                         size_t count, loff_t pos)
241 {
242         struct iovec local_iov = {
243                 .iov_base = (char __user *)buf,
244                 .iov_len = count
245         };
246
247         return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
248 }
249
250
251 static struct file_operations raw_fops = {
252         .read   =       generic_file_read,
253         .aio_read =     generic_file_aio_read,
254         .write  =       raw_file_write,
255         .aio_write =    raw_file_aio_write,
256         .open   =       raw_open,
257         .release=       raw_release,
258         .ioctl  =       raw_ioctl,
259         .readv  =       generic_file_readv,
260         .writev =       generic_file_writev,
261         .owner  =       THIS_MODULE,
262 };
263
264 static struct file_operations raw_ctl_fops = {
265         .ioctl  =       raw_ctl_ioctl,
266         .open   =       raw_open,
267         .owner  =       THIS_MODULE,
268 };
269
270 static struct cdev raw_cdev = {
271         .kobj   =       {.name = "raw", },
272         .owner  =       THIS_MODULE,
273 };
274
275 static int __init raw_init(void)
276 {
277         int i;
278         dev_t dev = MKDEV(RAW_MAJOR, 0);
279
280         if (register_chrdev_region(dev, MAX_RAW_MINORS, "raw"))
281                 goto error;
282
283         cdev_init(&raw_cdev, &raw_fops);
284         if (cdev_add(&raw_cdev, dev, MAX_RAW_MINORS)) {
285                 kobject_put(&raw_cdev.kobj);
286                 unregister_chrdev_region(dev, MAX_RAW_MINORS);
287                 goto error;
288         }
289
290         devfs_mk_cdev(MKDEV(RAW_MAJOR, 0),
291                       S_IFCHR | S_IRUGO | S_IWUGO,
292                       "raw/rawctl");
293         for (i = 1; i < MAX_RAW_MINORS; i++)
294                 devfs_mk_cdev(MKDEV(RAW_MAJOR, i),
295                               S_IFCHR | S_IRUGO | S_IWUGO,
296                               "raw/raw%d", i);
297         return 0;
298
299 error:
300         printk(KERN_ERR "error register raw device\n");
301         return 1;
302 }
303
304 static void __exit raw_exit(void)
305 {
306         int i;
307
308         for (i = 1; i < MAX_RAW_MINORS; i++)
309                 devfs_remove("raw/raw%d", i);
310         devfs_remove("raw/rawctl");
311         devfs_remove("raw");
312         cdev_del(&raw_cdev);
313         unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS);
314 }
315
316 module_init(raw_init);
317 module_exit(raw_exit);
318 MODULE_LICENSE("GPL");