aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ocfs2/inode.c')
-rw-r--r--fs/ocfs2/inode.c52
1 files changed, 48 insertions, 4 deletions
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index d4ecc0627716..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 */
554static 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]++;
569out:
570 spin_unlock(&osb->osb_lock);
571 return ret;
572}
573
574static 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
547static int ocfs2_wipe_inode(struct inode *inode, 584static 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);
598bail: 640bail:
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
@@ -903,10 +947,10 @@ void ocfs2_clear_inode(struct inode *inode)
903 "Clear inode of %"MLFu64", inode is locked\n", 947 "Clear inode of %"MLFu64", inode is locked\n",
904 oi->ip_blkno); 948 oi->ip_blkno);
905 949
906 mlog_bug_on_msg(down_trylock(&oi->ip_io_sem), 950 mlog_bug_on_msg(!mutex_trylock(&oi->ip_io_mutex),
907 "Clear inode of %"MLFu64", io_sem is locked\n", 951 "Clear inode of %"MLFu64", io_mutex is locked\n",
908 oi->ip_blkno); 952 oi->ip_blkno);
909 up(&oi->ip_io_sem); 953 mutex_unlock(&oi->ip_io_mutex);
910 954
911 /* 955 /*
912 * down_trylock() returns 0, down_write_trylock() returns 1 956 * down_trylock() returns 0, down_write_trylock() returns 1