Lock the filesystem while a device is suspended. [Kevin Corry, Joe Thornber] --- diff/drivers/md/dm.c 2004-03-01 15:43:26.000000000 +0000 +++ source/drivers/md/dm.c 2004-03-01 15:43:43.000000000 +0000 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,7 @@ struct target_io { */ #define DMF_BLOCK_IO 0 #define DMF_SUSPENDED 1 +#define DMF_FS_LOCKED 2 struct mapped_device { struct rw_semaphore lock; @@ -840,6 +842,46 @@ int dm_swap_table(struct mapped_device * } /* + * Functions to lock and unlock any filesystem running on the + * device. + */ +static int __lock_fs(struct mapped_device *md) +{ + struct block_device *bdev; + + if (test_and_set_bit(DMF_FS_LOCKED, &md->flags)) + return 0; + + bdev = bdget_disk(md->disk, 0); + if (!bdev) { + DMWARN("bdget failed in __lock_fs"); + return -ENOMEM; + } + + fsync_bdev_lockfs(bdev); + bdput(bdev); + return 0; +} + +static int __unlock_fs(struct mapped_device *md) +{ + struct block_device *bdev; + + if (!test_and_clear_bit(DMF_FS_LOCKED, &md->flags)) + return 0; + + bdev = bdget_disk(md->disk, 0); + if (!bdev) { + DMWARN("bdget failed in __unlock_fs"); + return -ENOMEM; + } + + unlockfs(bdev); + bdput(bdev); + return 0; +} + +/* * We need to be able to change a mapping table under a mounted * filesystem. For example we might want to move some data in * the background. Before the table can be swapped with @@ -850,13 +892,27 @@ int dm_suspend(struct mapped_device *md) { DECLARE_WAITQUEUE(wait, current); - down_write(&md->lock); + /* Flush I/O to the device. */ + down_read(&md->lock); + if (test_bit(DMF_BLOCK_IO, &md->flags)) { + up_read(&md->lock); + return -EINVAL; + } + + __lock_fs(md); + up_read(&md->lock); /* * First we set the BLOCK_IO flag so no more ios will be * mapped. */ + down_write(&md->lock); if (test_bit(DMF_BLOCK_IO, &md->flags)) { + /* + * If we get here we know another thread is + * trying to suspend as well, so we leave the fs + * locked for this thread. + */ up_write(&md->lock); return -EINVAL; } @@ -885,6 +941,7 @@ int dm_suspend(struct mapped_device *md) /* were we interrupted ? */ if (atomic_read(&md->pending)) { + __unlock_fs(md); clear_bit(DMF_BLOCK_IO, &md->flags); up_write(&md->lock); return -EINTR; @@ -918,6 +975,7 @@ int dm_resume(struct mapped_device *md) __flush_deferred_io(md, def); up_write(&md->lock); + __unlock_fs(md); blk_run_queues(); return 0;