summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoseph Qi <joseph.qi@huawei.com>2015-06-24 19:54:59 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-06-24 20:49:39 -0400
commitcf1776a9e834400ed8e2fea48ffa6daa9da28446 (patch)
treeb1612f8a870a1305cf32cc339119a68635091e6e
parente327284abb8aee3206cef3b790a283fea213a174 (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.c12
-rw-r--r--fs/ocfs2/journal.c47
-rw-r--r--fs/ocfs2/namei.c22
-rw-r--r--fs/ocfs2/namei.h4
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 2201unlock_inode:
2202 ocfs2_inode_unlock(inode, 1);
2203unlock_rw:
2204 ocfs2_rw_unlock(inode, 1);
2211next: 2205next:
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
2672int ocfs2_del_inode_from_orphan(struct ocfs2_super *osb, 2672int 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
2752bail_unlock_inode:
2753 ocfs2_inode_unlock(inode, 1);
2754 brelse(di_bh);
2755
2756bail: 2744bail:
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,
42int ocfs2_add_inode_to_orphan(struct ocfs2_super *osb, 42int ocfs2_add_inode_to_orphan(struct ocfs2_super *osb,
43 struct inode *inode); 43 struct inode *inode);
44int ocfs2_del_inode_from_orphan(struct ocfs2_super *osb, 44int 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);
47int ocfs2_mv_orphaned_inode_to_new(struct inode *dir, 47int 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);