Index: linux-2.6.27.21-0.1/block/blk-core.c =================================================================== --- linux-2.6.27.21-0.1.orig/block/blk-core.c 2009-04-23 02:12:51.000000000 -0600 +++ linux-2.6.27.21-0.1/block/blk-core.c 2009-05-22 08:38:02.000000000 -0600 @@ -1335,6 +1335,8 @@ #endif /* CONFIG_FAIL_MAKE_REQUEST */ +int dev_check_rdonly(struct block_device *bdev); + /* * Check whether this bio extends beyond the end of the device. */ @@ -1436,6 +1438,12 @@ if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) goto end_io; + /* this is cfs's dev_rdonly check */ + if (bio_rw(bio) == WRITE && dev_check_rdonly(bio->bi_bdev)) { + bio_endio(bio, bio->bi_size, 0); + break; + } + if (should_fail_request(bio)) goto end_io; @@ -2189,6 +2197,91 @@ } EXPORT_SYMBOL(kblockd_flush_work); + /* + * Debug code for turning block devices "read-only" (will discard writes + * silently). This is for filesystem crash/recovery testing. + */ +struct deventry { + dev_t dev; + struct deventry *next; +}; + +static struct deventry *devlist = NULL; +static spinlock_t devlock = SPIN_LOCK_UNLOCKED; + +int dev_check_rdonly(struct block_device *bdev) +{ + struct deventry *cur; + if (!bdev) return 0; + spin_lock(&devlock); + cur = devlist; + while(cur) { + if (bdev->bd_dev == cur->dev) { + spin_unlock(&devlock); + return 1; + } + cur = cur->next; + } + spin_unlock(&devlock); + return 0; +} + +void dev_set_rdonly(struct block_device *bdev) +{ + struct deventry *newdev, *cur; + + if (!bdev) + return; + newdev = kmalloc(sizeof(struct deventry), GFP_KERNEL); + if (!newdev) + return; + + spin_lock(&devlock); + cur = devlist; + while(cur) { + if (bdev->bd_dev == cur->dev) { + spin_unlock(&devlock); + kfree(newdev); + return; + } + cur = cur->next; + } + newdev->dev = bdev->bd_dev; + newdev->next = devlist; + devlist = newdev; + spin_unlock(&devlock); + printk(KERN_WARNING "Turning device %s (%#x) read-only\n", + bdev->bd_disk ? bdev->bd_disk->disk_name : "", bdev->bd_dev); +} + +void dev_clear_rdonly(struct block_device *bdev) +{ + struct deventry *cur, *last = NULL; + if (!bdev) return; + spin_lock(&devlock); + cur = devlist; + while(cur) { + if (bdev->bd_dev == cur->dev) { + if (last) + last->next = cur->next; + else + devlist = cur->next; + spin_unlock(&devlock); + kfree(cur); + printk(KERN_WARNING "Removing read-only on %s (%#x)\n", + bdev->bd_disk ? bdev->bd_disk->disk_name : + "unknown block", bdev->bd_dev); + return; + } + last = cur; + cur = cur->next; + } + spin_unlock(&devlock); +} + +EXPORT_SYMBOL(dev_set_rdonly); +EXPORT_SYMBOL(dev_clear_rdonly); +EXPORT_SYMBOL(dev_check_rdonly); int __init blk_dev_init(void) { kblockd_workqueue = create_workqueue("kblockd"); Index: linux-2.6.27.21-0.1/fs/block_dev.c =================================================================== --- linux-2.6.27.21-0.1.orig/fs/block_dev.c 2009-04-23 02:12:56.000000000 -0600 +++ linux-2.6.27.21-0.1/fs/block_dev.c 2009-05-22 08:38:02.000000000 -0600 @@ -1208,6 +1208,7 @@ if (bdev != bdev->bd_contains) victim = bdev->bd_contains; bdev->bd_contains = NULL; + dev_clear_rdonly(bdev); } unlock_kernel(); mutex_unlock(&bdev->bd_mutex); Index: linux-2.6.27.21-0.1/include/linux/fs.h =================================================================== --- linux-2.6.27.21-0.1.orig/include/linux/fs.h 2009-05-22 08:38:00.000000000 -0600 +++ linux-2.6.27.21-0.1/include/linux/fs.h 2009-05-22 08:38:02.000000000 -0600 @@ -1898,6 +1898,10 @@ extern void submit_bio(int, struct bio *); extern int bdev_read_only(struct block_device *); #endif +#define HAVE_CLEAR_RDONLY_ON_PUT +extern void dev_set_rdonly(struct block_device *bdev); +extern int dev_check_rdonly(struct block_device *bdev); +extern void dev_clear_rdonly(struct block_device *bdev); extern int set_blocksize(struct block_device *, int); extern int sb_set_blocksize(struct super_block *, int); extern int sb_min_blocksize(struct super_block *, int);