Commit 48149ec3 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] probes

	introduced blk_register_region() and blk_unregister_region()
	removed blk_set_probe()
	switched to almost final variant of get_gendisk()
parent 177d3b13
......@@ -1528,12 +1528,12 @@ static struct block_device_operations floppy_fops =
.revalidate = floppy_revalidate,
};
static struct gendisk *floppy_find(int minor)
static struct gendisk *floppy_find(dev_t dev, int *part, void *data)
{
int drive = minor & 3;
if ((minor>> 2) > NUM_DISK_TYPES || drive >= FD_MAX_UNITS)
int drive = *part & 3;
if ((*part >> 2) > NUM_DISK_TYPES || drive >= FD_MAX_UNITS)
return NULL;
return disks[drive];
return get_disk(disks[drive]);
}
int fd1772_init(void)
......@@ -1589,7 +1589,8 @@ int fd1772_init(void)
sprintf(disks[i]->disk_name, "fd%d", i);
set_capacity(disks[i], MAX_DISK_SIZE * 2);
}
blk_set_probe(MAJOR_NR, floppy_find);
blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE,
floppy_find, NULL, NULL);
for (i = 0; i < FD_MAX_UNITS; i++)
add_disk(disks[i]);
......
......@@ -1758,12 +1758,12 @@ static int __init fd_probe_drives(void)
return -ENOMEM;
}
static struct gendisk *floppy_find(int minor)
static struct gendisk *floppy_find(dev_t dev, int *part, void *data)
{
int drive = minor & 3;
int drive = *part & 3;
if (unit[drive].type->code == FD_NODRIVE)
return NULL;
return unit[drive].gendisk;
return get_disk(unit[drive].gendisk);
}
int __init amiga_floppy_init(void)
......@@ -1808,9 +1808,7 @@ int __init amiga_floppy_init(void)
unregister_blkdev(MAJOR_NR,"fd");
return -EBUSY;
}
blk_set_probe(MAJOR_NR, floppy_find);
if (fd_probe_drives() < 1) { /* No usable drives */
blk_set_probe(MAJOR_NR, NULL);
free_irq(IRQ_AMIGA_CIAA_TB, NULL);
free_irq(IRQ_AMIGA_DSKBLK, NULL);
amiga_chip_free(raw_buf);
......@@ -1818,6 +1816,8 @@ int __init amiga_floppy_init(void)
unregister_blkdev(MAJOR_NR,"fd");
return -ENXIO;
}
blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE,
floppy_find, NULL, NULL);
/* initialize variables */
init_timer(&motor_on_timer);
......@@ -1877,7 +1877,7 @@ void cleanup_module(void)
kfree(unit[i].trackbuf);
}
}
blk_set_probe(MAJOR_NR, NULL);
blk_unregister_region(MKDEV(MAJOR_NR, 0), 256);
free_irq(IRQ_AMIGA_CIAA_TB, NULL);
free_irq(IRQ_AMIGA_DSKBLK, NULL);
custom.dmacon = DMAF_DISK; /* disable DMA */
......
......@@ -1910,13 +1910,13 @@ static struct block_device_operations floppy_fops = {
revalidate: floppy_revalidate,
};
static struct gendisk *floppy_find(int minor)
static struct gendisk *floppy_find(dev_t dev, int *part, void *data)
{
int drive = minor & 3;
int type = minor >> 2;
int drive = *part & 3;
int type = *part >> 2;
if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS)
return NULL;
return unit[drive].disk;
return get_disk(unit[drive].disk);
}
int __init atari_floppy_init (void)
......@@ -1975,7 +1975,8 @@ int __init atari_floppy_init (void)
}
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &ataflop_lock);
blk_set_probe(MAJOR_NR, floppy_find);
blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE,
floppy_find, NULL, NULL);
printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n",
DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E',
......@@ -2033,12 +2034,12 @@ int init_module (void)
void cleanup_module (void)
{
int i;
blk_unregister_region(MKDEV(MAJOR_NR, 0), 256);
for (i = 0; i < FD_MAX_UNITS; i++) {
del_gendisk(unit[i].disk);
put_disk(unit[i].disk);
}
unregister_blkdev(MAJOR_NR, "fd");
blk_set_probe(MAJOR_NR, NULL);
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
del_timer_sync(&fd_timer);
......
......@@ -4212,14 +4212,14 @@ static struct platform_device floppy_device = {
},
};
static struct gendisk *floppy_find(int minor)
static struct gendisk *floppy_find(dev_t dev, int *part, void *data)
{
int drive = (minor&3) | ((minor&0x80) >> 5);
int drive = (*part&3) | ((*part&0x80) >> 5);
if (drive >= N_DRIVE ||
!(allowed_drive_mask & (1 << drive)) ||
fdc_state[FDC(drive)].version == FDC_NONE)
return NULL;
return disks[drive];
return get_disk(disks[drive]);
}
int __init floppy_init(void)
......@@ -4249,7 +4249,8 @@ int __init floppy_init(void)
sprintf(disks[i]->disk_name, "fd%d", i);
}
blk_set_probe(MAJOR_NR, floppy_find);
blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE,
floppy_find, NULL, NULL);
for (i=0; i<256; i++)
if (ITYPE(i))
......@@ -4368,9 +4369,9 @@ int __init floppy_init(void)
out1:
del_timer(&fd_timeout);
out2:
blk_unregister_region(MKDEV(MAJOR_NR, 0), 256);
unregister_blkdev(MAJOR_NR,"fd");
blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
blk_set_probe(MAJOR_NR, NULL);
out:
for (i=0; i<N_DRIVE; i++)
put_disk(disks[i]);
......@@ -4563,8 +4564,8 @@ void cleanup_module(void)
platform_device_unregister(&floppy_device);
devfs_unregister (devfs_handle);
blk_unregister_region(MKDEV(MAJOR_NR, 0), 256);
unregister_blkdev(MAJOR_NR, "fd");
blk_set_probe(MAJOR_NR, NULL);
for (drive = 0; drive < N_DRIVE; drive++) {
if ((allowed_drive_mask & (1 << drive)) &&
fdc_state[FDC(drive)].version != FDC_NONE)
......
......@@ -24,6 +24,7 @@
#include <linux/spinlock.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/kmod.h>
static rwlock_t gendisk_lock;
......@@ -33,22 +34,74 @@ static rwlock_t gendisk_lock;
*/
static LIST_HEAD(gendisk_list);
/*
* TEMPORARY KLUDGE.
*/
static struct {
struct list_head list;
struct gendisk *(*get)(int minor);
} gendisks[MAX_BLKDEV];
struct blk_probe {
struct blk_probe *next;
dev_t dev;
unsigned long range;
struct module *owner;
struct gendisk *(*get)(dev_t dev, int *part, void *data);
void (*lock)(dev_t, void *);
void *data;
} *probes[MAX_BLKDEV];
/* index in the above */
static inline int dev_to_index(dev_t dev)
{
return MAJOR(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 index = dev_to_index(dev);
struct blk_probe *p = kmalloc(sizeof(struct blk_probe), GFP_KERNEL);
struct blk_probe **s;
p->owner = module;
p->get = probe;
p->lock = lock;
p->dev = dev;
p->range = range;
p->data = data;
write_lock(&gendisk_lock);
for (s = &probes[index]; *s && (*s)->range < range; s = &(*s)->next)
;
p->next = *s;
*s = p;
write_unlock(&gendisk_lock);
}
void blk_set_probe(int major, struct gendisk *(p)(int))
void blk_unregister_region(dev_t dev, unsigned long range)
{
int index = dev_to_index(dev);
struct blk_probe **s;
write_lock(&gendisk_lock);
gendisks[major].get = p;
for (s = &probes[index]; *s; s = &(*s)->next) {
struct blk_probe *p = *s;
if (p->dev == dev || p->range == range) {
*s = p->next;
kfree(p);
break;
}
}
write_unlock(&gendisk_lock);
}
EXPORT_SYMBOL(blk_set_probe); /* Will go away */
EXPORT_SYMBOL(blk_register_region);
EXPORT_SYMBOL(blk_unregister_region);
static struct gendisk *exact_match(dev_t dev, int *part, void *data)
{
struct gendisk *p = data;
*part = MINOR(dev) - p->first_minor;
return p;
}
static void exact_lock(dev_t dev, void *data)
{
struct gendisk *p = data;
get_disk(p);
}
/**
* add_gendisk - add partitioning information to kernel list
......@@ -60,10 +113,11 @@ EXPORT_SYMBOL(blk_set_probe); /* Will go away */
void add_disk(struct gendisk *disk)
{
write_lock(&gendisk_lock);
list_add(&disk->list, &gendisks[disk->major].list);
list_add_tail(&disk->full_list, &gendisk_list);
write_unlock(&gendisk_lock);
disk->flags |= GENHD_FL_UP;
blk_register_region(MKDEV(disk->major, disk->first_minor), disk->minors,
NULL, exact_match, exact_lock, disk);
register_disk(disk);
}
......@@ -74,8 +128,9 @@ void unlink_gendisk(struct gendisk *disk)
{
write_lock(&gendisk_lock);
list_del_init(&disk->full_list);
list_del_init(&disk->list);
write_unlock(&gendisk_lock);
blk_unregister_region(MKDEV(disk->major, disk->first_minor),
disk->minors);
}
/**
......@@ -88,30 +143,40 @@ void unlink_gendisk(struct gendisk *disk)
struct gendisk *
get_gendisk(dev_t dev, int *part)
{
int index = dev_to_index(dev);
struct gendisk *disk;
struct list_head *p;
int major = MAJOR(dev);
int minor = MINOR(dev);
struct blk_probe *p;
unsigned best = ~0U;
*part = 0;
retry:
read_lock(&gendisk_lock);
if (gendisks[major].get) {
disk = gendisks[major].get(minor);
if (disk)
get_disk(disk);
read_unlock(&gendisk_lock);
return disk;
}
list_for_each(p, &gendisks[major].list) {
disk = list_entry(p, struct gendisk, list);
if (disk->first_minor > minor)
for (p = probes[index]; p; p = p->next) {
struct gendisk *(*probe)(dev_t, int *, void *);
struct module *owner;
void *data;
if (p->dev > dev || p->dev + p->range <= dev)
continue;
if (disk->first_minor + disk->minors <= minor)
if (p->range >= best) {
read_unlock(&gendisk_lock);
return NULL;
}
if (!try_inc_mod_count(p->owner))
continue;
get_disk(disk);
owner = p->owner;
data = p->data;
probe = p->get;
best = p->range;
*part = dev - p->dev;
if (p->lock)
p->lock(dev, data);
read_unlock(&gendisk_lock);
*part = minor - disk->first_minor;
return disk;
disk = probe(dev, part, data);
/* Currently ->owner protects _only_ ->probe() itself. */
if (owner)
__MOD_DEC_USE_COUNT(owner);
if (disk)
return disk;
goto retry;
}
read_unlock(&gendisk_lock);
return NULL;
......@@ -183,8 +248,6 @@ struct seq_operations partitions_op = {
extern int blk_dev_init(void);
extern int soc_probe(void);
extern int atmdev_init(void);
struct device_class disk_devclass = {
.name = "disk",
......@@ -193,13 +256,26 @@ struct device_class disk_devclass = {
static struct bus_type disk_bus = {
name: "block",
};
static struct gendisk *base_probe(dev_t dev, int *part, void *data)
{
char name[20];
sprintf(name, "block-major-%d", MAJOR(dev));
request_module(name);
return NULL;
}
int __init device_init(void)
{
struct blk_probe *base = kmalloc(sizeof(struct blk_probe), GFP_KERNEL);
int i;
rwlock_init(&gendisk_lock);
for (i = 0; i < MAX_BLKDEV; i++)
INIT_LIST_HEAD(&gendisks[i].list);
memset(base, 0, sizeof(struct blk_probe));
base->dev = MKDEV(1,0);
base->range = MKDEV(MAX_BLKDEV-1, 255) - base->dev + 1;
base->get = base_probe;
for (i = 1; i < MAX_BLKDEV; i++)
probes[i] = base;
blk_dev_init();
devclass_register(&disk_devclass);
bus_register(&disk_bus);
......
......@@ -345,11 +345,10 @@ static struct block_device_operations z2_fops =
.release = z2_release,
};
static struct gendisk *z2_find(int minor)
static struct gendisk *z2_find(dev_t dev, int *part, void *data)
{
if (minor > Z2MINOR_COUNT)
return NULL;
return z2ram_gendisk;
*part = 0;
return get_disk(z2ram_gendisk);
}
int __init
......@@ -377,7 +376,8 @@ z2_init( void )
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_z2_request, &z2ram_lock);
add_disk(z2ram_gendisk);
blk_set_probe(MAJOR_NR, z2_find);
blk_register_region(MKDEV(MAJOR_NR, 0), Z2MINOR_COUNT, THIS_MODULE,
z2_find, NULL, NULL);
return 0;
}
......@@ -404,8 +404,7 @@ void
cleanup_module( void )
{
int i, j;
blk_set_probe(MAJOR_NR, NULL);
blk_unregister_region(MKDEV(MAJOR_NR, 0), 256);
if ( unregister_blkdev( MAJOR_NR, DEVICE_NAME ) != 0 )
printk( KERN_ERR DEVICE_NAME ": unregister of device failed\n");
......
......@@ -606,6 +606,13 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
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;
}
down(&bdev->bd_sem);
old = bdev->bd_op;
......@@ -617,9 +624,6 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
if (owner)
__MOD_DEC_USE_COUNT(owner);
}
disk = get_gendisk(bdev->bd_dev, &part);
if (!disk)
goto out1;
if (!bdev->bd_contains) {
bdev->bd_contains = bdev;
if (part) {
......
......@@ -275,8 +275,12 @@ extern struct gendisk *alloc_disk(int minors);
extern struct gendisk *get_disk(struct gendisk *disk);
extern void put_disk(struct gendisk *disk);
/* will go away */
extern void blk_set_probe(int major, struct gendisk *(p)(int));
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 *),
void *data);
extern void blk_unregister_region(dev_t dev, unsigned long range);
#endif
......
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