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