diff options
author | Mark Fasheh <mark.fasheh@oracle.com> | 2006-02-22 20:35:08 -0500 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2006-03-01 14:32:41 -0500 |
commit | b4df6ed8db0c387d38292e31f00adc4cd297ed5a (patch) | |
tree | d7dcaeecfa55b3fd9d6c4844d90e07759182f845 /fs/ocfs2/inode.c | |
parent | 895928b8380cc697ac56e9732cedf549c0a4f79c (diff) |
[PATCH] ocfs2: fix orphan recovery deadlock
Orphan dir recovery can deadlock with another process in
ocfs2_delete_inode() in some corner cases. Fix this by tracking recovery
state more closely and allowing it to handle inode wipes which might
deadlock.
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Diffstat (limited to 'fs/ocfs2/inode.c')
-rw-r--r-- | fs/ocfs2/inode.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 8122489c5762..315472a5c192 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include "dlmglue.h" | 41 | #include "dlmglue.h" |
42 | #include "extent_map.h" | 42 | #include "extent_map.h" |
43 | #include "file.h" | 43 | #include "file.h" |
44 | #include "heartbeat.h" | ||
44 | #include "inode.h" | 45 | #include "inode.h" |
45 | #include "journal.h" | 46 | #include "journal.h" |
46 | #include "namei.h" | 47 | #include "namei.h" |
@@ -544,6 +545,42 @@ bail: | |||
544 | return status; | 545 | return status; |
545 | } | 546 | } |
546 | 547 | ||
548 | /* | ||
549 | * Serialize with orphan dir recovery. If the process doing | ||
550 | * recovery on this orphan dir does an iget() with the dir | ||
551 | * i_mutex held, we'll deadlock here. Instead we detect this | ||
552 | * and exit early - recovery will wipe this inode for us. | ||
553 | */ | ||
554 | static int ocfs2_check_orphan_recovery_state(struct ocfs2_super *osb, | ||
555 | int slot) | ||
556 | { | ||
557 | int ret = 0; | ||
558 | |||
559 | spin_lock(&osb->osb_lock); | ||
560 | if (ocfs2_node_map_test_bit(osb, &osb->osb_recovering_orphan_dirs, slot)) { | ||
561 | mlog(0, "Recovery is happening on orphan dir %d, will skip " | ||
562 | "this inode\n", slot); | ||
563 | ret = -EDEADLK; | ||
564 | goto out; | ||
565 | } | ||
566 | /* This signals to the orphan recovery process that it should | ||
567 | * wait for us to handle the wipe. */ | ||
568 | osb->osb_orphan_wipes[slot]++; | ||
569 | out: | ||
570 | spin_unlock(&osb->osb_lock); | ||
571 | return ret; | ||
572 | } | ||
573 | |||
574 | static void ocfs2_signal_wipe_completion(struct ocfs2_super *osb, | ||
575 | int slot) | ||
576 | { | ||
577 | spin_lock(&osb->osb_lock); | ||
578 | osb->osb_orphan_wipes[slot]--; | ||
579 | spin_unlock(&osb->osb_lock); | ||
580 | |||
581 | wake_up(&osb->osb_wipe_event); | ||
582 | } | ||
583 | |||
547 | static int ocfs2_wipe_inode(struct inode *inode, | 584 | static int ocfs2_wipe_inode(struct inode *inode, |
548 | struct buffer_head *di_bh) | 585 | struct buffer_head *di_bh) |
549 | { | 586 | { |
@@ -555,6 +592,11 @@ static int ocfs2_wipe_inode(struct inode *inode, | |||
555 | /* We've already voted on this so it should be readonly - no | 592 | /* We've already voted on this so it should be readonly - no |
556 | * spinlock needed. */ | 593 | * spinlock needed. */ |
557 | orphaned_slot = OCFS2_I(inode)->ip_orphaned_slot; | 594 | orphaned_slot = OCFS2_I(inode)->ip_orphaned_slot; |
595 | |||
596 | status = ocfs2_check_orphan_recovery_state(osb, orphaned_slot); | ||
597 | if (status) | ||
598 | return status; | ||
599 | |||
558 | orphan_dir_inode = ocfs2_get_system_file_inode(osb, | 600 | orphan_dir_inode = ocfs2_get_system_file_inode(osb, |
559 | ORPHAN_DIR_SYSTEM_INODE, | 601 | ORPHAN_DIR_SYSTEM_INODE, |
560 | orphaned_slot); | 602 | orphaned_slot); |
@@ -597,6 +639,7 @@ bail_unlock_dir: | |||
597 | brelse(orphan_dir_bh); | 639 | brelse(orphan_dir_bh); |
598 | bail: | 640 | bail: |
599 | iput(orphan_dir_inode); | 641 | iput(orphan_dir_inode); |
642 | ocfs2_signal_wipe_completion(osb, orphaned_slot); | ||
600 | 643 | ||
601 | return status; | 644 | return status; |
602 | } | 645 | } |
@@ -822,7 +865,8 @@ void ocfs2_delete_inode(struct inode *inode) | |||
822 | 865 | ||
823 | status = ocfs2_wipe_inode(inode, di_bh); | 866 | status = ocfs2_wipe_inode(inode, di_bh); |
824 | if (status < 0) { | 867 | if (status < 0) { |
825 | mlog_errno(status); | 868 | if (status != -EDEADLK) |
869 | mlog_errno(status); | ||
826 | goto bail_unlock_inode; | 870 | goto bail_unlock_inode; |
827 | } | 871 | } |
828 | 872 | ||