diff options
author | Joseph Qi <joseph.qi@huawei.com> | 2015-02-16 19:00:12 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-16 20:56:05 -0500 |
commit | 4813962beef7586f890a645a1bda77691da4b74a (patch) | |
tree | 75885da49ee8bc539aa41c6af8395a4f88c2a7d9 /fs | |
parent | 3a83b342c87e6d21290de8dc76ec20a67821261d (diff) |
ocfs2: wait for orphan recovery first once append O_DIRECT write crash
If one node has crashed with orphan entry leftover, another node which do
append O_DIRECT write to the same file will override the
i_dio_orphaned_slot. Then the old entry won't be cleaned forever. If
this case happens, we let it wait for orphan recovery first.
Signed-off-by: Joseph Qi <joseph.qi@huawei.com>
Cc: Weiwei Wang <wangww631@huawei.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Xuejiufei <xuejiufei@huawei.com>
Cc: alex chen <alex.chen@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/inode.h | 2 | ||||
-rw-r--r-- | fs/ocfs2/journal.c | 2 | ||||
-rw-r--r-- | fs/ocfs2/namei.c | 37 | ||||
-rw-r--r-- | fs/ocfs2/super.c | 2 |
4 files changed, 43 insertions, 0 deletions
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h index ca3431ee7f24..5e86b247c821 100644 --- a/fs/ocfs2/inode.h +++ b/fs/ocfs2/inode.h | |||
@@ -81,6 +81,8 @@ struct ocfs2_inode_info | |||
81 | tid_t i_sync_tid; | 81 | tid_t i_sync_tid; |
82 | tid_t i_datasync_tid; | 82 | tid_t i_datasync_tid; |
83 | 83 | ||
84 | wait_queue_head_t append_dio_wq; | ||
85 | |||
84 | struct dquot *i_dquot[MAXQUOTAS]; | 86 | struct dquot *i_dquot[MAXQUOTAS]; |
85 | }; | 87 | }; |
86 | 88 | ||
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 9730f5350ef4..ff531928269e 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
@@ -2204,6 +2204,8 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, | |||
2204 | ret = ocfs2_del_inode_from_orphan(osb, inode, 0, 0); | 2204 | ret = ocfs2_del_inode_from_orphan(osb, inode, 0, 0); |
2205 | if (ret) | 2205 | if (ret) |
2206 | mlog_errno(ret); | 2206 | mlog_errno(ret); |
2207 | |||
2208 | wake_up(&OCFS2_I(inode)->append_dio_wq); | ||
2207 | } /* else if ORPHAN_NO_NEED_TRUNCATE, do nothing */ | 2209 | } /* else if ORPHAN_NO_NEED_TRUNCATE, do nothing */ |
2208 | 2210 | ||
2209 | next: | 2211 | next: |
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 7eec45d0d85f..b5c3a5ea3ee6 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -2577,6 +2577,27 @@ leave: | |||
2577 | return status; | 2577 | return status; |
2578 | } | 2578 | } |
2579 | 2579 | ||
2580 | static int ocfs2_dio_orphan_recovered(struct inode *inode) | ||
2581 | { | ||
2582 | int ret; | ||
2583 | struct buffer_head *di_bh = NULL; | ||
2584 | struct ocfs2_dinode *di = NULL; | ||
2585 | |||
2586 | ret = ocfs2_inode_lock(inode, &di_bh, 1); | ||
2587 | if (ret < 0) { | ||
2588 | mlog_errno(ret); | ||
2589 | return 0; | ||
2590 | } | ||
2591 | |||
2592 | di = (struct ocfs2_dinode *) di_bh->b_data; | ||
2593 | ret = !(di->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL)); | ||
2594 | ocfs2_inode_unlock(inode, 1); | ||
2595 | brelse(di_bh); | ||
2596 | |||
2597 | return ret; | ||
2598 | } | ||
2599 | |||
2600 | #define OCFS2_DIO_ORPHANED_FL_CHECK_INTERVAL 10000 | ||
2580 | int ocfs2_add_inode_to_orphan(struct ocfs2_super *osb, | 2601 | int ocfs2_add_inode_to_orphan(struct ocfs2_super *osb, |
2581 | struct inode *inode) | 2602 | struct inode *inode) |
2582 | { | 2603 | { |
@@ -2586,13 +2607,29 @@ int ocfs2_add_inode_to_orphan(struct ocfs2_super *osb, | |||
2586 | struct buffer_head *di_bh = NULL; | 2607 | struct buffer_head *di_bh = NULL; |
2587 | int status = 0; | 2608 | int status = 0; |
2588 | handle_t *handle = NULL; | 2609 | handle_t *handle = NULL; |
2610 | struct ocfs2_dinode *di = NULL; | ||
2589 | 2611 | ||
2612 | restart: | ||
2590 | status = ocfs2_inode_lock(inode, &di_bh, 1); | 2613 | status = ocfs2_inode_lock(inode, &di_bh, 1); |
2591 | if (status < 0) { | 2614 | if (status < 0) { |
2592 | mlog_errno(status); | 2615 | mlog_errno(status); |
2593 | goto bail; | 2616 | goto bail; |
2594 | } | 2617 | } |
2595 | 2618 | ||
2619 | di = (struct ocfs2_dinode *) di_bh->b_data; | ||
2620 | /* | ||
2621 | * Another append dio crashed? | ||
2622 | * If so, wait for recovery first. | ||
2623 | */ | ||
2624 | if (unlikely(di->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL))) { | ||
2625 | ocfs2_inode_unlock(inode, 1); | ||
2626 | brelse(di_bh); | ||
2627 | wait_event_interruptible_timeout(OCFS2_I(inode)->append_dio_wq, | ||
2628 | ocfs2_dio_orphan_recovered(inode), | ||
2629 | msecs_to_jiffies(OCFS2_DIO_ORPHANED_FL_CHECK_INTERVAL)); | ||
2630 | goto restart; | ||
2631 | } | ||
2632 | |||
2596 | status = ocfs2_prepare_orphan_dir(osb, &orphan_dir_inode, | 2633 | status = ocfs2_prepare_orphan_dir(osb, &orphan_dir_inode, |
2597 | OCFS2_I(inode)->ip_blkno, | 2634 | OCFS2_I(inode)->ip_blkno, |
2598 | orphan_name, | 2635 | orphan_name, |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 87a1f7679d9b..26675185b886 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -1746,6 +1746,8 @@ static void ocfs2_inode_init_once(void *data) | |||
1746 | ocfs2_lock_res_init_once(&oi->ip_inode_lockres); | 1746 | ocfs2_lock_res_init_once(&oi->ip_inode_lockres); |
1747 | ocfs2_lock_res_init_once(&oi->ip_open_lockres); | 1747 | ocfs2_lock_res_init_once(&oi->ip_open_lockres); |
1748 | 1748 | ||
1749 | init_waitqueue_head(&oi->append_dio_wq); | ||
1750 | |||
1749 | ocfs2_metadata_cache_init(INODE_CACHE(&oi->vfs_inode), | 1751 | ocfs2_metadata_cache_init(INODE_CACHE(&oi->vfs_inode), |
1750 | &ocfs2_inode_caching_ops); | 1752 | &ocfs2_inode_caching_ops); |
1751 | 1753 | ||