new_bdev->bd_contains = NULL;
new_bdev->bd_inode = inode;
new_bdev->bd_part_count = 0;
- sema_init(&new_bdev->bd_part_sem, 1);
+ new_bdev->bd_invalidated = 0;
inode->i_mode = S_IFBLK;
inode->i_rdev = kdev;
inode->i_bdev = new_bdev;
disk = get_gendisk(dev);
part = disk->part + minor(dev) - disk->first_minor;
- if (disk && disk->minor_shift) {
- if (!down_trylock(&bdev->bd_part_sem)) {
- if (!bdev->bd_part_count) {
- if (wipe_partitions(dev) == 0) {
- if (bdops->revalidate)
- bdops->revalidate(dev);
- grok_partitions(dev, part[0].nr_sects);
- }
- }
- up(&bdev->bd_part_sem);
- }
- } else {
- if (bdops->revalidate)
- bdops->revalidate(dev);
- }
+ if (bdops->revalidate)
+ bdops->revalidate(dev);
+ if (disk && disk->minor_shift)
+ bdev->bd_invalidated = 1;
return 1;
}
+int full_check_disk_change(struct block_device *bdev)
+{
+ int res;
+ down(&bdev->bd_sem);
+ res = check_disk_change(bdev);
+ if (bdev->bd_invalidated && !bdev->bd_part_count) {
+ struct gendisk *g = get_gendisk(to_kdev_t(bdev->bd_dev));
+ struct hd_struct *part;
+ part = g->part + MINOR(bdev->bd_dev) - g->first_minor;
+ bdev->bd_invalidated = 0;
+ wipe_partitions(to_kdev_t(bdev->bd_dev));
+ if (part[0].nr_sects)
+ check_partition(g, bdev);
+ }
+ up(&bdev->bd_sem);
+ return res;
+}
+
+/*
+ * Will die as soon as two remaining callers get converted.
+ */
int __check_disk_change(dev_t dev)
{
struct block_device *bdev = bdget(dev);
return 0;
if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0)
return 0;
- res = check_disk_change(bdev);
+ res = full_check_disk_change(bdev);
blkdev_put(bdev, BDEV_RAW);
return res;
}
+static void bd_set_size(struct block_device *bdev, loff_t size)
+{
+ unsigned bsize = bdev_hardsect_size(bdev);
+ bdev->bd_inode->i_size = size;
+ while (bsize < PAGE_CACHE_SIZE) {
+ if (size & bsize)
+ break;
+ bsize <<= 1;
+ }
+ bdev->bd_block_size = bsize;
+ bdev->bd_inode->i_blkbits = blksize_bits(bsize);
+}
+
static int do_open(struct block_device *bdev, struct inode *inode, struct file *file)
{
int ret = -ENXIO;
}
}
if (bdev->bd_contains == bdev) {
+ struct gendisk *g = get_gendisk(dev);
if (bdev->bd_op->open) {
ret = bdev->bd_op->open(inode, file);
if (ret)
goto out2;
}
- } else {
- down(&bdev->bd_contains->bd_part_sem);
- bdev->bd_contains->bd_part_count++;
- up(&bdev->bd_contains->bd_part_sem);
- }
- if (!bdev->bd_openers) {
- struct blk_dev_struct *p = blk_dev + major(dev);
- struct gendisk *g = get_gendisk(dev);
- unsigned bsize = bdev_hardsect_size(bdev);
-
- bdev->bd_offset = 0;
- if (g) {
- struct hd_struct *p;
- p = g->part + minor(dev) - g->first_minor;
- bdev->bd_inode->i_size = (loff_t) p->nr_sects << 9;
- bdev->bd_offset = p->start_sect;
- } else if (blk_size[major(dev)])
- bdev->bd_inode->i_size =
- (loff_t) blk_size[major(dev)][minor(dev)] << 10;
- else
- bdev->bd_inode->i_size = 0;
- while (bsize < PAGE_CACHE_SIZE) {
- if (bdev->bd_inode->i_size & bsize)
- break;
- bsize <<= 1;
- }
- bdev->bd_block_size = bsize;
- bdev->bd_inode->i_blkbits = blksize_bits(bsize);
- if (p->queue)
- bdev->bd_queue = p->queue(dev);
- else
- bdev->bd_queue = &p->request_queue;
- if (bdev->bd_inode->i_data.backing_dev_info ==
- &default_backing_dev_info) {
+ if (!bdev->bd_openers) {
+ struct blk_dev_struct *p = blk_dev + major(dev);
struct backing_dev_info *bdi;
-
+ sector_t sect = 0;
+
+ bdev->bd_offset = 0;
+ if (g) {
+ struct hd_struct *p;
+ p = g->part + minor(dev) - g->first_minor;
+ sect = p->nr_sects;
+ } else if (blk_size[major(dev)])
+ sect = blk_size[major(dev)][minor(dev)] << 1;
+ if (p->queue)
+ bdev->bd_queue = p->queue(dev);
+ else
+ bdev->bd_queue = &p->request_queue;
+ bd_set_size(bdev, (loff_t)sect << 9);
bdi = blk_get_backing_dev_info(bdev);
if (bdi == NULL)
bdi = &default_backing_dev_info;
inode->i_data.backing_dev_info = bdi;
bdev->bd_inode->i_data.backing_dev_info = bdi;
}
+ if (bdev->bd_invalidated && !bdev->bd_part_count) {
+ struct hd_struct *part;
+ part = g->part + minor(dev) - g->first_minor;
+ bdev->bd_invalidated = 0;
+ wipe_partitions(dev);
+ if (part[0].nr_sects)
+ check_partition(g, bdev);
+ }
+ } else {
+ down(&bdev->bd_contains->bd_sem);
+ bdev->bd_contains->bd_part_count++;
+ if (!bdev->bd_openers) {
+ struct gendisk *g = get_gendisk(dev);
+ struct hd_struct *p;
+ p = g->part + minor(dev) - g->first_minor;
+ 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) {
+ bdev->bd_contains->bd_part_count--;
+ up(&bdev->bd_contains->bd_sem);
+ 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);
+ }
+ up(&bdev->bd_contains->bd_sem);
}
bdev->bd_openers++;
up(&bdev->bd_sem);
if (bdev->bd_op->release)
ret = bdev->bd_op->release(bd_inode, NULL);
} else {
- down(&bdev->bd_contains->bd_part_sem);
+ down(&bdev->bd_contains->bd_sem);
bdev->bd_contains->bd_part_count--;
- up(&bdev->bd_contains->bd_part_sem);
+ up(&bdev->bd_contains->bd_sem);
}
if (!bdev->bd_openers) {
if (bdev->bd_op->owner)
struct hd_struct *part;
int res;
- if (!disk)
+ if (!disk || !disk->minor_shift)
return -EINVAL;
part = disk->part + minor(dev) - disk->first_minor;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (down_trylock(&bdev->bd_part_sem));
+ if (down_trylock(&bdev->bd_sem));
return -EBUSY;
if (bdev->bd_part_count) {
- up(&bdev->bd_part_sem);
+ up(&bdev->bd_sem);
return -EBUSY;
}
res = wipe_partitions(dev);
if (!res) {
if (bdev->bd_op->revalidate)
bdev->bd_op->revalidate(dev);
- grok_partitions(dev, part[0].nr_sects);
+ if (part[0].nr_sects)
+ check_partition(disk, bdev);
}
- up(&bdev->bd_part_sem);
+ up(&bdev->bd_sem);
return res;
}
return;
}
-static void check_partition(struct gendisk *hd, kdev_t dev)
+/*
+ * DON'T EXPORT
+ */
+void check_partition(struct gendisk *hd, struct block_device *bdev)
{
devfs_handle_t de = NULL;
- struct block_device *bdev;
+ kdev_t dev = to_kdev_t(bdev->bd_dev);
char buf[64];
struct parsed_partitions *state;
int i;
if (n - COMPAQ_SMART2_MAJOR <= 7 || n - COMPAQ_CISS_MAJOR <= 7)
sprintf(state->name, "p");
}
- bdev = bdget(kdev_t_to_nr(dev));
- if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW))
- goto out;
state->limit = 1<<hd->minor_shift;
for (i = 0; check_part[i]; i++) {
int res, j;
if (res < 0) {
if (warn_no_part)
printk(" unable to read partition table\n");
- goto setup_devfs;
+ goto out;
}
p = hd->part + minor(dev) - hd->first_minor;
for (j = 1; j < state->limit; j++) {
md_autodetect_dev(mk_kdev(major(dev),minor(dev)+j));
#endif
}
- goto setup_devfs;
+ goto out;
}
printk(" unknown partition table\n");
-setup_devfs:
- blkdev_put(bdev, BDEV_RAW);
out:
driverfs_create_partitions(hd, minor(dev));
devfs_register_partitions (hd, minor(dev), 0);
void grok_partitions(kdev_t dev, long size)
{
- int minors, first_minor, end_minor;
+ struct block_device *bdev;
struct gendisk *g = get_gendisk(dev);
struct hd_struct *p;
if (!g)
return;
- minors = 1 << g->minor_shift;
- first_minor = minor(dev);
- if (first_minor & (minors-1)) {
- printk("grok_partitions: bad device 0x%02x:%02x\n",
- major(dev), first_minor);
- first_minor &= ~(minors-1);
- }
- end_minor = first_minor + minors;
-
- p = g->part + first_minor - g->first_minor;
+ p = g->part + minor(dev) - g->first_minor;
p[0].nr_sects = size;
/* No minors to use for partitions */
- if (minors == 1)
+ if (!g->minor_shift)
return;
/* No such device (e.g., media were just removed) */
if (!size)
return;
- check_partition(g, mk_kdev(g->major, first_minor));
+ bdev = bdget(kdev_t_to_nr(dev));
+ if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0)
+ return;
+ check_partition(g, bdev);
+ blkdev_put(bdev, BDEV_RAW);
}
unsigned char *read_dev_sector(struct block_device *bdev, unsigned long n, Sector *p)