]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Tao Ma <tao.ma@oracle.com> |
2 | Date: Wed, 12 Nov 2008 08:27:00 +0800 | |
3 | Subject: ocfs2/xattr: Reserve meta/data at the beginning of ocfs2_xattr_set. | |
4 | Patch-mainline: 2.6.29 | |
5 | ||
6 | In ocfs2 xattr set, we reserve metadata and clusters in any place | |
7 | they are needed. It is time-consuming and ineffective, so this | |
8 | patch try to reserve metadata and clusters at the beginning of | |
9 | ocfs2_xattr_set. | |
10 | ||
11 | Signed-off-by: Tao Ma <tao.ma@oracle.com> | |
12 | Signed-off-by: Mark Fasheh <mfasheh@suse.com> | |
13 | --- | |
14 | fs/ocfs2/alloc.h | 4 + | |
15 | fs/ocfs2/xattr.c | 483 ++++++++++++++++++++++++++++++++++++++++-------------- | |
16 | 2 files changed, 361 insertions(+), 126 deletions(-) | |
17 | ||
18 | diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h | |
19 | index c301cf2..3eb735e 100644 | |
20 | --- a/fs/ocfs2/alloc.h | |
21 | +++ b/fs/ocfs2/alloc.h | |
22 | @@ -176,6 +176,10 @@ static inline void ocfs2_init_dealloc_ctxt(struct ocfs2_cached_dealloc_ctxt *c) | |
23 | } | |
24 | int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt, | |
25 | u64 blkno, unsigned int bit); | |
26 | +static inline int ocfs2_dealloc_has_cluster(struct ocfs2_cached_dealloc_ctxt *c) | |
27 | +{ | |
28 | + return c->c_global_allocator != NULL; | |
29 | +} | |
30 | int ocfs2_run_deallocs(struct ocfs2_super *osb, | |
31 | struct ocfs2_cached_dealloc_ctxt *ctxt); | |
32 | ||
33 | diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c | |
34 | index f1da381..4fd201a 100644 | |
35 | --- a/fs/ocfs2/xattr.c | |
36 | +++ b/fs/ocfs2/xattr.c | |
37 | @@ -71,6 +71,12 @@ struct ocfs2_xattr_bucket { | |
38 | int bu_blocks; | |
39 | }; | |
40 | ||
41 | +struct ocfs2_xattr_set_ctxt { | |
42 | + struct ocfs2_alloc_context *meta_ac; | |
43 | + struct ocfs2_alloc_context *data_ac; | |
44 | + struct ocfs2_cached_dealloc_ctxt dealloc; | |
45 | +}; | |
46 | + | |
47 | #define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) | |
48 | #define OCFS2_XATTR_INLINE_SIZE 80 | |
49 | ||
50 | @@ -133,11 +139,13 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode, | |
51 | size_t buffer_size); | |
52 | ||
53 | static int ocfs2_xattr_create_index_block(struct inode *inode, | |
54 | - struct ocfs2_xattr_search *xs); | |
55 | + struct ocfs2_xattr_search *xs, | |
56 | + struct ocfs2_xattr_set_ctxt *ctxt); | |
57 | ||
58 | static int ocfs2_xattr_set_entry_index_block(struct inode *inode, | |
59 | struct ocfs2_xattr_info *xi, | |
60 | - struct ocfs2_xattr_search *xs); | |
61 | + struct ocfs2_xattr_search *xs, | |
62 | + struct ocfs2_xattr_set_ctxt *ctxt); | |
63 | ||
64 | static int ocfs2_delete_xattr_index_block(struct inode *inode, | |
65 | struct buffer_head *xb_bh); | |
66 | @@ -334,14 +342,13 @@ static void ocfs2_xattr_hash_entry(struct inode *inode, | |
67 | static int ocfs2_xattr_extend_allocation(struct inode *inode, | |
68 | u32 clusters_to_add, | |
69 | struct buffer_head *xattr_bh, | |
70 | - struct ocfs2_xattr_value_root *xv) | |
71 | + struct ocfs2_xattr_value_root *xv, | |
72 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
73 | { | |
74 | int status = 0; | |
75 | int restart_func = 0; | |
76 | int credits = 0; | |
77 | handle_t *handle = NULL; | |
78 | - struct ocfs2_alloc_context *data_ac = NULL; | |
79 | - struct ocfs2_alloc_context *meta_ac = NULL; | |
80 | enum ocfs2_alloc_restarted why; | |
81 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
82 | u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters); | |
83 | @@ -353,13 +360,6 @@ static int ocfs2_xattr_extend_allocation(struct inode *inode, | |
84 | ||
85 | restart_all: | |
86 | ||
87 | - status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0, | |
88 | - &data_ac, &meta_ac); | |
89 | - if (status) { | |
90 | - mlog_errno(status); | |
91 | - goto leave; | |
92 | - } | |
93 | - | |
94 | credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el, | |
95 | clusters_to_add); | |
96 | handle = ocfs2_start_trans(osb, credits); | |
97 | @@ -386,8 +386,8 @@ restarted_transaction: | |
98 | 0, | |
99 | &et, | |
100 | handle, | |
101 | - data_ac, | |
102 | - meta_ac, | |
103 | + ctxt->data_ac, | |
104 | + ctxt->meta_ac, | |
105 | &why); | |
106 | if ((status < 0) && (status != -EAGAIN)) { | |
107 | if (status != -ENOSPC) | |
108 | @@ -432,14 +432,6 @@ leave: | |
109 | ocfs2_commit_trans(osb, handle); | |
110 | handle = NULL; | |
111 | } | |
112 | - if (data_ac) { | |
113 | - ocfs2_free_alloc_context(data_ac); | |
114 | - data_ac = NULL; | |
115 | - } | |
116 | - if (meta_ac) { | |
117 | - ocfs2_free_alloc_context(meta_ac); | |
118 | - meta_ac = NULL; | |
119 | - } | |
120 | if ((!status) && restart_func) { | |
121 | restart_func = 0; | |
122 | goto restart_all; | |
123 | @@ -452,23 +444,16 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, | |
124 | struct buffer_head *root_bh, | |
125 | struct ocfs2_xattr_value_root *xv, | |
126 | u32 cpos, u32 phys_cpos, u32 len, | |
127 | - struct ocfs2_cached_dealloc_ctxt *dealloc) | |
128 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
129 | { | |
130 | int ret; | |
131 | u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); | |
132 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
133 | handle_t *handle; | |
134 | - struct ocfs2_alloc_context *meta_ac = NULL; | |
135 | struct ocfs2_extent_tree et; | |
136 | ||
137 | ocfs2_init_xattr_value_extent_tree(&et, inode, root_bh, xv); | |
138 | ||
139 | - ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac); | |
140 | - if (ret) { | |
141 | - mlog_errno(ret); | |
142 | - return ret; | |
143 | - } | |
144 | - | |
145 | handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); | |
146 | if (IS_ERR(handle)) { | |
147 | ret = PTR_ERR(handle); | |
148 | @@ -483,8 +468,8 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, | |
149 | goto out_commit; | |
150 | } | |
151 | ||
152 | - ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac, | |
153 | - dealloc); | |
154 | + ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, ctxt->meta_ac, | |
155 | + &ctxt->dealloc); | |
156 | if (ret) { | |
157 | mlog_errno(ret); | |
158 | goto out_commit; | |
159 | @@ -498,17 +483,13 @@ static int __ocfs2_remove_xattr_range(struct inode *inode, | |
160 | goto out_commit; | |
161 | } | |
162 | ||
163 | - ret = ocfs2_cache_cluster_dealloc(dealloc, phys_blkno, len); | |
164 | + ret = ocfs2_cache_cluster_dealloc(&ctxt->dealloc, phys_blkno, len); | |
165 | if (ret) | |
166 | mlog_errno(ret); | |
167 | ||
168 | out_commit: | |
169 | ocfs2_commit_trans(osb, handle); | |
170 | out: | |
171 | - | |
172 | - if (meta_ac) | |
173 | - ocfs2_free_alloc_context(meta_ac); | |
174 | - | |
175 | return ret; | |
176 | } | |
177 | ||
178 | @@ -516,15 +497,12 @@ static int ocfs2_xattr_shrink_size(struct inode *inode, | |
179 | u32 old_clusters, | |
180 | u32 new_clusters, | |
181 | struct buffer_head *root_bh, | |
182 | - struct ocfs2_xattr_value_root *xv) | |
183 | + struct ocfs2_xattr_value_root *xv, | |
184 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
185 | { | |
186 | int ret = 0; | |
187 | u32 trunc_len, cpos, phys_cpos, alloc_size; | |
188 | u64 block; | |
189 | - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
190 | - struct ocfs2_cached_dealloc_ctxt dealloc; | |
191 | - | |
192 | - ocfs2_init_dealloc_ctxt(&dealloc); | |
193 | ||
194 | if (old_clusters <= new_clusters) | |
195 | return 0; | |
196 | @@ -544,7 +522,7 @@ static int ocfs2_xattr_shrink_size(struct inode *inode, | |
197 | ||
198 | ret = __ocfs2_remove_xattr_range(inode, root_bh, xv, cpos, | |
199 | phys_cpos, alloc_size, | |
200 | - &dealloc); | |
201 | + ctxt); | |
202 | if (ret) { | |
203 | mlog_errno(ret); | |
204 | goto out; | |
205 | @@ -558,16 +536,14 @@ static int ocfs2_xattr_shrink_size(struct inode *inode, | |
206 | } | |
207 | ||
208 | out: | |
209 | - ocfs2_schedule_truncate_log_flush(osb, 1); | |
210 | - ocfs2_run_deallocs(osb, &dealloc); | |
211 | - | |
212 | return ret; | |
213 | } | |
214 | ||
215 | static int ocfs2_xattr_value_truncate(struct inode *inode, | |
216 | struct buffer_head *root_bh, | |
217 | struct ocfs2_xattr_value_root *xv, | |
218 | - int len) | |
219 | + int len, | |
220 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
221 | { | |
222 | int ret; | |
223 | u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, len); | |
224 | @@ -579,11 +555,11 @@ static int ocfs2_xattr_value_truncate(struct inode *inode, | |
225 | if (new_clusters > old_clusters) | |
226 | ret = ocfs2_xattr_extend_allocation(inode, | |
227 | new_clusters - old_clusters, | |
228 | - root_bh, xv); | |
229 | + root_bh, xv, ctxt); | |
230 | else | |
231 | ret = ocfs2_xattr_shrink_size(inode, | |
232 | old_clusters, new_clusters, | |
233 | - root_bh, xv); | |
234 | + root_bh, xv, ctxt); | |
235 | ||
236 | return ret; | |
237 | } | |
238 | @@ -1167,6 +1143,7 @@ out: | |
239 | static int ocfs2_xattr_set_value_outside(struct inode *inode, | |
240 | struct ocfs2_xattr_info *xi, | |
241 | struct ocfs2_xattr_search *xs, | |
242 | + struct ocfs2_xattr_set_ctxt *ctxt, | |
243 | size_t offs) | |
244 | { | |
245 | size_t name_len = strlen(xi->name); | |
246 | @@ -1186,7 +1163,7 @@ static int ocfs2_xattr_set_value_outside(struct inode *inode, | |
247 | xv->xr_list.l_next_free_rec = 0; | |
248 | ||
249 | ret = ocfs2_xattr_value_truncate(inode, xs->xattr_bh, xv, | |
250 | - xi->value_len); | |
251 | + xi->value_len, ctxt); | |
252 | if (ret < 0) { | |
253 | mlog_errno(ret); | |
254 | return ret; | |
255 | @@ -1317,6 +1294,7 @@ static void ocfs2_xattr_set_entry_local(struct inode *inode, | |
256 | static int ocfs2_xattr_set_entry(struct inode *inode, | |
257 | struct ocfs2_xattr_info *xi, | |
258 | struct ocfs2_xattr_search *xs, | |
259 | + struct ocfs2_xattr_set_ctxt *ctxt, | |
260 | int flag) | |
261 | { | |
262 | struct ocfs2_xattr_entry *last; | |
263 | @@ -1387,7 +1365,7 @@ static int ocfs2_xattr_set_entry(struct inode *inode, | |
264 | if (ocfs2_xattr_is_local(xs->here) && size == size_l) { | |
265 | /* Replace existing local xattr with tree root */ | |
266 | ret = ocfs2_xattr_set_value_outside(inode, xi, xs, | |
267 | - offs); | |
268 | + ctxt, offs); | |
269 | if (ret < 0) | |
270 | mlog_errno(ret); | |
271 | goto out; | |
272 | @@ -1406,7 +1384,8 @@ static int ocfs2_xattr_set_entry(struct inode *inode, | |
273 | ret = ocfs2_xattr_value_truncate(inode, | |
274 | xs->xattr_bh, | |
275 | xv, | |
276 | - xi->value_len); | |
277 | + xi->value_len, | |
278 | + ctxt); | |
279 | if (ret < 0) { | |
280 | mlog_errno(ret); | |
281 | goto out; | |
282 | @@ -1436,7 +1415,8 @@ static int ocfs2_xattr_set_entry(struct inode *inode, | |
283 | ret = ocfs2_xattr_value_truncate(inode, | |
284 | xs->xattr_bh, | |
285 | xv, | |
286 | - 0); | |
287 | + 0, | |
288 | + ctxt); | |
289 | if (ret < 0) | |
290 | mlog_errno(ret); | |
291 | } | |
292 | @@ -1531,7 +1511,7 @@ out_commit: | |
293 | * This is the second step for value size > INLINE_SIZE. | |
294 | */ | |
295 | size_t offs = le16_to_cpu(xs->here->xe_name_offset); | |
296 | - ret = ocfs2_xattr_set_value_outside(inode, xi, xs, offs); | |
297 | + ret = ocfs2_xattr_set_value_outside(inode, xi, xs, ctxt, offs); | |
298 | if (ret < 0) { | |
299 | int ret2; | |
300 | ||
301 | @@ -1555,6 +1535,10 @@ static int ocfs2_remove_value_outside(struct inode*inode, | |
302 | struct ocfs2_xattr_header *header) | |
303 | { | |
304 | int ret = 0, i; | |
305 | + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
306 | + struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, }; | |
307 | + | |
308 | + ocfs2_init_dealloc_ctxt(&ctxt.dealloc); | |
309 | ||
310 | for (i = 0; i < le16_to_cpu(header->xh_count); i++) { | |
311 | struct ocfs2_xattr_entry *entry = &header->xh_entries[i]; | |
312 | @@ -1567,14 +1551,17 @@ static int ocfs2_remove_value_outside(struct inode*inode, | |
313 | le16_to_cpu(entry->xe_name_offset); | |
314 | xv = (struct ocfs2_xattr_value_root *) | |
315 | (val + OCFS2_XATTR_SIZE(entry->xe_name_len)); | |
316 | - ret = ocfs2_xattr_value_truncate(inode, bh, xv, 0); | |
317 | + ret = ocfs2_xattr_value_truncate(inode, bh, xv, | |
318 | + 0, &ctxt); | |
319 | if (ret < 0) { | |
320 | mlog_errno(ret); | |
321 | - return ret; | |
322 | + break; | |
323 | } | |
324 | } | |
325 | } | |
326 | ||
327 | + ocfs2_schedule_truncate_log_flush(osb, 1); | |
328 | + ocfs2_run_deallocs(osb, &ctxt.dealloc); | |
329 | return ret; | |
330 | } | |
331 | ||
332 | @@ -1836,7 +1823,8 @@ static int ocfs2_xattr_ibody_find(struct inode *inode, | |
333 | */ | |
334 | static int ocfs2_xattr_ibody_set(struct inode *inode, | |
335 | struct ocfs2_xattr_info *xi, | |
336 | - struct ocfs2_xattr_search *xs) | |
337 | + struct ocfs2_xattr_search *xs, | |
338 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
339 | { | |
340 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | |
341 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; | |
342 | @@ -1853,7 +1841,7 @@ static int ocfs2_xattr_ibody_set(struct inode *inode, | |
343 | } | |
344 | } | |
345 | ||
346 | - ret = ocfs2_xattr_set_entry(inode, xi, xs, | |
347 | + ret = ocfs2_xattr_set_entry(inode, xi, xs, ctxt, | |
348 | (OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL)); | |
349 | out: | |
350 | up_write(&oi->ip_alloc_sem); | |
351 | @@ -1926,12 +1914,12 @@ cleanup: | |
352 | */ | |
353 | static int ocfs2_xattr_block_set(struct inode *inode, | |
354 | struct ocfs2_xattr_info *xi, | |
355 | - struct ocfs2_xattr_search *xs) | |
356 | + struct ocfs2_xattr_search *xs, | |
357 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
358 | { | |
359 | struct buffer_head *new_bh = NULL; | |
360 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
361 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data; | |
362 | - struct ocfs2_alloc_context *meta_ac = NULL; | |
363 | handle_t *handle = NULL; | |
364 | struct ocfs2_xattr_block *xblk = NULL; | |
365 | u16 suballoc_bit_start; | |
366 | @@ -1940,15 +1928,6 @@ static int ocfs2_xattr_block_set(struct inode *inode, | |
367 | int ret; | |
368 | ||
369 | if (!xs->xattr_bh) { | |
370 | - /* | |
371 | - * Alloc one external block for extended attribute | |
372 | - * outside of inode. | |
373 | - */ | |
374 | - ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac); | |
375 | - if (ret < 0) { | |
376 | - mlog_errno(ret); | |
377 | - goto out; | |
378 | - } | |
379 | handle = ocfs2_start_trans(osb, | |
380 | OCFS2_XATTR_BLOCK_CREATE_CREDITS); | |
381 | if (IS_ERR(handle)) { | |
382 | @@ -1963,7 +1942,7 @@ static int ocfs2_xattr_block_set(struct inode *inode, | |
383 | goto out_commit; | |
384 | } | |
385 | ||
386 | - ret = ocfs2_claim_metadata(osb, handle, meta_ac, 1, | |
387 | + ret = ocfs2_claim_metadata(osb, handle, ctxt->meta_ac, 1, | |
388 | &suballoc_bit_start, &num_got, | |
389 | &first_blkno); | |
390 | if (ret < 0) { | |
391 | @@ -1996,7 +1975,6 @@ static int ocfs2_xattr_block_set(struct inode *inode, | |
392 | xs->end = (void *)xblk + inode->i_sb->s_blocksize; | |
393 | xs->here = xs->header->xh_entries; | |
394 | ||
395 | - | |
396 | ret = ocfs2_journal_dirty(handle, new_bh); | |
397 | if (ret < 0) { | |
398 | mlog_errno(ret); | |
399 | @@ -2009,8 +1987,6 @@ static int ocfs2_xattr_block_set(struct inode *inode, | |
400 | out_commit: | |
401 | ocfs2_commit_trans(osb, handle); | |
402 | out: | |
403 | - if (meta_ac) | |
404 | - ocfs2_free_alloc_context(meta_ac); | |
405 | if (ret < 0) | |
406 | return ret; | |
407 | } else | |
408 | @@ -2018,22 +1994,266 @@ out: | |
409 | ||
410 | if (!(le16_to_cpu(xblk->xb_flags) & OCFS2_XATTR_INDEXED)) { | |
411 | /* Set extended attribute into external block */ | |
412 | - ret = ocfs2_xattr_set_entry(inode, xi, xs, OCFS2_HAS_XATTR_FL); | |
413 | + ret = ocfs2_xattr_set_entry(inode, xi, xs, ctxt, | |
414 | + OCFS2_HAS_XATTR_FL); | |
415 | if (!ret || ret != -ENOSPC) | |
416 | goto end; | |
417 | ||
418 | - ret = ocfs2_xattr_create_index_block(inode, xs); | |
419 | + ret = ocfs2_xattr_create_index_block(inode, xs, ctxt); | |
420 | if (ret) | |
421 | goto end; | |
422 | } | |
423 | ||
424 | - ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs); | |
425 | + ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs, ctxt); | |
426 | ||
427 | end: | |
428 | ||
429 | return ret; | |
430 | } | |
431 | ||
432 | +/* Check whether the new xattr can be inserted into the inode. */ | |
433 | +static int ocfs2_xattr_can_be_in_inode(struct inode *inode, | |
434 | + struct ocfs2_xattr_info *xi, | |
435 | + struct ocfs2_xattr_search *xs) | |
436 | +{ | |
437 | + u64 value_size; | |
438 | + struct ocfs2_xattr_entry *last; | |
439 | + int free, i; | |
440 | + size_t min_offs = xs->end - xs->base; | |
441 | + | |
442 | + if (!xs->header) | |
443 | + return 0; | |
444 | + | |
445 | + last = xs->header->xh_entries; | |
446 | + | |
447 | + for (i = 0; i < le16_to_cpu(xs->header->xh_count); i++) { | |
448 | + size_t offs = le16_to_cpu(last->xe_name_offset); | |
449 | + if (offs < min_offs) | |
450 | + min_offs = offs; | |
451 | + last += 1; | |
452 | + } | |
453 | + | |
454 | + free = min_offs - ((void *)last - xs->base) - sizeof(__u32); | |
455 | + if (free < 0) | |
456 | + return 0; | |
457 | + | |
458 | + BUG_ON(!xs->not_found); | |
459 | + | |
460 | + if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) | |
461 | + value_size = OCFS2_XATTR_ROOT_SIZE; | |
462 | + else | |
463 | + value_size = OCFS2_XATTR_SIZE(xi->value_len); | |
464 | + | |
465 | + if (free >= sizeof(struct ocfs2_xattr_entry) + | |
466 | + OCFS2_XATTR_SIZE(strlen(xi->name)) + value_size) | |
467 | + return 1; | |
468 | + | |
469 | + return 0; | |
470 | +} | |
471 | + | |
472 | +static int ocfs2_calc_xattr_set_need(struct inode *inode, | |
473 | + struct ocfs2_dinode *di, | |
474 | + struct ocfs2_xattr_info *xi, | |
475 | + struct ocfs2_xattr_search *xis, | |
476 | + struct ocfs2_xattr_search *xbs, | |
477 | + int *clusters_need, | |
478 | + int *meta_need) | |
479 | +{ | |
480 | + int ret = 0, old_in_xb = 0; | |
481 | + int clusters_add = 0, meta_add = 0; | |
482 | + struct buffer_head *bh = NULL; | |
483 | + struct ocfs2_xattr_block *xb = NULL; | |
484 | + struct ocfs2_xattr_entry *xe = NULL; | |
485 | + struct ocfs2_xattr_value_root *xv = NULL; | |
486 | + char *base = NULL; | |
487 | + int name_offset, name_len = 0; | |
488 | + u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, | |
489 | + xi->value_len); | |
490 | + u64 value_size; | |
491 | + | |
492 | + /* | |
493 | + * delete a xattr doesn't need metadata and cluster allocation. | |
494 | + * so return. | |
495 | + */ | |
496 | + if (!xi->value) | |
497 | + goto out; | |
498 | + | |
499 | + if (xis->not_found && xbs->not_found) { | |
500 | + if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) | |
501 | + clusters_add += new_clusters; | |
502 | + | |
503 | + goto meta_guess; | |
504 | + } | |
505 | + | |
506 | + if (!xis->not_found) { | |
507 | + xe = xis->here; | |
508 | + name_offset = le16_to_cpu(xe->xe_name_offset); | |
509 | + name_len = OCFS2_XATTR_SIZE(xe->xe_name_len); | |
510 | + base = xis->base; | |
511 | + } else { | |
512 | + int i, block_off; | |
513 | + xb = (struct ocfs2_xattr_block *)xbs->xattr_bh->b_data; | |
514 | + xe = xbs->here; | |
515 | + name_offset = le16_to_cpu(xe->xe_name_offset); | |
516 | + name_len = OCFS2_XATTR_SIZE(xe->xe_name_len); | |
517 | + i = xbs->here - xbs->header->xh_entries; | |
518 | + old_in_xb = 1; | |
519 | + | |
520 | + if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) { | |
521 | + ret = ocfs2_xattr_bucket_get_name_value(inode, | |
522 | + bucket_xh(xbs->bucket), | |
523 | + i, &block_off, | |
524 | + &name_offset); | |
525 | + base = bucket_block(xbs->bucket, block_off); | |
526 | + } else | |
527 | + base = xbs->base; | |
528 | + } | |
529 | + | |
530 | + /* do cluster allocation guess first. */ | |
531 | + value_size = le64_to_cpu(xe->xe_value_size); | |
532 | + | |
533 | + if (old_in_xb) { | |
534 | + /* | |
535 | + * In xattr set, we always try to set the xe in inode first, | |
536 | + * so if it can be inserted into inode successfully, the old | |
537 | + * one will be removed from the xattr block, and this xattr | |
538 | + * will be inserted into inode as a new xattr in inode. | |
539 | + */ | |
540 | + if (ocfs2_xattr_can_be_in_inode(inode, xi, xis)) { | |
541 | + clusters_add += new_clusters; | |
542 | + goto out; | |
543 | + } | |
544 | + } | |
545 | + | |
546 | + if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) { | |
547 | + /* the new values will be stored outside. */ | |
548 | + u32 old_clusters = 0; | |
549 | + | |
550 | + if (!ocfs2_xattr_is_local(xe)) { | |
551 | + old_clusters = ocfs2_clusters_for_bytes(inode->i_sb, | |
552 | + value_size); | |
553 | + xv = (struct ocfs2_xattr_value_root *) | |
554 | + (base + name_offset + name_len); | |
555 | + } else | |
556 | + xv = &def_xv.xv; | |
557 | + | |
558 | + if (old_clusters >= new_clusters) | |
559 | + goto out; | |
560 | + else { | |
561 | + meta_add += ocfs2_extend_meta_needed(&xv->xr_list); | |
562 | + clusters_add += new_clusters - old_clusters; | |
563 | + goto out; | |
564 | + } | |
565 | + } else { | |
566 | + /* | |
567 | + * Now the new value will be stored inside. So if the new | |
568 | + * value is smaller than the size of value root or the old | |
569 | + * value, we don't need any allocation, otherwise we have | |
570 | + * to guess metadata allocation. | |
571 | + */ | |
572 | + if ((ocfs2_xattr_is_local(xe) && value_size >= xi->value_len) || | |
573 | + (!ocfs2_xattr_is_local(xe) && | |
574 | + OCFS2_XATTR_ROOT_SIZE >= xi->value_len)) | |
575 | + goto out; | |
576 | + } | |
577 | + | |
578 | +meta_guess: | |
579 | + /* calculate metadata allocation. */ | |
580 | + if (di->i_xattr_loc) { | |
581 | + if (!xbs->xattr_bh) { | |
582 | + ret = ocfs2_read_block(inode, | |
583 | + le64_to_cpu(di->i_xattr_loc), | |
584 | + &bh); | |
585 | + if (ret) { | |
586 | + mlog_errno(ret); | |
587 | + goto out; | |
588 | + } | |
589 | + | |
590 | + xb = (struct ocfs2_xattr_block *)bh->b_data; | |
591 | + } else | |
592 | + xb = (struct ocfs2_xattr_block *)xbs->xattr_bh->b_data; | |
593 | + | |
594 | + if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) { | |
595 | + struct ocfs2_extent_list *el = | |
596 | + &xb->xb_attrs.xb_root.xt_list; | |
597 | + meta_add += ocfs2_extend_meta_needed(el); | |
598 | + } | |
599 | + | |
600 | + /* | |
601 | + * This cluster will be used either for new bucket or for | |
602 | + * new xattr block. | |
603 | + * If the cluster size is the same as the bucket size, one | |
604 | + * more is needed since we may need to extend the bucket | |
605 | + * also. | |
606 | + */ | |
607 | + clusters_add += 1; | |
608 | + if (OCFS2_XATTR_BUCKET_SIZE == | |
609 | + OCFS2_SB(inode->i_sb)->s_clustersize) | |
610 | + clusters_add += 1; | |
611 | + } else | |
612 | + meta_add += 1; | |
613 | +out: | |
614 | + if (clusters_need) | |
615 | + *clusters_need = clusters_add; | |
616 | + if (meta_need) | |
617 | + *meta_need = meta_add; | |
618 | + brelse(bh); | |
619 | + return ret; | |
620 | +} | |
621 | + | |
622 | +static int ocfs2_init_xattr_set_ctxt(struct inode *inode, | |
623 | + struct ocfs2_dinode *di, | |
624 | + struct ocfs2_xattr_info *xi, | |
625 | + struct ocfs2_xattr_search *xis, | |
626 | + struct ocfs2_xattr_search *xbs, | |
627 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
628 | +{ | |
629 | + int clusters_add, meta_add, ret; | |
630 | + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
631 | + | |
632 | + memset(ctxt, 0, sizeof(struct ocfs2_xattr_set_ctxt)); | |
633 | + | |
634 | + ocfs2_init_dealloc_ctxt(&ctxt->dealloc); | |
635 | + | |
636 | + ret = ocfs2_calc_xattr_set_need(inode, di, xi, xis, xbs, | |
637 | + &clusters_add, &meta_add); | |
638 | + if (ret) { | |
639 | + mlog_errno(ret); | |
640 | + return ret; | |
641 | + } | |
642 | + | |
643 | + mlog(0, "Set xattr %s, reserve meta blocks = %d, clusters = %d\n", | |
644 | + xi->name, meta_add, clusters_add); | |
645 | + | |
646 | + if (meta_add) { | |
647 | + ret = ocfs2_reserve_new_metadata_blocks(osb, meta_add, | |
648 | + &ctxt->meta_ac); | |
649 | + if (ret) { | |
650 | + mlog_errno(ret); | |
651 | + goto out; | |
652 | + } | |
653 | + } | |
654 | + | |
655 | + if (clusters_add) { | |
656 | + ret = ocfs2_reserve_clusters(osb, clusters_add, &ctxt->data_ac); | |
657 | + if (ret) | |
658 | + mlog_errno(ret); | |
659 | + } | |
660 | +out: | |
661 | + if (ret) { | |
662 | + if (ctxt->meta_ac) { | |
663 | + ocfs2_free_alloc_context(ctxt->meta_ac); | |
664 | + ctxt->meta_ac = NULL; | |
665 | + } | |
666 | + | |
667 | + /* | |
668 | + * We cannot have an error and a non null ctxt->data_ac. | |
669 | + */ | |
670 | + } | |
671 | + | |
672 | + return ret; | |
673 | +} | |
674 | + | |
675 | /* | |
676 | * ocfs2_xattr_set() | |
677 | * | |
678 | @@ -2051,6 +2271,8 @@ int ocfs2_xattr_set(struct inode *inode, | |
679 | struct buffer_head *di_bh = NULL; | |
680 | struct ocfs2_dinode *di; | |
681 | int ret; | |
682 | + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
683 | + struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, }; | |
684 | ||
685 | struct ocfs2_xattr_info xi = { | |
686 | .name_index = name_index, | |
687 | @@ -2115,15 +2337,21 @@ int ocfs2_xattr_set(struct inode *inode, | |
688 | goto cleanup; | |
689 | } | |
690 | ||
691 | + ret = ocfs2_init_xattr_set_ctxt(inode, di, &xi, &xis, &xbs, &ctxt); | |
692 | + if (ret) { | |
693 | + mlog_errno(ret); | |
694 | + goto cleanup; | |
695 | + } | |
696 | + | |
697 | if (!value) { | |
698 | /* Remove existing extended attribute */ | |
699 | if (!xis.not_found) | |
700 | - ret = ocfs2_xattr_ibody_set(inode, &xi, &xis); | |
701 | + ret = ocfs2_xattr_ibody_set(inode, &xi, &xis, &ctxt); | |
702 | else if (!xbs.not_found) | |
703 | - ret = ocfs2_xattr_block_set(inode, &xi, &xbs); | |
704 | + ret = ocfs2_xattr_block_set(inode, &xi, &xbs, &ctxt); | |
705 | } else { | |
706 | /* We always try to set extended attribute into inode first*/ | |
707 | - ret = ocfs2_xattr_ibody_set(inode, &xi, &xis); | |
708 | + ret = ocfs2_xattr_ibody_set(inode, &xi, &xis, &ctxt); | |
709 | if (!ret && !xbs.not_found) { | |
710 | /* | |
711 | * If succeed and that extended attribute existing in | |
712 | @@ -2131,7 +2359,7 @@ int ocfs2_xattr_set(struct inode *inode, | |
713 | */ | |
714 | xi.value = NULL; | |
715 | xi.value_len = 0; | |
716 | - ret = ocfs2_xattr_block_set(inode, &xi, &xbs); | |
717 | + ret = ocfs2_xattr_block_set(inode, &xi, &xbs, &ctxt); | |
718 | } else if (ret == -ENOSPC) { | |
719 | if (di->i_xattr_loc && !xbs.xattr_bh) { | |
720 | ret = ocfs2_xattr_block_find(inode, name_index, | |
721 | @@ -2143,9 +2371,9 @@ int ocfs2_xattr_set(struct inode *inode, | |
722 | * If no space in inode, we will set extended attribute | |
723 | * into external block. | |
724 | */ | |
725 | - ret = ocfs2_xattr_block_set(inode, &xi, &xbs); | |
726 | + ret = ocfs2_xattr_block_set(inode, &xi, &xbs, &ctxt); | |
727 | if (ret) | |
728 | - goto cleanup; | |
729 | + goto free; | |
730 | if (!xis.not_found) { | |
731 | /* | |
732 | * If succeed and that extended attribute | |
733 | @@ -2153,10 +2381,19 @@ int ocfs2_xattr_set(struct inode *inode, | |
734 | */ | |
735 | xi.value = NULL; | |
736 | xi.value_len = 0; | |
737 | - ret = ocfs2_xattr_ibody_set(inode, &xi, &xis); | |
738 | + ret = ocfs2_xattr_ibody_set(inode, &xi, | |
739 | + &xis, &ctxt); | |
740 | } | |
741 | } | |
742 | } | |
743 | +free: | |
744 | + if (ctxt.data_ac) | |
745 | + ocfs2_free_alloc_context(ctxt.data_ac); | |
746 | + if (ctxt.meta_ac) | |
747 | + ocfs2_free_alloc_context(ctxt.meta_ac); | |
748 | + if (ocfs2_dealloc_has_cluster(&ctxt.dealloc)) | |
749 | + ocfs2_schedule_truncate_log_flush(osb, 1); | |
750 | + ocfs2_run_deallocs(osb, &ctxt.dealloc); | |
751 | cleanup: | |
752 | up_write(&OCFS2_I(inode)->ip_xattr_sem); | |
753 | ocfs2_inode_unlock(inode, 1); | |
754 | @@ -2734,7 +2971,8 @@ static void ocfs2_xattr_update_xattr_search(struct inode *inode, | |
755 | } | |
756 | ||
757 | static int ocfs2_xattr_create_index_block(struct inode *inode, | |
758 | - struct ocfs2_xattr_search *xs) | |
759 | + struct ocfs2_xattr_search *xs, | |
760 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
761 | { | |
762 | int ret, credits = OCFS2_SUBALLOC_ALLOC; | |
763 | u32 bit_off, len; | |
764 | @@ -2742,7 +2980,6 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, | |
765 | handle_t *handle; | |
766 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
767 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | |
768 | - struct ocfs2_alloc_context *data_ac; | |
769 | struct buffer_head *xb_bh = xs->xattr_bh; | |
770 | struct ocfs2_xattr_block *xb = | |
771 | (struct ocfs2_xattr_block *)xb_bh->b_data; | |
772 | @@ -2755,12 +2992,6 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, | |
773 | BUG_ON(xb_flags & OCFS2_XATTR_INDEXED); | |
774 | BUG_ON(!xs->bucket); | |
775 | ||
776 | - ret = ocfs2_reserve_clusters(osb, 1, &data_ac); | |
777 | - if (ret) { | |
778 | - mlog_errno(ret); | |
779 | - goto out; | |
780 | - } | |
781 | - | |
782 | /* | |
783 | * XXX: | |
784 | * We can use this lock for now, and maybe move to a dedicated mutex | |
785 | @@ -2787,7 +3018,8 @@ static int ocfs2_xattr_create_index_block(struct inode *inode, | |
786 | goto out_commit; | |
787 | } | |
788 | ||
789 | - ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len); | |
790 | + ret = __ocfs2_claim_clusters(osb, handle, ctxt->data_ac, | |
791 | + 1, 1, &bit_off, &len); | |
792 | if (ret) { | |
793 | mlog_errno(ret); | |
794 | goto out_commit; | |
795 | @@ -2850,10 +3082,6 @@ out_commit: | |
796 | out_sem: | |
797 | up_write(&oi->ip_alloc_sem); | |
798 | ||
799 | -out: | |
800 | - if (data_ac) | |
801 | - ocfs2_free_alloc_context(data_ac); | |
802 | - | |
803 | return ret; | |
804 | } | |
805 | ||
806 | @@ -3614,7 +3842,8 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, | |
807 | u32 *num_clusters, | |
808 | u32 prev_cpos, | |
809 | u64 prev_blkno, | |
810 | - int *extend) | |
811 | + int *extend, | |
812 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
813 | { | |
814 | int ret, credits; | |
815 | u16 bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); | |
816 | @@ -3622,8 +3851,6 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, | |
817 | u32 clusters_to_add = 1, bit_off, num_bits, v_start = 0; | |
818 | u64 block; | |
819 | handle_t *handle = NULL; | |
820 | - struct ocfs2_alloc_context *data_ac = NULL; | |
821 | - struct ocfs2_alloc_context *meta_ac = NULL; | |
822 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
823 | struct ocfs2_extent_tree et; | |
824 | ||
825 | @@ -3634,13 +3861,6 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, | |
826 | ||
827 | ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh); | |
828 | ||
829 | - ret = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0, | |
830 | - &data_ac, &meta_ac); | |
831 | - if (ret) { | |
832 | - mlog_errno(ret); | |
833 | - goto leave; | |
834 | - } | |
835 | - | |
836 | credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el, | |
837 | clusters_to_add); | |
838 | handle = ocfs2_start_trans(osb, credits); | |
839 | @@ -3658,7 +3878,7 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, | |
840 | goto leave; | |
841 | } | |
842 | ||
843 | - ret = __ocfs2_claim_clusters(osb, handle, data_ac, 1, | |
844 | + ret = __ocfs2_claim_clusters(osb, handle, ctxt->data_ac, 1, | |
845 | clusters_to_add, &bit_off, &num_bits); | |
846 | if (ret < 0) { | |
847 | if (ret != -ENOSPC) | |
848 | @@ -3719,7 +3939,7 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, | |
849 | mlog(0, "Insert %u clusters at block %llu for xattr at %u\n", | |
850 | num_bits, (unsigned long long)block, v_start); | |
851 | ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block, | |
852 | - num_bits, 0, meta_ac); | |
853 | + num_bits, 0, ctxt->meta_ac); | |
854 | if (ret < 0) { | |
855 | mlog_errno(ret); | |
856 | goto leave; | |
857 | @@ -3734,10 +3954,6 @@ static int ocfs2_add_new_xattr_cluster(struct inode *inode, | |
858 | leave: | |
859 | if (handle) | |
860 | ocfs2_commit_trans(osb, handle); | |
861 | - if (data_ac) | |
862 | - ocfs2_free_alloc_context(data_ac); | |
863 | - if (meta_ac) | |
864 | - ocfs2_free_alloc_context(meta_ac); | |
865 | ||
866 | return ret; | |
867 | } | |
868 | @@ -3821,7 +4037,8 @@ out: | |
869 | */ | |
870 | static int ocfs2_add_new_xattr_bucket(struct inode *inode, | |
871 | struct buffer_head *xb_bh, | |
872 | - struct buffer_head *header_bh) | |
873 | + struct buffer_head *header_bh, | |
874 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
875 | { | |
876 | struct ocfs2_xattr_header *first_xh = NULL; | |
877 | struct buffer_head *first_bh = NULL; | |
878 | @@ -3872,7 +4089,8 @@ static int ocfs2_add_new_xattr_bucket(struct inode *inode, | |
879 | &num_clusters, | |
880 | e_cpos, | |
881 | p_blkno, | |
882 | - &extend); | |
883 | + &extend, | |
884 | + ctxt); | |
885 | if (ret) { | |
886 | mlog_errno(ret); | |
887 | goto out; | |
888 | @@ -4147,7 +4365,8 @@ out: | |
889 | static int ocfs2_xattr_bucket_value_truncate(struct inode *inode, | |
890 | struct buffer_head *header_bh, | |
891 | int xe_off, | |
892 | - int len) | |
893 | + int len, | |
894 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
895 | { | |
896 | int ret, offset; | |
897 | u64 value_blk; | |
898 | @@ -4182,7 +4401,7 @@ static int ocfs2_xattr_bucket_value_truncate(struct inode *inode, | |
899 | ||
900 | mlog(0, "truncate %u in xattr bucket %llu to %d bytes.\n", | |
901 | xe_off, (unsigned long long)header_bh->b_blocknr, len); | |
902 | - ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len); | |
903 | + ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len, ctxt); | |
904 | if (ret) { | |
905 | mlog_errno(ret); | |
906 | goto out; | |
907 | @@ -4200,8 +4419,9 @@ out: | |
908 | } | |
909 | ||
910 | static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode, | |
911 | - struct ocfs2_xattr_search *xs, | |
912 | - int len) | |
913 | + struct ocfs2_xattr_search *xs, | |
914 | + int len, | |
915 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
916 | { | |
917 | int ret, offset; | |
918 | struct ocfs2_xattr_entry *xe = xs->here; | |
919 | @@ -4211,7 +4431,7 @@ static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode, | |
920 | ||
921 | offset = xe - xh->xh_entries; | |
922 | ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket->bu_bhs[0], | |
923 | - offset, len); | |
924 | + offset, len, ctxt); | |
925 | if (ret) | |
926 | mlog_errno(ret); | |
927 | ||
928 | @@ -4375,7 +4595,8 @@ out_commit: | |
929 | */ | |
930 | static int ocfs2_xattr_set_in_bucket(struct inode *inode, | |
931 | struct ocfs2_xattr_info *xi, | |
932 | - struct ocfs2_xattr_search *xs) | |
933 | + struct ocfs2_xattr_search *xs, | |
934 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
935 | { | |
936 | int ret, local = 1; | |
937 | size_t value_len; | |
938 | @@ -4403,7 +4624,8 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode, | |
939 | value_len = 0; | |
940 | ||
941 | ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs, | |
942 | - value_len); | |
943 | + value_len, | |
944 | + ctxt); | |
945 | if (ret) | |
946 | goto out; | |
947 | ||
948 | @@ -4434,7 +4656,7 @@ static int ocfs2_xattr_set_in_bucket(struct inode *inode, | |
949 | ||
950 | /* allocate the space now for the outside block storage. */ | |
951 | ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs, | |
952 | - value_len); | |
953 | + value_len, ctxt); | |
954 | if (ret) { | |
955 | mlog_errno(ret); | |
956 | ||
957 | @@ -4485,7 +4707,8 @@ static int ocfs2_check_xattr_bucket_collision(struct inode *inode, | |
958 | ||
959 | static int ocfs2_xattr_set_entry_index_block(struct inode *inode, | |
960 | struct ocfs2_xattr_info *xi, | |
961 | - struct ocfs2_xattr_search *xs) | |
962 | + struct ocfs2_xattr_search *xs, | |
963 | + struct ocfs2_xattr_set_ctxt *ctxt) | |
964 | { | |
965 | struct ocfs2_xattr_header *xh; | |
966 | struct ocfs2_xattr_entry *xe; | |
967 | @@ -4603,7 +4826,8 @@ try_again: | |
968 | ||
969 | ret = ocfs2_add_new_xattr_bucket(inode, | |
970 | xs->xattr_bh, | |
971 | - xs->bucket->bu_bhs[0]); | |
972 | + xs->bucket->bu_bhs[0], | |
973 | + ctxt); | |
974 | if (ret) { | |
975 | mlog_errno(ret); | |
976 | goto out; | |
977 | @@ -4622,7 +4846,7 @@ try_again: | |
978 | } | |
979 | ||
980 | xattr_set: | |
981 | - ret = ocfs2_xattr_set_in_bucket(inode, xi, xs); | |
982 | + ret = ocfs2_xattr_set_in_bucket(inode, xi, xs, ctxt); | |
983 | out: | |
984 | mlog_exit(ret); | |
985 | return ret; | |
986 | @@ -4636,6 +4860,10 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, | |
987 | struct ocfs2_xattr_header *xh = bucket_xh(bucket); | |
988 | u16 i; | |
989 | struct ocfs2_xattr_entry *xe; | |
990 | + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
991 | + struct ocfs2_xattr_set_ctxt ctxt = {NULL, NULL,}; | |
992 | + | |
993 | + ocfs2_init_dealloc_ctxt(&ctxt.dealloc); | |
994 | ||
995 | for (i = 0; i < le16_to_cpu(xh->xh_count); i++) { | |
996 | xe = &xh->xh_entries[i]; | |
997 | @@ -4644,13 +4872,16 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, | |
998 | ||
999 | ret = ocfs2_xattr_bucket_value_truncate(inode, | |
1000 | bucket->bu_bhs[0], | |
1001 | - i, 0); | |
1002 | + i, 0, &ctxt); | |
1003 | if (ret) { | |
1004 | mlog_errno(ret); | |
1005 | break; | |
1006 | } | |
1007 | } | |
1008 | ||
1009 | + ocfs2_schedule_truncate_log_flush(osb, 1); | |
1010 | + ocfs2_run_deallocs(osb, &ctxt.dealloc); | |
1011 | + | |
1012 | return ret; | |
1013 | } | |
1014 | ||
1015 | -- | |
1016 | 1.5.6 | |
1017 |