]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Tao Ma <tao.ma@oracle.com> |
2 | Subject: [PATCH] ocfs2: Resolve deadlock in ocfs2_xattr_free_block. | |
3 | Patch-mainline: 2.6.28? | |
4 | References: FATE302067 | |
5 | ||
6 | In ocfs2_xattr_free_block, we take a cluster lock on xb_alloc_inode while we | |
7 | have a transaction open. This will deadlock the downconvert thread, so fix | |
8 | it. | |
9 | ||
10 | We can clean up how xattr blocks are removed while here - this patch also | |
11 | moves the mechanism of releasing xattr block (including both value, xattr | |
12 | tree and xattr block) into this function. | |
13 | ||
14 | Signed-off-by: Tao Ma <tao.ma@oracle.com> | |
15 | Signed-off-by: Mark Fasheh <mfasheh@suse.com> | |
16 | --- | |
17 | fs/ocfs2/xattr.c | 152 +++++++++++++++++++++++++++++------------------------- | |
18 | 1 files changed, 82 insertions(+), 70 deletions(-) | |
19 | ||
20 | diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c | |
21 | index ed50f9a..bbe87d0 100644 | |
22 | --- a/fs/ocfs2/xattr.c | |
23 | +++ b/fs/ocfs2/xattr.c | |
24 | @@ -1443,51 +1443,6 @@ out: | |
25 | ||
26 | } | |
27 | ||
28 | -static int ocfs2_xattr_free_block(handle_t *handle, | |
29 | - struct ocfs2_super *osb, | |
30 | - struct ocfs2_xattr_block *xb) | |
31 | -{ | |
32 | - struct inode *xb_alloc_inode; | |
33 | - struct buffer_head *xb_alloc_bh = NULL; | |
34 | - u64 blk = le64_to_cpu(xb->xb_blkno); | |
35 | - u16 bit = le16_to_cpu(xb->xb_suballoc_bit); | |
36 | - u64 bg_blkno = ocfs2_which_suballoc_group(blk, bit); | |
37 | - int ret = 0; | |
38 | - | |
39 | - xb_alloc_inode = ocfs2_get_system_file_inode(osb, | |
40 | - EXTENT_ALLOC_SYSTEM_INODE, | |
41 | - le16_to_cpu(xb->xb_suballoc_slot)); | |
42 | - if (!xb_alloc_inode) { | |
43 | - ret = -ENOMEM; | |
44 | - mlog_errno(ret); | |
45 | - goto out; | |
46 | - } | |
47 | - mutex_lock(&xb_alloc_inode->i_mutex); | |
48 | - | |
49 | - ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1); | |
50 | - if (ret < 0) { | |
51 | - mlog_errno(ret); | |
52 | - goto out_mutex; | |
53 | - } | |
54 | - ret = ocfs2_extend_trans(handle, OCFS2_SUBALLOC_FREE); | |
55 | - if (ret < 0) { | |
56 | - mlog_errno(ret); | |
57 | - goto out_unlock; | |
58 | - } | |
59 | - ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh, | |
60 | - bit, bg_blkno, 1); | |
61 | - if (ret < 0) | |
62 | - mlog_errno(ret); | |
63 | -out_unlock: | |
64 | - ocfs2_inode_unlock(xb_alloc_inode, 1); | |
65 | - brelse(xb_alloc_bh); | |
66 | -out_mutex: | |
67 | - mutex_unlock(&xb_alloc_inode->i_mutex); | |
68 | - iput(xb_alloc_inode); | |
69 | -out: | |
70 | - return ret; | |
71 | -} | |
72 | - | |
73 | static int ocfs2_remove_value_outside(struct inode*inode, | |
74 | struct buffer_head *bh, | |
75 | struct ocfs2_xattr_header *header) | |
76 | @@ -1549,6 +1504,84 @@ static int ocfs2_xattr_block_remove(struct inode *inode, | |
77 | return ret; | |
78 | } | |
79 | ||
80 | +static int ocfs2_xattr_free_block(struct inode *inode, | |
81 | + u64 block) | |
82 | +{ | |
83 | + struct inode *xb_alloc_inode; | |
84 | + struct buffer_head *xb_alloc_bh = NULL; | |
85 | + struct buffer_head *blk_bh = NULL; | |
86 | + struct ocfs2_xattr_block *xb; | |
87 | + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
88 | + handle_t *handle; | |
89 | + int ret = 0; | |
90 | + u64 blk, bg_blkno; | |
91 | + u16 bit; | |
92 | + | |
93 | + ret = ocfs2_read_block(osb, block, &blk_bh, | |
94 | + OCFS2_BH_CACHED, inode); | |
95 | + if (ret < 0) { | |
96 | + mlog_errno(ret); | |
97 | + goto out; | |
98 | + } | |
99 | + | |
100 | + /*Verify the signature of xattr block*/ | |
101 | + if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, | |
102 | + strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { | |
103 | + ret = -EFAULT; | |
104 | + goto out; | |
105 | + } | |
106 | + | |
107 | + ret = ocfs2_xattr_block_remove(inode, blk_bh); | |
108 | + if (ret < 0) { | |
109 | + mlog_errno(ret); | |
110 | + goto out; | |
111 | + } | |
112 | + | |
113 | + xb = (struct ocfs2_xattr_block *)blk_bh->b_data; | |
114 | + blk = le64_to_cpu(xb->xb_blkno); | |
115 | + bit = le16_to_cpu(xb->xb_suballoc_bit); | |
116 | + bg_blkno = ocfs2_which_suballoc_group(blk, bit); | |
117 | + | |
118 | + xb_alloc_inode = ocfs2_get_system_file_inode(osb, | |
119 | + EXTENT_ALLOC_SYSTEM_INODE, | |
120 | + le16_to_cpu(xb->xb_suballoc_slot)); | |
121 | + if (!xb_alloc_inode) { | |
122 | + ret = -ENOMEM; | |
123 | + mlog_errno(ret); | |
124 | + goto out; | |
125 | + } | |
126 | + mutex_lock(&xb_alloc_inode->i_mutex); | |
127 | + | |
128 | + ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1); | |
129 | + if (ret < 0) { | |
130 | + mlog_errno(ret); | |
131 | + goto out_mutex; | |
132 | + } | |
133 | + | |
134 | + handle = ocfs2_start_trans(osb, OCFS2_SUBALLOC_FREE); | |
135 | + if (IS_ERR(handle)) { | |
136 | + ret = PTR_ERR(handle); | |
137 | + mlog_errno(ret); | |
138 | + goto out_unlock; | |
139 | + } | |
140 | + | |
141 | + ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh, | |
142 | + bit, bg_blkno, 1); | |
143 | + if (ret < 0) | |
144 | + mlog_errno(ret); | |
145 | + | |
146 | + ocfs2_commit_trans(osb, handle); | |
147 | +out_unlock: | |
148 | + ocfs2_inode_unlock(xb_alloc_inode, 1); | |
149 | + brelse(xb_alloc_bh); | |
150 | +out_mutex: | |
151 | + mutex_unlock(&xb_alloc_inode->i_mutex); | |
152 | + iput(xb_alloc_inode); | |
153 | +out: | |
154 | + brelse(blk_bh); | |
155 | + return ret; | |
156 | +} | |
157 | + | |
158 | /* | |
159 | * ocfs2_xattr_remove() | |
160 | * | |
161 | @@ -1556,9 +1589,6 @@ static int ocfs2_xattr_block_remove(struct inode *inode, | |
162 | */ | |
163 | int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | |
164 | { | |
165 | - struct ocfs2_xattr_block *xb; | |
166 | - struct buffer_head *blk_bh = NULL; | |
167 | - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
168 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | |
169 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | |
170 | handle_t *handle; | |
171 | @@ -1577,22 +1607,10 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | |
172 | goto out; | |
173 | } | |
174 | } | |
175 | - if (di->i_xattr_loc) { | |
176 | - ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), | |
177 | - le64_to_cpu(di->i_xattr_loc), | |
178 | - &blk_bh, OCFS2_BH_CACHED, inode); | |
179 | - if (ret < 0) { | |
180 | - mlog_errno(ret); | |
181 | - return ret; | |
182 | - } | |
183 | - /*Verify the signature of xattr block*/ | |
184 | - if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE, | |
185 | - strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) { | |
186 | - ret = -EFAULT; | |
187 | - goto out; | |
188 | - } | |
189 | ||
190 | - ret = ocfs2_xattr_block_remove(inode, blk_bh); | |
191 | + if (di->i_xattr_loc) { | |
192 | + ret = ocfs2_xattr_free_block(inode, | |
193 | + le64_to_cpu(di->i_xattr_loc)); | |
194 | if (ret < 0) { | |
195 | mlog_errno(ret); | |
196 | goto out; | |
197 | @@ -1613,11 +1631,7 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | |
198 | goto out_commit; | |
199 | } | |
200 | ||
201 | - if (di->i_xattr_loc) { | |
202 | - xb = (struct ocfs2_xattr_block *)blk_bh->b_data; | |
203 | - ocfs2_xattr_free_block(handle, osb, xb); | |
204 | - di->i_xattr_loc = cpu_to_le64(0); | |
205 | - } | |
206 | + di->i_xattr_loc = 0; | |
207 | ||
208 | spin_lock(&oi->ip_lock); | |
209 | oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL); | |
210 | @@ -1630,8 +1644,6 @@ int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh) | |
211 | out_commit: | |
212 | ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); | |
213 | out: | |
214 | - brelse(blk_bh); | |
215 | - | |
216 | return ret; | |
217 | } | |
218 | ||
219 | -- | |
220 | 1.5.4.5 | |
221 |