[dm-devel] [PATCH] handle failures in __lock_fs
Christoph Hellwig
hch at lst.de
Thu Feb 10 21:45:11 UTC 2005
I have a patch pending that allows freeze_bdev to return errors.
To handle that in DM __lock_fs need to properly unwind and it's caller
must not ignore the return value. Detailed changelog:
- add a new member frozen_bdev to struct mapped_device to store the
frozen block device instead of needing a second bdget_disk in
__unlock_fs
- handle the possibility of freeze_bdev returning an error
- properly unwind all state in __lockfs in case of failure
- check __unlock_fs return value to void because it doesn't return a
useful value
- use gotos to properly unwind in dm_suspend
- handle __lock_fs error return
- use test_and_set_bit for DMF_BLOCK_IO
Question: how does dm_table_presuspend_targets need to be undone?
--- 1.62/drivers/md/dm.c 2005-02-03 16:16:04 +01:00
+++ edited/drivers/md/dm.c 2005-02-10 22:45:38 +01:00
@@ -90,6 +90,7 @@ struct mapped_device {
* freeze/thaw support require holding onto a super block
*/
struct super_block *frozen_sb;
+ struct block_device *frozen_bdev;
};
#define MIN_IOS 256
@@ -975,44 +976,43 @@ int dm_swap_table(struct mapped_device *
*/
static int __lock_fs(struct mapped_device *md)
{
- struct block_device *bdev;
+ int error = -ENOMEM;
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;
- }
+ md->frozen_bdev = bdget_disk(md->disk, 0);
+ if (!md->frozen_bdev)
+ goto out;
WARN_ON(md->frozen_sb);
- md->frozen_sb = freeze_bdev(bdev);
+ md->frozen_sb = freeze_bdev(md->frozen_bdev);
+ if (IS_ERR(md->frozen_sb)) {
+ error = PTR_ERR(md->frozen_sb);
+ goto out_bdput;
+ }
+
/* don't bdput right now, we don't want the bdev
* to go away while it is locked. We'll bdput
* in __unlock_fs
*/
return 0;
+
+ out_bdput:
+ bdput(md->frozen_bdev);
+ out:
+ clear_bit(DMF_FS_LOCKED, &md->flags);
+ md->frozen_sb = NULL;
+ return error;
}
-static int __unlock_fs(struct mapped_device *md)
+static void __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;
+ if (test_and_clear_bit(DMF_FS_LOCKED, &md->flags)) {
+ thaw_bdev(md->frozen_bdev, md->frozen_sb);
+ bdput(md->frozen_bdev);
+ md->frozen_sb = NULL;
}
-
- thaw_bdev(bdev, md->frozen_sb);
- md->frozen_sb = NULL;
- bdput(bdev);
- bdput(bdev);
- return 0;
}
/*
@@ -1026,37 +1026,41 @@ int dm_suspend(struct mapped_device *md)
{
struct dm_table *map;
DECLARE_WAITQUEUE(wait, current);
+ int error = -EINVAL;
/* Flush I/O to the device. */
down_read(&md->lock);
- if (test_bit(DMF_BLOCK_IO, &md->flags)) {
- up_read(&md->lock);
- return -EINVAL;
- }
+ if (test_bit(DMF_BLOCK_IO, &md->flags))
+ goto out_read_unlock;
map = dm_get_table(md);
if (map)
dm_table_presuspend_targets(map);
- __lock_fs(md);
+
+ error = __lock_fs(md);
+ if (error) {
+ /* XXX(hch): no need to undo dm_table_presuspend_targets? */
+ if (map)
+ dm_table_put(map);
+ goto out_read_unlock;
+ }
up_read(&md->lock);
/*
- * First we set the BLOCK_IO flag so no more ios will be
- * mapped.
+ * First we set the BLOCK_IO flag so no more ios will be mapped.
+ *
+ * If the flag is already set we know another thread is trying to
+ * suspend as well, so we leave the fs locked for this thread.
*/
+ error = -EINVAL;
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;
+ if (test_and_set_bit(DMF_BLOCK_IO, &md->flags)) {
+ if (map)
+ dm_table_put(map);
+ goto out_write_unlock;
}
- set_bit(DMF_BLOCK_IO, &md->flags);
add_wait_queue(&md->wait, &wait);
up_write(&md->lock);
@@ -1084,12 +1088,9 @@ int dm_suspend(struct mapped_device *md)
remove_wait_queue(&md->wait, &wait);
/* were we interrupted ? */
- if (atomic_read(&md->pending)) {
- __unlock_fs(md);
- clear_bit(DMF_BLOCK_IO, &md->flags);
- up_write(&md->lock);
- return -EINTR;
- }
+ error = -EINTR;
+ if (atomic_read(&md->pending))
+ goto out_unfreeze;
set_bit(DMF_SUSPENDED, &md->flags);
@@ -1100,6 +1101,16 @@ int dm_suspend(struct mapped_device *md)
up_write(&md->lock);
return 0;
+
+ out_unfreeze:
+ __unlock_fs(md);
+ clear_bit(DMF_BLOCK_IO, &md->flags);
+ out_write_unlock:
+ up_write(&md->lock);
+ return error;
+ out_read_unlock:
+ up_read(&md->lock);
+ return error;
}
int dm_resume(struct mapped_device *md)
More information about the dm-devel
mailing list