diff options
| author | Andrew Morton <akpm@zip.com.au> | 2002-07-28 03:23:39 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-07-28 03:23:39 -0700 |
| commit | 603e29ca3a7e5ebac53bd85082224b50113f80b6 (patch) | |
| tree | 30ac0fa5c0ed8eb5138d2d48d131fa6dad40a103 | |
| parent | 0d85f8bf8d8491a813152235929f9bcb9b7b6589 (diff) | |
[PATCH] permit modular build of raw driver
This patch allows the raw driver to be built as a kernel module.
It also cleans up a bunch of stuff, C99ifies the initialisers, gives
lots of symbols static scope, etc.
The module is unloadable when there are zero bindings. The current
ioctl() interface have no way of undoing a binding - it only allows
bindings to be overwritten. So I overloaded a bind to major=0,minor=0
to mean "undo the binding". I'll update the raw(8) manpage for that.
generic_file_direct_IO has been exported to modules.
The call to invalidate_inode_pages2() has been removed from all
generic_file_driect_IO() callers, into generic_file_direct_IO() itself.
Mainly to avoid exporting invalidate_inode_pages2() to modules.
| -rw-r--r-- | drivers/char/Config.help | 6 | ||||
| -rw-r--r-- | drivers/char/Config.in | 2 | ||||
| -rw-r--r-- | drivers/char/Makefile | 3 | ||||
| -rw-r--r-- | drivers/char/raw.c | 259 | ||||
| -rw-r--r-- | fs/direct-io.c | 2 | ||||
| -rw-r--r-- | kernel/ksyms.c | 1 | ||||
| -rw-r--r-- | mm/filemap.c | 2 |
7 files changed, 132 insertions, 143 deletions
diff --git a/drivers/char/Config.help b/drivers/char/Config.help index 8d7658267d31..a3b8d1254791 100644 --- a/drivers/char/Config.help +++ b/drivers/char/Config.help @@ -1110,3 +1110,9 @@ CONFIG_HVC_CONSOLE pSeries machines when partitioned support a hypervisor virtual console. This driver allows each pSeries partition to have a console which is accessed via the HMC. + +CONFIG_RAW_DRIVER + The raw driver permits block devices to be bound to /dev/raw/rawN. + Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. + See the raw(8) manpage for more details. + diff --git a/drivers/char/Config.in b/drivers/char/Config.in index a2489a9daf9b..7eb721082265 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -198,4 +198,6 @@ if [ "$CONFIG_X86" = "y" ]; then tristate 'ACP Modem (Mwave) support' CONFIG_MWAVE fi +tristate ' RAW driver (/dev/raw/rawN)' CONFIG_RAW_DRIVER + endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile index d7044c9b2b06..c87477e36509 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -7,7 +7,7 @@ # FONTMAPFILE = cp437.uni -obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o +obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o pty.o misc.o random.o # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. @@ -146,6 +146,7 @@ obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o +obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_PRINTER) += lp.o diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 200e5a23b156..1da088fc6626 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -12,161 +12,106 @@ #include <linux/fs.h> #include <linux/major.h> #include <linux/blkdev.h> +#include <linux/module.h> #include <linux/raw.h> #include <linux/capability.h> -#include <linux/smp_lock.h> + #include <asm/uaccess.h> -typedef struct raw_device_data_s { +struct raw_device_data { struct block_device *binding; int inuse; - struct semaphore mutex; -} raw_device_data_t; - -static raw_device_data_t raw_devices[256]; - -static ssize_t rw_raw_dev(int rw, struct file *, char *, size_t, loff_t *); - -ssize_t raw_read(struct file *, char *, size_t, loff_t *); -ssize_t raw_write(struct file *, const char *, size_t, loff_t *); -int raw_open(struct inode *, struct file *); -int raw_release(struct inode *, struct file *); -int raw_ctl_ioctl(struct inode *, struct file *, unsigned int, unsigned long); -int raw_ioctl(struct inode *, struct file *, unsigned int, unsigned long); - - -static struct file_operations raw_fops = { - read: raw_read, - write: raw_write, - open: raw_open, - release: raw_release, - ioctl: raw_ioctl, -}; - -static struct file_operations raw_ctl_fops = { - ioctl: raw_ctl_ioctl, - open: raw_open, }; -static int __init raw_init(void) -{ - int i; - register_chrdev(RAW_MAJOR, "raw", &raw_fops); - - for (i = 0; i < 256; i++) - init_MUTEX(&raw_devices[i].mutex); - - return 0; -} - -__initcall(raw_init); +static struct raw_device_data raw_devices[256]; +static DECLARE_MUTEX(raw_mutex); +static struct file_operations raw_ctl_fops; -/* +/* * Open/close code for raw IO. * - * Set the device's soft blocksize to the minimum possible. This gives the + * Set the device's soft blocksize to the minimum possible. This gives the * finest possible alignment and has no adverse impact on performance. */ -int raw_open(struct inode *inode, struct file *filp) +static int raw_open(struct inode *inode, struct file *filp) { - int minor; - struct block_device * bdev; + const int minor = minor(inode->i_rdev); + struct block_device *bdev; int err; - minor = minor(inode->i_rdev); - - /* - * Is it the control device? - */ - - if (minor == 0) { + if (minor == 0) { /* It is the control device */ filp->f_op = &raw_ctl_fops; return 0; } - down(&raw_devices[minor].mutex); + down(&raw_mutex); /* - * No, it is a normal raw device. All we need to do on open is - * to check that the device is bound. + * All we need to do on open is check that the device is bound. */ bdev = raw_devices[minor].binding; err = -ENODEV; - if (!bdev) - goto out; - - atomic_inc(&bdev->bd_count); - err = blkdev_get(bdev, filp->f_mode, 0, BDEV_RAW); - if (!err) { - int minsize = bdev_hardsect_size(bdev); - - if (bdev) { - int ret; - - ret = set_blocksize(bdev, minsize); - if (ret) - printk("%s: set_blocksize() failed: %d\n", - __FUNCTION__, ret); + if (bdev) { + atomic_inc(&bdev->bd_count); + err = blkdev_get(bdev, filp->f_mode, 0, BDEV_RAW); + if (!err) { + err = set_blocksize(bdev, bdev_hardsect_size(bdev)); + raw_devices[minor].inuse++; } - raw_devices[minor].inuse++; } - out: - up(&raw_devices[minor].mutex); - + up(&raw_mutex); return err; } -int raw_release(struct inode *inode, struct file *filp) +static int raw_release(struct inode *inode, struct file *filp) { - int minor; + const int minor= minor(inode->i_rdev); struct block_device *bdev; - minor = minor(inode->i_rdev); - down(&raw_devices[minor].mutex); + down(&raw_mutex); bdev = raw_devices[minor].binding; raw_devices[minor].inuse--; - up(&raw_devices[minor].mutex); + up(&raw_mutex); blkdev_put(bdev, BDEV_RAW); return 0; } -/* Forward ioctls to the underlying block device. */ -int raw_ioctl(struct inode *inode, - struct file *filp, - unsigned int command, - unsigned long arg) +/* + * Forward ioctls to the underlying block device. + */ +static int +raw_ioctl(struct inode *inode, struct file *filp, + unsigned int command, unsigned long arg) { - int minor = minor(inode->i_rdev); - int err; - struct block_device *b; + const int minor = minor(inode->i_rdev); + int err; + struct block_device *bdev; err = -ENODEV; if (minor < 1 && minor > 255) goto out; - b = raw_devices[minor].binding; + bdev = raw_devices[minor].binding; err = -EINVAL; - if (b == NULL) + if (bdev == NULL) goto out; - if (b->bd_inode && b->bd_op && b->bd_op->ioctl) - err = b->bd_op->ioctl(b->bd_inode, NULL, command, arg); + if (bdev->bd_inode && bdev->bd_op && bdev->bd_op->ioctl) + err = bdev->bd_op->ioctl(bdev->bd_inode, NULL, command, arg); out: return err; } /* * Deal with ioctls against the raw-device control interface, to bind - * and unbind other raw devices. + * and unbind other raw devices. */ - -int raw_ctl_ioctl(struct inode *inode, - struct file *filp, - unsigned int command, - unsigned long arg) +static int +raw_ctl_ioctl(struct inode *inode, struct file *filp, + unsigned int command, unsigned long arg) { struct raw_config_request rq; + struct raw_device_data *rawdev; int err; - int minor; switch (command) { case RAW_SETBIND: @@ -178,10 +123,10 @@ int raw_ctl_ioctl(struct inode *inode, if (copy_from_user(&rq, (void *) arg, sizeof(rq))) goto out; - minor = rq.raw_minor; err = -EINVAL; - if (minor <= 0 || minor > MINORMASK) + if (rq.raw_minor < 0 || rq.raw_minor > MINORMASK) goto out; + rawdev = &raw_devices[rq.raw_minor]; if (command == RAW_SETBIND) { /* @@ -192,11 +137,11 @@ int raw_ctl_ioctl(struct inode *inode, if (!capable(CAP_SYS_ADMIN)) goto out; - /* + /* * For now, we don't need to check that the underlying * block device is present or not: we can do that when * the raw device is opened. Just check that the - * major/minor numbers make sense. + * major/minor numbers make sense. */ err = -EINVAL; @@ -205,23 +150,33 @@ int raw_ctl_ioctl(struct inode *inode, rq.block_minor > MINORMASK) goto out; - down(&raw_devices[minor].mutex); + down(&raw_mutex); err = -EBUSY; - if (raw_devices[minor].inuse) { - up(&raw_devices[minor].mutex); + if (rawdev->inuse) { + up(&raw_mutex); goto out; } - if (raw_devices[minor].binding) - bdput(raw_devices[minor].binding); - raw_devices[minor].binding = - bdget(kdev_t_to_nr(mk_kdev(rq.block_major, - rq.block_minor))); - up(&raw_devices[minor].mutex); + if (rawdev->binding) { + bdput(rawdev->binding); + MOD_DEC_USE_COUNT; + } + if (rq.block_major == 0 && rq.block_minor == 0) { + /* unbind */ + rawdev->binding = NULL; + } else { + kdev_t kdev; + + kdev = mk_kdev(rq.block_major, rq.block_minor); + rawdev->binding = bdget(kdev_t_to_nr(kdev)); + MOD_INC_USE_COUNT; + } + up(&raw_mutex); } else { struct block_device *bdev; kdev_t dev; - bdev = raw_devices[minor].binding; + down(&raw_mutex); + bdev = rawdev->binding; if (bdev) { dev = to_kdev_t(bdev->bd_dev); rq.block_major = major(dev); @@ -229,8 +184,9 @@ int raw_ctl_ioctl(struct inode *inode, } else { rq.block_major = rq.block_minor = 0; } + up(&raw_mutex); err = -EFAULT; - if (copy_to_user((void *) arg, &rq, sizeof(rq))) + if (copy_to_user((void *)arg, &rq, sizeof(rq))) goto out; } err = 0; @@ -244,46 +200,69 @@ out: return err; } -ssize_t raw_read(struct file *filp, char * buf, size_t size, loff_t *offp) -{ - return rw_raw_dev(READ, filp, buf, size, offp); -} - -ssize_t raw_write(struct file *filp, const char *buf, size_t size, loff_t *offp) -{ - return rw_raw_dev(WRITE, filp, (char *)buf, size, offp); -} - -ssize_t +static ssize_t rw_raw_dev(int rw, struct file *filp, char *buf, size_t size, loff_t *offp) { - struct block_device *bdev; - struct inode *inode; - int minor; + const int minor = minor(filp->f_dentry->d_inode->i_rdev); + struct block_device *bdev = raw_devices[minor].binding; + struct inode *inode = bdev->bd_inode; ssize_t ret = 0; - minor = minor(filp->f_dentry->d_inode->i_rdev); - bdev = raw_devices[minor].binding; - inode = bdev->bd_inode; - if (size == 0) goto out; - if (size < 0) { - ret = -EINVAL; + ret = -EINVAL; + if (size < 0) goto out; - } - if (*offp >= inode->i_size) { - ret = -ENXIO; + ret = -ENXIO; + if (*offp >= inode->i_size) goto out; - } + if (size + *offp > inode->i_size) size = inode->i_size - *offp; - ret = generic_file_direct_IO(rw, inode, buf, *offp, size); if (ret > 0) *offp += ret; - if (inode->i_mapping->nrpages) - invalidate_inode_pages2(inode->i_mapping); out: return ret; } + +static ssize_t +raw_read(struct file *filp, char * buf, size_t size, loff_t *offp) +{ + return rw_raw_dev(READ, filp, buf, size, offp); +} + +static ssize_t +raw_write(struct file *filp, const char *buf, size_t size, loff_t *offp) +{ + return rw_raw_dev(WRITE, filp, (char *)buf, size, offp); +} + +static struct file_operations raw_fops = { + .read = raw_read, + .write = raw_write, + .open = raw_open, + .release= raw_release, + .ioctl = raw_ioctl, + .owner = THIS_MODULE, +}; + +static struct file_operations raw_ctl_fops = { + .ioctl = raw_ctl_ioctl, + .open = raw_open, + .owner = THIS_MODULE, +}; + +static int __init raw_init(void) +{ + register_chrdev(RAW_MAJOR, "raw", &raw_fops); + return 0; +} + +static void __exit raw_exit(void) +{ + unregister_chrdev(RAW_MAJOR, "raw"); +} + +module_init(raw_init); +module_exit(raw_exit); diff --git a/fs/direct-io.c b/fs/direct-io.c index 5fa04d8a9c84..504d38dd8c57 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -625,6 +625,8 @@ generic_file_direct_IO(int rw, struct inode *inode, char *buf, goto out; } retval = mapping->a_ops->direct_IO(rw, inode, buf, offset, count); + if (inode->i_mapping->nrpages) + invalidate_inode_pages2(inode->i_mapping); out: return retval; } diff --git a/kernel/ksyms.c b/kernel/ksyms.c index f18263655052..3f62625b5cab 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -340,6 +340,7 @@ EXPORT_SYMBOL(register_disk); EXPORT_SYMBOL(read_dev_sector); EXPORT_SYMBOL(init_buffer); EXPORT_SYMBOL(wipe_partitions); +EXPORT_SYMBOL(generic_file_direct_IO); /* tty routines */ EXPORT_SYMBOL(tty_hangup); diff --git a/mm/filemap.c b/mm/filemap.c index 6b19b188f265..c12485a44814 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2056,8 +2056,6 @@ generic_file_write(struct file *file, const char *buf, mark_inode_dirty(inode); } *ppos = end; - if (mapping->nrpages) - invalidate_inode_pages2(mapping); } /* * Sync the fs metadata but not the minor inode changes and |
