diff options
author | Ingo Molnar <mingo@elte.hu> | 2011-04-21 05:39:21 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-04-21 05:39:28 -0400 |
commit | 42ac9e87fdd89b77fa2ca0a5226023c1c2d83226 (patch) | |
tree | dfdb1b720347a40f24a89a3e9c2727ae26ad5f01 /fs/btrfs/inode.c | |
parent | 057f3fadb347e9c51b07e1b277bbdda79f976768 (diff) | |
parent | f0e615c3cb72b42191b558c130409335812621d8 (diff) |
Merge commit 'v2.6.39-rc4' into sched/core
Merge reason: Pick up upstream fixes.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 165 |
1 files changed, 116 insertions, 49 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5cc64ab9c485..fcd66b6a8086 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -1770,9 +1770,12 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
1770 | add_pending_csums(trans, inode, ordered_extent->file_offset, | 1770 | add_pending_csums(trans, inode, ordered_extent->file_offset, |
1771 | &ordered_extent->list); | 1771 | &ordered_extent->list); |
1772 | 1772 | ||
1773 | btrfs_ordered_update_i_size(inode, 0, ordered_extent); | 1773 | ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent); |
1774 | ret = btrfs_update_inode(trans, root, inode); | 1774 | if (!ret) { |
1775 | BUG_ON(ret); | 1775 | ret = btrfs_update_inode(trans, root, inode); |
1776 | BUG_ON(ret); | ||
1777 | } | ||
1778 | ret = 0; | ||
1776 | out: | 1779 | out: |
1777 | if (nolock) { | 1780 | if (nolock) { |
1778 | if (trans) | 1781 | if (trans) |
@@ -2590,6 +2593,13 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, | |||
2590 | struct btrfs_inode_item *item, | 2593 | struct btrfs_inode_item *item, |
2591 | struct inode *inode) | 2594 | struct inode *inode) |
2592 | { | 2595 | { |
2596 | if (!leaf->map_token) | ||
2597 | map_private_extent_buffer(leaf, (unsigned long)item, | ||
2598 | sizeof(struct btrfs_inode_item), | ||
2599 | &leaf->map_token, &leaf->kaddr, | ||
2600 | &leaf->map_start, &leaf->map_len, | ||
2601 | KM_USER1); | ||
2602 | |||
2593 | btrfs_set_inode_uid(leaf, item, inode->i_uid); | 2603 | btrfs_set_inode_uid(leaf, item, inode->i_uid); |
2594 | btrfs_set_inode_gid(leaf, item, inode->i_gid); | 2604 | btrfs_set_inode_gid(leaf, item, inode->i_gid); |
2595 | btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size); | 2605 | btrfs_set_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size); |
@@ -2618,6 +2628,11 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, | |||
2618 | btrfs_set_inode_rdev(leaf, item, inode->i_rdev); | 2628 | btrfs_set_inode_rdev(leaf, item, inode->i_rdev); |
2619 | btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags); | 2629 | btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags); |
2620 | btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group); | 2630 | btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group); |
2631 | |||
2632 | if (leaf->map_token) { | ||
2633 | unmap_extent_buffer(leaf, leaf->map_token, KM_USER1); | ||
2634 | leaf->map_token = NULL; | ||
2635 | } | ||
2621 | } | 2636 | } |
2622 | 2637 | ||
2623 | /* | 2638 | /* |
@@ -4207,10 +4222,8 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4207 | struct btrfs_key found_key; | 4222 | struct btrfs_key found_key; |
4208 | struct btrfs_path *path; | 4223 | struct btrfs_path *path; |
4209 | int ret; | 4224 | int ret; |
4210 | u32 nritems; | ||
4211 | struct extent_buffer *leaf; | 4225 | struct extent_buffer *leaf; |
4212 | int slot; | 4226 | int slot; |
4213 | int advance; | ||
4214 | unsigned char d_type; | 4227 | unsigned char d_type; |
4215 | int over = 0; | 4228 | int over = 0; |
4216 | u32 di_cur; | 4229 | u32 di_cur; |
@@ -4253,27 +4266,19 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4253 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 4266 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
4254 | if (ret < 0) | 4267 | if (ret < 0) |
4255 | goto err; | 4268 | goto err; |
4256 | advance = 0; | ||
4257 | 4269 | ||
4258 | while (1) { | 4270 | while (1) { |
4259 | leaf = path->nodes[0]; | 4271 | leaf = path->nodes[0]; |
4260 | nritems = btrfs_header_nritems(leaf); | ||
4261 | slot = path->slots[0]; | 4272 | slot = path->slots[0]; |
4262 | if (advance || slot >= nritems) { | 4273 | if (slot >= btrfs_header_nritems(leaf)) { |
4263 | if (slot >= nritems - 1) { | 4274 | ret = btrfs_next_leaf(root, path); |
4264 | ret = btrfs_next_leaf(root, path); | 4275 | if (ret < 0) |
4265 | if (ret) | 4276 | goto err; |
4266 | break; | 4277 | else if (ret > 0) |
4267 | leaf = path->nodes[0]; | 4278 | break; |
4268 | nritems = btrfs_header_nritems(leaf); | 4279 | continue; |
4269 | slot = path->slots[0]; | ||
4270 | } else { | ||
4271 | slot++; | ||
4272 | path->slots[0]++; | ||
4273 | } | ||
4274 | } | 4280 | } |
4275 | 4281 | ||
4276 | advance = 1; | ||
4277 | item = btrfs_item_nr(leaf, slot); | 4282 | item = btrfs_item_nr(leaf, slot); |
4278 | btrfs_item_key_to_cpu(leaf, &found_key, slot); | 4283 | btrfs_item_key_to_cpu(leaf, &found_key, slot); |
4279 | 4284 | ||
@@ -4282,7 +4287,7 @@ static int btrfs_real_readdir(struct file *filp, void *dirent, | |||
4282 | if (btrfs_key_type(&found_key) != key_type) | 4287 | if (btrfs_key_type(&found_key) != key_type) |
4283 | break; | 4288 | break; |
4284 | if (found_key.offset < filp->f_pos) | 4289 | if (found_key.offset < filp->f_pos) |
4285 | continue; | 4290 | goto next; |
4286 | 4291 | ||
4287 | filp->f_pos = found_key.offset; | 4292 | filp->f_pos = found_key.offset; |
4288 | 4293 | ||
@@ -4335,6 +4340,8 @@ skip: | |||
4335 | di_cur += di_len; | 4340 | di_cur += di_len; |
4336 | di = (struct btrfs_dir_item *)((char *)di + di_len); | 4341 | di = (struct btrfs_dir_item *)((char *)di + di_len); |
4337 | } | 4342 | } |
4343 | next: | ||
4344 | path->slots[0]++; | ||
4338 | } | 4345 | } |
4339 | 4346 | ||
4340 | /* Reached end of directory/root. Bump pos past the last item. */ | 4347 | /* Reached end of directory/root. Bump pos past the last item. */ |
@@ -4527,14 +4534,17 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
4527 | BUG_ON(!path); | 4534 | BUG_ON(!path); |
4528 | 4535 | ||
4529 | inode = new_inode(root->fs_info->sb); | 4536 | inode = new_inode(root->fs_info->sb); |
4530 | if (!inode) | 4537 | if (!inode) { |
4538 | btrfs_free_path(path); | ||
4531 | return ERR_PTR(-ENOMEM); | 4539 | return ERR_PTR(-ENOMEM); |
4540 | } | ||
4532 | 4541 | ||
4533 | if (dir) { | 4542 | if (dir) { |
4534 | trace_btrfs_inode_request(dir); | 4543 | trace_btrfs_inode_request(dir); |
4535 | 4544 | ||
4536 | ret = btrfs_set_inode_index(dir, index); | 4545 | ret = btrfs_set_inode_index(dir, index); |
4537 | if (ret) { | 4546 | if (ret) { |
4547 | btrfs_free_path(path); | ||
4538 | iput(inode); | 4548 | iput(inode); |
4539 | return ERR_PTR(ret); | 4549 | return ERR_PTR(ret); |
4540 | } | 4550 | } |
@@ -4834,9 +4844,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, | |||
4834 | if (inode->i_nlink == ~0U) | 4844 | if (inode->i_nlink == ~0U) |
4835 | return -EMLINK; | 4845 | return -EMLINK; |
4836 | 4846 | ||
4837 | btrfs_inc_nlink(inode); | ||
4838 | inode->i_ctime = CURRENT_TIME; | ||
4839 | |||
4840 | err = btrfs_set_inode_index(dir, &index); | 4847 | err = btrfs_set_inode_index(dir, &index); |
4841 | if (err) | 4848 | if (err) |
4842 | goto fail; | 4849 | goto fail; |
@@ -4852,6 +4859,9 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, | |||
4852 | goto fail; | 4859 | goto fail; |
4853 | } | 4860 | } |
4854 | 4861 | ||
4862 | btrfs_inc_nlink(inode); | ||
4863 | inode->i_ctime = CURRENT_TIME; | ||
4864 | |||
4855 | btrfs_set_trans_block_group(trans, dir); | 4865 | btrfs_set_trans_block_group(trans, dir); |
4856 | ihold(inode); | 4866 | ihold(inode); |
4857 | 4867 | ||
@@ -5221,7 +5231,7 @@ again: | |||
5221 | btrfs_mark_buffer_dirty(leaf); | 5231 | btrfs_mark_buffer_dirty(leaf); |
5222 | } | 5232 | } |
5223 | set_extent_uptodate(io_tree, em->start, | 5233 | set_extent_uptodate(io_tree, em->start, |
5224 | extent_map_end(em) - 1, GFP_NOFS); | 5234 | extent_map_end(em) - 1, NULL, GFP_NOFS); |
5225 | goto insert; | 5235 | goto insert; |
5226 | } else { | 5236 | } else { |
5227 | printk(KERN_ERR "btrfs unknown found_type %d\n", found_type); | 5237 | printk(KERN_ERR "btrfs unknown found_type %d\n", found_type); |
@@ -5428,17 +5438,30 @@ out: | |||
5428 | } | 5438 | } |
5429 | 5439 | ||
5430 | static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | 5440 | static struct extent_map *btrfs_new_extent_direct(struct inode *inode, |
5441 | struct extent_map *em, | ||
5431 | u64 start, u64 len) | 5442 | u64 start, u64 len) |
5432 | { | 5443 | { |
5433 | struct btrfs_root *root = BTRFS_I(inode)->root; | 5444 | struct btrfs_root *root = BTRFS_I(inode)->root; |
5434 | struct btrfs_trans_handle *trans; | 5445 | struct btrfs_trans_handle *trans; |
5435 | struct extent_map *em; | ||
5436 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 5446 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
5437 | struct btrfs_key ins; | 5447 | struct btrfs_key ins; |
5438 | u64 alloc_hint; | 5448 | u64 alloc_hint; |
5439 | int ret; | 5449 | int ret; |
5450 | bool insert = false; | ||
5440 | 5451 | ||
5441 | btrfs_drop_extent_cache(inode, start, start + len - 1, 0); | 5452 | /* |
5453 | * Ok if the extent map we looked up is a hole and is for the exact | ||
5454 | * range we want, there is no reason to allocate a new one, however if | ||
5455 | * it is not right then we need to free this one and drop the cache for | ||
5456 | * our range. | ||
5457 | */ | ||
5458 | if (em->block_start != EXTENT_MAP_HOLE || em->start != start || | ||
5459 | em->len != len) { | ||
5460 | free_extent_map(em); | ||
5461 | em = NULL; | ||
5462 | insert = true; | ||
5463 | btrfs_drop_extent_cache(inode, start, start + len - 1, 0); | ||
5464 | } | ||
5442 | 5465 | ||
5443 | trans = btrfs_join_transaction(root, 0); | 5466 | trans = btrfs_join_transaction(root, 0); |
5444 | if (IS_ERR(trans)) | 5467 | if (IS_ERR(trans)) |
@@ -5454,10 +5477,12 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | |||
5454 | goto out; | 5477 | goto out; |
5455 | } | 5478 | } |
5456 | 5479 | ||
5457 | em = alloc_extent_map(GFP_NOFS); | ||
5458 | if (!em) { | 5480 | if (!em) { |
5459 | em = ERR_PTR(-ENOMEM); | 5481 | em = alloc_extent_map(GFP_NOFS); |
5460 | goto out; | 5482 | if (!em) { |
5483 | em = ERR_PTR(-ENOMEM); | ||
5484 | goto out; | ||
5485 | } | ||
5461 | } | 5486 | } |
5462 | 5487 | ||
5463 | em->start = start; | 5488 | em->start = start; |
@@ -5467,9 +5492,15 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, | |||
5467 | em->block_start = ins.objectid; | 5492 | em->block_start = ins.objectid; |
5468 | em->block_len = ins.offset; | 5493 | em->block_len = ins.offset; |
5469 | em->bdev = root->fs_info->fs_devices->latest_bdev; | 5494 | em->bdev = root->fs_info->fs_devices->latest_bdev; |
5495 | |||
5496 | /* | ||
5497 | * We need to do this because if we're using the original em we searched | ||
5498 | * for, we could have EXTENT_FLAG_VACANCY set, and we don't want that. | ||
5499 | */ | ||
5500 | em->flags = 0; | ||
5470 | set_bit(EXTENT_FLAG_PINNED, &em->flags); | 5501 | set_bit(EXTENT_FLAG_PINNED, &em->flags); |
5471 | 5502 | ||
5472 | while (1) { | 5503 | while (insert) { |
5473 | write_lock(&em_tree->lock); | 5504 | write_lock(&em_tree->lock); |
5474 | ret = add_extent_mapping(em_tree, em); | 5505 | ret = add_extent_mapping(em_tree, em); |
5475 | write_unlock(&em_tree->lock); | 5506 | write_unlock(&em_tree->lock); |
@@ -5687,8 +5718,7 @@ must_cow: | |||
5687 | * it above | 5718 | * it above |
5688 | */ | 5719 | */ |
5689 | len = bh_result->b_size; | 5720 | len = bh_result->b_size; |
5690 | free_extent_map(em); | 5721 | em = btrfs_new_extent_direct(inode, em, start, len); |
5691 | em = btrfs_new_extent_direct(inode, start, len); | ||
5692 | if (IS_ERR(em)) | 5722 | if (IS_ERR(em)) |
5693 | return PTR_ERR(em); | 5723 | return PTR_ERR(em); |
5694 | len = min(len, em->len - (start - em->start)); | 5724 | len = min(len, em->len - (start - em->start)); |
@@ -5851,8 +5881,10 @@ again: | |||
5851 | } | 5881 | } |
5852 | 5882 | ||
5853 | add_pending_csums(trans, inode, ordered->file_offset, &ordered->list); | 5883 | add_pending_csums(trans, inode, ordered->file_offset, &ordered->list); |
5854 | btrfs_ordered_update_i_size(inode, 0, ordered); | 5884 | ret = btrfs_ordered_update_i_size(inode, 0, ordered); |
5855 | btrfs_update_inode(trans, root, inode); | 5885 | if (!ret) |
5886 | btrfs_update_inode(trans, root, inode); | ||
5887 | ret = 0; | ||
5856 | out_unlock: | 5888 | out_unlock: |
5857 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset, | 5889 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset, |
5858 | ordered->file_offset + ordered->len - 1, | 5890 | ordered->file_offset + ordered->len - 1, |
@@ -5938,7 +5970,7 @@ static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev, | |||
5938 | 5970 | ||
5939 | static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, | 5971 | static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, |
5940 | int rw, u64 file_offset, int skip_sum, | 5972 | int rw, u64 file_offset, int skip_sum, |
5941 | u32 *csums) | 5973 | u32 *csums, int async_submit) |
5942 | { | 5974 | { |
5943 | int write = rw & REQ_WRITE; | 5975 | int write = rw & REQ_WRITE; |
5944 | struct btrfs_root *root = BTRFS_I(inode)->root; | 5976 | struct btrfs_root *root = BTRFS_I(inode)->root; |
@@ -5949,13 +5981,24 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, | |||
5949 | if (ret) | 5981 | if (ret) |
5950 | goto err; | 5982 | goto err; |
5951 | 5983 | ||
5952 | if (write && !skip_sum) { | 5984 | if (skip_sum) |
5985 | goto map; | ||
5986 | |||
5987 | if (write && async_submit) { | ||
5953 | ret = btrfs_wq_submit_bio(root->fs_info, | 5988 | ret = btrfs_wq_submit_bio(root->fs_info, |
5954 | inode, rw, bio, 0, 0, | 5989 | inode, rw, bio, 0, 0, |
5955 | file_offset, | 5990 | file_offset, |
5956 | __btrfs_submit_bio_start_direct_io, | 5991 | __btrfs_submit_bio_start_direct_io, |
5957 | __btrfs_submit_bio_done); | 5992 | __btrfs_submit_bio_done); |
5958 | goto err; | 5993 | goto err; |
5994 | } else if (write) { | ||
5995 | /* | ||
5996 | * If we aren't doing async submit, calculate the csum of the | ||
5997 | * bio now. | ||
5998 | */ | ||
5999 | ret = btrfs_csum_one_bio(root, inode, bio, file_offset, 1); | ||
6000 | if (ret) | ||
6001 | goto err; | ||
5959 | } else if (!skip_sum) { | 6002 | } else if (!skip_sum) { |
5960 | ret = btrfs_lookup_bio_sums_dio(root, inode, bio, | 6003 | ret = btrfs_lookup_bio_sums_dio(root, inode, bio, |
5961 | file_offset, csums); | 6004 | file_offset, csums); |
@@ -5963,7 +6006,8 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, | |||
5963 | goto err; | 6006 | goto err; |
5964 | } | 6007 | } |
5965 | 6008 | ||
5966 | ret = btrfs_map_bio(root, rw, bio, 0, 1); | 6009 | map: |
6010 | ret = btrfs_map_bio(root, rw, bio, 0, async_submit); | ||
5967 | err: | 6011 | err: |
5968 | bio_put(bio); | 6012 | bio_put(bio); |
5969 | return ret; | 6013 | return ret; |
@@ -5985,15 +6029,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
5985 | int nr_pages = 0; | 6029 | int nr_pages = 0; |
5986 | u32 *csums = dip->csums; | 6030 | u32 *csums = dip->csums; |
5987 | int ret = 0; | 6031 | int ret = 0; |
6032 | int async_submit = 0; | ||
5988 | int write = rw & REQ_WRITE; | 6033 | int write = rw & REQ_WRITE; |
5989 | 6034 | ||
5990 | bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS); | ||
5991 | if (!bio) | ||
5992 | return -ENOMEM; | ||
5993 | bio->bi_private = dip; | ||
5994 | bio->bi_end_io = btrfs_end_dio_bio; | ||
5995 | atomic_inc(&dip->pending_bios); | ||
5996 | |||
5997 | map_length = orig_bio->bi_size; | 6035 | map_length = orig_bio->bi_size; |
5998 | ret = btrfs_map_block(map_tree, READ, start_sector << 9, | 6036 | ret = btrfs_map_block(map_tree, READ, start_sector << 9, |
5999 | &map_length, NULL, 0); | 6037 | &map_length, NULL, 0); |
@@ -6002,6 +6040,19 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
6002 | return -EIO; | 6040 | return -EIO; |
6003 | } | 6041 | } |
6004 | 6042 | ||
6043 | if (map_length >= orig_bio->bi_size) { | ||
6044 | bio = orig_bio; | ||
6045 | goto submit; | ||
6046 | } | ||
6047 | |||
6048 | async_submit = 1; | ||
6049 | bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS); | ||
6050 | if (!bio) | ||
6051 | return -ENOMEM; | ||
6052 | bio->bi_private = dip; | ||
6053 | bio->bi_end_io = btrfs_end_dio_bio; | ||
6054 | atomic_inc(&dip->pending_bios); | ||
6055 | |||
6005 | while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) { | 6056 | while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) { |
6006 | if (unlikely(map_length < submit_len + bvec->bv_len || | 6057 | if (unlikely(map_length < submit_len + bvec->bv_len || |
6007 | bio_add_page(bio, bvec->bv_page, bvec->bv_len, | 6058 | bio_add_page(bio, bvec->bv_page, bvec->bv_len, |
@@ -6015,7 +6066,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
6015 | atomic_inc(&dip->pending_bios); | 6066 | atomic_inc(&dip->pending_bios); |
6016 | ret = __btrfs_submit_dio_bio(bio, inode, rw, | 6067 | ret = __btrfs_submit_dio_bio(bio, inode, rw, |
6017 | file_offset, skip_sum, | 6068 | file_offset, skip_sum, |
6018 | csums); | 6069 | csums, async_submit); |
6019 | if (ret) { | 6070 | if (ret) { |
6020 | bio_put(bio); | 6071 | bio_put(bio); |
6021 | atomic_dec(&dip->pending_bios); | 6072 | atomic_dec(&dip->pending_bios); |
@@ -6052,8 +6103,9 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, | |||
6052 | } | 6103 | } |
6053 | } | 6104 | } |
6054 | 6105 | ||
6106 | submit: | ||
6055 | ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, | 6107 | ret = __btrfs_submit_dio_bio(bio, inode, rw, file_offset, skip_sum, |
6056 | csums); | 6108 | csums, async_submit); |
6057 | if (!ret) | 6109 | if (!ret) |
6058 | return 0; | 6110 | return 0; |
6059 | 6111 | ||
@@ -6148,6 +6200,7 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io | |||
6148 | unsigned long nr_segs) | 6200 | unsigned long nr_segs) |
6149 | { | 6201 | { |
6150 | int seg; | 6202 | int seg; |
6203 | int i; | ||
6151 | size_t size; | 6204 | size_t size; |
6152 | unsigned long addr; | 6205 | unsigned long addr; |
6153 | unsigned blocksize_mask = root->sectorsize - 1; | 6206 | unsigned blocksize_mask = root->sectorsize - 1; |
@@ -6162,8 +6215,22 @@ static ssize_t check_direct_IO(struct btrfs_root *root, int rw, struct kiocb *io | |||
6162 | addr = (unsigned long)iov[seg].iov_base; | 6215 | addr = (unsigned long)iov[seg].iov_base; |
6163 | size = iov[seg].iov_len; | 6216 | size = iov[seg].iov_len; |
6164 | end += size; | 6217 | end += size; |
6165 | if ((addr & blocksize_mask) || (size & blocksize_mask)) | 6218 | if ((addr & blocksize_mask) || (size & blocksize_mask)) |
6166 | goto out; | 6219 | goto out; |
6220 | |||
6221 | /* If this is a write we don't need to check anymore */ | ||
6222 | if (rw & WRITE) | ||
6223 | continue; | ||
6224 | |||
6225 | /* | ||
6226 | * Check to make sure we don't have duplicate iov_base's in this | ||
6227 | * iovec, if so return EINVAL, otherwise we'll get csum errors | ||
6228 | * when reading back. | ||
6229 | */ | ||
6230 | for (i = seg + 1; i < nr_segs; i++) { | ||
6231 | if (iov[seg].iov_base == iov[i].iov_base) | ||
6232 | goto out; | ||
6233 | } | ||
6167 | } | 6234 | } |
6168 | retval = 0; | 6235 | retval = 0; |
6169 | out: | 6236 | out: |