Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.30-rc2 307 lines 7.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/major.h> 14#include <linux/blkdev.h> 15#include <linux/module.h> 16#include <linux/raw.h> 17#include <linux/capability.h> 18#include <linux/uio.h> 19#include <linux/cdev.h> 20#include <linux/device.h> 21#include <linux/mutex.h> 22#include <linux/smp_lock.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 const 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 lock_kernel(); 58 mutex_lock(&raw_mutex); 59 60 /* 61 * All we need to do on open is check that the device is bound. 62 */ 63 bdev = raw_devices[minor].binding; 64 err = -ENODEV; 65 if (!bdev) 66 goto out; 67 igrab(bdev->bd_inode); 68 err = blkdev_get(bdev, filp->f_mode); 69 if (err) 70 goto out; 71 err = bd_claim(bdev, raw_open); 72 if (err) 73 goto out1; 74 err = set_blocksize(bdev, bdev_hardsect_size(bdev)); 75 if (err) 76 goto out2; 77 filp->f_flags |= O_DIRECT; 78 filp->f_mapping = bdev->bd_inode->i_mapping; 79 if (++raw_devices[minor].inuse == 1) 80 filp->f_path.dentry->d_inode->i_mapping = 81 bdev->bd_inode->i_mapping; 82 filp->private_data = bdev; 83 mutex_unlock(&raw_mutex); 84 unlock_kernel(); 85 return 0; 86 87out2: 88 bd_release(bdev); 89out1: 90 blkdev_put(bdev, filp->f_mode); 91out: 92 mutex_unlock(&raw_mutex); 93 unlock_kernel(); 94 return err; 95} 96 97/* 98 * When the final fd which refers to this character-special node is closed, we 99 * make its ->mapping point back at its own i_data. 100 */ 101static int raw_release(struct inode *inode, struct file *filp) 102{ 103 const int minor= iminor(inode); 104 struct block_device *bdev; 105 106 mutex_lock(&raw_mutex); 107 bdev = raw_devices[minor].binding; 108 if (--raw_devices[minor].inuse == 0) { 109 /* Here inode->i_mapping == bdev->bd_inode->i_mapping */ 110 inode->i_mapping = &inode->i_data; 111 inode->i_mapping->backing_dev_info = &default_backing_dev_info; 112 } 113 mutex_unlock(&raw_mutex); 114 115 bd_release(bdev); 116 blkdev_put(bdev, filp->f_mode); 117 return 0; 118} 119 120/* 121 * Forward ioctls to the underlying block device. 122 */ 123static int 124raw_ioctl(struct inode *inode, struct file *filp, 125 unsigned int command, unsigned long arg) 126{ 127 struct block_device *bdev = filp->private_data; 128 129 return blkdev_ioctl(bdev, 0, command, arg); 130} 131 132static void bind_device(struct raw_config_request *rq) 133{ 134 device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor)); 135 device_create(raw_class, NULL, MKDEV(RAW_MAJOR, rq->raw_minor), NULL, 136 "raw%d", rq->raw_minor); 137} 138 139/* 140 * Deal with ioctls against the raw-device control interface, to bind 141 * and unbind other raw devices. 142 */ 143static int raw_ctl_ioctl(struct inode *inode, struct file *filp, 144 unsigned int command, unsigned long arg) 145{ 146 struct raw_config_request rq; 147 struct raw_device_data *rawdev; 148 int err = 0; 149 150 switch (command) { 151 case RAW_SETBIND: 152 case RAW_GETBIND: 153 154 /* First, find out which raw minor we want */ 155 156 if (copy_from_user(&rq, (void __user *) arg, sizeof(rq))) { 157 err = -EFAULT; 158 goto out; 159 } 160 161 if (rq.raw_minor <= 0 || rq.raw_minor >= MAX_RAW_MINORS) { 162 err = -EINVAL; 163 goto out; 164 } 165 rawdev = &raw_devices[rq.raw_minor]; 166 167 if (command == RAW_SETBIND) { 168 dev_t dev; 169 170 /* 171 * This is like making block devices, so demand the 172 * same capability 173 */ 174 if (!capable(CAP_SYS_ADMIN)) { 175 err = -EPERM; 176 goto out; 177 } 178 179 /* 180 * For now, we don't need to check that the underlying 181 * block device is present or not: we can do that when 182 * the raw device is opened. Just check that the 183 * major/minor numbers make sense. 184 */ 185 186 dev = MKDEV(rq.block_major, rq.block_minor); 187 if ((rq.block_major == 0 && rq.block_minor != 0) || 188 MAJOR(dev) != rq.block_major || 189 MINOR(dev) != rq.block_minor) { 190 err = -EINVAL; 191 goto out; 192 } 193 194 mutex_lock(&raw_mutex); 195 if (rawdev->inuse) { 196 mutex_unlock(&raw_mutex); 197 err = -EBUSY; 198 goto out; 199 } 200 if (rawdev->binding) { 201 bdput(rawdev->binding); 202 module_put(THIS_MODULE); 203 } 204 if (rq.block_major == 0 && rq.block_minor == 0) { 205 /* unbind */ 206 rawdev->binding = NULL; 207 device_destroy(raw_class, 208 MKDEV(RAW_MAJOR, rq.raw_minor)); 209 } else { 210 rawdev->binding = bdget(dev); 211 if (rawdev->binding == NULL) 212 err = -ENOMEM; 213 else { 214 __module_get(THIS_MODULE); 215 bind_device(&rq); 216 } 217 } 218 mutex_unlock(&raw_mutex); 219 } else { 220 struct block_device *bdev; 221 222 mutex_lock(&raw_mutex); 223 bdev = rawdev->binding; 224 if (bdev) { 225 rq.block_major = MAJOR(bdev->bd_dev); 226 rq.block_minor = MINOR(bdev->bd_dev); 227 } else { 228 rq.block_major = rq.block_minor = 0; 229 } 230 mutex_unlock(&raw_mutex); 231 if (copy_to_user((void __user *)arg, &rq, sizeof(rq))) { 232 err = -EFAULT; 233 goto out; 234 } 235 } 236 break; 237 default: 238 err = -EINVAL; 239 break; 240 } 241out: 242 return err; 243} 244 245static const struct file_operations raw_fops = { 246 .read = do_sync_read, 247 .aio_read = generic_file_aio_read, 248 .write = do_sync_write, 249 .aio_write = generic_file_aio_write_nolock, 250 .open = raw_open, 251 .release= raw_release, 252 .ioctl = raw_ioctl, 253 .owner = THIS_MODULE, 254}; 255 256static const struct file_operations raw_ctl_fops = { 257 .ioctl = raw_ctl_ioctl, 258 .open = raw_open, 259 .owner = THIS_MODULE, 260}; 261 262static struct cdev raw_cdev; 263 264static int __init raw_init(void) 265{ 266 dev_t dev = MKDEV(RAW_MAJOR, 0); 267 int ret; 268 269 ret = register_chrdev_region(dev, MAX_RAW_MINORS, "raw"); 270 if (ret) 271 goto error; 272 273 cdev_init(&raw_cdev, &raw_fops); 274 ret = cdev_add(&raw_cdev, dev, MAX_RAW_MINORS); 275 if (ret) { 276 kobject_put(&raw_cdev.kobj); 277 goto error_region; 278 } 279 280 raw_class = class_create(THIS_MODULE, "raw"); 281 if (IS_ERR(raw_class)) { 282 printk(KERN_ERR "Error creating raw class.\n"); 283 cdev_del(&raw_cdev); 284 ret = PTR_ERR(raw_class); 285 goto error_region; 286 } 287 device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); 288 289 return 0; 290 291error_region: 292 unregister_chrdev_region(dev, MAX_RAW_MINORS); 293error: 294 return ret; 295} 296 297static void __exit raw_exit(void) 298{ 299 device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); 300 class_destroy(raw_class); 301 cdev_del(&raw_cdev); 302 unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS); 303} 304 305module_init(raw_init); 306module_exit(raw_exit); 307MODULE_LICENSE("GPL");