[PATCH] - and RFC - O_EXCL for block devices

Neil Brown (neilb@cse.unsw.edu.au)
Wed, 12 Jun 2002 20:05:46 +1000 (EST)


fs/block_dev.c contains bd_claim and bd_release that can be used to
provide exclusive access to block devices.
This is currently used when mounting a filesystem from a block device,
when enabling swap to a block device, and when incorporating a block
device into an md/raid array.

This patch
- enhances bd_claim to claim the whole block device when a partition
is claimed and
- (possibly more contravertially) defines open(.., O_EXCL) on a
block device to bd_claim that device for that file. This makes
it trivial for applications like mkfs and fsck to check if a
device is mounted, but does not stop them from accessing the
device that is mounted.

SUS says that open with O_EXCL but without O_CREAT is undefined,
so this doesn't break SUS compliance.

Other places where bd_claim should be used:

LVM
loop

but I'll leave those for others to fix.

NeilBrown

(patch against 2.5.21 ... actually cset 1.474)

### Comments for ChangeSet
Extension to block device claiming

1/ when a partition is claimed, claim the whole device for partitioning
2/ when a blockdev is opened O_EXCL, claim for that file.

----------- Diffstat output ------------
block_dev.c | 38 ++++++++++++++++++++++++++++++++++----
1 files changed, 34 insertions(+), 4 deletions(-)

--- ./fs/block_dev.c 2002/06/12 06:20:49 1.1
+++ ./fs/block_dev.c 2002/06/12 09:57:41
@@ -376,15 +376,34 @@
spin_unlock(&bdev_lock);
}

-int bd_claim(struct block_device *bdev, void *holder)
+static int __bd_claim(struct block_device *bdev, void *holder)
{
int res = -EBUSY;
- spin_lock(&bdev_lock);
if (!bdev->bd_holder || bdev->bd_holder == holder) {
bdev->bd_holder = holder;
bdev->bd_holders++;
res = 0;
}
+ return res;
+}
+
+static void __bd_release(struct block_device *bdev)
+{
+ if (!--bdev->bd_holders)
+ bdev->bd_holder = NULL;
+}
+
+int bd_claim(struct block_device *bdev, void *holder)
+{
+ int res = 0;
+ spin_lock(&bdev_lock);
+ if (bdev->bd_contains != bdev)
+ res = __bd_claim(bdev->bd_contains, bd_claim);
+ if (!res) {
+ res = __bd_claim(bdev, holder);
+ if (res && bdev->bd_contains != bdev)
+ __bd_release(bdev->bd_contains);
+ }
spin_unlock(&bdev_lock);
return res;
}
@@ -392,8 +411,9 @@
void bd_release(struct block_device *bdev)
{
spin_lock(&bdev_lock);
- if (!--bdev->bd_holders)
- bdev->bd_holder = NULL;
+ if (bdev->bd_contains != bdev)
+ __bd_release(bdev->bd_contains);
+ __bd_release(bdev);
spin_unlock(&bdev_lock);
}

@@ -653,6 +673,14 @@
bd_acquire(inode);
bdev = inode->i_bdev;

+ if (filp->f_flags & O_EXCL) {
+ int res = bd_claim(bdev, filp);
+ if (res) {
+ bdput(bdev);
+ return res;
+ }
+ }
+
return do_open(bdev, inode, filp);
}

@@ -692,6 +720,8 @@

int blkdev_close(struct inode * inode, struct file * filp)
{
+ if (inode->i_bdev->bd_holder == filp)
+ bd_release(inode->i_bdev);
return blkdev_put(inode->i_bdev, BDEV_FILE);
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/