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