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