summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Viro <viro@www.linux.org.uk>2003-08-30 22:51:54 -0700
committerLinus Torvalds <torvalds@home.osdl.org>2003-08-30 22:51:54 -0700
commitfdf6f5efe399c351d85620ceb82ce2d15c6cf907 (patch)
treedca103e0cbcf6fbdd5f32b79756e9713a76c824a
parentf2820f23b7adb742047f9d38191b9bb8cf0cb6a5 (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.c24
-rw-r--r--drivers/block/ioctl.c21
-rw-r--r--drivers/block/ll_rw_blk.c31
-rw-r--r--fs/block_dev.c8
-rw-r--r--fs/partitions/check.c12
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/genhd.h2
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)
{