Commit fdf6f5ef authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] dev_t handling cleanups (12/12)

added the exclusion between ADD_PARTITION/DELETE_PARTITION/open() (BLKPG
ioctls didn't grab ->bd_sem when they should have).

added bdev->bd_part; it is set at open() to point to the hd_struct of
partition in question, reset on final close.

blk_partition_remap() uses ->bd_part instead of the current mess

  ->bd_offset is gone, we use ->bd_part->start_sect instead

added missing ->release() to hd_struct kobject, moved kfree() into it

  ->bd_part cotributes to refcount of hd_struct - we bump it when

  ->bd_part is set and drop when it's reset.
parent f2820f23
......@@ -576,13 +576,10 @@ EXPORT_SYMBOL(put_disk);
void set_device_ro(struct block_device *bdev, int flag)
{
struct gendisk *disk = bdev->bd_disk;
if (bdev->bd_contains != bdev) {
int part = bdev->bd_dev - MKDEV(disk->major, disk->first_minor);
struct hd_struct *p = disk->part[part-1];
if (p) p->policy = flag;
} else
disk->policy = flag;
if (bdev->bd_contains != bdev)
bdev->bd_part->policy = flag;
else
bdev->bd_disk->policy = flag;
}
void set_disk_ro(struct gendisk *disk, int flag)
......@@ -595,17 +592,12 @@ void set_disk_ro(struct gendisk *disk, int flag)
int bdev_read_only(struct block_device *bdev)
{
struct gendisk *disk;
if (!bdev)
return 0;
disk = bdev->bd_disk;
if (bdev->bd_contains != bdev) {
int part = bdev->bd_dev - MKDEV(disk->major, disk->first_minor);
struct hd_struct *p = disk->part[part-1];
if (p) return p->policy;
return 0;
} else
return disk->policy;
else if (bdev->bd_contains != bdev)
return bdev->bd_part->policy;
else
return bdev->bd_disk->policy;
}
int invalidate_partition(struct gendisk *disk, int index)
......
......@@ -8,7 +8,6 @@
static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
{
struct block_device *bdevp;
int holder;
struct gendisk *disk;
struct blkpg_ioctl_arg a;
struct blkpg_partition p;
......@@ -41,8 +40,11 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
return -EINVAL;
}
/* partition number in use? */
if (disk->part[part - 1])
down(&bdev->bd_sem);
if (disk->part[part - 1]) {
up(&bdev->bd_sem);
return -EBUSY;
}
/* overlap? */
for (i = 0; i < disk->minors - 1; i++) {
struct hd_struct *s = disk->part[i];
......@@ -50,22 +52,26 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
if (!s)
continue;
if (!(start+length <= s->start_sect ||
start >= s->start_sect + s->nr_sects))
start >= s->start_sect + s->nr_sects)) {
up(&bdev->bd_sem);
return -EBUSY;
}
}
/* all seems OK */
add_partition(disk, part, start, length);
up(&bdev->bd_sem);
return 0;
case BLKPG_DEL_PARTITION:
if (!disk->part[part-1])
return -ENXIO;
if (disk->part[part - 1]->nr_sects == 0)
return -ENXIO;
/* partition in use? Incomplete check for now. */
bdevp = bdget_disk(disk, part);
if (!bdevp)
return -ENOMEM;
if (bd_claim(bdevp, &holder) < 0) {
down(&bdevp->bd_sem);
if (bdevp->bd_openers) {
up(&bdevp->bd_sem);
bdput(bdevp);
return -EBUSY;
}
......@@ -73,9 +79,12 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
fsync_bdev(bdevp);
invalidate_bdev(bdevp, 0);
down(&bdev->bd_sem);
delete_partition(disk, part);
bd_release(bdevp);
up(&bdev->bd_sem);
up(&bdevp->bd_sem);
bdput(bdevp);
return 0;
default:
return -EINVAL;
......
......@@ -2043,12 +2043,10 @@ static int __make_request(request_queue_t *q, struct bio *bio)
static inline void blk_partition_remap(struct bio *bio)
{
struct block_device *bdev = bio->bi_bdev;
struct gendisk *disk = bdev->bd_disk;
struct hd_struct *p;
if (bdev == bdev->bd_contains)
return;
p = disk->part[bdev->bd_dev-MKDEV(disk->major,disk->first_minor)-1];
if (bdev != bdev->bd_contains) {
struct hd_struct *p = bdev->bd_part;
switch (bio->bi_rw) {
case READ:
p->read_sectors += bio_sectors(bio);
......@@ -2059,8 +2057,9 @@ static inline void blk_partition_remap(struct bio *bio)
p->writes++;
break;
}
bio->bi_sector += bdev->bd_offset;
bio->bi_sector += p->start_sect;
bio->bi_bdev = bdev->bd_contains;
}
}
/**
......
......@@ -540,7 +540,6 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
if (ret)
goto out_first;
}
bdev->bd_offset = 0;
if (!bdev->bd_openers) {
bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);
bdi = blk_get_backing_dev_info(bdev);
......@@ -572,7 +571,8 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file *
ret = -ENXIO;
goto out_first;
}
bdev->bd_offset = p->start_sect;
kobject_get(&p->kobj);
bdev->bd_part = p;
bd_set_size(bdev, (loff_t) p->nr_sects << 9);
up(&whole->bd_sem);
}
......@@ -693,6 +693,10 @@ int blkdev_put(struct block_device *bdev, int kind)
put_disk(disk);
module_put(owner);
if (bdev->bd_contains != bdev) {
kobject_put(&bdev->bd_part->kobj);
bdev->bd_part = NULL;
}
bdev->bd_disk = NULL;
bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
if (bdev != bdev->bd_contains) {
......
......@@ -267,7 +267,14 @@ static struct attribute * default_attrs[] = {
extern struct subsystem block_subsys;
static void part_release(struct kobject *kobj)
{
struct hd_struct * p = container_of(kobj,struct hd_struct,kobj);
kfree(p);
}
struct kobj_type ktype_part = {
.release = part_release,
.default_attrs = default_attrs,
.sysfs_ops = &part_sysfs_ops,
};
......@@ -279,13 +286,12 @@ void delete_partition(struct gendisk *disk, int part)
return;
if (!p->nr_sects)
return;
disk->part[part-1] = NULL;
p->start_sect = 0;
p->nr_sects = 0;
p->reads = p->writes = p->read_sectors = p->write_sectors = 0;
devfs_remove("%s/part%d", disk->devfs_name, part);
kobject_unregister(&p->kobj);
disk->part[part-1] = NULL;
kfree(p);
}
void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
......@@ -300,7 +306,6 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
p->start_sect = start;
p->nr_sects = len;
p->partno = part;
disk->part[part-1] = p;
devfs_mk_bdev(MKDEV(disk->major, disk->first_minor + part),
S_IFBLK|S_IRUSR|S_IWUSR,
......@@ -310,6 +315,7 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
p->kobj.parent = &disk->kobj;
p->kobj.ktype = &ktype_part;
kobject_register(&p->kobj);
disk->part[part-1] = p;
}
static void disk_sysfs_symlinks(struct gendisk *disk)
......
......@@ -345,7 +345,7 @@ struct block_device {
int bd_holders;
struct block_device * bd_contains;
unsigned bd_block_size;
sector_t bd_offset;
struct hd_struct * bd_part;
unsigned bd_part_count;
int bd_invalidated;
struct gendisk * bd_disk;
......
......@@ -197,7 +197,7 @@ extern void rand_initialize_disk(struct gendisk *disk);
static inline sector_t get_start_sect(struct block_device *bdev)
{
return bdev->bd_offset;
return bdev->bd_part->start_sect;
}
static inline sector_t get_capacity(struct gendisk *disk)
{
......
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