Commit eaa0bfbd authored by Alexander Viro's avatar Alexander Viro Committed by James Bottomley

[PATCH] block_device_operations always picked from gendisk

	* do_open() cleaned up
	* we always pick block_device_operations from gendisk->fops now
	* register_blkdev() just stores the name of driver, nothing more
	* ->bd_op and ->bd_queue removed - we have that in gendisk
	* get_blkfops() is gone
parent 0b0f135d
......@@ -40,7 +40,7 @@ struct blk_probe {
unsigned long range;
struct module *owner;
struct gendisk *(*get)(dev_t dev, int *part, void *data);
void (*lock)(dev_t, void *);
int (*lock)(dev_t, void *);
void *data;
} *probes[MAX_BLKDEV];
......@@ -52,7 +52,7 @@ static inline int dev_to_index(dev_t dev)
void blk_register_region(dev_t dev, unsigned long range, struct module *module,
struct gendisk *(*probe)(dev_t, int *, void *),
void (*lock)(dev_t, void *), void *data)
int (*lock)(dev_t, void *), void *data)
{
int index = dev_to_index(dev);
struct blk_probe *p = kmalloc(sizeof(struct blk_probe), GFP_KERNEL);
......@@ -97,10 +97,12 @@ static struct gendisk *exact_match(dev_t dev, int *part, void *data)
return p;
}
static void exact_lock(dev_t dev, void *data)
static int exact_lock(dev_t dev, void *data)
{
struct gendisk *p = data;
get_disk(p);
if (!get_disk(p))
return -1;
return 0;
}
/**
......@@ -167,8 +169,11 @@ get_gendisk(dev_t dev, int *part)
probe = p->get;
best = p->range;
*part = dev - p->dev;
if (p->lock)
p->lock(dev, data);
if (p->lock && p->lock(dev, data) < 0) {
if (owner)
__MOD_DEC_USE_COUNT(owner);
continue;
}
read_unlock(&gendisk_lock);
disk = probe(dev, part, data);
/* Currently ->owner protects _only_ ->probe() itself. */
......@@ -323,6 +328,12 @@ struct gendisk *alloc_disk(int minors)
struct gendisk *get_disk(struct gendisk *disk)
{
struct module *owner;
if (!disk->fops)
return NULL;
owner = disk->fops->owner;
if (owner && !try_inc_mod_count(owner))
return NULL;
atomic_inc(&disk->disk_dev.refcount);
return disk;
}
......
......@@ -122,6 +122,7 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
unsigned long arg)
{
struct block_device *bdev = inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
struct backing_dev_info *bdi;
int holder;
int ret, n;
......@@ -146,7 +147,7 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
case BLKSSZGET: /* get block device hardware sector size */
return put_int(arg, bdev_hardsect_size(bdev));
case BLKSECTGET:
return put_ushort(arg, bdev->bd_queue->max_sectors);
return put_ushort(arg, bdev_get_queue(bdev)->max_sectors);
case BLKRASET:
case BLKFRASET:
if(!capable(CAP_SYS_ADMIN))
......@@ -184,8 +185,8 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
case BLKFLSBUF:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (bdev->bd_op->ioctl) {
ret = bdev->bd_op->ioctl(inode, file, cmd, arg);
if (disk->fops->ioctl) {
ret = disk->fops->ioctl(inode, file, cmd, arg);
if (ret != -EINVAL)
return ret;
}
......@@ -193,8 +194,8 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
invalidate_bdev(bdev, 0);
return 0;
case BLKROSET:
if (bdev->bd_op->ioctl) {
ret = bdev->bd_op->ioctl(inode, file, cmd, arg);
if (disk->fops->ioctl) {
ret = disk->fops->ioctl(inode, file, cmd, arg);
if (ret != -EINVAL)
return ret;
}
......@@ -205,8 +206,8 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
set_device_ro(bdev, n);
return 0;
default:
if (bdev->bd_op->ioctl) {
ret = bdev->bd_op->ioctl(inode, file, cmd, arg);
if (disk->fops->ioctl) {
ret = disk->fops->ioctl(inode, file, cmd, arg);
if (ret != -EINVAL)
return ret;
}
......
......@@ -351,10 +351,9 @@ static int rd_open(struct inode * inode, struct file * filp)
rd_bdev[unit] = bdev;
bdev->bd_openers++;
bdev->bd_block_size = rd_blocksize;
bdev->bd_inode->i_size = get_capacity(rd_disks[unit])<<9;
inode->i_mapping->a_ops = &ramdisk_aops;
inode->i_mapping->backing_dev_info = &rd_backing_dev_info;
get_disk(bdev->bd_disk);
bdev->bd_inode->i_size = get_capacity(bdev->bd_disk) << 9;
}
return 0;
......
......@@ -68,6 +68,7 @@ static int raw_open(struct inode *inode, struct file *filp)
}
}
}
filp->private_data = bdev;
up(&raw_mutex);
return err;
}
......@@ -92,22 +93,9 @@ static int
raw_ioctl(struct inode *inode, struct file *filp,
unsigned int command, unsigned long arg)
{
const int minor = minor(inode->i_rdev);
int err;
struct block_device *bdev;
err = -ENODEV;
if (minor < 1 && minor > 255)
goto out;
struct block_device *bdev = filp->private_data;
bdev = raw_devices[minor].binding;
err = -EINVAL;
if (bdev == NULL)
goto out;
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;
return blkdev_ioctl(bdev->bd_inode, NULL, command, arg);
}
/*
......
......@@ -973,11 +973,10 @@ int init_irq (ide_hwif_t *hwif)
EXPORT_SYMBOL(init_irq);
static void ata_lock(dev_t dev, void *data)
static int ata_lock(dev_t dev, void *data)
{
ide_hwif_t *hwif = data;
int unit = MINOR(dev) >> PARTN_BITS;
get_disk(hwif->drives[unit].disk);
/* FIXME: we want to pin hwif down */
return 0;
}
struct gendisk *ata_probe(dev_t dev, int *part, void *data)
......@@ -985,10 +984,8 @@ struct gendisk *ata_probe(dev_t dev, int *part, void *data)
ide_hwif_t *hwif = data;
int unit = MINOR(dev) >> PARTN_BITS;
ide_drive_t *drive = &hwif->drives[unit];
if (!drive->present) {
put_disk(drive->disk);
if (!drive->present)
return NULL;
}
if (!drive->driver) {
if (drive->media == ide_disk)
(void) request_module("ide-disk");
......@@ -1001,11 +998,9 @@ struct gendisk *ata_probe(dev_t dev, int *part, void *data)
if (drive->media == ide_floppy)
(void) request_module("ide-floppy");
}
if (!drive->driver) {
put_disk(drive->disk);
if (!drive->driver)
return NULL;
}
return drive->disk;
return get_disk(drive->disk);
}
static int alloc_disks(ide_hwif_t *hwif)
......
......@@ -306,8 +306,6 @@ struct block_device *bdget(dev_t dev)
atomic_set(&new_bdev->bd_count,1);
new_bdev->bd_dev = dev;
new_bdev->bd_op = NULL;
new_bdev->bd_queue = NULL;
new_bdev->bd_contains = NULL;
new_bdev->bd_inode = inode;
new_bdev->bd_part_count = 0;
......@@ -434,10 +432,7 @@ void bd_release(struct block_device *bdev)
spin_unlock(&bdev_lock);
}
static struct {
const char *name;
struct block_device_operations *bdops;
} blkdevs[MAX_BLKDEV];
static const char *blkdevs[MAX_BLKDEV];
int get_blkdev_list(char * p)
{
......@@ -446,44 +441,20 @@ int get_blkdev_list(char * p)
len = sprintf(p, "\nBlock devices:\n");
for (i = 0; i < MAX_BLKDEV ; i++) {
if (blkdevs[i].bdops) {
len += sprintf(p+len, "%3d %s\n", i, blkdevs[i].name);
}
if (blkdevs[i])
len += sprintf(p+len, "%3d %s\n", i, blkdevs[i]);
}
return len;
}
/*
Return the function table of a device.
Load the driver if needed.
*/
struct block_device_operations * get_blkfops(unsigned int major)
{
struct block_device_operations *ret = NULL;
/* major 0 is used for non-device mounts */
if (major && major < MAX_BLKDEV) {
#ifdef CONFIG_KMOD
if (!blkdevs[major].bdops) {
char name[20];
sprintf(name, "block-major-%d", major);
request_module(name);
}
#endif
ret = blkdevs[major].bdops;
}
return ret;
}
int register_blkdev(unsigned int major, const char * name, struct block_device_operations *bdops)
{
if (devfs_only())
return 0;
if (major == 0) {
for (major = MAX_BLKDEV-1; major > 0; major--) {
if (blkdevs[major].bdops == NULL) {
blkdevs[major].name = name;
blkdevs[major].bdops = bdops;
if (blkdevs[major] == NULL) {
blkdevs[major] = name;
return major;
}
}
......@@ -491,10 +462,9 @@ int register_blkdev(unsigned int major, const char * name, struct block_device_o
}
if (major >= MAX_BLKDEV)
return -EINVAL;
if (blkdevs[major].bdops && blkdevs[major].bdops != bdops)
if (blkdevs[major])
return -EBUSY;
blkdevs[major].name = name;
blkdevs[major].bdops = bdops;
blkdevs[major] = name;
return 0;
}
......@@ -504,12 +474,11 @@ int unregister_blkdev(unsigned int major, const char * name)
return 0;
if (major >= MAX_BLKDEV)
return -EINVAL;
if (!blkdevs[major].bdops)
if (!blkdevs[major])
return -EINVAL;
if (strcmp(blkdevs[major].name, name))
if (strcmp(blkdevs[major], name))
return -EINVAL;
blkdevs[major].name = NULL;
blkdevs[major].bdops = NULL;
blkdevs[major] = NULL;
return 0;
}
......@@ -524,7 +493,8 @@ int unregister_blkdev(unsigned int major, const char * name)
*/
int check_disk_change(struct block_device *bdev)
{
struct block_device_operations * bdops = bdev->bd_op;
struct gendisk *disk = bdev->bd_disk;
struct block_device_operations * bdops = disk->fops;
kdev_t dev = to_kdev_t(bdev->bd_dev);
if (!bdops->media_changed)
......@@ -587,66 +557,33 @@ static void bd_set_size(struct block_device *bdev, loff_t size)
static int do_open(struct block_device *bdev, struct inode *inode, struct file *file)
{
int ret = -ENXIO;
kdev_t dev = to_kdev_t(bdev->bd_dev);
struct module *owner = NULL;
struct block_device_operations *ops, *old;
struct gendisk *disk;
int ret = -ENXIO;
int part;
lock_kernel();
ops = get_blkfops(major(dev));
if (ops) {
owner = ops->owner;
if (owner)
__MOD_INC_USE_COUNT(owner);
}
disk = get_gendisk(bdev->bd_dev, &part);
if (!disk) {
if (owner)
__MOD_DEC_USE_COUNT(owner);
bdput(bdev);
return ret;
}
owner = disk->fops->owner;
down(&bdev->bd_sem);
old = bdev->bd_op;
if (!old) {
if (!ops)
goto out;
bdev->bd_op = ops;
} else {
if (owner)
__MOD_DEC_USE_COUNT(owner);
}
if (!bdev->bd_contains) {
bdev->bd_contains = bdev;
if (part) {
struct block_device *whole;
whole = bdget(MKDEV(disk->major, disk->first_minor));
ret = -ENOMEM;
if (!whole)
goto out1;
ret = blkdev_get(whole, file->f_mode, file->f_flags, BDEV_RAW);
if (ret)
goto out1;
bdev->bd_contains = whole;
}
}
if (bdev->bd_contains == bdev) {
if (!bdev->bd_openers) {
bdev->bd_disk = disk;
bdev->bd_queue = disk->queue;
}
if (bdev->bd_op->open) {
ret = bdev->bd_op->open(inode, file);
bdev->bd_contains = bdev;
if (!part) {
struct backing_dev_info *bdi;
if (disk->fops->open) {
ret = disk->fops->open(inode, file);
if (ret)
goto out2;
goto out_first;
}
if (!bdev->bd_openers) {
struct backing_dev_info *bdi;
bdev->bd_offset = 0;
bd_set_size(bdev, (loff_t)get_capacity(disk) << 9);
if (!bdev->bd_openers) {
bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);
bdi = blk_get_backing_dev_info(bdev);
if (bdi == NULL)
bdi = &default_backing_dev_info;
......@@ -655,49 +592,63 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
if (bdev->bd_invalidated)
rescan_partitions(disk, bdev);
} else {
down(&bdev->bd_contains->bd_sem);
bdev->bd_contains->bd_part_count++;
if (!bdev->bd_openers) {
struct hd_struct *p;
struct block_device *whole;
whole = bdget(MKDEV(disk->major, disk->first_minor));
ret = -ENOMEM;
if (!whole)
goto out_first;
ret = blkdev_get(whole, file->f_mode, file->f_flags, BDEV_RAW);
if (ret)
goto out_first;
bdev->bd_contains = whole;
down(&whole->bd_sem);
whole->bd_part_count++;
p = disk->part + part - 1;
bdev->bd_inode->i_data.backing_dev_info =
bdev->bd_contains->bd_inode->i_data.backing_dev_info;
whole->bd_inode->i_data.backing_dev_info;
if (!(disk->flags & GENHD_FL_UP) || !p->nr_sects) {
bdev->bd_contains->bd_part_count--;
up(&bdev->bd_contains->bd_sem);
whole->bd_part_count--;
up(&whole->bd_sem);
ret = -ENXIO;
goto out2;
goto out_first;
}
bdev->bd_queue = bdev->bd_contains->bd_queue;
bdev->bd_offset = p->start_sect;
bd_set_size(bdev, (loff_t) p->nr_sects << 9);
bdev->bd_disk = disk;
up(&whole->bd_sem);
}
} else {
put_disk(disk);
if (owner)
__MOD_DEC_USE_COUNT(owner);
if (bdev->bd_contains == bdev) {
if (bdev->bd_disk->fops->open) {
ret = bdev->bd_disk->fops->open(inode, file);
if (ret)
goto out;
}
if (bdev->bd_invalidated)
rescan_partitions(bdev->bd_disk, bdev);
} else {
down(&bdev->bd_contains->bd_sem);
bdev->bd_contains->bd_part_count++;
up(&bdev->bd_contains->bd_sem);
}
if (bdev->bd_openers++)
put_disk(disk);
}
bdev->bd_openers++;
up(&bdev->bd_sem);
unlock_kernel();
return 0;
out2:
if (!bdev->bd_openers) {
bdev->bd_queue = NULL;
out_first:
bdev->bd_disk = NULL;
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
if (bdev != bdev->bd_contains) {
if (bdev != bdev->bd_contains)
blkdev_put(bdev->bd_contains, BDEV_RAW);
bdev->bd_contains = NULL;
}
}
out1:
put_disk(disk);
if (!old) {
bdev->bd_op = NULL;
if (owner)
__MOD_DEC_USE_COUNT(owner);
}
out:
up(&bdev->bd_sem);
unlock_kernel();
......@@ -746,6 +697,7 @@ int blkdev_put(struct block_device *bdev, int kind)
{
int ret = 0;
struct inode *bd_inode = bdev->bd_inode;
struct gendisk *disk = bdev->bd_disk;
down(&bdev->bd_sem);
lock_kernel();
......@@ -758,26 +710,24 @@ int blkdev_put(struct block_device *bdev, int kind)
if (!--bdev->bd_openers)
kill_bdev(bdev);
if (bdev->bd_contains == bdev) {
if (bdev->bd_op->release)
ret = bdev->bd_op->release(bd_inode, NULL);
if (disk->fops->release)
ret = disk->fops->release(bd_inode, NULL);
} else {
down(&bdev->bd_contains->bd_sem);
bdev->bd_contains->bd_part_count--;
up(&bdev->bd_contains->bd_sem);
}
if (!bdev->bd_openers) {
struct gendisk *disk = bdev->bd_disk;
if (bdev->bd_op->owner)
__MOD_DEC_USE_COUNT(bdev->bd_op->owner);
bdev->bd_op = NULL;
bdev->bd_queue = NULL;
struct module *owner = disk->fops->owner;
put_disk(disk);
if (owner)
__MOD_DEC_USE_COUNT(owner);
bdev->bd_disk = NULL;
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
if (bdev != bdev->bd_contains) {
blkdev_put(bdev->bd_contains, BDEV_RAW);
bdev->bd_contains = NULL;
}
put_disk(disk);
bdev->bd_contains = NULL;
}
unlock_kernel();
up(&bdev->bd_sem);
......@@ -836,7 +786,7 @@ int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
const char *__bdevname(kdev_t dev)
{
static char buffer[32];
const char * name = blkdevs[major(dev)].name;
const char * name = blkdevs[major(dev)];
if (!name)
name = "unknown-block";
......
......@@ -1569,15 +1569,10 @@ devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
return NULL;
}
if (ops == NULL)
{
if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major);
if (ops == NULL)
{
PRINTK ("(%s): NULL ops pointer\n", name);
return NULL;
}
PRINTK ("(%s): NULL ops, got %p from major table\n", name, ops);
}
if ( S_ISDIR (mode) )
{
PRINTK ("(%s): creating directories is not allowed\n", name);
......@@ -2380,27 +2375,19 @@ static int check_disc_changed (struct devfs_entry *de)
{
int tmp;
int retval = 0;
kdev_t dev = mk_kdev (de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
struct block_device *bdev;
struct block_device_operations *bdops;
dev_t dev = MKDEV(de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
extern int warn_no_part;
if ( !S_ISBLK (de->mode) ) return 0;
bdev = bdget (kdev_t_to_nr (dev) );
if (!bdev) return 0;
bdops = devfs_get_ops (de);
if (!bdops) return 0;
bdev->bd_op = bdops;
if (!S_ISBLK(de->mode))
return 0;
/* Ugly hack to disable messages about unable to read partition table */
tmp = warn_no_part;
warn_no_part = 0;
retval = full_check_disk_change (bdev);
retval = __check_disk_change(dev);
warn_no_part = tmp;
devfs_put_ops (de);
return retval;
} /* End Function check_disc_changed */
/**
* scan_dir_for_removable - Scan a directory for removable media devices and check media.
* @dir: The directory.
......@@ -2582,12 +2569,8 @@ static struct inode *_devfs_get_vfs_inode (struct super_block *sb,
{
inode->i_rdev = mk_kdev (de->u.fcb.u.device.major,
de->u.fcb.u.device.minor);
if (bd_acquire (inode) == 0)
{
if (!inode->i_bdev->bd_op && de->u.fcb.ops)
inode->i_bdev->bd_op = de->u.fcb.ops;
}
else PRINTK ("(%d): no block device from bdget()\n",(int)inode->i_ino);
if (bd_acquire (inode) != 0)
PRINTK ("(%d): no block device from bdget()\n",(int)inode->i_ino);
is_fcb = TRUE;
}
else if ( S_ISFIFO (de->mode) ) inode->i_fop = &def_fifo_fops;
......@@ -2706,7 +2689,6 @@ static int devfs_open (struct inode *inode, struct file *file)
if ( S_ISBLK (inode->i_mode) )
{
file->f_op = &def_blk_fops;
if (ops) inode->i_bdev->bd_op = ops;
err = def_blk_fops.open (inode, file); /* Module refcount unchanged */
}
else
......
......@@ -14,6 +14,7 @@
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/blk.h>
#include <linux/kmod.h>
......@@ -511,8 +512,8 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
bdev->bd_invalidated = 0;
for (p = 1; p < disk->minors; p++)
delete_partition(disk, p);
if (bdev->bd_op->revalidate_disk)
bdev->bd_op->revalidate_disk(disk);
if (disk->fops->revalidate_disk)
disk->fops->revalidate_disk(disk);
if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
return res;
for (p = 1; p < state->limit; p++) {
......@@ -613,9 +614,12 @@ char *partition_name(dev_t dev)
*/
hd = get_gendisk(dev, &part);
dname->name = NULL;
if (hd)
if (hd) {
dname->name = disk_name(hd, part, dname->namebuf);
if (hd->fops->owner)
__MOD_DEC_USE_COUNT(hd->fops->owner);
put_disk(hd);
}
if (!dname->name) {
sprintf(dname->namebuf, "[dev %s]", kdevname(to_kdev_t(dev)));
dname->name = dname->namebuf;
......
......@@ -23,7 +23,6 @@
#include <linux/config.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/acct.h>
#include <linux/blkdev.h>
#include <linux/quotaops.h>
......@@ -465,11 +464,8 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type,
{
struct inode *inode;
struct block_device *bdev;
struct block_device_operations *bdops;
devfs_handle_t de;
struct super_block * s;
struct nameidata nd;
kdev_t dev;
int error = 0;
mode_t mode = FMODE_READ; /* we always need it ;-) */
......@@ -490,15 +486,10 @@ struct super_block *get_sb_bdev(struct file_system_type *fs_type,
if (error)
goto out;
bdev = inode->i_bdev;
de = devfs_get_handle_from_inode (inode);
bdops = devfs_get_ops (de); /* Increments module use count */
if (bdops) bdev->bd_op = bdops;
/* Done with lookups, semaphore down */
dev = to_kdev_t(bdev->bd_dev);
if (!(flags & MS_RDONLY))
mode |= FMODE_WRITE;
error = blkdev_get(bdev, mode, 0, BDEV_FS);
devfs_put_ops (de); /* Decrement module use count now we're safe */
if (error)
goto out;
error = -EACCES;
......
......@@ -312,7 +312,7 @@ extern void __blk_stop_queue(request_queue_t *q);
static inline request_queue_t *bdev_get_queue(struct block_device *bdev)
{
return bdev->bd_queue;
return bdev->bd_disk->queue;
}
/*
......
......@@ -348,8 +348,6 @@ struct block_device {
struct inode * bd_inode;
dev_t bd_dev; /* not a kdev_t - it's a search key */
int bd_openers;
struct block_device_operations *bd_op;
struct request_queue *bd_queue;
struct semaphore bd_sem; /* open/close mutex */
struct list_head bd_inodes;
void * bd_holder;
......@@ -1096,7 +1094,6 @@ extern void bd_release(struct block_device *);
extern void blk_run_queues(void);
/* fs/devices.c */
extern struct block_device_operations *get_blkfops(unsigned int);
extern int register_chrdev(unsigned int, const char *, struct file_operations *);
extern int unregister_chrdev(unsigned int, const char *);
extern int chrdev_open(struct inode *, struct file *);
......
......@@ -282,7 +282,7 @@ extern void put_disk(struct gendisk *disk);
extern void blk_register_region(dev_t dev, unsigned long range,
struct module *module,
struct gendisk *(*probe)(dev_t, int *, void *),
void (*lock)(dev_t, void *),
int (*lock)(dev_t, void *),
void *data);
extern void blk_unregister_region(dev_t dev, unsigned long range);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment