diff options
author | Joseph Qi <joseph.qi@huawei.com> | 2015-06-24 19:54:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-24 20:49:39 -0400 |
commit | cf1776a9e834400ed8e2fea48ffa6daa9da28446 (patch) | |
tree | b1612f8a870a1305cf32cc339119a68635091e6e | |
parent | e327284abb8aee3206cef3b790a283fea213a174 (diff) |
ocfs2: fix a tiny race when truncate dio orohaned entry
Once dio crashed it will leave an entry in orphan dir. And orphan scan
will take care of the clean up. There is a tiny race case that the same
entry will be truncated twice and then trigger the BUG in
ocfs2_del_inode_from_orphan.
Signed-off-by: Joseph Qi <joseph.qi@huawei.com>
Cc: Mark Fasheh <mfasheh@suse.com>
Cc: Joel Becker <jlbec@evilplan.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/ocfs2/aops.c | 12 | ||||
-rw-r--r-- | fs/ocfs2/journal.c | 47 | ||||
-rw-r--r-- | fs/ocfs2/namei.c | 22 | ||||
-rw-r--r-- | fs/ocfs2/namei.h | 4 |
4 files changed, 39 insertions, 46 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index f906a250da6a..395f4b356baa 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -925,13 +925,23 @@ clean_orphan: | |||
925 | int update_isize = written > 0 ? 1 : 0; | 925 | int update_isize = written > 0 ? 1 : 0; |
926 | loff_t end = update_isize ? offset + written : 0; | 926 | loff_t end = update_isize ? offset + written : 0; |
927 | 927 | ||
928 | tmp_ret = ocfs2_del_inode_from_orphan(osb, inode, | 928 | tmp_ret = ocfs2_inode_lock(inode, &di_bh, 1); |
929 | if (tmp_ret < 0) { | ||
930 | ret = tmp_ret; | ||
931 | mlog_errno(ret); | ||
932 | goto out; | ||
933 | } | ||
934 | |||
935 | tmp_ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh, | ||
929 | update_isize, end); | 936 | update_isize, end); |
930 | if (tmp_ret < 0) { | 937 | if (tmp_ret < 0) { |
931 | ret = tmp_ret; | 938 | ret = tmp_ret; |
939 | mlog_errno(ret); | ||
932 | goto out; | 940 | goto out; |
933 | } | 941 | } |
934 | 942 | ||
943 | ocfs2_inode_unlock(inode, 1); | ||
944 | |||
935 | tmp_ret = jbd2_journal_force_commit(journal); | 945 | tmp_ret = jbd2_journal_force_commit(journal); |
936 | if (tmp_ret < 0) { | 946 | if (tmp_ret < 0) { |
937 | ret = tmp_ret; | 947 | ret = tmp_ret; |
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index ff531928269e..4205da06000d 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
@@ -2137,6 +2137,8 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, | |||
2137 | struct inode *inode = NULL; | 2137 | struct inode *inode = NULL; |
2138 | struct inode *iter; | 2138 | struct inode *iter; |
2139 | struct ocfs2_inode_info *oi; | 2139 | struct ocfs2_inode_info *oi; |
2140 | struct buffer_head *di_bh = NULL; | ||
2141 | struct ocfs2_dinode *di = NULL; | ||
2140 | 2142 | ||
2141 | trace_ocfs2_recover_orphans(slot); | 2143 | trace_ocfs2_recover_orphans(slot); |
2142 | 2144 | ||
@@ -2157,16 +2159,22 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, | |||
2157 | iter = oi->ip_next_orphan; | 2159 | iter = oi->ip_next_orphan; |
2158 | oi->ip_next_orphan = NULL; | 2160 | oi->ip_next_orphan = NULL; |
2159 | 2161 | ||
2162 | ret = ocfs2_rw_lock(inode, 1); | ||
2163 | if (ret < 0) { | ||
2164 | mlog_errno(ret); | ||
2165 | goto next; | ||
2166 | } | ||
2160 | /* | 2167 | /* |
2161 | * We need to take and drop the inode lock to | 2168 | * We need to take and drop the inode lock to |
2162 | * force read inode from disk. | 2169 | * force read inode from disk. |
2163 | */ | 2170 | */ |
2164 | ret = ocfs2_inode_lock(inode, NULL, 0); | 2171 | ret = ocfs2_inode_lock(inode, &di_bh, 1); |
2165 | if (ret) { | 2172 | if (ret) { |
2166 | mlog_errno(ret); | 2173 | mlog_errno(ret); |
2167 | goto next; | 2174 | goto unlock_rw; |
2168 | } | 2175 | } |
2169 | ocfs2_inode_unlock(inode, 0); | 2176 | |
2177 | di = (struct ocfs2_dinode *)di_bh->b_data; | ||
2170 | 2178 | ||
2171 | if (inode->i_nlink == 0) { | 2179 | if (inode->i_nlink == 0) { |
2172 | spin_lock(&oi->ip_lock); | 2180 | spin_lock(&oi->ip_lock); |
@@ -2174,43 +2182,30 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, | |||
2174 | * ocfs2_delete_inode. */ | 2182 | * ocfs2_delete_inode. */ |
2175 | oi->ip_flags |= OCFS2_INODE_MAYBE_ORPHANED; | 2183 | oi->ip_flags |= OCFS2_INODE_MAYBE_ORPHANED; |
2176 | spin_unlock(&oi->ip_lock); | 2184 | spin_unlock(&oi->ip_lock); |
2177 | } else if (orphan_reco_type == ORPHAN_NEED_TRUNCATE) { | 2185 | } else if ((orphan_reco_type == ORPHAN_NEED_TRUNCATE) && |
2178 | struct buffer_head *di_bh = NULL; | 2186 | (di->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL))) { |
2179 | |||
2180 | ret = ocfs2_rw_lock(inode, 1); | ||
2181 | if (ret) { | ||
2182 | mlog_errno(ret); | ||
2183 | goto next; | ||
2184 | } | ||
2185 | |||
2186 | ret = ocfs2_inode_lock(inode, &di_bh, 1); | ||
2187 | if (ret < 0) { | ||
2188 | ocfs2_rw_unlock(inode, 1); | ||
2189 | mlog_errno(ret); | ||
2190 | goto next; | ||
2191 | } | ||
2192 | |||
2193 | ret = ocfs2_truncate_file(inode, di_bh, | 2187 | ret = ocfs2_truncate_file(inode, di_bh, |
2194 | i_size_read(inode)); | 2188 | i_size_read(inode)); |
2195 | ocfs2_inode_unlock(inode, 1); | ||
2196 | ocfs2_rw_unlock(inode, 1); | ||
2197 | brelse(di_bh); | ||
2198 | if (ret < 0) { | 2189 | if (ret < 0) { |
2199 | if (ret != -ENOSPC) | 2190 | if (ret != -ENOSPC) |
2200 | mlog_errno(ret); | 2191 | mlog_errno(ret); |
2201 | goto next; | 2192 | goto unlock_inode; |
2202 | } | 2193 | } |
2203 | 2194 | ||
2204 | ret = ocfs2_del_inode_from_orphan(osb, inode, 0, 0); | 2195 | ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh, 0, 0); |
2205 | if (ret) | 2196 | if (ret) |
2206 | mlog_errno(ret); | 2197 | mlog_errno(ret); |
2207 | 2198 | ||
2208 | wake_up(&OCFS2_I(inode)->append_dio_wq); | 2199 | wake_up(&OCFS2_I(inode)->append_dio_wq); |
2209 | } /* else if ORPHAN_NO_NEED_TRUNCATE, do nothing */ | 2200 | } /* else if ORPHAN_NO_NEED_TRUNCATE, do nothing */ |
2210 | 2201 | unlock_inode: | |
2202 | ocfs2_inode_unlock(inode, 1); | ||
2203 | unlock_rw: | ||
2204 | ocfs2_rw_unlock(inode, 1); | ||
2211 | next: | 2205 | next: |
2212 | iput(inode); | 2206 | iput(inode); |
2213 | 2207 | brelse(di_bh); | |
2208 | di_bh = NULL; | ||
2214 | inode = iter; | 2209 | inode = iter; |
2215 | } | 2210 | } |
2216 | 2211 | ||
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 176fe6afd94e..08a7a5b70494 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -2670,30 +2670,22 @@ bail: | |||
2670 | } | 2670 | } |
2671 | 2671 | ||
2672 | int ocfs2_del_inode_from_orphan(struct ocfs2_super *osb, | 2672 | int ocfs2_del_inode_from_orphan(struct ocfs2_super *osb, |
2673 | struct inode *inode, int update_isize, | 2673 | struct inode *inode, struct buffer_head *di_bh, |
2674 | loff_t end) | 2674 | int update_isize, loff_t end) |
2675 | { | 2675 | { |
2676 | struct inode *orphan_dir_inode = NULL; | 2676 | struct inode *orphan_dir_inode = NULL; |
2677 | struct buffer_head *orphan_dir_bh = NULL; | 2677 | struct buffer_head *orphan_dir_bh = NULL; |
2678 | struct buffer_head *di_bh = NULL; | 2678 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; |
2679 | struct ocfs2_dinode *di = NULL; | ||
2680 | handle_t *handle = NULL; | 2679 | handle_t *handle = NULL; |
2681 | int status = 0; | 2680 | int status = 0; |
2682 | 2681 | ||
2683 | status = ocfs2_inode_lock(inode, &di_bh, 1); | ||
2684 | if (status < 0) { | ||
2685 | mlog_errno(status); | ||
2686 | goto bail; | ||
2687 | } | ||
2688 | di = (struct ocfs2_dinode *) di_bh->b_data; | ||
2689 | |||
2690 | orphan_dir_inode = ocfs2_get_system_file_inode(osb, | 2682 | orphan_dir_inode = ocfs2_get_system_file_inode(osb, |
2691 | ORPHAN_DIR_SYSTEM_INODE, | 2683 | ORPHAN_DIR_SYSTEM_INODE, |
2692 | le16_to_cpu(di->i_dio_orphaned_slot)); | 2684 | le16_to_cpu(di->i_dio_orphaned_slot)); |
2693 | if (!orphan_dir_inode) { | 2685 | if (!orphan_dir_inode) { |
2694 | status = -ENOENT; | 2686 | status = -ENOENT; |
2695 | mlog_errno(status); | 2687 | mlog_errno(status); |
2696 | goto bail_unlock_inode; | 2688 | goto bail; |
2697 | } | 2689 | } |
2698 | 2690 | ||
2699 | mutex_lock(&orphan_dir_inode->i_mutex); | 2691 | mutex_lock(&orphan_dir_inode->i_mutex); |
@@ -2702,7 +2694,7 @@ int ocfs2_del_inode_from_orphan(struct ocfs2_super *osb, | |||
2702 | mutex_unlock(&orphan_dir_inode->i_mutex); | 2694 | mutex_unlock(&orphan_dir_inode->i_mutex); |
2703 | iput(orphan_dir_inode); | 2695 | iput(orphan_dir_inode); |
2704 | mlog_errno(status); | 2696 | mlog_errno(status); |
2705 | goto bail_unlock_inode; | 2697 | goto bail; |
2706 | } | 2698 | } |
2707 | 2699 | ||
2708 | handle = ocfs2_start_trans(osb, | 2700 | handle = ocfs2_start_trans(osb, |
@@ -2749,10 +2741,6 @@ bail_unlock_orphan: | |||
2749 | brelse(orphan_dir_bh); | 2741 | brelse(orphan_dir_bh); |
2750 | iput(orphan_dir_inode); | 2742 | iput(orphan_dir_inode); |
2751 | 2743 | ||
2752 | bail_unlock_inode: | ||
2753 | ocfs2_inode_unlock(inode, 1); | ||
2754 | brelse(di_bh); | ||
2755 | |||
2756 | bail: | 2744 | bail: |
2757 | return status; | 2745 | return status; |
2758 | } | 2746 | } |
diff --git a/fs/ocfs2/namei.h b/fs/ocfs2/namei.h index 5ddecce172fa..e173329eb830 100644 --- a/fs/ocfs2/namei.h +++ b/fs/ocfs2/namei.h | |||
@@ -42,8 +42,8 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, | |||
42 | int ocfs2_add_inode_to_orphan(struct ocfs2_super *osb, | 42 | int ocfs2_add_inode_to_orphan(struct ocfs2_super *osb, |
43 | struct inode *inode); | 43 | struct inode *inode); |
44 | int ocfs2_del_inode_from_orphan(struct ocfs2_super *osb, | 44 | int ocfs2_del_inode_from_orphan(struct ocfs2_super *osb, |
45 | struct inode *inode, int update_isize, | 45 | struct inode *inode, struct buffer_head *di_bh, |
46 | loff_t end); | 46 | int update_isize, loff_t end); |
47 | int ocfs2_mv_orphaned_inode_to_new(struct inode *dir, | 47 | int ocfs2_mv_orphaned_inode_to_new(struct inode *dir, |
48 | struct inode *new_inode, | 48 | struct inode *new_inode, |
49 | struct dentry *new_dentry); | 49 | struct dentry *new_dentry); |