Commit 79c2cfb8 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] (9/15) big struct block_device * push (first series)

 - this one is interesting and will play in the next series as well;
   affected place is fs/block_dev.c::do_open().  We check if bdev is
   a partition (same way it is done in generic_make_request()) and
   if it is - open entire disk and put pointer to its bdev into a
   new field bdev->bd_contains.  Otherwise (non-partition) we
   set bdev->bd_contains to bdev.  Corresponding cleanup done in
   blkdev_put() (and failure path in do_open()) - when the last opener
   goes away we close bdev->bd_contains if bdev is a partition (i.e.
   not equal to its ->bd_contains) and set it to NULL.
   Immediate effect is that we can get from bdev of partition to
   bdev of disk when submitting a bio, but it also opens a way
   to handle partition-parsing in a sane way.  That will be done
   in the next series.
parent eec08e21
......@@ -353,6 +353,7 @@ 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_contains = NULL;
new_bdev->bd_inode = inode;
inode->i_mode = S_IFBLK;
inode->i_rdev = kdev;
......@@ -590,28 +591,62 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
{
int ret = -ENXIO;
kdev_t dev = to_kdev_t(bdev->bd_dev);
struct module *owner = NULL;
down(&bdev->bd_sem);
lock_kernel();
if (!bdev->bd_op)
if (!bdev->bd_op) {
bdev->bd_op = get_blkfops(major(dev));
if (bdev->bd_op) {
ret = 0;
if (bdev->bd_op->owner)
__MOD_INC_USE_COUNT(bdev->bd_op->owner);
if (bdev->bd_op->open)
if (!bdev->bd_op)
goto out;
owner = bdev->bd_op->owner;
if (owner)
__MOD_INC_USE_COUNT(owner);
}
if (!bdev->bd_contains) {
unsigned minor = minor(dev);
struct gendisk *g = get_gendisk(dev);
bdev->bd_contains = bdev;
if (g) {
int shift = g->minor_shift;
unsigned minor0 = (minor >> shift) << shift;
if (minor != minor0) {
struct block_device *disk;
disk = bdget(MKDEV(major(dev), minor0));
ret = -ENOMEM;
if (!disk)
goto out1;
ret = blkdev_get(disk, file->f_mode, file->f_flags, BDEV_RAW);
if (ret)
goto out1;
bdev->bd_contains = disk;
}
}
}
if (bdev->bd_op->open) {
ret = bdev->bd_op->open(inode, file);
if (!ret) {
if (ret)
goto out2;
}
bdev->bd_openers++;
bdev->bd_inode->i_size = blkdev_size(dev);
bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
} else {
if (bdev->bd_op->owner)
__MOD_DEC_USE_COUNT(bdev->bd_op->owner);
if (!bdev->bd_openers)
unlock_kernel();
up(&bdev->bd_sem);
return 0;
out2:
if (!bdev->bd_openers) {
bdev->bd_op = NULL;
if (bdev != bdev->bd_contains) {
blkdev_put(bdev->bd_contains, BDEV_RAW);
bdev->bd_contains = NULL;
}
}
out1:
if (owner)
__MOD_DEC_USE_COUNT(owner);
out:
unlock_kernel();
up(&bdev->bd_sem);
if (ret)
......@@ -676,8 +711,13 @@ int blkdev_put(struct block_device *bdev, int kind)
ret = bdev->bd_op->release(bd_inode, NULL);
if (bdev->bd_op->owner)
__MOD_DEC_USE_COUNT(bdev->bd_op->owner);
if (!bdev->bd_openers)
if (!bdev->bd_openers) {
bdev->bd_op = NULL;
if (bdev != bdev->bd_contains) {
blkdev_put(bdev->bd_contains, BDEV_RAW);
bdev->bd_contains = NULL;
}
}
unlock_kernel();
up(&bdev->bd_sem);
bdput(bdev);
......
......@@ -251,6 +251,7 @@ static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor
else
printk(KERN_INFO " %s:", disk_name(hd, minor(dev), buf));
bdev = bdget(kdev_t_to_nr(dev));
bdev->bd_contains = bdev;
bdev->bd_inode->i_size = (loff_t)hd->part[minor(dev)].nr_sects << 9;
bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
for (i = 0; check_part[i]; i++) {
......
......@@ -420,6 +420,7 @@ struct block_device {
struct list_head bd_inodes;
void * bd_holder;
int bd_holders;
struct block_device * bd_contains;
};
struct inode {
......
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