diff options
| author | Alexander Viro <viro@www.linux.org.uk> | 2003-08-30 22:51:54 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.osdl.org> | 2003-08-30 22:51:54 -0700 |
| commit | fdf6f5efe399c351d85620ceb82ce2d15c6cf907 (patch) | |
| tree | dca103e0cbcf6fbdd5f32b79756e9713a76c824a | |
| parent | f2820f23b7adb742047f9d38191b9bb8cf0cb6a5 (diff) | |
[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.
| -rw-r--r-- | drivers/block/genhd.c | 24 | ||||
| -rw-r--r-- | drivers/block/ioctl.c | 21 | ||||
| -rw-r--r-- | drivers/block/ll_rw_blk.c | 31 | ||||
| -rw-r--r-- | fs/block_dev.c | 8 | ||||
| -rw-r--r-- | fs/partitions/check.c | 12 | ||||
| -rw-r--r-- | include/linux/fs.h | 2 | ||||
| -rw-r--r-- | include/linux/genhd.h | 2 |
7 files changed, 55 insertions, 45 deletions
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 24e066a8fb35..16a58ad04008 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -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) diff --git a/drivers/block/ioctl.c b/drivers/block/ioctl.c index 9f3f411f2389..701461265c34 100644 --- a/drivers/block/ioctl.c +++ b/drivers/block/ioctl.c @@ -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; diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index f09d20d1e41a..98a3182919c5 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2043,24 +2043,23 @@ end_io: 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]; - switch (bio->bi_rw) { - case READ: - p->read_sectors += bio_sectors(bio); - p->reads++; - break; - case WRITE: - p->write_sectors += bio_sectors(bio); - p->writes++; - break; + if (bdev != bdev->bd_contains) { + struct hd_struct *p = bdev->bd_part; + + switch (bio->bi_rw) { + case READ: + p->read_sectors += bio_sectors(bio); + p->reads++; + break; + case WRITE: + 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; } /** diff --git a/fs/block_dev.c b/fs/block_dev.c index 94e7f9fd6398..ddfcb6284b5a 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -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) { diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 7370a2f00539..08585ea0bcf1 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -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) diff --git a/include/linux/fs.h b/include/linux/fs.h index 090bc3ab5c6b..108e53f176c9 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -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; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 3e4ef6b13683..623baf2fd239 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -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) { |
