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