diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/Makefile | 3 | ||||
-rw-r--r-- | fs/ocfs2/alloc.c | 184 | ||||
-rw-r--r-- | fs/ocfs2/alloc.h | 42 | ||||
-rw-r--r-- | fs/ocfs2/aops.c | 5 | ||||
-rw-r--r-- | fs/ocfs2/cluster/masklog.c | 1 | ||||
-rw-r--r-- | fs/ocfs2/cluster/masklog.h | 1 | ||||
-rw-r--r-- | fs/ocfs2/dir.c | 11 | ||||
-rw-r--r-- | fs/ocfs2/extent_map.c | 60 | ||||
-rw-r--r-- | fs/ocfs2/extent_map.h | 4 | ||||
-rw-r--r-- | fs/ocfs2/file.c | 9 | ||||
-rw-r--r-- | fs/ocfs2/suballoc.c | 5 | ||||
-rw-r--r-- | fs/ocfs2/suballoc.h | 3 | ||||
-rw-r--r-- | fs/ocfs2/xattr.c | 305 |
13 files changed, 569 insertions, 64 deletions
diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile index f6956de56fdb..af63980319c3 100644 --- a/fs/ocfs2/Makefile +++ b/fs/ocfs2/Makefile | |||
@@ -34,7 +34,8 @@ ocfs2-objs := \ | |||
34 | symlink.o \ | 34 | symlink.o \ |
35 | sysfile.o \ | 35 | sysfile.o \ |
36 | uptodate.o \ | 36 | uptodate.o \ |
37 | ver.o | 37 | ver.o \ |
38 | xattr.o \ | ||
38 | 39 | ||
39 | ocfs2_stackglue-objs := stackglue.o | 40 | ocfs2_stackglue-objs := stackglue.o |
40 | ocfs2_stack_o2cb-objs := stack_o2cb.o | 41 | ocfs2_stack_o2cb-objs := stack_o2cb.o |
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index cacfc118b71c..e45421fee204 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
@@ -78,6 +78,7 @@ struct ocfs2_extent_tree { | |||
78 | struct ocfs2_extent_tree_operations *eops; | 78 | struct ocfs2_extent_tree_operations *eops; |
79 | struct buffer_head *root_bh; | 79 | struct buffer_head *root_bh; |
80 | struct ocfs2_extent_list *root_el; | 80 | struct ocfs2_extent_list *root_el; |
81 | void *private; | ||
81 | }; | 82 | }; |
82 | 83 | ||
83 | static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, | 84 | static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et, |
@@ -136,9 +137,50 @@ static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = { | |||
136 | .sanity_check = ocfs2_dinode_sanity_check, | 137 | .sanity_check = ocfs2_dinode_sanity_check, |
137 | }; | 138 | }; |
138 | 139 | ||
140 | static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et, | ||
141 | u64 blkno) | ||
142 | { | ||
143 | struct ocfs2_xattr_value_root *xv = | ||
144 | (struct ocfs2_xattr_value_root *)et->private; | ||
145 | |||
146 | xv->xr_last_eb_blk = cpu_to_le64(blkno); | ||
147 | } | ||
148 | |||
149 | static u64 ocfs2_xattr_value_get_last_eb_blk(struct ocfs2_extent_tree *et) | ||
150 | { | ||
151 | struct ocfs2_xattr_value_root *xv = | ||
152 | (struct ocfs2_xattr_value_root *) et->private; | ||
153 | |||
154 | return le64_to_cpu(xv->xr_last_eb_blk); | ||
155 | } | ||
156 | |||
157 | static void ocfs2_xattr_value_update_clusters(struct inode *inode, | ||
158 | struct ocfs2_extent_tree *et, | ||
159 | u32 clusters) | ||
160 | { | ||
161 | struct ocfs2_xattr_value_root *xv = | ||
162 | (struct ocfs2_xattr_value_root *)et->private; | ||
163 | |||
164 | le32_add_cpu(&xv->xr_clusters, clusters); | ||
165 | } | ||
166 | |||
167 | static int ocfs2_xattr_value_sanity_check(struct inode *inode, | ||
168 | struct ocfs2_extent_tree *et) | ||
169 | { | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static struct ocfs2_extent_tree_operations ocfs2_xattr_et_ops = { | ||
174 | .set_last_eb_blk = ocfs2_xattr_value_set_last_eb_blk, | ||
175 | .get_last_eb_blk = ocfs2_xattr_value_get_last_eb_blk, | ||
176 | .update_clusters = ocfs2_xattr_value_update_clusters, | ||
177 | .sanity_check = ocfs2_xattr_value_sanity_check, | ||
178 | }; | ||
179 | |||
139 | static struct ocfs2_extent_tree* | 180 | static struct ocfs2_extent_tree* |
140 | ocfs2_new_extent_tree(struct buffer_head *bh, | 181 | ocfs2_new_extent_tree(struct buffer_head *bh, |
141 | enum ocfs2_extent_tree_type et_type) | 182 | enum ocfs2_extent_tree_type et_type, |
183 | void *private) | ||
142 | { | 184 | { |
143 | struct ocfs2_extent_tree *et; | 185 | struct ocfs2_extent_tree *et; |
144 | 186 | ||
@@ -149,12 +191,16 @@ static struct ocfs2_extent_tree* | |||
149 | et->type = et_type; | 191 | et->type = et_type; |
150 | get_bh(bh); | 192 | get_bh(bh); |
151 | et->root_bh = bh; | 193 | et->root_bh = bh; |
194 | et->private = private; | ||
152 | 195 | ||
153 | /* current we only support dinode extent. */ | ||
154 | BUG_ON(et->type != OCFS2_DINODE_EXTENT); | ||
155 | if (et_type == OCFS2_DINODE_EXTENT) { | 196 | if (et_type == OCFS2_DINODE_EXTENT) { |
156 | et->root_el = &((struct ocfs2_dinode *)bh->b_data)->id2.i_list; | 197 | et->root_el = &((struct ocfs2_dinode *)bh->b_data)->id2.i_list; |
157 | et->eops = &ocfs2_dinode_et_ops; | 198 | et->eops = &ocfs2_dinode_et_ops; |
199 | } else if (et_type == OCFS2_XATTR_VALUE_EXTENT) { | ||
200 | struct ocfs2_xattr_value_root *xv = | ||
201 | (struct ocfs2_xattr_value_root *) private; | ||
202 | et->root_el = &xv->xr_list; | ||
203 | et->eops = &ocfs2_xattr_et_ops; | ||
158 | } | 204 | } |
159 | 205 | ||
160 | return et; | 206 | return et; |
@@ -495,7 +541,8 @@ struct ocfs2_merge_ctxt { | |||
495 | int ocfs2_num_free_extents(struct ocfs2_super *osb, | 541 | int ocfs2_num_free_extents(struct ocfs2_super *osb, |
496 | struct inode *inode, | 542 | struct inode *inode, |
497 | struct buffer_head *root_bh, | 543 | struct buffer_head *root_bh, |
498 | enum ocfs2_extent_tree_type type) | 544 | enum ocfs2_extent_tree_type type, |
545 | void *private) | ||
499 | { | 546 | { |
500 | int retval; | 547 | int retval; |
501 | struct ocfs2_extent_list *el = NULL; | 548 | struct ocfs2_extent_list *el = NULL; |
@@ -517,6 +564,12 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb, | |||
517 | if (fe->i_last_eb_blk) | 564 | if (fe->i_last_eb_blk) |
518 | last_eb_blk = le64_to_cpu(fe->i_last_eb_blk); | 565 | last_eb_blk = le64_to_cpu(fe->i_last_eb_blk); |
519 | el = &fe->id2.i_list; | 566 | el = &fe->id2.i_list; |
567 | } else if (type == OCFS2_XATTR_VALUE_EXTENT) { | ||
568 | struct ocfs2_xattr_value_root *xv = | ||
569 | (struct ocfs2_xattr_value_root *) private; | ||
570 | |||
571 | last_eb_blk = le64_to_cpu(xv->xr_last_eb_blk); | ||
572 | el = &xv->xr_list; | ||
520 | } | 573 | } |
521 | 574 | ||
522 | if (last_eb_blk) { | 575 | if (last_eb_blk) { |
@@ -4209,33 +4262,25 @@ out: | |||
4209 | * | 4262 | * |
4210 | * The caller needs to update fe->i_clusters | 4263 | * The caller needs to update fe->i_clusters |
4211 | */ | 4264 | */ |
4212 | int ocfs2_insert_extent(struct ocfs2_super *osb, | 4265 | static int ocfs2_insert_extent(struct ocfs2_super *osb, |
4213 | handle_t *handle, | 4266 | handle_t *handle, |
4214 | struct inode *inode, | 4267 | struct inode *inode, |
4215 | struct buffer_head *root_bh, | 4268 | struct buffer_head *root_bh, |
4216 | u32 cpos, | 4269 | u32 cpos, |
4217 | u64 start_blk, | 4270 | u64 start_blk, |
4218 | u32 new_clusters, | 4271 | u32 new_clusters, |
4219 | u8 flags, | 4272 | u8 flags, |
4220 | struct ocfs2_alloc_context *meta_ac, | 4273 | struct ocfs2_alloc_context *meta_ac, |
4221 | enum ocfs2_extent_tree_type et_type) | 4274 | struct ocfs2_extent_tree *et) |
4222 | { | 4275 | { |
4223 | int status; | 4276 | int status; |
4224 | int uninitialized_var(free_records); | 4277 | int uninitialized_var(free_records); |
4225 | struct buffer_head *last_eb_bh = NULL; | 4278 | struct buffer_head *last_eb_bh = NULL; |
4226 | struct ocfs2_insert_type insert = {0, }; | 4279 | struct ocfs2_insert_type insert = {0, }; |
4227 | struct ocfs2_extent_rec rec; | 4280 | struct ocfs2_extent_rec rec; |
4228 | struct ocfs2_extent_tree *et = NULL; | ||
4229 | 4281 | ||
4230 | BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); | 4282 | BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL); |
4231 | 4283 | ||
4232 | et = ocfs2_new_extent_tree(root_bh, et_type); | ||
4233 | if (!et) { | ||
4234 | status = -ENOMEM; | ||
4235 | mlog_errno(status); | ||
4236 | goto bail; | ||
4237 | } | ||
4238 | |||
4239 | mlog(0, "add %u clusters at position %u to inode %llu\n", | 4284 | mlog(0, "add %u clusters at position %u to inode %llu\n", |
4240 | new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno); | 4285 | new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno); |
4241 | 4286 | ||
@@ -4287,9 +4332,68 @@ bail: | |||
4287 | if (last_eb_bh) | 4332 | if (last_eb_bh) |
4288 | brelse(last_eb_bh); | 4333 | brelse(last_eb_bh); |
4289 | 4334 | ||
4335 | mlog_exit(status); | ||
4336 | return status; | ||
4337 | } | ||
4338 | |||
4339 | int ocfs2_dinode_insert_extent(struct ocfs2_super *osb, | ||
4340 | handle_t *handle, | ||
4341 | struct inode *inode, | ||
4342 | struct buffer_head *root_bh, | ||
4343 | u32 cpos, | ||
4344 | u64 start_blk, | ||
4345 | u32 new_clusters, | ||
4346 | u8 flags, | ||
4347 | struct ocfs2_alloc_context *meta_ac) | ||
4348 | { | ||
4349 | int status; | ||
4350 | struct ocfs2_extent_tree *et = NULL; | ||
4351 | |||
4352 | et = ocfs2_new_extent_tree(root_bh, OCFS2_DINODE_EXTENT, NULL); | ||
4353 | if (!et) { | ||
4354 | status = -ENOMEM; | ||
4355 | mlog_errno(status); | ||
4356 | goto bail; | ||
4357 | } | ||
4358 | |||
4359 | status = ocfs2_insert_extent(osb, handle, inode, root_bh, | ||
4360 | cpos, start_blk, new_clusters, | ||
4361 | flags, meta_ac, et); | ||
4362 | |||
4290 | if (et) | 4363 | if (et) |
4291 | ocfs2_free_extent_tree(et); | 4364 | ocfs2_free_extent_tree(et); |
4292 | mlog_exit(status); | 4365 | bail: |
4366 | return status; | ||
4367 | } | ||
4368 | |||
4369 | int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, | ||
4370 | handle_t *handle, | ||
4371 | struct inode *inode, | ||
4372 | struct buffer_head *root_bh, | ||
4373 | u32 cpos, | ||
4374 | u64 start_blk, | ||
4375 | u32 new_clusters, | ||
4376 | u8 flags, | ||
4377 | struct ocfs2_alloc_context *meta_ac, | ||
4378 | void *private) | ||
4379 | { | ||
4380 | int status; | ||
4381 | struct ocfs2_extent_tree *et = NULL; | ||
4382 | |||
4383 | et = ocfs2_new_extent_tree(root_bh, OCFS2_XATTR_VALUE_EXTENT, private); | ||
4384 | if (!et) { | ||
4385 | status = -ENOMEM; | ||
4386 | mlog_errno(status); | ||
4387 | goto bail; | ||
4388 | } | ||
4389 | |||
4390 | status = ocfs2_insert_extent(osb, handle, inode, root_bh, | ||
4391 | cpos, start_blk, new_clusters, | ||
4392 | flags, meta_ac, et); | ||
4393 | |||
4394 | if (et) | ||
4395 | ocfs2_free_extent_tree(et); | ||
4396 | bail: | ||
4293 | return status; | 4397 | return status; |
4294 | } | 4398 | } |
4295 | 4399 | ||
@@ -4311,7 +4415,8 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb, | |||
4311 | struct ocfs2_alloc_context *data_ac, | 4415 | struct ocfs2_alloc_context *data_ac, |
4312 | struct ocfs2_alloc_context *meta_ac, | 4416 | struct ocfs2_alloc_context *meta_ac, |
4313 | enum ocfs2_alloc_restarted *reason_ret, | 4417 | enum ocfs2_alloc_restarted *reason_ret, |
4314 | enum ocfs2_extent_tree_type type) | 4418 | enum ocfs2_extent_tree_type type, |
4419 | void *private) | ||
4315 | { | 4420 | { |
4316 | int status = 0; | 4421 | int status = 0; |
4317 | int free_extents; | 4422 | int free_extents; |
@@ -4325,7 +4430,8 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb, | |||
4325 | if (mark_unwritten) | 4430 | if (mark_unwritten) |
4326 | flags = OCFS2_EXT_UNWRITTEN; | 4431 | flags = OCFS2_EXT_UNWRITTEN; |
4327 | 4432 | ||
4328 | free_extents = ocfs2_num_free_extents(osb, inode, root_bh, type); | 4433 | free_extents = ocfs2_num_free_extents(osb, inode, root_bh, type, |
4434 | private); | ||
4329 | if (free_extents < 0) { | 4435 | if (free_extents < 0) { |
4330 | status = free_extents; | 4436 | status = free_extents; |
4331 | mlog_errno(status); | 4437 | mlog_errno(status); |
@@ -4372,9 +4478,16 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb, | |||
4372 | block = ocfs2_clusters_to_blocks(osb->sb, bit_off); | 4478 | block = ocfs2_clusters_to_blocks(osb->sb, bit_off); |
4373 | mlog(0, "Allocating %u clusters at block %u for inode %llu\n", | 4479 | mlog(0, "Allocating %u clusters at block %u for inode %llu\n", |
4374 | num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno); | 4480 | num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno); |
4375 | status = ocfs2_insert_extent(osb, handle, inode, root_bh, | 4481 | if (type == OCFS2_DINODE_EXTENT) |
4376 | *logical_offset, block, num_bits, | 4482 | status = ocfs2_dinode_insert_extent(osb, handle, inode, root_bh, |
4377 | flags, meta_ac, type); | 4483 | *logical_offset, block, |
4484 | num_bits, flags, meta_ac); | ||
4485 | else | ||
4486 | status = ocfs2_xattr_value_insert_extent(osb, handle, | ||
4487 | inode, root_bh, | ||
4488 | *logical_offset, | ||
4489 | block, num_bits, flags, | ||
4490 | meta_ac, private); | ||
4378 | if (status < 0) { | 4491 | if (status < 0) { |
4379 | mlog_errno(status); | 4492 | mlog_errno(status); |
4380 | goto leave; | 4493 | goto leave; |
@@ -4655,7 +4768,8 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, | |||
4655 | handle_t *handle, u32 cpos, u32 len, u32 phys, | 4768 | handle_t *handle, u32 cpos, u32 len, u32 phys, |
4656 | struct ocfs2_alloc_context *meta_ac, | 4769 | struct ocfs2_alloc_context *meta_ac, |
4657 | struct ocfs2_cached_dealloc_ctxt *dealloc, | 4770 | struct ocfs2_cached_dealloc_ctxt *dealloc, |
4658 | enum ocfs2_extent_tree_type et_type) | 4771 | enum ocfs2_extent_tree_type et_type, |
4772 | void *private) | ||
4659 | { | 4773 | { |
4660 | int ret, index; | 4774 | int ret, index; |
4661 | u64 start_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys); | 4775 | u64 start_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys); |
@@ -4676,7 +4790,7 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, | |||
4676 | goto out; | 4790 | goto out; |
4677 | } | 4791 | } |
4678 | 4792 | ||
4679 | et = ocfs2_new_extent_tree(root_bh, et_type); | 4793 | et = ocfs2_new_extent_tree(root_bh, et_type, private); |
4680 | if (!et) { | 4794 | if (!et) { |
4681 | ret = -ENOMEM; | 4795 | ret = -ENOMEM; |
4682 | mlog_errno(ret); | 4796 | mlog_errno(ret); |
@@ -4964,7 +5078,8 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, | |||
4964 | u32 cpos, u32 len, handle_t *handle, | 5078 | u32 cpos, u32 len, handle_t *handle, |
4965 | struct ocfs2_alloc_context *meta_ac, | 5079 | struct ocfs2_alloc_context *meta_ac, |
4966 | struct ocfs2_cached_dealloc_ctxt *dealloc, | 5080 | struct ocfs2_cached_dealloc_ctxt *dealloc, |
4967 | enum ocfs2_extent_tree_type et_type) | 5081 | enum ocfs2_extent_tree_type et_type, |
5082 | void *private) | ||
4968 | { | 5083 | { |
4969 | int ret, index; | 5084 | int ret, index; |
4970 | u32 rec_range, trunc_range; | 5085 | u32 rec_range, trunc_range; |
@@ -4973,7 +5088,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, | |||
4973 | struct ocfs2_path *path = NULL; | 5088 | struct ocfs2_path *path = NULL; |
4974 | struct ocfs2_extent_tree *et = NULL; | 5089 | struct ocfs2_extent_tree *et = NULL; |
4975 | 5090 | ||
4976 | et = ocfs2_new_extent_tree(root_bh, et_type); | 5091 | et = ocfs2_new_extent_tree(root_bh, et_type, private); |
4977 | if (!et) { | 5092 | if (!et) { |
4978 | ret = -ENOMEM; | 5093 | ret = -ENOMEM; |
4979 | mlog_errno(ret); | 5094 | mlog_errno(ret); |
@@ -6608,9 +6723,8 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode, | |||
6608 | * this proves to be false, we could always re-build | 6723 | * this proves to be false, we could always re-build |
6609 | * the in-inode data from our pages. | 6724 | * the in-inode data from our pages. |
6610 | */ | 6725 | */ |
6611 | ret = ocfs2_insert_extent(osb, handle, inode, di_bh, | 6726 | ret = ocfs2_dinode_insert_extent(osb, handle, inode, di_bh, |
6612 | 0, block, 1, 0, | 6727 | 0, block, 1, 0, NULL); |
6613 | NULL, OCFS2_DINODE_EXTENT); | ||
6614 | if (ret) { | 6728 | if (ret) { |
6615 | mlog_errno(ret); | 6729 | mlog_errno(ret); |
6616 | goto out_commit; | 6730 | goto out_commit; |
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h index 5e090c5d8498..ec7baeb2ea7d 100644 --- a/fs/ocfs2/alloc.h +++ b/fs/ocfs2/alloc.h | |||
@@ -28,19 +28,29 @@ | |||
28 | 28 | ||
29 | enum ocfs2_extent_tree_type { | 29 | enum ocfs2_extent_tree_type { |
30 | OCFS2_DINODE_EXTENT = 0, | 30 | OCFS2_DINODE_EXTENT = 0, |
31 | OCFS2_XATTR_VALUE_EXTENT, | ||
31 | }; | 32 | }; |
32 | 33 | ||
33 | struct ocfs2_alloc_context; | 34 | struct ocfs2_alloc_context; |
34 | int ocfs2_insert_extent(struct ocfs2_super *osb, | 35 | int ocfs2_dinode_insert_extent(struct ocfs2_super *osb, |
35 | handle_t *handle, | 36 | handle_t *handle, |
36 | struct inode *inode, | 37 | struct inode *inode, |
37 | struct buffer_head *root_bh, | 38 | struct buffer_head *root_bh, |
38 | u32 cpos, | 39 | u32 cpos, |
39 | u64 start_blk, | 40 | u64 start_blk, |
40 | u32 new_clusters, | 41 | u32 new_clusters, |
41 | u8 flags, | 42 | u8 flags, |
42 | struct ocfs2_alloc_context *meta_ac, | 43 | struct ocfs2_alloc_context *meta_ac); |
43 | enum ocfs2_extent_tree_type et_type); | 44 | int ocfs2_xattr_value_insert_extent(struct ocfs2_super *osb, |
45 | handle_t *handle, | ||
46 | struct inode *inode, | ||
47 | struct buffer_head *root_bh, | ||
48 | u32 cpos, | ||
49 | u64 start_blk, | ||
50 | u32 new_clusters, | ||
51 | u8 flags, | ||
52 | struct ocfs2_alloc_context *meta_ac, | ||
53 | void *private); | ||
44 | enum ocfs2_alloc_restarted { | 54 | enum ocfs2_alloc_restarted { |
45 | RESTART_NONE = 0, | 55 | RESTART_NONE = 0, |
46 | RESTART_TRANS, | 56 | RESTART_TRANS, |
@@ -57,22 +67,26 @@ int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb, | |||
57 | struct ocfs2_alloc_context *data_ac, | 67 | struct ocfs2_alloc_context *data_ac, |
58 | struct ocfs2_alloc_context *meta_ac, | 68 | struct ocfs2_alloc_context *meta_ac, |
59 | enum ocfs2_alloc_restarted *reason_ret, | 69 | enum ocfs2_alloc_restarted *reason_ret, |
60 | enum ocfs2_extent_tree_type type); | 70 | enum ocfs2_extent_tree_type type, |
71 | void *private); | ||
61 | struct ocfs2_cached_dealloc_ctxt; | 72 | struct ocfs2_cached_dealloc_ctxt; |
62 | int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, | 73 | int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *root_bh, |
63 | handle_t *handle, u32 cpos, u32 len, u32 phys, | 74 | handle_t *handle, u32 cpos, u32 len, u32 phys, |
64 | struct ocfs2_alloc_context *meta_ac, | 75 | struct ocfs2_alloc_context *meta_ac, |
65 | struct ocfs2_cached_dealloc_ctxt *dealloc, | 76 | struct ocfs2_cached_dealloc_ctxt *dealloc, |
66 | enum ocfs2_extent_tree_type et_type); | 77 | enum ocfs2_extent_tree_type et_type, |
78 | void *private); | ||
67 | int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, | 79 | int ocfs2_remove_extent(struct inode *inode, struct buffer_head *root_bh, |
68 | u32 cpos, u32 len, handle_t *handle, | 80 | u32 cpos, u32 len, handle_t *handle, |
69 | struct ocfs2_alloc_context *meta_ac, | 81 | struct ocfs2_alloc_context *meta_ac, |
70 | struct ocfs2_cached_dealloc_ctxt *dealloc, | 82 | struct ocfs2_cached_dealloc_ctxt *dealloc, |
71 | enum ocfs2_extent_tree_type et_type); | 83 | enum ocfs2_extent_tree_type et_type, |
84 | void *private); | ||
72 | int ocfs2_num_free_extents(struct ocfs2_super *osb, | 85 | int ocfs2_num_free_extents(struct ocfs2_super *osb, |
73 | struct inode *inode, | 86 | struct inode *inode, |
74 | struct buffer_head *root_bh, | 87 | struct buffer_head *root_bh, |
75 | enum ocfs2_extent_tree_type et_type); | 88 | enum ocfs2_extent_tree_type et_type, |
89 | void *private); | ||
76 | 90 | ||
77 | /* | 91 | /* |
78 | * how many new metadata chunks would an allocation need at maximum? | 92 | * how many new metadata chunks would an allocation need at maximum? |
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index e7acd2867904..530b1ff599c0 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -1279,7 +1279,7 @@ static int ocfs2_write_cluster(struct address_space *mapping, | |||
1279 | ret = ocfs2_mark_extent_written(inode, wc->w_di_bh, | 1279 | ret = ocfs2_mark_extent_written(inode, wc->w_di_bh, |
1280 | wc->w_handle, cpos, 1, phys, | 1280 | wc->w_handle, cpos, 1, phys, |
1281 | meta_ac, &wc->w_dealloc, | 1281 | meta_ac, &wc->w_dealloc, |
1282 | OCFS2_DINODE_EXTENT); | 1282 | OCFS2_DINODE_EXTENT, NULL); |
1283 | if (ret < 0) { | 1283 | if (ret < 0) { |
1284 | mlog_errno(ret); | 1284 | mlog_errno(ret); |
1285 | goto out; | 1285 | goto out; |
@@ -1721,7 +1721,8 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, | |||
1721 | 1721 | ||
1722 | ret = ocfs2_lock_allocators(inode, wc->w_di_bh, &di->id2.i_list, | 1722 | ret = ocfs2_lock_allocators(inode, wc->w_di_bh, &di->id2.i_list, |
1723 | clusters_to_alloc, extents_to_split, | 1723 | clusters_to_alloc, extents_to_split, |
1724 | &data_ac, &meta_ac); | 1724 | &data_ac, &meta_ac, |
1725 | OCFS2_DINODE_EXTENT, NULL); | ||
1725 | if (ret) { | 1726 | if (ret) { |
1726 | mlog_errno(ret); | 1727 | mlog_errno(ret); |
1727 | goto out; | 1728 | goto out; |
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c index 23c732f27529..d8a0cb92cef6 100644 --- a/fs/ocfs2/cluster/masklog.c +++ b/fs/ocfs2/cluster/masklog.c | |||
@@ -109,6 +109,7 @@ static struct mlog_attribute mlog_attrs[MLOG_MAX_BITS] = { | |||
109 | define_mask(CONN), | 109 | define_mask(CONN), |
110 | define_mask(QUORUM), | 110 | define_mask(QUORUM), |
111 | define_mask(EXPORT), | 111 | define_mask(EXPORT), |
112 | define_mask(XATTR), | ||
112 | define_mask(ERROR), | 113 | define_mask(ERROR), |
113 | define_mask(NOTICE), | 114 | define_mask(NOTICE), |
114 | define_mask(KTHREAD), | 115 | define_mask(KTHREAD), |
diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h index 597e064bb94f..57670c680471 100644 --- a/fs/ocfs2/cluster/masklog.h +++ b/fs/ocfs2/cluster/masklog.h | |||
@@ -112,6 +112,7 @@ | |||
112 | #define ML_CONN 0x0000000004000000ULL /* net connection management */ | 112 | #define ML_CONN 0x0000000004000000ULL /* net connection management */ |
113 | #define ML_QUORUM 0x0000000008000000ULL /* net connection quorum */ | 113 | #define ML_QUORUM 0x0000000008000000ULL /* net connection quorum */ |
114 | #define ML_EXPORT 0x0000000010000000ULL /* ocfs2 export operations */ | 114 | #define ML_EXPORT 0x0000000010000000ULL /* ocfs2 export operations */ |
115 | #define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */ | ||
115 | /* bits that are infrequently given and frequently matched in the high word */ | 116 | /* bits that are infrequently given and frequently matched in the high word */ |
116 | #define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */ | 117 | #define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */ |
117 | #define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */ | 118 | #define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */ |
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index d17c34b0ac6b..5426a02c12bb 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -1305,8 +1305,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
1305 | * This should never fail as our extent list is empty and all | 1305 | * This should never fail as our extent list is empty and all |
1306 | * related blocks have been journaled already. | 1306 | * related blocks have been journaled already. |
1307 | */ | 1307 | */ |
1308 | ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0, | 1308 | ret = ocfs2_dinode_insert_extent(osb, handle, dir, di_bh, 0, blkno, |
1309 | NULL, OCFS2_DINODE_EXTENT); | 1309 | len, 0, NULL); |
1310 | if (ret) { | 1310 | if (ret) { |
1311 | mlog_errno(ret); | 1311 | mlog_errno(ret); |
1312 | goto out_commit; | 1312 | goto out_commit; |
@@ -1337,8 +1337,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
1337 | } | 1337 | } |
1338 | blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); | 1338 | blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off); |
1339 | 1339 | ||
1340 | ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno, | 1340 | ret = ocfs2_dinode_insert_extent(osb, handle, dir, di_bh, 1, |
1341 | len, 0, NULL, OCFS2_DINODE_EXTENT); | 1341 | blkno, len, 0, NULL); |
1342 | if (ret) { | 1342 | if (ret) { |
1343 | mlog_errno(ret); | 1343 | mlog_errno(ret); |
1344 | goto out_commit; | 1344 | goto out_commit; |
@@ -1482,7 +1482,8 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, | |||
1482 | spin_unlock(&OCFS2_I(dir)->ip_lock); | 1482 | spin_unlock(&OCFS2_I(dir)->ip_lock); |
1483 | num_free_extents = ocfs2_num_free_extents(osb, dir, | 1483 | num_free_extents = ocfs2_num_free_extents(osb, dir, |
1484 | parent_fe_bh, | 1484 | parent_fe_bh, |
1485 | OCFS2_DINODE_EXTENT); | 1485 | OCFS2_DINODE_EXTENT, |
1486 | NULL); | ||
1486 | if (num_free_extents < 0) { | 1487 | if (num_free_extents < 0) { |
1487 | status = num_free_extents; | 1488 | status = num_free_extents; |
1488 | mlog_errno(status); | 1489 | mlog_errno(status); |
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index aed268e80b49..a7b1cfa735bf 100644 --- a/fs/ocfs2/extent_map.c +++ b/fs/ocfs2/extent_map.c | |||
@@ -551,6 +551,66 @@ static void ocfs2_relative_extent_offsets(struct super_block *sb, | |||
551 | *num_clusters = le16_to_cpu(rec->e_leaf_clusters) - coff; | 551 | *num_clusters = le16_to_cpu(rec->e_leaf_clusters) - coff; |
552 | } | 552 | } |
553 | 553 | ||
554 | int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, | ||
555 | u32 *p_cluster, u32 *num_clusters, | ||
556 | struct ocfs2_extent_list *el) | ||
557 | { | ||
558 | int ret = 0, i; | ||
559 | struct buffer_head *eb_bh = NULL; | ||
560 | struct ocfs2_extent_block *eb; | ||
561 | struct ocfs2_extent_rec *rec; | ||
562 | u32 coff; | ||
563 | |||
564 | if (el->l_tree_depth) { | ||
565 | ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh); | ||
566 | if (ret) { | ||
567 | mlog_errno(ret); | ||
568 | goto out; | ||
569 | } | ||
570 | |||
571 | eb = (struct ocfs2_extent_block *) eb_bh->b_data; | ||
572 | el = &eb->h_list; | ||
573 | |||
574 | if (el->l_tree_depth) { | ||
575 | ocfs2_error(inode->i_sb, | ||
576 | "Inode %lu has non zero tree depth in " | ||
577 | "xattr leaf block %llu\n", inode->i_ino, | ||
578 | (unsigned long long)eb_bh->b_blocknr); | ||
579 | ret = -EROFS; | ||
580 | goto out; | ||
581 | } | ||
582 | } | ||
583 | |||
584 | i = ocfs2_search_extent_list(el, v_cluster); | ||
585 | if (i == -1) { | ||
586 | ret = -EROFS; | ||
587 | mlog_errno(ret); | ||
588 | goto out; | ||
589 | } else { | ||
590 | rec = &el->l_recs[i]; | ||
591 | BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); | ||
592 | |||
593 | if (!rec->e_blkno) { | ||
594 | ocfs2_error(inode->i_sb, "Inode %lu has bad extent " | ||
595 | "record (%u, %u, 0) in xattr", inode->i_ino, | ||
596 | le32_to_cpu(rec->e_cpos), | ||
597 | ocfs2_rec_clusters(el, rec)); | ||
598 | ret = -EROFS; | ||
599 | goto out; | ||
600 | } | ||
601 | coff = v_cluster - le32_to_cpu(rec->e_cpos); | ||
602 | *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb, | ||
603 | le64_to_cpu(rec->e_blkno)); | ||
604 | *p_cluster = *p_cluster + coff; | ||
605 | if (num_clusters) | ||
606 | *num_clusters = ocfs2_rec_clusters(el, rec) - coff; | ||
607 | } | ||
608 | out: | ||
609 | if (eb_bh) | ||
610 | brelse(eb_bh); | ||
611 | return ret; | ||
612 | } | ||
613 | |||
554 | int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, | 614 | int ocfs2_get_clusters(struct inode *inode, u32 v_cluster, |
555 | u32 *p_cluster, u32 *num_clusters, | 615 | u32 *p_cluster, u32 *num_clusters, |
556 | unsigned int *extent_flags) | 616 | unsigned int *extent_flags) |
diff --git a/fs/ocfs2/extent_map.h b/fs/ocfs2/extent_map.h index 1b97490e1ea8..1c4aa8b06f34 100644 --- a/fs/ocfs2/extent_map.h +++ b/fs/ocfs2/extent_map.h | |||
@@ -53,4 +53,8 @@ int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, | |||
53 | int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 53 | int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
54 | u64 map_start, u64 map_len); | 54 | u64 map_start, u64 map_len); |
55 | 55 | ||
56 | int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, | ||
57 | u32 *p_cluster, u32 *num_clusters, | ||
58 | struct ocfs2_extent_list *el); | ||
59 | |||
56 | #endif /* _EXTENT_MAP_H */ | 60 | #endif /* _EXTENT_MAP_H */ |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 7bb4fde70054..89d8541f85b5 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -515,7 +515,7 @@ int ocfs2_add_inode_data(struct ocfs2_super *osb, | |||
515 | clusters_to_add, mark_unwritten, | 515 | clusters_to_add, mark_unwritten, |
516 | fe_bh, el, handle, | 516 | fe_bh, el, handle, |
517 | data_ac, meta_ac, reason_ret, | 517 | data_ac, meta_ac, reason_ret, |
518 | OCFS2_DINODE_EXTENT); | 518 | OCFS2_DINODE_EXTENT, NULL); |
519 | } | 519 | } |
520 | 520 | ||
521 | static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start, | 521 | static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start, |
@@ -565,7 +565,7 @@ restart_all: | |||
565 | clusters_to_add); | 565 | clusters_to_add); |
566 | status = ocfs2_lock_allocators(inode, bh, &fe->id2.i_list, | 566 | status = ocfs2_lock_allocators(inode, bh, &fe->id2.i_list, |
567 | clusters_to_add, 0, &data_ac, | 567 | clusters_to_add, 0, &data_ac, |
568 | &meta_ac); | 568 | &meta_ac, OCFS2_DINODE_EXTENT, NULL); |
569 | if (status) { | 569 | if (status) { |
570 | mlog_errno(status); | 570 | mlog_errno(status); |
571 | goto leave; | 571 | goto leave; |
@@ -1237,7 +1237,8 @@ static int __ocfs2_remove_inode_range(struct inode *inode, | |||
1237 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | 1237 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; |
1238 | 1238 | ||
1239 | ret = ocfs2_lock_allocators(inode, di_bh, &di->id2.i_list, | 1239 | ret = ocfs2_lock_allocators(inode, di_bh, &di->id2.i_list, |
1240 | 0, 1, NULL, &meta_ac); | 1240 | 0, 1, NULL, &meta_ac, |
1241 | OCFS2_DINODE_EXTENT, NULL); | ||
1241 | if (ret) { | 1242 | if (ret) { |
1242 | mlog_errno(ret); | 1243 | mlog_errno(ret); |
1243 | return ret; | 1244 | return ret; |
@@ -1268,7 +1269,7 @@ static int __ocfs2_remove_inode_range(struct inode *inode, | |||
1268 | } | 1269 | } |
1269 | 1270 | ||
1270 | ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac, | 1271 | ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac, |
1271 | dealloc, OCFS2_DINODE_EXTENT); | 1272 | dealloc, OCFS2_DINODE_EXTENT, NULL); |
1272 | if (ret) { | 1273 | if (ret) { |
1273 | mlog_errno(ret); | 1274 | mlog_errno(ret); |
1274 | goto out_commit; | 1275 | goto out_commit; |
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index b642c825fb7c..bb774d70d268 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -1909,7 +1909,8 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh, | |||
1909 | struct ocfs2_extent_list *root_el, | 1909 | struct ocfs2_extent_list *root_el, |
1910 | u32 clusters_to_add, u32 extents_to_split, | 1910 | u32 clusters_to_add, u32 extents_to_split, |
1911 | struct ocfs2_alloc_context **data_ac, | 1911 | struct ocfs2_alloc_context **data_ac, |
1912 | struct ocfs2_alloc_context **meta_ac) | 1912 | struct ocfs2_alloc_context **meta_ac, |
1913 | enum ocfs2_extent_tree_type type, void *private) | ||
1913 | { | 1914 | { |
1914 | int ret = 0, num_free_extents; | 1915 | int ret = 0, num_free_extents; |
1915 | unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split; | 1916 | unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split; |
@@ -1922,7 +1923,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh, | |||
1922 | BUG_ON(clusters_to_add != 0 && data_ac == NULL); | 1923 | BUG_ON(clusters_to_add != 0 && data_ac == NULL); |
1923 | 1924 | ||
1924 | num_free_extents = ocfs2_num_free_extents(osb, inode, root_bh, | 1925 | num_free_extents = ocfs2_num_free_extents(osb, inode, root_bh, |
1925 | OCFS2_DINODE_EXTENT); | 1926 | type, private); |
1926 | if (num_free_extents < 0) { | 1927 | if (num_free_extents < 0) { |
1927 | ret = num_free_extents; | 1928 | ret = num_free_extents; |
1928 | mlog_errno(ret); | 1929 | mlog_errno(ret); |
diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h index a3e531e62df2..9e026c8afee4 100644 --- a/fs/ocfs2/suballoc.h +++ b/fs/ocfs2/suballoc.h | |||
@@ -166,5 +166,6 @@ int ocfs2_lock_allocators(struct inode *inode, struct buffer_head *root_bh, | |||
166 | struct ocfs2_extent_list *root_el, | 166 | struct ocfs2_extent_list *root_el, |
167 | u32 clusters_to_add, u32 extents_to_split, | 167 | u32 clusters_to_add, u32 extents_to_split, |
168 | struct ocfs2_alloc_context **data_ac, | 168 | struct ocfs2_alloc_context **data_ac, |
169 | struct ocfs2_alloc_context **meta_ac); | 169 | struct ocfs2_alloc_context **meta_ac, |
170 | enum ocfs2_extent_tree_type type, void *private); | ||
170 | #endif /* _CHAINALLOC_H_ */ | 171 | #endif /* _CHAINALLOC_H_ */ |
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c new file mode 100644 index 000000000000..9604a4cd02bb --- /dev/null +++ b/fs/ocfs2/xattr.c | |||
@@ -0,0 +1,305 @@ | |||
1 | /* -*- mode: c; c-basic-offset: 8; -*- | ||
2 | * vim: noexpandtab sw=8 ts=8 sts=0: | ||
3 | * | ||
4 | * xattr.c | ||
5 | * | ||
6 | * Copyright (C) 2008 Oracle. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public | ||
10 | * License as published by the Free Software Foundation; either | ||
11 | * version 2 of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public | ||
19 | * License along with this program; if not, write to the | ||
20 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
21 | * Boston, MA 021110-1307, USA. | ||
22 | */ | ||
23 | |||
24 | #define MLOG_MASK_PREFIX ML_XATTR | ||
25 | #include <cluster/masklog.h> | ||
26 | |||
27 | #include "ocfs2.h" | ||
28 | #include "alloc.h" | ||
29 | #include "dlmglue.h" | ||
30 | #include "file.h" | ||
31 | #include "inode.h" | ||
32 | #include "journal.h" | ||
33 | #include "ocfs2_fs.h" | ||
34 | #include "suballoc.h" | ||
35 | #include "uptodate.h" | ||
36 | #include "buffer_head_io.h" | ||
37 | |||
38 | static int ocfs2_xattr_extend_allocation(struct inode *inode, | ||
39 | u32 clusters_to_add, | ||
40 | struct buffer_head *xattr_bh, | ||
41 | struct ocfs2_xattr_value_root *xv) | ||
42 | { | ||
43 | int status = 0; | ||
44 | int restart_func = 0; | ||
45 | int credits = 0; | ||
46 | handle_t *handle = NULL; | ||
47 | struct ocfs2_alloc_context *data_ac = NULL; | ||
48 | struct ocfs2_alloc_context *meta_ac = NULL; | ||
49 | enum ocfs2_alloc_restarted why; | ||
50 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
51 | struct ocfs2_extent_list *root_el = &xv->xr_list; | ||
52 | u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters); | ||
53 | |||
54 | mlog(0, "(clusters_to_add for xattr= %u)\n", clusters_to_add); | ||
55 | |||
56 | restart_all: | ||
57 | |||
58 | status = ocfs2_lock_allocators(inode, xattr_bh, root_el, | ||
59 | clusters_to_add, 0, &data_ac, | ||
60 | &meta_ac, OCFS2_XATTR_VALUE_EXTENT, xv); | ||
61 | if (status) { | ||
62 | mlog_errno(status); | ||
63 | goto leave; | ||
64 | } | ||
65 | |||
66 | credits = ocfs2_calc_extend_credits(osb->sb, root_el, clusters_to_add); | ||
67 | handle = ocfs2_start_trans(osb, credits); | ||
68 | if (IS_ERR(handle)) { | ||
69 | status = PTR_ERR(handle); | ||
70 | handle = NULL; | ||
71 | mlog_errno(status); | ||
72 | goto leave; | ||
73 | } | ||
74 | |||
75 | restarted_transaction: | ||
76 | status = ocfs2_journal_access(handle, inode, xattr_bh, | ||
77 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
78 | if (status < 0) { | ||
79 | mlog_errno(status); | ||
80 | goto leave; | ||
81 | } | ||
82 | |||
83 | prev_clusters = le32_to_cpu(xv->xr_clusters); | ||
84 | status = ocfs2_add_clusters_in_btree(osb, | ||
85 | inode, | ||
86 | &logical_start, | ||
87 | clusters_to_add, | ||
88 | 0, | ||
89 | xattr_bh, | ||
90 | root_el, | ||
91 | handle, | ||
92 | data_ac, | ||
93 | meta_ac, | ||
94 | &why, | ||
95 | OCFS2_XATTR_VALUE_EXTENT, | ||
96 | xv); | ||
97 | if ((status < 0) && (status != -EAGAIN)) { | ||
98 | if (status != -ENOSPC) | ||
99 | mlog_errno(status); | ||
100 | goto leave; | ||
101 | } | ||
102 | |||
103 | status = ocfs2_journal_dirty(handle, xattr_bh); | ||
104 | if (status < 0) { | ||
105 | mlog_errno(status); | ||
106 | goto leave; | ||
107 | } | ||
108 | |||
109 | clusters_to_add -= le32_to_cpu(xv->xr_clusters) - prev_clusters; | ||
110 | |||
111 | if (why != RESTART_NONE && clusters_to_add) { | ||
112 | if (why == RESTART_META) { | ||
113 | mlog(0, "restarting function.\n"); | ||
114 | restart_func = 1; | ||
115 | } else { | ||
116 | BUG_ON(why != RESTART_TRANS); | ||
117 | |||
118 | mlog(0, "restarting transaction.\n"); | ||
119 | /* TODO: This can be more intelligent. */ | ||
120 | credits = ocfs2_calc_extend_credits(osb->sb, | ||
121 | root_el, | ||
122 | clusters_to_add); | ||
123 | status = ocfs2_extend_trans(handle, credits); | ||
124 | if (status < 0) { | ||
125 | /* handle still has to be committed at | ||
126 | * this point. */ | ||
127 | status = -ENOMEM; | ||
128 | mlog_errno(status); | ||
129 | goto leave; | ||
130 | } | ||
131 | goto restarted_transaction; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | leave: | ||
136 | if (handle) { | ||
137 | ocfs2_commit_trans(osb, handle); | ||
138 | handle = NULL; | ||
139 | } | ||
140 | if (data_ac) { | ||
141 | ocfs2_free_alloc_context(data_ac); | ||
142 | data_ac = NULL; | ||
143 | } | ||
144 | if (meta_ac) { | ||
145 | ocfs2_free_alloc_context(meta_ac); | ||
146 | meta_ac = NULL; | ||
147 | } | ||
148 | if ((!status) && restart_func) { | ||
149 | restart_func = 0; | ||
150 | goto restart_all; | ||
151 | } | ||
152 | |||
153 | return status; | ||
154 | } | ||
155 | |||
156 | static int __ocfs2_remove_xattr_range(struct inode *inode, | ||
157 | struct buffer_head *root_bh, | ||
158 | struct ocfs2_xattr_value_root *xv, | ||
159 | u32 cpos, u32 phys_cpos, u32 len, | ||
160 | struct ocfs2_cached_dealloc_ctxt *dealloc) | ||
161 | { | ||
162 | int ret; | ||
163 | u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); | ||
164 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
165 | struct inode *tl_inode = osb->osb_tl_inode; | ||
166 | handle_t *handle; | ||
167 | struct ocfs2_alloc_context *meta_ac = NULL; | ||
168 | |||
169 | ret = ocfs2_lock_allocators(inode, root_bh, &xv->xr_list, | ||
170 | 0, 1, NULL, &meta_ac, | ||
171 | OCFS2_XATTR_VALUE_EXTENT, xv); | ||
172 | if (ret) { | ||
173 | mlog_errno(ret); | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | mutex_lock(&tl_inode->i_mutex); | ||
178 | |||
179 | if (ocfs2_truncate_log_needs_flush(osb)) { | ||
180 | ret = __ocfs2_flush_truncate_log(osb); | ||
181 | if (ret < 0) { | ||
182 | mlog_errno(ret); | ||
183 | goto out; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS); | ||
188 | if (IS_ERR(handle)) { | ||
189 | ret = PTR_ERR(handle); | ||
190 | mlog_errno(ret); | ||
191 | goto out; | ||
192 | } | ||
193 | |||
194 | ret = ocfs2_journal_access(handle, inode, root_bh, | ||
195 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
196 | if (ret) { | ||
197 | mlog_errno(ret); | ||
198 | goto out_commit; | ||
199 | } | ||
200 | |||
201 | ret = ocfs2_remove_extent(inode, root_bh, cpos, len, handle, meta_ac, | ||
202 | dealloc, OCFS2_XATTR_VALUE_EXTENT, xv); | ||
203 | if (ret) { | ||
204 | mlog_errno(ret); | ||
205 | goto out_commit; | ||
206 | } | ||
207 | |||
208 | le32_add_cpu(&xv->xr_clusters, -len); | ||
209 | |||
210 | ret = ocfs2_journal_dirty(handle, root_bh); | ||
211 | if (ret) { | ||
212 | mlog_errno(ret); | ||
213 | goto out_commit; | ||
214 | } | ||
215 | |||
216 | ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len); | ||
217 | if (ret) | ||
218 | mlog_errno(ret); | ||
219 | |||
220 | out_commit: | ||
221 | ocfs2_commit_trans(osb, handle); | ||
222 | out: | ||
223 | mutex_unlock(&tl_inode->i_mutex); | ||
224 | |||
225 | if (meta_ac) | ||
226 | ocfs2_free_alloc_context(meta_ac); | ||
227 | |||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | static int ocfs2_xattr_shrink_size(struct inode *inode, | ||
232 | u32 old_clusters, | ||
233 | u32 new_clusters, | ||
234 | struct buffer_head *root_bh, | ||
235 | struct ocfs2_xattr_value_root *xv) | ||
236 | { | ||
237 | int ret = 0; | ||
238 | u32 trunc_len, cpos, phys_cpos, alloc_size; | ||
239 | u64 block; | ||
240 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
241 | struct ocfs2_cached_dealloc_ctxt dealloc; | ||
242 | |||
243 | ocfs2_init_dealloc_ctxt(&dealloc); | ||
244 | |||
245 | if (old_clusters <= new_clusters) | ||
246 | return 0; | ||
247 | |||
248 | cpos = new_clusters; | ||
249 | trunc_len = old_clusters - new_clusters; | ||
250 | while (trunc_len) { | ||
251 | ret = ocfs2_xattr_get_clusters(inode, cpos, &phys_cpos, | ||
252 | &alloc_size, &xv->xr_list); | ||
253 | if (ret) { | ||
254 | mlog_errno(ret); | ||
255 | goto out; | ||
256 | } | ||
257 | |||
258 | if (alloc_size > trunc_len) | ||
259 | alloc_size = trunc_len; | ||
260 | |||
261 | ret = __ocfs2_remove_xattr_range(inode, root_bh, xv, cpos, | ||
262 | phys_cpos, alloc_size, | ||
263 | &dealloc); | ||
264 | if (ret) { | ||
265 | mlog_errno(ret); | ||
266 | goto out; | ||
267 | } | ||
268 | |||
269 | block = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); | ||
270 | ocfs2_remove_xattr_clusters_from_cache(inode, block, | ||
271 | alloc_size); | ||
272 | cpos += alloc_size; | ||
273 | trunc_len -= alloc_size; | ||
274 | } | ||
275 | |||
276 | out: | ||
277 | ocfs2_schedule_truncate_log_flush(osb, 1); | ||
278 | ocfs2_run_deallocs(osb, &dealloc); | ||
279 | |||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | static int ocfs2_xattr_value_truncate(struct inode *inode, | ||
284 | struct buffer_head *root_bh, | ||
285 | struct ocfs2_xattr_value_root *xv, | ||
286 | int len) | ||
287 | { | ||
288 | int ret; | ||
289 | u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, len); | ||
290 | u32 old_clusters = le32_to_cpu(xv->xr_clusters); | ||
291 | |||
292 | if (new_clusters == old_clusters) | ||
293 | return 0; | ||
294 | |||
295 | if (new_clusters > old_clusters) | ||
296 | ret = ocfs2_xattr_extend_allocation(inode, | ||
297 | new_clusters - old_clusters, | ||
298 | root_bh, xv); | ||
299 | else | ||
300 | ret = ocfs2_xattr_shrink_size(inode, | ||
301 | old_clusters, new_clusters, | ||
302 | root_bh, xv); | ||
303 | |||
304 | return ret; | ||
305 | } | ||