diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-07-17 12:54:40 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:04 -0400 |
commit | ee6e6504e147a59a9f4d582662c105e9d72ae638 (patch) | |
tree | be932cc04abb860ed76ab8d4c4c28353ed50bebb | |
parent | ba1da2f442ec91a1534afa893f9bef7e33056ace (diff) |
Add a per-inode lock around btrfs_drop_extents
btrfs_drop_extents is always called with a range lock held on the inode.
But, it may operate on extents outside that range as it drops and splits
them.
This patch adds a per-inode mutex that is held while calling
btrfs_drop_extents and while inserting new extents into the tree. It
prevents races from two procs working against adjacent ranges in the tree.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/btrfs_inode.h | 1 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 2 | ||||
-rw-r--r-- | fs/btrfs/file.c | 8 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 10 |
4 files changed, 21 insertions, 0 deletions
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 81c0444f37b6..3bf40591742a 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h | |||
@@ -32,6 +32,7 @@ struct btrfs_inode { | |||
32 | struct extent_io_tree io_tree; | 32 | struct extent_io_tree io_tree; |
33 | struct extent_io_tree io_failure_tree; | 33 | struct extent_io_tree io_failure_tree; |
34 | struct mutex csum_mutex; | 34 | struct mutex csum_mutex; |
35 | struct mutex extent_mutex; | ||
35 | struct inode vfs_inode; | 36 | struct inode vfs_inode; |
36 | struct btrfs_ordered_inode_tree ordered_tree; | 37 | struct btrfs_ordered_inode_tree ordered_tree; |
37 | 38 | ||
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 343d1101c31c..4036c62b6671 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1671,6 +1671,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans, | |||
1671 | ret = __free_extent(trans, root, bytenr, num_bytes, root_objectid, | 1671 | ret = __free_extent(trans, root, bytenr, num_bytes, root_objectid, |
1672 | ref_generation, owner_objectid, owner_offset, | 1672 | ref_generation, owner_objectid, owner_offset, |
1673 | pin, pin == 0); | 1673 | pin, pin == 0); |
1674 | |||
1675 | finish_current_insert(trans, root->fs_info->extent_root); | ||
1674 | pending_ret = del_pending_extents(trans, root->fs_info->extent_root); | 1676 | pending_ret = del_pending_extents(trans, root->fs_info->extent_root); |
1675 | return ret ? ret : pending_ret; | 1677 | return ret ? ret : pending_ret; |
1676 | } | 1678 | } |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 3e4e5c227c0c..40ad1b2958cb 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -242,6 +242,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
242 | u64 end_of_last_block; | 242 | u64 end_of_last_block; |
243 | u64 end_pos = pos + write_bytes; | 243 | u64 end_pos = pos + write_bytes; |
244 | u64 inline_size; | 244 | u64 inline_size; |
245 | int did_inline = 0; | ||
245 | loff_t isize = i_size_read(inode); | 246 | loff_t isize = i_size_read(inode); |
246 | 247 | ||
247 | start_pos = pos & ~((u64)root->sectorsize - 1); | 248 | start_pos = pos & ~((u64)root->sectorsize - 1); |
@@ -275,6 +276,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
275 | if (hole_size > 0) { | 276 | if (hole_size > 0) { |
276 | btrfs_wait_ordered_range(inode, last_pos_in_file, | 277 | btrfs_wait_ordered_range(inode, last_pos_in_file, |
277 | last_pos_in_file + hole_size); | 278 | last_pos_in_file + hole_size); |
279 | mutex_lock(&BTRFS_I(inode)->extent_mutex); | ||
278 | err = btrfs_drop_extents(trans, root, inode, | 280 | err = btrfs_drop_extents(trans, root, inode, |
279 | last_pos_in_file, | 281 | last_pos_in_file, |
280 | last_pos_in_file + hole_size, | 282 | last_pos_in_file + hole_size, |
@@ -289,6 +291,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
289 | 0, 0, hole_size, 0); | 291 | 0, 0, hole_size, 0); |
290 | btrfs_drop_extent_cache(inode, last_pos_in_file, | 292 | btrfs_drop_extent_cache(inode, last_pos_in_file, |
291 | last_pos_in_file + hole_size -1); | 293 | last_pos_in_file + hole_size -1); |
294 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | ||
292 | btrfs_check_file(root, inode); | 295 | btrfs_check_file(root, inode); |
293 | } | 296 | } |
294 | if (err) | 297 | if (err) |
@@ -321,6 +324,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
321 | /* step one, delete the existing extents in this range */ | 324 | /* step one, delete the existing extents in this range */ |
322 | aligned_end = (pos + write_bytes + root->sectorsize - 1) & | 325 | aligned_end = (pos + write_bytes + root->sectorsize - 1) & |
323 | ~((u64)root->sectorsize - 1); | 326 | ~((u64)root->sectorsize - 1); |
327 | mutex_lock(&BTRFS_I(inode)->extent_mutex); | ||
324 | err = btrfs_drop_extents(trans, root, inode, start_pos, | 328 | err = btrfs_drop_extents(trans, root, inode, start_pos, |
325 | aligned_end, aligned_end, &hint_byte); | 329 | aligned_end, aligned_end, &hint_byte); |
326 | if (err) | 330 | if (err) |
@@ -332,9 +336,13 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
332 | inline_size, pages, 0, num_pages); | 336 | inline_size, pages, 0, num_pages); |
333 | btrfs_drop_extent_cache(inode, start_pos, aligned_end - 1); | 337 | btrfs_drop_extent_cache(inode, start_pos, aligned_end - 1); |
334 | BUG_ON(err); | 338 | BUG_ON(err); |
339 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | ||
340 | did_inline = 1; | ||
335 | } | 341 | } |
336 | if (end_pos > isize) { | 342 | if (end_pos > isize) { |
337 | i_size_write(inode, end_pos); | 343 | i_size_write(inode, end_pos); |
344 | if (did_inline) | ||
345 | BTRFS_I(inode)->disk_i_size = end_pos; | ||
338 | btrfs_update_inode(trans, root, inode); | 346 | btrfs_update_inode(trans, root, inode); |
339 | } | 347 | } |
340 | failed: | 348 | failed: |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 293355c92a4f..0d1e2ba47a9c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -516,6 +516,8 @@ int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end, | |||
516 | trans->transid, inode->i_ino, | 516 | trans->transid, inode->i_ino, |
517 | ordered_extent->file_offset, &ins); | 517 | ordered_extent->file_offset, &ins); |
518 | BUG_ON(ret); | 518 | BUG_ON(ret); |
519 | |||
520 | mutex_lock(&BTRFS_I(inode)->extent_mutex); | ||
519 | ret = btrfs_drop_extents(trans, root, inode, | 521 | ret = btrfs_drop_extents(trans, root, inode, |
520 | ordered_extent->file_offset, | 522 | ordered_extent->file_offset, |
521 | ordered_extent->file_offset + | 523 | ordered_extent->file_offset + |
@@ -531,6 +533,8 @@ int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end, | |||
531 | btrfs_drop_extent_cache(inode, ordered_extent->file_offset, | 533 | btrfs_drop_extent_cache(inode, ordered_extent->file_offset, |
532 | ordered_extent->file_offset + | 534 | ordered_extent->file_offset + |
533 | ordered_extent->len - 1); | 535 | ordered_extent->len - 1); |
536 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | ||
537 | |||
534 | inode->i_blocks += ordered_extent->len >> 9; | 538 | inode->i_blocks += ordered_extent->len >> 9; |
535 | unlock_extent(io_tree, ordered_extent->file_offset, | 539 | unlock_extent(io_tree, ordered_extent->file_offset, |
536 | ordered_extent->file_offset + ordered_extent->len - 1, | 540 | ordered_extent->file_offset + ordered_extent->len - 1, |
@@ -1399,6 +1403,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
1399 | 1403 | ||
1400 | trans = btrfs_start_transaction(root, 1); | 1404 | trans = btrfs_start_transaction(root, 1); |
1401 | btrfs_set_trans_block_group(trans, inode); | 1405 | btrfs_set_trans_block_group(trans, inode); |
1406 | mutex_lock(&BTRFS_I(inode)->extent_mutex); | ||
1402 | err = btrfs_drop_extents(trans, root, inode, | 1407 | err = btrfs_drop_extents(trans, root, inode, |
1403 | hole_start, block_end, hole_start, | 1408 | hole_start, block_end, hole_start, |
1404 | &alloc_hint); | 1409 | &alloc_hint); |
@@ -1412,6 +1417,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
1412 | (u64)-1); | 1417 | (u64)-1); |
1413 | btrfs_check_file(root, inode); | 1418 | btrfs_check_file(root, inode); |
1414 | } | 1419 | } |
1420 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | ||
1415 | btrfs_end_transaction(trans, root); | 1421 | btrfs_end_transaction(trans, root); |
1416 | unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS); | 1422 | unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS); |
1417 | if (err) | 1423 | if (err) |
@@ -1578,6 +1584,7 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p) | |||
1578 | inode->i_mapping, GFP_NOFS); | 1584 | inode->i_mapping, GFP_NOFS); |
1579 | btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree); | 1585 | btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree); |
1580 | mutex_init(&BTRFS_I(inode)->csum_mutex); | 1586 | mutex_init(&BTRFS_I(inode)->csum_mutex); |
1587 | mutex_init(&BTRFS_I(inode)->extent_mutex); | ||
1581 | return 0; | 1588 | return 0; |
1582 | } | 1589 | } |
1583 | 1590 | ||
@@ -1880,6 +1887,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
1880 | inode->i_mapping, GFP_NOFS); | 1887 | inode->i_mapping, GFP_NOFS); |
1881 | btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree); | 1888 | btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree); |
1882 | mutex_init(&BTRFS_I(inode)->csum_mutex); | 1889 | mutex_init(&BTRFS_I(inode)->csum_mutex); |
1890 | mutex_init(&BTRFS_I(inode)->extent_mutex); | ||
1883 | BTRFS_I(inode)->delalloc_bytes = 0; | 1891 | BTRFS_I(inode)->delalloc_bytes = 0; |
1884 | BTRFS_I(inode)->disk_i_size = 0; | 1892 | BTRFS_I(inode)->disk_i_size = 0; |
1885 | BTRFS_I(inode)->root = root; | 1893 | BTRFS_I(inode)->root = root; |
@@ -2105,6 +2113,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, | |||
2105 | extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree, | 2113 | extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree, |
2106 | inode->i_mapping, GFP_NOFS); | 2114 | inode->i_mapping, GFP_NOFS); |
2107 | mutex_init(&BTRFS_I(inode)->csum_mutex); | 2115 | mutex_init(&BTRFS_I(inode)->csum_mutex); |
2116 | mutex_init(&BTRFS_I(inode)->extent_mutex); | ||
2108 | BTRFS_I(inode)->delalloc_bytes = 0; | 2117 | BTRFS_I(inode)->delalloc_bytes = 0; |
2109 | BTRFS_I(inode)->disk_i_size = 0; | 2118 | BTRFS_I(inode)->disk_i_size = 0; |
2110 | BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; | 2119 | BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; |
@@ -3079,6 +3088,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, | |||
3079 | extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree, | 3088 | extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree, |
3080 | inode->i_mapping, GFP_NOFS); | 3089 | inode->i_mapping, GFP_NOFS); |
3081 | mutex_init(&BTRFS_I(inode)->csum_mutex); | 3090 | mutex_init(&BTRFS_I(inode)->csum_mutex); |
3091 | mutex_init(&BTRFS_I(inode)->extent_mutex); | ||
3082 | BTRFS_I(inode)->delalloc_bytes = 0; | 3092 | BTRFS_I(inode)->delalloc_bytes = 0; |
3083 | BTRFS_I(inode)->disk_i_size = 0; | 3093 | BTRFS_I(inode)->disk_i_size = 0; |
3084 | BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; | 3094 | BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; |