From b8ed178862df2381b14b12c9b3c4f7f39053c5e5 Mon Sep 17 00:00:00 2001 From: Alexander Viro Date: Tue, 15 Oct 2002 04:23:25 -0700 Subject: [PATCH] early allocation of ->part allocation of ->part[] moved to alloc_disk(); alloc_disk() got an argument (number of minors expected). Freeing is in put_disk(). --- include/linux/genhd.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux/genhd.h') diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 62781b452fe9..70c58d8b7e86 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -69,6 +69,7 @@ struct hd_struct { #define GENHD_FL_DRIVERFS 2 #define GENHD_FL_DEVFS 4 #define GENHD_FL_CD 8 +#define GENHD_FL_UP 16 struct gendisk { int major; /* major number of driver */ @@ -262,7 +263,7 @@ char *disk_name (struct gendisk *hd, int part, char *buf); extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev); extern void update_partition(struct gendisk *disk, int part); -extern struct gendisk *alloc_disk(void); +extern struct gendisk *alloc_disk(int minors); extern void put_disk(struct gendisk *disk); /* will go away */ -- cgit v1.2.3 From 847c633af8a42e49030ff941fb64fb3ece6c95ef Mon Sep 17 00:00:00 2001 From: Alexander Viro Date: Tue, 15 Oct 2002 04:23:32 -0700 Subject: [PATCH] disk->minor_shift cleanup new field - disk->minors (1 << disk->minor_shift). Almost all uses of ->minor_shift had that form and thus had been replaced. --- drivers/block/acsi.c | 5 ++++- drivers/block/blkpg.c | 6 +++--- drivers/block/genhd.c | 6 +++--- drivers/ide/ide-cd.c | 1 + drivers/ide/ide-disk.c | 1 + drivers/ide/ide-floppy.c | 1 + fs/block_dev.c | 4 ++-- fs/partitions/check.c | 18 +++++++++--------- include/linux/genhd.h | 1 + 9 files changed, 25 insertions(+), 18 deletions(-) (limited to 'include/linux/genhd.h') diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index 006ff8b23e32..7eb385a51182 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -1739,7 +1739,10 @@ int acsi_init( void ) sprintf(disk->disk_name, "ad%c", 'a'+i); disk->major = MAJOR_NR; disk->first_minor = i << 4; - disk->minor_shift = (acsi_info[i].type==HARDDISK)?4:0; + if (acsi_info[i].type != HARDDISK) { + disk->minor_shift = 0; + disk->minors = 1; + } disk->fops = &acsi_fops; set_capacity(disk, acsi_info[i].size); add_disk(disk); diff --git a/drivers/block/blkpg.c b/drivers/block/blkpg.c index 7b55729fa29a..7fff17616401 100644 --- a/drivers/block/blkpg.c +++ b/drivers/block/blkpg.c @@ -97,7 +97,7 @@ int add_partition(struct block_device *bdev, struct blkpg_partition *p) return -EINVAL; if (part) BUG(); - if (p->pno <= 0 || p->pno >= (1 << g->minor_shift)) + if (p->pno <= 0 || p->pno >= g->minors) return -EINVAL; /* partition number in use? */ @@ -105,7 +105,7 @@ int add_partition(struct block_device *bdev, struct blkpg_partition *p) return -EBUSY; /* overlap? */ - for (i = 0; i < (1<minor_shift) - 1; i++) + for (i = 0; i < g->minors - 1; i++) if (!(ppstart+pplength <= g->part[i].start_sect || ppstart >= g->part[i].start_sect + g->part[i].nr_sects)) return -EBUSY; @@ -142,7 +142,7 @@ int del_partition(struct block_device *bdev, struct blkpg_partition *p) return -EINVAL; if (part) BUG(); - if (p->pno <= 0 || p->pno >= (1 << g->minor_shift)) + if (p->pno <= 0 || p->pno >= g->minors) return -EINVAL; /* existing drive and partition? */ diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index b230df7f7b70..8ecb1461f43e 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -61,7 +61,7 @@ void add_disk(struct gendisk *disk) { write_lock(&gendisk_lock); list_add(&disk->list, &gendisks[disk->major].list); - if (disk->minor_shift) + if (disk->minors > 1) list_add_tail(&disk->full_list, &gendisk_list); else INIT_LIST_HEAD(&disk->full_list); @@ -107,7 +107,7 @@ get_gendisk(dev_t dev, int *part) disk = list_entry(p, struct gendisk, list); if (disk->first_minor > minor) continue; - if (disk->first_minor + (1<minor_shift) <= minor) + if (disk->first_minor + disk->minors <= minor) continue; read_unlock(&gendisk_lock); *part = minor - disk->first_minor; @@ -163,7 +163,7 @@ static int show_partition(struct seq_file *part, void *v) sgp->major, sgp->first_minor, (unsigned long long)get_capacity(sgp) >> 1, disk_name(sgp, 0, buf)); - for (n = 0; n < (1<minor_shift) - 1; n++) { + for (n = 0; n < sgp->minors - 1; n++) { if (sgp->part[n].nr_sects == 0) continue; seq_printf(part, "%4d %4d %10llu %s\n", diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 6e5d283aa93a..3471aba90f64 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -3193,6 +3193,7 @@ static int ide_cdrom_attach (ide_drive_t *drive) memset(info, 0, sizeof (struct cdrom_info)); drive->driver_data = info; DRIVER(drive)->busy++; + g->minors = 1; g->minor_shift = 0; g->de = drive->de; g->flags = GENHD_FL_CD; diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 5ff3daf64280..5b0c1ca8e75d 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -1871,6 +1871,7 @@ static int idedisk_attach(ide_drive_t *drive) goto failed; } DRIVER(drive)->busy--; + g->minors = 1 << PARTN_BITS; g->minor_shift = PARTN_BITS; g->de = drive->de; g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 60e3aed69166..fca1f92f896d 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -2108,6 +2108,7 @@ static int idefloppy_attach (ide_drive_t *drive) DRIVER(drive)->busy++; idefloppy_setup (drive, floppy); DRIVER(drive)->busy--; + g->minors = 1 << PARTN_BITS; g->minor_shift = PARTN_BITS; g->de = drive->de; g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; diff --git a/fs/block_dev.c b/fs/block_dev.c index 981b8df8efc8..47db3ea5e63b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -540,7 +540,7 @@ int check_disk_change(struct block_device *bdev) disk = get_gendisk(bdev->bd_dev, &part); if (bdops->revalidate) bdops->revalidate(dev); - if (disk && disk->minor_shift) + if (disk && disk->minors > 1) bdev->bd_invalidated = 1; return 1; } @@ -799,7 +799,7 @@ static int blkdev_reread_part(struct block_device *bdev) struct gendisk *disk = get_gendisk(bdev->bd_dev, &part); int res = 0; - if (!disk || !disk->minor_shift || bdev != bdev->bd_contains) + if (!disk || disk->minors == 1 || bdev != bdev->bd_contains) return -EINVAL; if (part) BUG(); diff --git a/fs/partitions/check.c b/fs/partitions/check.c index b3164b9ca071..72e71ea060e7 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -130,7 +130,7 @@ static DEVICE_ATTR(type,S_IRUGO,partition_device_type_read,NULL); static void driverfs_create_partitions(struct gendisk *hd) { - int max_p = 1<minor_shift; + int max_p = hd->minors; struct hd_struct *p = hd->part; char name[DEVICE_NAME_SIZE]; char bus_id[BUS_ID_SIZE]; @@ -187,7 +187,7 @@ static void driverfs_create_partitions(struct gendisk *hd) static void driverfs_remove_partitions(struct gendisk *hd) { - int max_p = 1<minor_shift; + int max_p = hd->minors; struct device *dev; struct hd_struct *p; int part; @@ -233,7 +233,7 @@ static void check_partition(struct gendisk *hd, struct block_device *bdev) if (isdigit(state->name[strlen(state->name)-1])) sprintf(state->name, "p"); } - state->limit = 1<minor_shift; + state->limit = hd->minors; for (i = 0; check_part[i]; i++) { int res, j; struct hd_struct *p; @@ -298,7 +298,7 @@ static void devfs_create_partitions(struct gendisk *dev) unsigned int devfs_flags = DEVFS_FL_DEFAULT; char dirname[64], symlink[16]; static devfs_handle_t devfs_handle; - int part, max_p = 1<minor_shift; + int part, max_p = dev->minors; struct hd_struct *p = dev->part; if (dev->flags & GENHD_FL_REMOVABLE) @@ -380,7 +380,7 @@ static void devfs_remove_partitions(struct gendisk *dev) { #ifdef CONFIG_DEVFS_FS int part; - for (part = (1<minor_shift)-1; part--; ) { + for (part = dev->minors-1; part--; ) { devfs_unregister(dev->part[part].de); dev->part[part].de = NULL; } @@ -401,7 +401,7 @@ void register_disk(struct gendisk *disk) devfs_create_cdrom(disk); /* No minors to use for partitions */ - if (!disk->minor_shift) + if (disk->minors == 1) return; /* No such device (e.g., media were just removed) */ @@ -458,7 +458,7 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) if (res) return res; bdev->bd_invalidated = 0; - for (p = 0; p < (1<minor_shift) - 1; p++) { + for (p = 0; p < disk->minors - 1; p++) { disk->part[p].start_sect = 0; disk->part[p].nr_sects = 0; } @@ -466,7 +466,7 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) bdev->bd_op->revalidate(dev); if (get_capacity(disk)) check_partition(disk, bdev); - for (p = 1; p < (1<minor_shift); p++) + for (p = 1; p < disk->minors; p++) update_partition(disk, p); return res; } @@ -495,7 +495,7 @@ fail: static int wipe_partitions(struct gendisk *disk) { - int max_p = 1 << disk->minor_shift; + int max_p = disk->minors; kdev_t devp; int res; int p; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 70c58d8b7e86..6e1f68900bba 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -74,6 +74,7 @@ struct hd_struct { struct gendisk { int major; /* major number of driver */ int first_minor; + int minors; int minor_shift; /* number of times minor is shifted to get real minor */ char disk_name[16]; /* name of major driver */ -- cgit v1.2.3 From afae25b7c8d594f6349e81dce2b16ce44aa9f0ed Mon Sep 17 00:00:00 2001 From: Alexander Viro Date: Tue, 15 Oct 2002 04:25:18 -0700 Subject: [PATCH] preparation to use of driverfs refcounts, part 1 - partitions * update_partition() split into add_partition() and delete_partition(). * all updating of ->part[] is switched to these two (including initial filling/final cleaning). * per-partition devices are allocated on-demand and never reused. We allocate struct device in add_partition() and put reference to it into hd_struct. ->release() for that struct device frees it. delete_partition() removes reference from hd_struct and does put_device() on it. Basically, we get rid of problems with reused struct device by never reusing them... At that point devices for partitions are nice and sane. --- drivers/block/ioctl.c | 8 +- fs/partitions/check.c | 289 ++++++++++++++++++++++---------------------------- include/linux/genhd.h | 5 +- 3 files changed, 134 insertions(+), 168 deletions(-) (limited to 'include/linux/genhd.h') diff --git a/drivers/block/ioctl.c b/drivers/block/ioctl.c index fb6a8edb8e21..4af05bc32db2 100644 --- a/drivers/block/ioctl.c +++ b/drivers/block/ioctl.c @@ -58,9 +58,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) return -EBUSY; } /* all seems OK */ - disk->part[part - 1].start_sect = start; - disk->part[part - 1].nr_sects = length; - update_partition(disk, part); + add_partition(disk, part, start, length); return 0; case BLKPG_DEL_PARTITION: if (disk->part[part - 1].nr_sects == 0) @@ -79,9 +77,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) fsync_bdev(bdevp); invalidate_bdev(bdevp, 0); - disk->part[part].start_sect = 0; - disk->part[part].nr_sects = 0; - update_partition(disk, part); + delete_partition(disk, part); bd_release(bdevp); bdput(bdevp); return 0; diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 72e71ea060e7..a61a83ded312 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -130,96 +130,49 @@ static DEVICE_ATTR(type,S_IRUGO,partition_device_type_read,NULL); static void driverfs_create_partitions(struct gendisk *hd) { - int max_p = hd->minors; - struct hd_struct *p = hd->part; - char name[DEVICE_NAME_SIZE]; - char bus_id[BUS_ID_SIZE]; - struct device *dev, *parent; - int part; + struct device *parent = hd->driverfs_dev; + struct device *dev = &hd->disk_dev; /* if driverfs not supported by subsystem, skip partitions */ if (!(hd->flags & GENHD_FL_DRIVERFS)) return; - parent = hd->driverfs_dev; - if (parent) { - sprintf(name, "%s", parent->name); - sprintf(bus_id, "%s:", parent->bus_id); + sprintf(dev->name, "%sdisc", parent->name); + sprintf(dev->bus_id, "%sdisc", parent->bus_id); + dev->parent = parent; + dev->bus = parent->bus; } else { - *name = *bus_id = '\0'; + sprintf(dev->name, "disc"); + sprintf(dev->bus_id, "disc"); } - - dev = &hd->disk_dev; dev->driver_data = (void *)(long)__mkdev(hd->major, hd->first_minor); - sprintf(dev->name, "%sdisc", name); - sprintf(dev->bus_id, "%sdisc", bus_id); - for (part=1; part < max_p; part++) { - dev = &p[part-1].hd_driverfs_dev; - sprintf(dev->name, "%spart%d", name, part); - sprintf(dev->bus_id, "%s:p%d", bus_id, part); - if (!p[part-1].nr_sects) - continue; - dev->driver_data = - (void *)(long)__mkdev(hd->major, hd->first_minor+part); - } - - dev = &hd->disk_dev; - dev->parent = parent; - if (parent) - dev->bus = parent->bus; device_register(dev); device_create_file(dev, &dev_attr_type); device_create_file(dev, &dev_attr_kdev); - - for (part=0; part < max_p-1; part++) { - dev = &p[part].hd_driverfs_dev; - dev->parent = parent; - if (parent) - dev->bus = parent->bus; - if (!dev->driver_data) - continue; - device_register(dev); - device_create_file(dev, &dev_attr_type); - device_create_file(dev, &dev_attr_kdev); - } } static void driverfs_remove_partitions(struct gendisk *hd) { - int max_p = hd->minors; - struct device *dev; - struct hd_struct *p; - int part; - - for (part=1, p = hd->part; part < max_p; part++, p++) { - dev = &p->hd_driverfs_dev; - if (dev->driver_data) { - device_remove_file(dev, &dev_attr_type); - device_remove_file(dev, &dev_attr_kdev); - put_device(dev); - dev->driver_data = NULL; - } - } - dev = &hd->disk_dev; - if (dev->driver_data) { - device_remove_file(dev, &dev_attr_type); - device_remove_file(dev, &dev_attr_kdev); - put_device(dev); - dev->driver_data = NULL; - } + struct device *dev = &hd->disk_dev; + if (!(hd->flags & GENHD_FL_DRIVERFS)) + return; + device_remove_file(dev, &dev_attr_type); + device_remove_file(dev, &dev_attr_kdev); + put_device(dev); } -static void check_partition(struct gendisk *hd, struct block_device *bdev) +static struct parsed_partitions * +check_partition(struct gendisk *hd, struct block_device *bdev) { + struct parsed_partitions *state; devfs_handle_t de = NULL; char buf[64]; - struct parsed_partitions *state; - int i; + int i, res; state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL); if (!state) - return; + return NULL; if (hd->flags & GENHD_FL_DEVFS) de = hd->de; @@ -234,31 +187,19 @@ static void check_partition(struct gendisk *hd, struct block_device *bdev) sprintf(state->name, "p"); } state->limit = hd->minors; - for (i = 0; check_part[i]; i++) { - int res, j; - struct hd_struct *p; + i = res = 0; + while (!res && check_part[i]) { memset(&state->parts, 0, sizeof(state->parts)); - res = check_part[i](state, bdev); - if (!res) - continue; - if (res < 0) { - if (warn_no_part) - printk(" unable to read partition table\n"); - return; - } - p = hd->part; - for (j = 1; j < state->limit; j++) { - p[j-1].start_sect = state->parts[j].from; - p[j-1].nr_sects = state->parts[j].size; -#if CONFIG_BLK_DEV_MD - if (!state->parts[j].flags) - continue; - md_autodetect_dev(bdev->bd_dev+j); -#endif - } - return; + res = check_part[i++](state, bdev); } - printk(" unknown partition table\n"); + if (res > 0) + return state; + if (!res) + printk(" unknown partition table\n"); + else if (warn_no_part) + printk(" unable to read partition table\n"); + kfree(state); + return NULL; } static void devfs_register_partition(struct gendisk *dev, int part) @@ -329,9 +270,6 @@ static void devfs_create_partitions(struct gendisk *dev) devfs_auto_unregister(dev->disk_de, slave); if (!(dev->flags & GENHD_FL_DEVFS)) devfs_auto_unregister (slave, dir); - for (part = 1; part < max_p; part++, p++) - if (p->nr_sects) - devfs_register_partition(dev, part); #endif } @@ -379,11 +317,6 @@ static void devfs_create_cdrom(struct gendisk *dev) static void devfs_remove_partitions(struct gendisk *dev) { #ifdef CONFIG_DEVFS_FS - int part; - for (part = dev->minors-1; part--; ) { - devfs_unregister(dev->part[part].de); - dev->part[part].de = NULL; - } devfs_unregister(dev->disk_de); dev->disk_de = NULL; if (dev->flags & GENHD_FL_CD) @@ -393,10 +326,69 @@ static void devfs_remove_partitions(struct gendisk *dev) #endif } +void delete_partition(struct gendisk *disk, int part) +{ + struct hd_struct *p = disk->part + part - 1; + struct device *dev; + if (!p->nr_sects) + return; + p->start_sect = 0; + p->nr_sects = 0; + devfs_unregister(p->de); + dev = p->hd_driverfs_dev; + p->hd_driverfs_dev = NULL; + if (dev) { + device_remove_file(dev, &dev_attr_type); + device_remove_file(dev, &dev_attr_kdev); + device_unregister(dev); + } +} + +static void part_release(struct device *dev) +{ + kfree(dev); +} + +void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) +{ + struct hd_struct *p = disk->part + part - 1; + struct device *parent = disk->disk_dev.parent; + struct device *dev; + + p->start_sect = start; + p->nr_sects = len; + devfs_register_partition(disk, part); + if (!(disk->flags & GENHD_FL_DRIVERFS)) + return; + dev = kmalloc(sizeof(struct device), GFP_KERNEL); + if (!dev) + return; + memset(dev, 0, sizeof(struct device)); + if (parent) { + sprintf(dev->name, "%spart%d", parent->name, part); + sprintf(dev->bus_id, "%s:p%d", parent->bus_id, part); + dev->parent = parent; + dev->bus = parent->bus; + } else { + sprintf(dev->name, "part%d", part); + sprintf(dev->bus_id, "p%d", part); + } + dev->release = part_release; + dev->driver_data = + (void *)(long)__mkdev(disk->major, disk->first_minor+part); + device_register(dev); + device_create_file(dev, &dev_attr_type); + device_create_file(dev, &dev_attr_kdev); + p->hd_driverfs_dev = dev; +} + /* Not exported, helper to add_disk(). */ void register_disk(struct gendisk *disk) { + struct parsed_partitions *state; struct block_device *bdev; + int j; + if (disk->flags & GENHD_FL_CD) devfs_create_cdrom(disk); @@ -411,45 +403,33 @@ void register_disk(struct gendisk *disk) bdev = bdget(MKDEV(disk->major, disk->first_minor)); if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0) return; - check_partition(disk, bdev); + state = check_partition(disk, bdev); driverfs_create_partitions(disk); devfs_create_partitions(disk); - blkdev_put(bdev, BDEV_RAW); -} - -void update_partition(struct gendisk *disk, int part) -{ - struct hd_struct *p = disk->part + part - 1; - struct device *dev = &p->hd_driverfs_dev; - - if (!p->nr_sects) { - if (p->de) { - devfs_unregister(p->de); - p->de = NULL; - } - if (dev->driver_data) { - device_remove_file(dev, &dev_attr_type); - device_remove_file(dev, &dev_attr_kdev); - put_device(dev); - dev->driver_data = NULL; + if (state) { + for (j = 1; j < state->limit; j++) { + sector_t size = state->parts[j].size; + sector_t from = state->parts[j].from; + if (!size) + continue; + add_partition(disk, j, from, size); +#if CONFIG_BLK_DEV_MD + if (!state->parts[j].flags) + continue; + md_autodetect_dev(bdev->bd_dev+j); +#endif } - return; + kfree(state); } - if (!p->de) - devfs_register_partition(disk, part); - if (dev->driver_data || !(disk->flags & GENHD_FL_DRIVERFS)) - return; - dev->driver_data = - (void *)(long)__mkdev(disk->major, disk->first_minor+part); - device_register(dev); - device_create_file(dev, &dev_attr_type); - device_create_file(dev, &dev_attr_kdev); + blkdev_put(bdev, BDEV_RAW); } int rescan_partitions(struct gendisk *disk, struct block_device *bdev) { kdev_t dev = to_kdev_t(bdev->bd_dev); + struct parsed_partitions *state; int p, res; + if (!bdev->bd_invalidated) return 0; if (bdev->bd_part_count) @@ -458,16 +438,25 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) if (res) return res; bdev->bd_invalidated = 0; - for (p = 0; p < disk->minors - 1; p++) { - disk->part[p].start_sect = 0; - disk->part[p].nr_sects = 0; - } + for (p = 1; p < disk->minors; p++) + delete_partition(disk, p); if (bdev->bd_op->revalidate) bdev->bd_op->revalidate(dev); - if (get_capacity(disk)) - check_partition(disk, bdev); - for (p = 1; p < disk->minors; p++) - update_partition(disk, p); + if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) + return res; + for (p = 1; p < state->limit; p++) { + sector_t size = state->parts[p].size; + sector_t from = state->parts[p].from; + if (!size) + continue; + add_partition(disk, p, from, size); +#if CONFIG_BLK_DEV_MD + if (!state->parts[j].flags) + continue; + md_autodetect_dev(bdev->bd_dev+p); +#endif + } + kfree(state); return res; } @@ -493,45 +482,25 @@ fail: return NULL; } -static int wipe_partitions(struct gendisk *disk) +void del_gendisk(struct gendisk *disk) { int max_p = disk->minors; kdev_t devp; - int res; int p; /* invalidate stuff */ for (p = max_p - 1; p > 0; p--) { devp = mk_kdev(disk->major,disk->first_minor + p); -#if 0 /* %%% superfluous? */ - if (disk->part[p-1].nr_sects == 0) - continue; -#endif - res = invalidate_device(devp, 1); - if (res) - return res; - disk->part[p-1].start_sect = 0; - disk->part[p-1].nr_sects = 0; + invalidate_device(devp, 1); + delete_partition(disk, p); } devp = mk_kdev(disk->major,disk->first_minor); -#if 0 /* %%% superfluous? */ - if (disk->part[p].nr_sects == 0) - continue; -#endif - res = invalidate_device(devp, 1); - if (res) - return res; + invalidate_device(devp, 1); disk->capacity = 0; - return 0; -} - -void del_gendisk(struct gendisk *disk) -{ - driverfs_remove_partitions(disk); - wipe_partitions(disk); + disk->flags &= ~GENHD_FL_UP; unlink_gendisk(disk); + driverfs_remove_partitions(disk); devfs_remove_partitions(disk); - disk->flags &= ~GENHD_FL_UP; } struct dev_name { diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 6e1f68900bba..6b859fad6a8a 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -62,7 +62,7 @@ struct hd_struct { sector_t start_sect; sector_t nr_sects; devfs_handle_t de; /* primary (master) devfs entry */ - struct device hd_driverfs_dev; /* support driverfs hiearchy */ + struct device *hd_driverfs_dev; /* support driverfs hiearchy */ }; #define GENHD_FL_REMOVABLE 1 @@ -262,7 +262,8 @@ struct unixware_disklabel { char *disk_name (struct gendisk *hd, int part, char *buf); extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev); -extern void update_partition(struct gendisk *disk, int part); +extern void add_partition(struct gendisk *, int, sector_t, sector_t); +extern void delete_partition(struct gendisk *, int); extern struct gendisk *alloc_disk(int minors); extern void put_disk(struct gendisk *disk); -- cgit v1.2.3 From 68c16870dcfaba7c9e2dd5055a2caf4edcf42e87 Mon Sep 17 00:00:00 2001 From: Alexander Viro Date: Tue, 15 Oct 2002 04:25:32 -0700 Subject: [PATCH] refcounts for gendisks Finally. We use disk->dev.refcount as a gendisk refcount. New helper - get_disk(): atomic_inc on refcount. get_gendisk() does it on return, callers of get_gendisk() do put_disk() when they are done. --- drivers/block/genhd.c | 10 ++++++++++ drivers/block/ioctl.c | 47 +++++++++++++++++++++++++++++++++++++---------- fs/block_dev.c | 23 ++++++++++++++++++----- fs/partitions/check.c | 1 + include/linux/genhd.h | 7 +++++-- 5 files changed, 71 insertions(+), 17 deletions(-) (limited to 'include/linux/genhd.h') diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index ecb2dcdf214d..1cc4655c04c9 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -100,6 +100,8 @@ get_gendisk(dev_t dev, int *part) read_lock(&gendisk_lock); if (gendisks[major].get) { disk = gendisks[major].get(minor); + if (disk) + get_disk(disk); read_unlock(&gendisk_lock); return disk; } @@ -109,6 +111,7 @@ get_gendisk(dev_t dev, int *part) continue; if (disk->first_minor + disk->minors <= minor) continue; + get_disk(disk); read_unlock(&gendisk_lock); *part = minor - disk->first_minor; return disk; @@ -244,6 +247,12 @@ struct gendisk *alloc_disk(int minors) return disk; } +struct gendisk *get_disk(struct gendisk *disk) +{ + atomic_inc(&disk->disk_dev.refcount); + return disk; +} + void put_disk(struct gendisk *disk) { if (disk) @@ -251,4 +260,5 @@ void put_disk(struct gendisk *disk) } EXPORT_SYMBOL(alloc_disk); +EXPORT_SYMBOL(get_disk); EXPORT_SYMBOL(put_disk); diff --git a/drivers/block/ioctl.c b/drivers/block/ioctl.c index 4af05bc32db2..de2da2b44cad 100644 --- a/drivers/block/ioctl.c +++ b/drivers/block/ioctl.c @@ -25,13 +25,17 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) disk = get_gendisk(bdev->bd_dev, &part); if (!disk) return -ENXIO; - if (bdev != bdev->bd_contains) + if (bdev != bdev->bd_contains) { + put_disk(disk); return -EINVAL; + } if (part) BUG(); part = p.pno; - if (part <= 0 || part >= disk->minors) + if (part <= 0 || part >= disk->minors) { + put_disk(disk); return -EINVAL; + } switch (a.op) { case BLKPG_ADD_PARTITION: @@ -42,34 +46,46 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) sizeof(long long) > sizeof(long)) { long pstart = start, plength = length; if (pstart != start || plength != length - || pstart < 0 || plength < 0) + || pstart < 0 || plength < 0) { + put_disk(disk); return -EINVAL; + } } /* partition number in use? */ - if (disk->part[part - 1].nr_sects != 0) + if (disk->part[part - 1].nr_sects != 0) { + put_disk(disk); return -EBUSY; + } /* overlap? */ for (i = 0; i < disk->minors - 1; i++) { struct hd_struct *s = &disk->part[i]; if (!(start+length <= s->start_sect || - start >= s->start_sect + s->nr_sects)) + start >= s->start_sect + s->nr_sects)) { + put_disk(disk); return -EBUSY; + } } /* all seems OK */ add_partition(disk, part, start, length); + put_disk(disk); return 0; case BLKPG_DEL_PARTITION: - if (disk->part[part - 1].nr_sects == 0) + if (disk->part[part - 1].nr_sects == 0) { + put_disk(disk); return -ENXIO; + } /* partition in use? Incomplete check for now. */ bdevp = bdget(MKDEV(disk->major, disk->first_minor) + part); - if (!bdevp) + if (!bdevp) { + put_disk(disk); return -ENOMEM; + } if (bd_claim(bdevp, &holder) < 0) { bdput(bdevp); + put_disk(disk); return -EBUSY; } @@ -80,8 +96,10 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) delete_partition(disk, part); bd_release(bdevp); bdput(bdevp); + put_disk(disk); return 0; default: + put_disk(disk); return -EINVAL; } } @@ -92,16 +110,25 @@ static int blkdev_reread_part(struct block_device *bdev) struct gendisk *disk = get_gendisk(bdev->bd_dev, &part); int res = 0; - if (!disk || disk->minors == 1 || bdev != bdev->bd_contains) + if (!disk) return -EINVAL; + if (disk->minors == 1 || bdev != bdev->bd_contains) { + put_disk(disk); + return -EINVAL; + } if (part) BUG(); - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN)) { + put_disk(disk); return -EACCES; - if (down_trylock(&bdev->bd_sem)) + } + if (down_trylock(&bdev->bd_sem)) { + put_disk(disk); return -EBUSY; + } res = rescan_partitions(disk, bdev); up(&bdev->bd_sem); + put_disk(disk); return res; } diff --git a/fs/block_dev.c b/fs/block_dev.c index dff0244e63a6..d029636b07e6 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -542,6 +542,7 @@ int check_disk_change(struct block_device *bdev) bdops->revalidate(dev); if (disk && disk->minors > 1) bdev->bd_invalidated = 1; + put_disk(disk); return 1; } @@ -553,7 +554,9 @@ int full_check_disk_change(struct block_device *bdev) BUG(); down(&bdev->bd_sem); if (check_disk_change(bdev)) { - rescan_partitions(get_gendisk(bdev->bd_dev, &n), bdev); + struct gendisk *disk = get_gendisk(bdev->bd_dev, &n); + rescan_partitions(disk, bdev); + put_disk(disk); res = 1; } up(&bdev->bd_sem); @@ -622,13 +625,18 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * struct block_device *disk; disk = bdget(MKDEV(g->major, g->first_minor)); ret = -ENOMEM; - if (!disk) + if (!disk) { + put_disk(g); goto out1; + } ret = blkdev_get(disk, file->f_mode, file->f_flags, BDEV_RAW); - if (ret) + if (ret) { + put_disk(g); goto out1; + } bdev->bd_contains = disk; } + put_disk(g); } if (bdev->bd_contains == bdev) { int part; @@ -643,8 +651,10 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * if (bdev->bd_op->open) { ret = bdev->bd_op->open(inode, file); - if (ret) + if (ret) { + put_disk(g); goto out2; + } } if (!bdev->bd_openers) { struct backing_dev_info *bdi; @@ -662,6 +672,7 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * } if (bdev->bd_invalidated) rescan_partitions(g, bdev); + put_disk(g); } else { down(&bdev->bd_contains->bd_sem); bdev->bd_contains->bd_part_count++; @@ -673,15 +684,17 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * inode->i_data.backing_dev_info = bdev->bd_inode->i_data.backing_dev_info = bdev->bd_contains->bd_inode->i_data.backing_dev_info; - if (!p->nr_sects) { + if (!(g->flags & GENHD_FL_UP) || !p->nr_sects) { bdev->bd_contains->bd_part_count--; up(&bdev->bd_contains->bd_sem); + put_disk(g); ret = -ENXIO; goto out2; } bdev->bd_queue = bdev->bd_contains->bd_queue; bdev->bd_offset = p->start_sect; bd_set_size(bdev, (loff_t) p->nr_sects << 9); + put_disk(g); } up(&bdev->bd_contains->bd_sem); } diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 5fc23d047567..e6ed1a443116 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -616,6 +616,7 @@ char *partition_name(dev_t dev) dname->name = NULL; if (hd) dname->name = disk_name(hd, part, dname->namebuf); + put_disk(hd); if (!dname->name) { sprintf(dname->namebuf, "[dev %s]", kdevname(to_kdev_t(dev))); dname->name = dname->namebuf; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 6b859fad6a8a..030ee2f87891 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -266,6 +266,7 @@ extern void add_partition(struct gendisk *, int, sector_t, sector_t); extern void delete_partition(struct gendisk *, int); 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 */ @@ -273,9 +274,11 @@ extern void blk_set_probe(int major, struct gendisk *(p)(int)); static inline unsigned int disk_index (kdev_t dev) { - int part; + int part, res; struct gendisk *g = get_gendisk(kdev_t_to_nr(dev), &part); - return g ? (minor(dev) >> g->minor_shift) : 0; + res = g ? (minor(dev) >> g->minor_shift) : 0; + put_disk(g); + return res; } #endif -- cgit v1.2.3 From 5682bcc620dbee99319997718c8929ec0d797854 Mon Sep 17 00:00:00 2001 From: Alexander Viro Date: Tue, 15 Oct 2002 04:25:37 -0700 Subject: [PATCH] bdev->bd_disk introduced There we go - now we can put a reference to gendisk into block_device. Which we do in do_open(). Most of the callers of get_gendisk() are simply using bdev->bd_disk now (and most of the put_disk() calls introduced on previous step disappear). We also put that pointer into struct request - ->rq_disk. That allows to get rid of disk_index() kludges in md.c (we simply count relevant IO in the struct gendisk fields) and kill the export of get_gendisk(). Notice that by now we can move _all_ IO counters into gendisk. That will kill a bunch of per-major arrays and more importantly, allow to merge sard in clean way. FWIW, we probably could show them as disk/partitions attributes in driverfs... --- drivers/block/genhd.c | 10 ++----- drivers/block/ioctl.c | 65 +++++++++--------------------------------- drivers/block/ll_rw_blk.c | 15 +++++++++- drivers/block/rd.c | 1 + drivers/md/md.c | 23 ++------------- fs/block_dev.c | 72 ++++++++++++++++++----------------------------- include/linux/blkdev.h | 1 + include/linux/fs.h | 1 + include/linux/genhd.h | 13 +++------ 9 files changed, 68 insertions(+), 133 deletions(-) (limited to 'include/linux/genhd.h') diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 1cc4655c04c9..449e69061bbc 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -61,10 +61,7 @@ void add_disk(struct gendisk *disk) { write_lock(&gendisk_lock); list_add(&disk->list, &gendisks[disk->major].list); - if (disk->minors > 1) - list_add_tail(&disk->full_list, &gendisk_list); - else - INIT_LIST_HEAD(&disk->full_list); + list_add_tail(&disk->full_list, &gendisk_list); write_unlock(&gendisk_lock); disk->flags |= GENHD_FL_UP; register_disk(disk); @@ -120,8 +117,6 @@ get_gendisk(dev_t dev, int *part) return NULL; } -EXPORT_SYMBOL(get_gendisk); - #ifdef CONFIG_PROC_FS /* iterator */ static void *part_start(struct seq_file *part, loff_t *pos) @@ -158,7 +153,7 @@ static int show_partition(struct seq_file *part, void *v) seq_puts(part, "major minor #blocks name\n\n"); /* Don't show non-partitionable devices or empty devices */ - if (!get_capacity(sgp)) + if (!get_capacity(sgp) || sgp->minors == 1) return 0; /* show the full disk and all non-0 size partitions of it */ @@ -239,6 +234,7 @@ struct gendisk *alloc_disk(int minors) disk->minors = minors; while (minors >>= 1) disk->minor_shift++; + INIT_LIST_HEAD(&disk->full_list); disk->disk_dev.bus = &disk_bus; disk->disk_dev.release = disk_release; disk->disk_dev.driver_data = disk; diff --git a/drivers/block/ioctl.c b/drivers/block/ioctl.c index de2da2b44cad..e420c691763d 100644 --- a/drivers/block/ioctl.c +++ b/drivers/block/ioctl.c @@ -22,21 +22,12 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) return -EFAULT; if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) return -EFAULT; - disk = get_gendisk(bdev->bd_dev, &part); - if (!disk) - return -ENXIO; - if (bdev != bdev->bd_contains) { - put_disk(disk); + disk = bdev->bd_disk; + if (bdev != bdev->bd_contains) return -EINVAL; - } - if (part) - BUG(); part = p.pno; - if (part <= 0 || part >= disk->minors) { - put_disk(disk); + if (part <= 0 || part >= disk->minors) return -EINVAL; - } - switch (a.op) { case BLKPG_ADD_PARTITION: start = p.start >> 9; @@ -46,49 +37,33 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) sizeof(long long) > sizeof(long)) { long pstart = start, plength = length; if (pstart != start || plength != length - || pstart < 0 || plength < 0) { - put_disk(disk); + || pstart < 0 || plength < 0) return -EINVAL; - } } - /* partition number in use? */ - if (disk->part[part - 1].nr_sects != 0) { - put_disk(disk); + if (disk->part[part - 1].nr_sects != 0) return -EBUSY; - } - /* overlap? */ for (i = 0; i < disk->minors - 1; i++) { struct hd_struct *s = &disk->part[i]; if (!(start+length <= s->start_sect || - start >= s->start_sect + s->nr_sects)) { - put_disk(disk); + start >= s->start_sect + s->nr_sects)) return -EBUSY; - } } /* all seems OK */ add_partition(disk, part, start, length); - put_disk(disk); return 0; case BLKPG_DEL_PARTITION: - if (disk->part[part - 1].nr_sects == 0) { - put_disk(disk); + if (disk->part[part - 1].nr_sects == 0) return -ENXIO; - } - /* partition in use? Incomplete check for now. */ bdevp = bdget(MKDEV(disk->major, disk->first_minor) + part); - if (!bdevp) { - put_disk(disk); + if (!bdevp) return -ENOMEM; - } if (bd_claim(bdevp, &holder) < 0) { bdput(bdevp); - put_disk(disk); return -EBUSY; } - /* all seems OK */ fsync_bdev(bdevp); invalidate_bdev(bdevp, 0); @@ -96,39 +71,25 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) delete_partition(disk, part); bd_release(bdevp); bdput(bdevp); - put_disk(disk); return 0; default: - put_disk(disk); return -EINVAL; } } static int blkdev_reread_part(struct block_device *bdev) { - int part; - struct gendisk *disk = get_gendisk(bdev->bd_dev, &part); - int res = 0; + struct gendisk *disk = bdev->bd_disk; + int res; - if (!disk) - return -EINVAL; - if (disk->minors == 1 || bdev != bdev->bd_contains) { - put_disk(disk); + if (disk->minors == 1 || bdev != bdev->bd_contains) return -EINVAL; - } - if (part) - BUG(); - if (!capable(CAP_SYS_ADMIN)) { - put_disk(disk); + if (!capable(CAP_SYS_ADMIN)) return -EACCES; - } - if (down_trylock(&bdev->bd_sem)) { - put_disk(disk); + if (down_trylock(&bdev->bd_sem)) return -EBUSY; - } res = rescan_partitions(disk, bdev); up(&bdev->bd_sem); - put_disk(disk); return res; } diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index ea56c1d8456c..eb877e50a8d1 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1427,7 +1427,19 @@ void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) int rw = rq_data_dir(rq); unsigned int index; - index = disk_index(rq->rq_dev); + if (!rq->rq_disk) + return; + + if (rw == READ) { + rq->rq_disk->rio += new_io; + rq->rq_disk->reads += nr_sectors; + } else if (rw == WRITE) { + rq->rq_disk->wio += new_io; + rq->rq_disk->writes += nr_sectors; + } + + index = rq->rq_disk->first_minor >> rq->rq_disk->minor_shift; + if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) return; @@ -1747,6 +1759,7 @@ get_rq: req->waiting = NULL; req->bio = req->biotail = bio; req->rq_dev = to_kdev_t(bio->bi_bdev->bd_dev); + req->rq_disk = bio->bi_bdev->bd_disk; add_request(q, req, insert_here); out: if (freereq) diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 7d72b786080c..bbd247fa29dc 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -381,6 +381,7 @@ static int rd_open(struct inode * inode, struct file * filp) rd_bdev[unit]->bd_inode->i_mapping->a_ops = &ramdisk_aops; rd_bdev[unit]->bd_inode->i_size = rd_length[unit]; rd_bdev[unit]->bd_queue = &blk_dev[MAJOR_NR].request_queue; + rd_bdev[unit]->bd_disk = get_disk(rd_disks[unit]); } return 0; diff --git a/drivers/md/md.c b/drivers/md/md.c index 205bb0fdeee0..784e3b69213e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2731,18 +2731,9 @@ int unregister_md_personality(int pnum) return 0; } -static unsigned int sync_io[DK_MAX_MAJOR][DK_MAX_DISK]; void md_sync_acct(mdk_rdev_t *rdev, unsigned long nr_sectors) { - kdev_t dev = to_kdev_t(rdev->bdev->bd_dev); - unsigned int major = major(dev); - unsigned int index; - - index = disk_index(dev); - if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) - return; - - sync_io[major][index] += nr_sectors; + rdev->bdev->bd_disk->sync_io += nr_sectors; } static int is_mddev_idle(mddev_t *mddev) @@ -2754,16 +2745,8 @@ static int is_mddev_idle(mddev_t *mddev) idle = 1; ITERATE_RDEV(mddev,rdev,tmp) { - kdev_t dev = to_kdev_t(rdev->bdev->bd_dev); - int major = major(dev); - int idx = disk_index(dev); - - if ((idx >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) - continue; - - curr_events = kstat.dk_drive_rblk[major][idx] + - kstat.dk_drive_wblk[major][idx] ; - curr_events -= sync_io[major][idx]; + struct gendisk *disk = rdev->bdev->bd_disk; + curr_events = disk->reads + disk->writes - disk->sync_io; if ((curr_events - rdev->last_events) > 32) { rdev->last_events = curr_events; idle = 0; diff --git a/fs/block_dev.c b/fs/block_dev.c index d029636b07e6..1ad7f467993b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -526,8 +526,6 @@ int check_disk_change(struct block_device *bdev) { struct block_device_operations * bdops = bdev->bd_op; kdev_t dev = to_kdev_t(bdev->bd_dev); - struct gendisk *disk; - int part; if (bdops->check_media_change == NULL) return 0; @@ -537,26 +535,21 @@ int check_disk_change(struct block_device *bdev) if (invalidate_device(dev, 0)) printk("VFS: busy inodes on changed media.\n"); - disk = get_gendisk(bdev->bd_dev, &part); if (bdops->revalidate) bdops->revalidate(dev); - if (disk && disk->minors > 1) + if (bdev->bd_disk->minors > 1) bdev->bd_invalidated = 1; - put_disk(disk); return 1; } int full_check_disk_change(struct block_device *bdev) { int res = 0; - int n; if (bdev->bd_contains != bdev) BUG(); down(&bdev->bd_sem); if (check_disk_change(bdev)) { - struct gendisk *disk = get_gendisk(bdev->bd_dev, &n); - rescan_partitions(disk, bdev); - put_disk(disk); + rescan_partitions(bdev->bd_disk, bdev); res = 1; } up(&bdev->bd_sem); @@ -598,6 +591,8 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * kdev_t dev = to_kdev_t(bdev->bd_dev); struct module *owner = NULL; struct block_device_operations *ops, *old; + struct gendisk *disk; + int part; lock_kernel(); ops = get_blkfops(major(dev)); @@ -617,53 +612,41 @@ 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) { - int part; - struct gendisk *g = get_gendisk(bdev->bd_dev, &part); bdev->bd_contains = bdev; - if (g && part) { - struct block_device *disk; - disk = bdget(MKDEV(g->major, g->first_minor)); + if (part) { + struct block_device *whole; + whole = bdget(MKDEV(disk->major, disk->first_minor)); ret = -ENOMEM; - if (!disk) { - put_disk(g); + if (!whole) goto out1; - } - ret = blkdev_get(disk, file->f_mode, file->f_flags, BDEV_RAW); - if (ret) { - put_disk(g); + ret = blkdev_get(whole, file->f_mode, file->f_flags, BDEV_RAW); + if (ret) goto out1; - } - bdev->bd_contains = disk; + bdev->bd_contains = whole; } - put_disk(g); } if (bdev->bd_contains == bdev) { - int part; - struct gendisk *g = get_gendisk(bdev->bd_dev, &part); - + if (!bdev->bd_openers) + bdev->bd_disk = disk; if (!bdev->bd_queue) { struct blk_dev_struct *p = blk_dev + major(dev); bdev->bd_queue = &p->request_queue; if (p->queue) bdev->bd_queue = p->queue(dev); } - if (bdev->bd_op->open) { ret = bdev->bd_op->open(inode, file); - if (ret) { - put_disk(g); + if (ret) goto out2; - } } if (!bdev->bd_openers) { struct backing_dev_info *bdi; - sector_t sect = 0; - bdev->bd_offset = 0; - if (g) - sect = get_capacity(g); - bd_set_size(bdev, (loff_t)sect << 9); + 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; @@ -671,34 +654,31 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * bdev->bd_inode->i_data.backing_dev_info = bdi; } if (bdev->bd_invalidated) - rescan_partitions(g, bdev); - put_disk(g); + rescan_partitions(disk, bdev); } else { down(&bdev->bd_contains->bd_sem); bdev->bd_contains->bd_part_count++; if (!bdev->bd_openers) { - int part; - struct gendisk *g = get_gendisk(bdev->bd_dev, &part); struct hd_struct *p; - p = g->part + part - 1; + p = disk->part + part - 1; inode->i_data.backing_dev_info = bdev->bd_inode->i_data.backing_dev_info = bdev->bd_contains->bd_inode->i_data.backing_dev_info; - if (!(g->flags & GENHD_FL_UP) || !p->nr_sects) { + if (!(disk->flags & GENHD_FL_UP) || !p->nr_sects) { bdev->bd_contains->bd_part_count--; up(&bdev->bd_contains->bd_sem); - put_disk(g); ret = -ENXIO; goto out2; } bdev->bd_queue = bdev->bd_contains->bd_queue; bdev->bd_offset = p->start_sect; bd_set_size(bdev, (loff_t) p->nr_sects << 9); - put_disk(g); + bdev->bd_disk = disk; } up(&bdev->bd_contains->bd_sem); } - bdev->bd_openers++; + if (bdev->bd_openers++) + put_disk(disk); up(&bdev->bd_sem); unlock_kernel(); return 0; @@ -712,6 +692,7 @@ out2: } } out1: + put_disk(disk); if (!old) { bdev->bd_op = NULL; if (owner) @@ -785,15 +766,18 @@ int blkdev_put(struct block_device *bdev, int kind) 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; + 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); } unlock_kernel(); up(&bdev->bd_sem); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 607641c6cfb1..ccb56d58de6a 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -34,6 +34,7 @@ struct request { int rq_status; /* should split this into a few status bits */ kdev_t rq_dev; + struct gendisk *rq_disk; int errors; sector_t sector; unsigned long nr_sectors; diff --git a/include/linux/fs.h b/include/linux/fs.h index cac13f931cec..bca164f4265a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -359,6 +359,7 @@ struct block_device { sector_t bd_offset; unsigned bd_part_count; int bd_invalidated; + struct gendisk * bd_disk; }; struct inode { diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 030ee2f87891..9de2f51ae935 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -90,6 +90,10 @@ struct gendisk { devfs_handle_t disk_de; /* piled higher and deeper */ struct device *driverfs_dev; struct device disk_dev; + + unsigned sync_io; /* RAID */ + unsigned reads, writes; + unsigned rio, wio; }; /* drivers/block/genhd.c */ @@ -272,15 +276,6 @@ extern void put_disk(struct gendisk *disk); /* will go away */ extern void blk_set_probe(int major, struct gendisk *(p)(int)); -static inline unsigned int disk_index (kdev_t dev) -{ - int part, res; - struct gendisk *g = get_gendisk(kdev_t_to_nr(dev), &part); - res = g ? (minor(dev) >> g->minor_shift) : 0; - put_disk(g); - return res; -} - #endif #endif -- cgit v1.2.3