diff options
| author | Alexander Viro <viro@math.psu.edu> | 2002-08-10 02:22:02 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@penguin.transmeta.com> | 2002-08-10 02:22:02 -0700 |
| commit | 951f4be9c9bab97236c84734e892ee4d379c68af (patch) | |
| tree | ed6b6027d4b4c5c8933bb1f91b4f0771154fa225 /include/linux/blkdev.h | |
| parent | 9804df6ca4f1a9fe9e1045801ceec383a3aaf0ad (diff) | |
[PATCH] fix check_disk_change() deadlocks
Small, but tricky: fix for check_disk_change() deadlocks.
What we do is
a) opening block device shifted from check_partition() to
grok_partitions(); check_partitions() takes opened
struct block_device.
b) all callers of check_disk_change() fall in two groups -
ones that are called only from some ->open() and ones
that are _never_ called from ->open(). There is no
middle ground. We split the thing in two functions -
check_disk_change() for the first class and full_check_....
for the second. The former (ones inside ->open()) doesn't
touch partition tables but marks the bdev as "had been
invalidated". In the end of do_open() we check if
bdev is marked and call wipe_partitions()/check_partition()
if it is - at that point bdev is fully set up and ready.
c) ->bd_part_sem kludge is gone - we use ->bd_sem instead.
That is, do_open() on a partition grabs ->bd_sem on entire
disk and picks partition data while under it; do_open() on
entire disk rereads partition if needed before dropping
->bd_sem (right before dropping it); BLKRRPART does
trylock on ->bd_sem and then checks ->bd_part_count -
same logics as before, except that we use ->bd_sem instead
of ->bd_part_sem.
That kills recursive open(), gives us the same exclusion rules as
we had and makes sure that actual IO (including rereading partition
tables) is done only when we are ready to do it.
It actually sounds a lot nastier than it is. do_open() is a one sick
puppy right now, but we have everything in one place and _out_ of drivers
(and 20-odd equally sick puppies are gone from them, along with about
the same number of races).
Now we are almost ready to clean it up for good - all that remains to
do before that is to get the rest of drivers (cciss, DAC960, i2o and
a couple of ancients - xd and acsi) using per-disk gendisks. Then
most of that crap will disappear.
BTW, the only generic ioctl remaining in the drivers is HDIO_GETGEO -
a lot of foo_ioctl() starts with if (cmd != HDIO_GETGEO) return -EINVAL; ;-)
Diffstat (limited to 'include/linux/blkdev.h')
| -rw-r--r-- | include/linux/blkdev.h | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index f83c52f82ab0..d0a89877ad94 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -279,6 +279,7 @@ extern struct blk_dev_struct blk_dev[MAX_BLKDEV]; extern void grok_partitions(kdev_t dev, long size); extern int wipe_partitions(kdev_t dev); extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size); +extern void check_partition(struct gendisk *disk, struct block_device *bdev); extern void generic_make_request(struct bio *bio); extern inline request_queue_t *bdev_get_queue(struct block_device *bdev); extern void blk_put_request(struct request *); |
