<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: viro@www.linux.org.uk

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

added bdev-&gt;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 -&gt;bd_part instead of the current mess

-&gt;bd_offset is gone, we use -&gt;bd_part-&gt;start_sect instead

added missing -&gt;release() to hd_struct kobject, moved kfree() into it

-&gt;bd_part contributes to refcount of hd_struct - we bump it when -&gt;bd_part
is set and drop when it's reset.



 drivers/block/genhd.c     |   24 ++++++++----------------
 drivers/block/ioctl.c     |   21 +++++++++++++++------
 drivers/block/ll_rw_blk.c |   31 +++++++++++++++----------------
 fs/block_dev.c            |    8 ++++++--
 fs/partitions/check.c     |   12 +++++++++---
 include/linux/fs.h        |    2 +-
 include/linux/genhd.h     |    2 +-
 7 files changed, 55 insertions(+), 45 deletions(-)

diff -puN drivers/block/genhd.c~large-dev_t-12 drivers/block/genhd.c
--- 25/drivers/block/genhd.c~large-dev_t-12	2003-08-27 10:31:45.000000000 -0700
+++ 25-akpm/drivers/block/genhd.c	2003-08-27 10:31:45.000000000 -0700
@@ -576,13 +576,10 @@ EXPORT_SYMBOL(put_disk);
 
 void set_device_ro(struct block_device *bdev, int flag)
 {
-	struct gendisk *disk = bdev-&gt;bd_disk;
-	if (bdev-&gt;bd_contains != bdev) {
-		int part = bdev-&gt;bd_dev - MKDEV(disk-&gt;major, disk-&gt;first_minor);
-		struct hd_struct *p = disk-&gt;part[part-1];
-		if (p) p-&gt;policy = flag;
-	} else
-		disk-&gt;policy = flag;
+	if (bdev-&gt;bd_contains != bdev)
+		bdev-&gt;bd_part-&gt;policy = flag;
+	else
+		bdev-&gt;bd_disk-&gt;policy = flag;
 }
 
 void set_disk_ro(struct gendisk *disk, int flag)
@@ -595,17 +592,12 @@ void set_disk_ro(struct gendisk *disk, i
 
 int bdev_read_only(struct block_device *bdev)
 {
-	struct gendisk *disk;
 	if (!bdev)
 		return 0;
-	disk = bdev-&gt;bd_disk;
-	if (bdev-&gt;bd_contains != bdev) {
-		int part = bdev-&gt;bd_dev - MKDEV(disk-&gt;major, disk-&gt;first_minor);
-		struct hd_struct *p = disk-&gt;part[part-1];
-		if (p) return p-&gt;policy;
-		return 0;
-	} else
-		return disk-&gt;policy;
+	else if (bdev-&gt;bd_contains != bdev)
+		return bdev-&gt;bd_part-&gt;policy;
+	else
+		return bdev-&gt;bd_disk-&gt;policy;
 }
 
 int invalidate_partition(struct gendisk *disk, int index)
diff -puN drivers/block/ioctl.c~large-dev_t-12 drivers/block/ioctl.c
--- 25/drivers/block/ioctl.c~large-dev_t-12	2003-08-27 10:31:45.000000000 -0700
+++ 25-akpm/drivers/block/ioctl.c	2003-08-27 10:31:45.000000000 -0700
@@ -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_devi
 					return -EINVAL;
 			}
 			/* partition number in use? */
-			if (disk-&gt;part[part - 1])
+			down(&amp;bdev-&gt;bd_sem);
+			if (disk-&gt;part[part - 1]) {
+				up(&amp;bdev-&gt;bd_sem);
 				return -EBUSY;
+			}
 			/* overlap? */
 			for (i = 0; i &lt; disk-&gt;minors - 1; i++) {
 				struct hd_struct *s = disk-&gt;part[i];
@@ -50,22 +52,26 @@ static int blkpg_ioctl(struct block_devi
 				if (!s)
 					continue;
 				if (!(start+length &lt;= s-&gt;start_sect ||
-				      start &gt;= s-&gt;start_sect + s-&gt;nr_sects))
+				      start &gt;= s-&gt;start_sect + s-&gt;nr_sects)) {
+					up(&amp;bdev-&gt;bd_sem);
 					return -EBUSY;
+				}
 			}
 			/* all seems OK */
 			add_partition(disk, part, start, length);
+			up(&amp;bdev-&gt;bd_sem);
 			return 0;
 		case BLKPG_DEL_PARTITION:
 			if (!disk-&gt;part[part-1])
 				return -ENXIO;
 			if (disk-&gt;part[part - 1]-&gt;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, &amp;holder) &lt; 0) {
+			down(&amp;bdevp-&gt;bd_sem);
+			if (bdevp-&gt;bd_openers) {
+				up(&amp;bdevp-&gt;bd_sem);
 				bdput(bdevp);
 				return -EBUSY;
 			}
@@ -73,9 +79,12 @@ static int blkpg_ioctl(struct block_devi
 			fsync_bdev(bdevp);
 			invalidate_bdev(bdevp, 0);
 
+			down(&amp;bdev-&gt;bd_sem);
 			delete_partition(disk, part);
-			bd_release(bdevp);
+			up(&amp;bdev-&gt;bd_sem);
+			up(&amp;bdevp-&gt;bd_sem);
 			bdput(bdevp);
+
 			return 0;
 		default:
 			return -EINVAL;
diff -puN drivers/block/ll_rw_blk.c~large-dev_t-12 drivers/block/ll_rw_blk.c
--- 25/drivers/block/ll_rw_blk.c~large-dev_t-12	2003-08-27 10:31:45.000000000 -0700
+++ 25-akpm/drivers/block/ll_rw_blk.c	2003-08-27 10:31:45.000000000 -0700
@@ -2043,24 +2043,23 @@ end_io:
 static inline void blk_partition_remap(struct bio *bio)
 {
 	struct block_device *bdev = bio-&gt;bi_bdev;
-	struct gendisk *disk = bdev-&gt;bd_disk;
-	struct hd_struct *p;
-	if (bdev == bdev-&gt;bd_contains)
-		return;
 
-	p = disk-&gt;part[bdev-&gt;bd_dev-MKDEV(disk-&gt;major,disk-&gt;first_minor)-1];
-	switch (bio-&gt;bi_rw) {
-	case READ:
-		p-&gt;read_sectors += bio_sectors(bio);
-		p-&gt;reads++;
-		break;
-	case WRITE:
-		p-&gt;write_sectors += bio_sectors(bio);
-		p-&gt;writes++;
-		break;
+	if (bdev != bdev-&gt;bd_contains) {
+		struct hd_struct *p = bdev-&gt;bd_part;
+
+		switch (bio-&gt;bi_rw) {
+		case READ:
+			p-&gt;read_sectors += bio_sectors(bio);
+			p-&gt;reads++;
+			break;
+		case WRITE:
+			p-&gt;write_sectors += bio_sectors(bio);
+			p-&gt;writes++;
+			break;
+		}
+		bio-&gt;bi_sector += p-&gt;start_sect;
+		bio-&gt;bi_bdev = bdev-&gt;bd_contains;
 	}
-	bio-&gt;bi_sector += bdev-&gt;bd_offset;
-	bio-&gt;bi_bdev = bdev-&gt;bd_contains;
 }
 
 /**
diff -puN fs/block_dev.c~large-dev_t-12 fs/block_dev.c
--- 25/fs/block_dev.c~large-dev_t-12	2003-08-27 10:31:45.000000000 -0700
+++ 25-akpm/fs/block_dev.c	2003-08-27 10:31:45.000000000 -0700
@@ -540,7 +540,6 @@ static int do_open(struct block_device *
 				if (ret)
 					goto out_first;
 			}
-			bdev-&gt;bd_offset = 0;
 			if (!bdev-&gt;bd_openers) {
 				bd_set_size(bdev,(loff_t)get_capacity(disk)&lt;&lt;9);
 				bdi = blk_get_backing_dev_info(bdev);
@@ -572,7 +571,8 @@ static int do_open(struct block_device *
 				ret = -ENXIO;
 				goto out_first;
 			}
-			bdev-&gt;bd_offset = p-&gt;start_sect;
+			kobject_get(&amp;p-&gt;kobj);
+			bdev-&gt;bd_part = p;
 			bd_set_size(bdev, (loff_t) p-&gt;nr_sects &lt;&lt; 9);
 			up(&amp;whole-&gt;bd_sem);
 		}
@@ -693,6 +693,10 @@ int blkdev_put(struct block_device *bdev
 		put_disk(disk);
 		module_put(owner);
 
+		if (bdev-&gt;bd_contains != bdev) {
+			kobject_put(&amp;bdev-&gt;bd_part-&gt;kobj);
+			bdev-&gt;bd_part = NULL;
+		}
 		bdev-&gt;bd_disk = NULL;
 		bdev-&gt;bd_inode-&gt;i_data.backing_dev_info = &amp;default_backing_dev_info;
 		if (bdev != bdev-&gt;bd_contains) {
diff -puN fs/partitions/check.c~large-dev_t-12 fs/partitions/check.c
--- 25/fs/partitions/check.c~large-dev_t-12	2003-08-27 10:31:45.000000000 -0700
+++ 25-akpm/fs/partitions/check.c	2003-08-27 10:31:45.000000000 -0700
@@ -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	= &amp;part_sysfs_ops,
 };
@@ -279,13 +286,12 @@ void delete_partition(struct gendisk *di
 		return;
 	if (!p-&gt;nr_sects)
 		return;
+	disk-&gt;part[part-1] = NULL;
 	p-&gt;start_sect = 0;
 	p-&gt;nr_sects = 0;
 	p-&gt;reads = p-&gt;writes = p-&gt;read_sectors = p-&gt;write_sectors = 0;
 	devfs_remove("%s/part%d", disk-&gt;devfs_name, part);
 	kobject_unregister(&amp;p-&gt;kobj);
-	disk-&gt;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,
 	p-&gt;start_sect = start;
 	p-&gt;nr_sects = len;
 	p-&gt;partno = part;
-	disk-&gt;part[part-1] = p;
 
 	devfs_mk_bdev(MKDEV(disk-&gt;major, disk-&gt;first_minor + part),
 			S_IFBLK|S_IRUSR|S_IWUSR,
@@ -310,6 +315,7 @@ void add_partition(struct gendisk *disk,
 	p-&gt;kobj.parent = &amp;disk-&gt;kobj;
 	p-&gt;kobj.ktype = &amp;ktype_part;
 	kobject_register(&amp;p-&gt;kobj);
+	disk-&gt;part[part-1] = p;
 }
 
 static void disk_sysfs_symlinks(struct gendisk *disk)
diff -puN include/linux/fs.h~large-dev_t-12 include/linux/fs.h
--- 25/include/linux/fs.h~large-dev_t-12	2003-08-27 10:31:45.000000000 -0700
+++ 25-akpm/include/linux/fs.h	2003-08-27 10:31:45.000000000 -0700
@@ -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 -puN include/linux/genhd.h~large-dev_t-12 include/linux/genhd.h
--- 25/include/linux/genhd.h~large-dev_t-12	2003-08-27 10:31:45.000000000 -0700
+++ 25-akpm/include/linux/genhd.h	2003-08-27 10:31:45.000000000 -0700
@@ -197,7 +197,7 @@ extern void rand_initialize_disk(struct 
 
 static inline sector_t get_start_sect(struct block_device *bdev)
 {
-	return bdev-&gt;bd_offset;
+	return bdev-&gt;bd_part-&gt;start_sect;
 }
 static inline sector_t get_capacity(struct gendisk *disk)
 {

_
</pre></body></html>