Received: from mnm [127.0.0.1]
	by localhost with POP3 (fetchmail-5.9.0)
	for akpm@localhost (single-drop); Tue, 26 Aug 2003 18:11:32 -0700 (PDT)
Received: from digeo-e2k04.digeo.com ([192.168.2.24]) by pao-ex01.pao.digeo.com with Microsoft SMTPSVC(5.0.2195.5329);
	 Tue, 26 Aug 2003 18:07:20 -0700
Received: from digeo-nav01.digeo.com ([192.168.1.233]) by digeo-e2k04.digeo.com with Microsoft SMTPSVC(5.0.2195.5329);
	 Tue, 26 Aug 2003 18:07:19 -0700
Received: from packet.digeo.com ([192.168.17.15])
 by digeo-nav01.digeo.com (SAVSMTP 3.1.1.32) with SMTP id M2003082618094705354
 for <akpm@digeo.com>; Tue, 26 Aug 2003 18:09:47 -0700
Received: from www.linux.org.uk (parcelfarce.linux.theplanet.co.uk [195.92.249.252])
	by packet.digeo.com (8.12.8/8.12.8) with ESMTP id h7R16RGl017205
	for <akpm@digeo.com>; Tue, 26 Aug 2003 18:06:29 -0700 (PDT)
Received: from viro by www.linux.org.uk with local (Exim 4.22)
	id 19rolV-0002I4-WB
	for akpm@digeo.com; Wed, 27 Aug 2003 02:06:25 +0100
To: akpm@digeo.com
Subject: [PATCH] large dev_t work - first series (12/12)
Message-Id: <E19rolV-0002I4-WB@www.linux.org.uk>
From: viro@www.linux.org.uk
Date: Wed, 27 Aug 2003 02:06:25 +0100
X-Scanned-By: MIMEDefang 2.30 (www . roaringpenguin . com / mimedefang)
Return-Path: viro@www.linux.org.uk
X-OriginalArrivalTime: 27 Aug 2003 01:07:19.0535 (UTC) FILETIME=[903BDFF0:01C36C37]
X-Spam-Status: No, hits=-8.6 required=6.0
	tests=BAYES_01,NO_REAL_NAME,PATCH_UNIFIED_DIFF
	autolearn=ham version=2.53
X-Spam-Level: 
X-Spam-Checker-Version: SpamAssassin 2.53 (1.174.2.15-2003-03-30-exp)

	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.

diff -urN B4-imajor/drivers/block/genhd.c B4-bd_part/drivers/block/genhd.c
--- B4-imajor/drivers/block/genhd.c	Tue Aug 26 20:17:22 2003
+++ B4-bd_part/drivers/block/genhd.c	Tue Aug 26 19:06:15 2003
@@ -576,13 +576,10 @@
 
 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 @@
 
 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 -urN B4-imajor/drivers/block/ioctl.c B4-bd_part/drivers/block/ioctl.c
--- B4-imajor/drivers/block/ioctl.c	Tue Aug 26 20:17:22 2003
+++ B4-bd_part/drivers/block/ioctl.c	Tue Aug 26 19:06:15 2003
@@ -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 @@
 					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 @@
 				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 @@
 			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 -urN B4-imajor/drivers/block/ll_rw_blk.c B4-bd_part/drivers/block/ll_rw_blk.c
--- B4-imajor/drivers/block/ll_rw_blk.c	Tue Aug 26 20:17:22 2003
+++ B4-bd_part/drivers/block/ll_rw_blk.c	Tue Aug 26 19:06:15 2003
@@ -2043,24 +2043,23 @@
 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 -urN B4-imajor/fs/block_dev.c B4-bd_part/fs/block_dev.c
--- B4-imajor/fs/block_dev.c	Tue Aug 26 20:17:22 2003
+++ B4-bd_part/fs/block_dev.c	Tue Aug 26 19:06:15 2003
@@ -540,7 +540,6 @@
 				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 @@
 				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 @@
 		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 -urN B4-imajor/fs/partitions/check.c B4-bd_part/fs/partitions/check.c
--- B4-imajor/fs/partitions/check.c	Tue Aug 26 20:17:22 2003
+++ B4-bd_part/fs/partitions/check.c	Tue Aug 26 19:06:15 2003
@@ -267,7 +267,14 @@
 
 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 @@
 		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 @@
 	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 @@
 	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 -urN B4-imajor/include/linux/fs.h B4-bd_part/include/linux/fs.h
--- B4-imajor/include/linux/fs.h	Tue Aug 26 20:17:22 2003
+++ B4-bd_part/include/linux/fs.h	Tue Aug 26 19:06:15 2003
@@ -345,7 +345,7 @@
 	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 -urN B4-imajor/include/linux/genhd.h B4-bd_part/include/linux/genhd.h
--- B4-imajor/include/linux/genhd.h	Tue Aug 26 20:17:22 2003
+++ B4-bd_part/include/linux/genhd.h	Tue Aug 26 19:06:15 2003
@@ -197,7 +197,7 @@
 
 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)
 {