diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-05-02 15:53:43 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-05-02 15:53:43 -0400 |
commit | 35b7e476107e3d54f03384e0f2fa3dfd68933353 (patch) | |
tree | 51a7e7cffad309b0aa0d3d054d7ecc5b8be72298 /fs/btrfs | |
parent | 090d18753c7fb73f7d846c3a89a50cd35136d144 (diff) |
Btrfs: fix page cache memory leak
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/bit-radix.c | 2 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
-rw-r--r-- | fs/btrfs/dir-item.c | 11 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 8 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 2 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 12 | ||||
-rw-r--r-- | fs/btrfs/hash.c | 1 | ||||
-rw-r--r-- | fs/btrfs/print-tree.c | 1 | ||||
-rw-r--r-- | fs/btrfs/super.c | 56 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 8 |
10 files changed, 59 insertions, 45 deletions
diff --git a/fs/btrfs/bit-radix.c b/fs/btrfs/bit-radix.c index 9fc42e99c7df..e9ace32d7bae 100644 --- a/fs/btrfs/bit-radix.c +++ b/fs/btrfs/bit-radix.c | |||
@@ -22,9 +22,7 @@ int set_radix_bit(struct radix_tree_root *radix, unsigned long bit) | |||
22 | return -ENOMEM; | 22 | return -ENOMEM; |
23 | memset(bits + 1, 0, BIT_ARRAY_BYTES - sizeof(unsigned long)); | 23 | memset(bits + 1, 0, BIT_ARRAY_BYTES - sizeof(unsigned long)); |
24 | bits[0] = slot; | 24 | bits[0] = slot; |
25 | radix_tree_preload(GFP_NOFS); | ||
26 | ret = radix_tree_insert(radix, slot, bits); | 25 | ret = radix_tree_insert(radix, slot, bits); |
27 | radix_tree_preload_end(); | ||
28 | if (ret) | 26 | if (ret) |
29 | return ret; | 27 | return ret; |
30 | } | 28 | } |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index e6bf9919536a..b5855a5365ef 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -8,6 +8,9 @@ | |||
8 | 8 | ||
9 | struct btrfs_trans_handle; | 9 | struct btrfs_trans_handle; |
10 | struct btrfs_transaction; | 10 | struct btrfs_transaction; |
11 | extern struct kmem_cache *btrfs_trans_handle_cachep; | ||
12 | extern struct kmem_cache *btrfs_transaction_cachep; | ||
13 | extern struct kmem_cache *btrfs_bit_radix_cachep; | ||
11 | extern struct kmem_cache *btrfs_path_cachep; | 14 | extern struct kmem_cache *btrfs_path_cachep; |
12 | 15 | ||
13 | #define BTRFS_MAGIC "_BtRfS_M" | 16 | #define BTRFS_MAGIC "_BtRfS_M" |
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 7a7e9846860a..00a28d90fea6 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c | |||
@@ -4,11 +4,12 @@ | |||
4 | #include "hash.h" | 4 | #include "hash.h" |
5 | #include "transaction.h" | 5 | #include "transaction.h" |
6 | 6 | ||
7 | struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle *trans, | 7 | static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle |
8 | struct btrfs_root *root, | 8 | *trans, |
9 | struct btrfs_path *path, | 9 | struct btrfs_root *root, |
10 | struct btrfs_key *cpu_key, | 10 | struct btrfs_path *path, |
11 | u32 data_size) | 11 | struct btrfs_key *cpu_key, |
12 | u32 data_size) | ||
12 | { | 13 | { |
13 | int ret; | 14 | int ret; |
14 | char *ptr; | 15 | char *ptr; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 354524adf984..5828a104dfef 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -5,7 +5,7 @@ | |||
5 | #include <linux/scatterlist.h> | 5 | #include <linux/scatterlist.h> |
6 | #include <linux/swap.h> | 6 | #include <linux/swap.h> |
7 | #include <linux/radix-tree.h> | 7 | #include <linux/radix-tree.h> |
8 | #include <linux/file.h> | 8 | #include <linux/writeback.h> |
9 | #include "ctree.h" | 9 | #include "ctree.h" |
10 | #include "disk-io.h" | 10 | #include "disk-io.h" |
11 | #include "transaction.h" | 11 | #include "transaction.h" |
@@ -694,7 +694,7 @@ static int free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | |||
694 | return 0; | 694 | return 0; |
695 | } | 695 | } |
696 | 696 | ||
697 | int del_fs_roots(struct btrfs_fs_info *fs_info) | 697 | static int del_fs_roots(struct btrfs_fs_info *fs_info) |
698 | { | 698 | { |
699 | int ret; | 699 | int ret; |
700 | struct btrfs_root *gang[8]; | 700 | struct btrfs_root *gang[8]; |
@@ -781,3 +781,7 @@ void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf) | |||
781 | brelse(buf); | 781 | brelse(buf); |
782 | } | 782 | } |
783 | 783 | ||
784 | void btrfs_btree_balance_dirty(struct btrfs_root *root) | ||
785 | { | ||
786 | balance_dirty_pages_ratelimited(root->fs_info->btree_inode->i_mapping); | ||
787 | } | ||
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 1ee7d2a55b5b..822ccb8aa4ae 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -55,4 +55,6 @@ int btrfs_insert_dev_radix(struct btrfs_root *root, | |||
55 | u64 num_blocks); | 55 | u64 num_blocks); |
56 | int btrfs_map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh, | 56 | int btrfs_map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh, |
57 | u64 logical); | 57 | u64 logical); |
58 | int btrfs_releasepage(struct page *page, gfp_t flags); | ||
59 | void btrfs_btree_balance_dirty(struct btrfs_root *root); | ||
58 | #endif | 60 | #endif |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 2837fddf7b1c..0e20d1c42fca 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -322,18 +322,10 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
322 | return 0; | 322 | return 0; |
323 | } | 323 | } |
324 | 324 | ||
325 | static int try_remove_page(struct address_space *mapping, unsigned long index) | ||
326 | { | ||
327 | int ret; | ||
328 | ret = invalidate_mapping_pages(mapping, index, index); | ||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | 325 | int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct |
333 | btrfs_root *root) | 326 | btrfs_root *root) |
334 | { | 327 | { |
335 | unsigned long gang[8]; | 328 | unsigned long gang[8]; |
336 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
337 | u64 first = 0; | 329 | u64 first = 0; |
338 | int ret; | 330 | int ret; |
339 | int i; | 331 | int i; |
@@ -348,9 +340,6 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | |||
348 | first = gang[0]; | 340 | first = gang[0]; |
349 | for (i = 0; i < ret; i++) { | 341 | for (i = 0; i < ret; i++) { |
350 | clear_radix_bit(pinned_radix, gang[i]); | 342 | clear_radix_bit(pinned_radix, gang[i]); |
351 | try_remove_page(btree_inode->i_mapping, | ||
352 | gang[i] << (PAGE_CACHE_SHIFT - | ||
353 | btree_inode->i_blkbits)); | ||
354 | } | 343 | } |
355 | } | 344 | } |
356 | return 0; | 345 | return 0; |
@@ -983,6 +972,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
983 | break; | 972 | break; |
984 | if (wret < 0) | 973 | if (wret < 0) |
985 | ret = wret; | 974 | ret = wret; |
975 | btrfs_btree_balance_dirty(root); | ||
986 | } | 976 | } |
987 | for (i = 0; i <= orig_level; i++) { | 977 | for (i = 0; i <= orig_level; i++) { |
988 | if (path->nodes[i]) { | 978 | if (path->nodes[i]) { |
diff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c index 22519b8e0cf2..32de1ea1b64e 100644 --- a/fs/btrfs/hash.c +++ b/fs/btrfs/hash.c | |||
@@ -11,6 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include "hash.h" | ||
14 | #define DELTA 0x9E3779B9 | 15 | #define DELTA 0x9E3779B9 |
15 | 16 | ||
16 | static void TEA_transform(__u32 buf[2], __u32 const in[]) | 17 | static void TEA_transform(__u32 buf[2], __u32 const in[]) |
diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index 2f95fc67a036..28813411de66 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <linux/module.h> | 1 | #include <linux/module.h> |
2 | #include "ctree.h" | 2 | #include "ctree.h" |
3 | #include "disk-io.h" | 3 | #include "disk-io.h" |
4 | #include "print-tree.h" | ||
4 | 5 | ||
5 | void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l) | 6 | void btrfs_print_leaf(struct btrfs_root *root, struct btrfs_leaf *l) |
6 | { | 7 | { |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index a29a781b86c2..130a1d3d9f5f 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -18,14 +18,14 @@ | |||
18 | #include "btrfs_inode.h" | 18 | #include "btrfs_inode.h" |
19 | #include "ioctl.h" | 19 | #include "ioctl.h" |
20 | 20 | ||
21 | void btrfs_fsinfo_release(struct kobject *obj) | 21 | static void btrfs_fsinfo_release(struct kobject *obj) |
22 | { | 22 | { |
23 | struct btrfs_fs_info *fsinfo = container_of(obj, | 23 | struct btrfs_fs_info *fsinfo = container_of(obj, |
24 | struct btrfs_fs_info, kobj); | 24 | struct btrfs_fs_info, kobj); |
25 | kfree(fsinfo); | 25 | kfree(fsinfo); |
26 | } | 26 | } |
27 | 27 | ||
28 | struct kobj_type btrfs_fsinfo_ktype = { | 28 | static struct kobj_type btrfs_fsinfo_ktype = { |
29 | .release = btrfs_fsinfo_release, | 29 | .release = btrfs_fsinfo_release, |
30 | }; | 30 | }; |
31 | 31 | ||
@@ -148,7 +148,6 @@ static void fill_inode_item(struct btrfs_inode_item *item, | |||
148 | BTRFS_I(inode)->block_group->key.objectid); | 148 | BTRFS_I(inode)->block_group->key.objectid); |
149 | } | 149 | } |
150 | 150 | ||
151 | |||
152 | static int btrfs_update_inode(struct btrfs_trans_handle *trans, | 151 | static int btrfs_update_inode(struct btrfs_trans_handle *trans, |
153 | struct btrfs_root *root, | 152 | struct btrfs_root *root, |
154 | struct inode *inode) | 153 | struct inode *inode) |
@@ -251,6 +250,7 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry) | |||
251 | ret = btrfs_unlink_trans(trans, root, dir, dentry); | 250 | ret = btrfs_unlink_trans(trans, root, dir, dentry); |
252 | btrfs_end_transaction(trans, root); | 251 | btrfs_end_transaction(trans, root); |
253 | mutex_unlock(&root->fs_info->fs_mutex); | 252 | mutex_unlock(&root->fs_info->fs_mutex); |
253 | btrfs_btree_balance_dirty(root); | ||
254 | return ret; | 254 | return ret; |
255 | } | 255 | } |
256 | 256 | ||
@@ -324,6 +324,7 @@ out: | |||
324 | btrfs_free_path(path); | 324 | btrfs_free_path(path); |
325 | mutex_unlock(&root->fs_info->fs_mutex); | 325 | mutex_unlock(&root->fs_info->fs_mutex); |
326 | ret = btrfs_end_transaction(trans, root); | 326 | ret = btrfs_end_transaction(trans, root); |
327 | btrfs_btree_balance_dirty(root); | ||
327 | if (ret && !err) | 328 | if (ret && !err) |
328 | err = ret; | 329 | err = ret; |
329 | return err; | 330 | return err; |
@@ -449,6 +450,7 @@ static void btrfs_delete_inode(struct inode *inode) | |||
449 | btrfs_free_inode(trans, root, inode); | 450 | btrfs_free_inode(trans, root, inode); |
450 | btrfs_end_transaction(trans, root); | 451 | btrfs_end_transaction(trans, root); |
451 | mutex_unlock(&root->fs_info->fs_mutex); | 452 | mutex_unlock(&root->fs_info->fs_mutex); |
453 | btrfs_btree_balance_dirty(root); | ||
452 | return; | 454 | return; |
453 | no_delete: | 455 | no_delete: |
454 | clear_inode(inode); | 456 | clear_inode(inode); |
@@ -481,7 +483,7 @@ out: | |||
481 | return ret; | 483 | return ret; |
482 | } | 484 | } |
483 | 485 | ||
484 | int fixup_tree_root_location(struct btrfs_root *root, | 486 | static int fixup_tree_root_location(struct btrfs_root *root, |
485 | struct btrfs_key *location, | 487 | struct btrfs_key *location, |
486 | struct btrfs_root **sub_root) | 488 | struct btrfs_root **sub_root) |
487 | { | 489 | { |
@@ -512,7 +514,7 @@ int fixup_tree_root_location(struct btrfs_root *root, | |||
512 | return 0; | 514 | return 0; |
513 | } | 515 | } |
514 | 516 | ||
515 | int btrfs_init_locked_inode(struct inode *inode, void *p) | 517 | static int btrfs_init_locked_inode(struct inode *inode, void *p) |
516 | { | 518 | { |
517 | struct btrfs_iget_args *args = p; | 519 | struct btrfs_iget_args *args = p; |
518 | inode->i_ino = args->ino; | 520 | inode->i_ino = args->ino; |
@@ -520,15 +522,15 @@ int btrfs_init_locked_inode(struct inode *inode, void *p) | |||
520 | return 0; | 522 | return 0; |
521 | } | 523 | } |
522 | 524 | ||
523 | int btrfs_find_actor(struct inode *inode, void *opaque) | 525 | static int btrfs_find_actor(struct inode *inode, void *opaque) |
524 | { | 526 | { |
525 | struct btrfs_iget_args *args = opaque; | 527 | struct btrfs_iget_args *args = opaque; |
526 | return (args->ino == inode->i_ino && | 528 | return (args->ino == inode->i_ino && |
527 | args->root == BTRFS_I(inode)->root); | 529 | args->root == BTRFS_I(inode)->root); |
528 | } | 530 | } |
529 | 531 | ||
530 | struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid, | 532 | static struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid, |
531 | struct btrfs_root *root) | 533 | struct btrfs_root *root) |
532 | { | 534 | { |
533 | struct inode *inode; | 535 | struct inode *inode; |
534 | struct btrfs_iget_args args; | 536 | struct btrfs_iget_args args; |
@@ -790,6 +792,7 @@ static void btrfs_dirty_inode(struct inode *inode) | |||
790 | btrfs_update_inode(trans, root, inode); | 792 | btrfs_update_inode(trans, root, inode); |
791 | btrfs_end_transaction(trans, root); | 793 | btrfs_end_transaction(trans, root); |
792 | mutex_unlock(&root->fs_info->fs_mutex); | 794 | mutex_unlock(&root->fs_info->fs_mutex); |
795 | btrfs_btree_balance_dirty(root); | ||
793 | } | 796 | } |
794 | 797 | ||
795 | static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | 798 | static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, |
@@ -913,6 +916,7 @@ out_unlock: | |||
913 | inode_dec_link_count(inode); | 916 | inode_dec_link_count(inode); |
914 | iput(inode); | 917 | iput(inode); |
915 | } | 918 | } |
919 | btrfs_btree_balance_dirty(root); | ||
916 | return err; | 920 | return err; |
917 | } | 921 | } |
918 | 922 | ||
@@ -1002,6 +1006,7 @@ out_unlock: | |||
1002 | mutex_unlock(&root->fs_info->fs_mutex); | 1006 | mutex_unlock(&root->fs_info->fs_mutex); |
1003 | if (drop_on_err) | 1007 | if (drop_on_err) |
1004 | iput(inode); | 1008 | iput(inode); |
1009 | btrfs_btree_balance_dirty(root); | ||
1005 | return err; | 1010 | return err; |
1006 | } | 1011 | } |
1007 | 1012 | ||
@@ -1099,7 +1104,6 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | |||
1099 | found_type != BTRFS_EXTENT_DATA_KEY) { | 1104 | found_type != BTRFS_EXTENT_DATA_KEY) { |
1100 | extent_end = 0; | 1105 | extent_end = 0; |
1101 | extent_start = 0; | 1106 | extent_start = 0; |
1102 | btrfs_release_path(root, path); | ||
1103 | goto out; | 1107 | goto out; |
1104 | } | 1108 | } |
1105 | found_type = btrfs_file_extent_type(item); | 1109 | found_type = btrfs_file_extent_type(item); |
@@ -1135,7 +1139,6 @@ static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | |||
1135 | btrfs_map_bh_to_logical(root, result, 0); | 1139 | btrfs_map_bh_to_logical(root, result, 0); |
1136 | } | 1140 | } |
1137 | out: | 1141 | out: |
1138 | btrfs_release_path(root, path); | ||
1139 | btrfs_free_path(path); | 1142 | btrfs_free_path(path); |
1140 | return err; | 1143 | return err; |
1141 | } | 1144 | } |
@@ -1231,13 +1234,13 @@ static int __btrfs_write_full_page(struct inode *inode, struct page *page, | |||
1231 | } else if (!buffer_mapped(bh) && buffer_dirty(bh)) { | 1234 | } else if (!buffer_mapped(bh) && buffer_dirty(bh)) { |
1232 | WARN_ON(bh->b_size != blocksize); | 1235 | WARN_ON(bh->b_size != blocksize); |
1233 | err = btrfs_get_block(inode, block, bh, 0); | 1236 | err = btrfs_get_block(inode, block, bh, 0); |
1234 | if (err) | 1237 | if (err) { |
1238 | printk("writepage going to recovery err %d\n", err); | ||
1235 | goto recover; | 1239 | goto recover; |
1240 | } | ||
1236 | if (buffer_new(bh)) { | 1241 | if (buffer_new(bh)) { |
1237 | /* blockdev mappings never come here */ | 1242 | /* blockdev mappings never come here */ |
1238 | clear_buffer_new(bh); | 1243 | clear_buffer_new(bh); |
1239 | unmap_underlying_metadata(bh->b_bdev, | ||
1240 | bh->b_blocknr); | ||
1241 | } | 1244 | } |
1242 | } | 1245 | } |
1243 | bh = bh->b_this_page; | 1246 | bh = bh->b_this_page; |
@@ -1303,11 +1306,6 @@ done: | |||
1303 | if (uptodate) | 1306 | if (uptodate) |
1304 | SetPageUptodate(page); | 1307 | SetPageUptodate(page); |
1305 | end_page_writeback(page); | 1308 | end_page_writeback(page); |
1306 | /* | ||
1307 | * The page and buffer_heads can be released at any time from | ||
1308 | * here on. | ||
1309 | */ | ||
1310 | wbc->pages_skipped++; /* We didn't write this page */ | ||
1311 | } | 1309 | } |
1312 | return err; | 1310 | return err; |
1313 | 1311 | ||
@@ -1409,10 +1407,11 @@ static void btrfs_truncate(struct inode *inode) | |||
1409 | btrfs_set_trans_block_group(trans, inode); | 1407 | btrfs_set_trans_block_group(trans, inode); |
1410 | ret = btrfs_truncate_in_trans(trans, root, inode); | 1408 | ret = btrfs_truncate_in_trans(trans, root, inode); |
1411 | BUG_ON(ret); | 1409 | BUG_ON(ret); |
1410 | btrfs_update_inode(trans, root, inode); | ||
1412 | ret = btrfs_end_transaction(trans, root); | 1411 | ret = btrfs_end_transaction(trans, root); |
1413 | BUG_ON(ret); | 1412 | BUG_ON(ret); |
1414 | mutex_unlock(&root->fs_info->fs_mutex); | 1413 | mutex_unlock(&root->fs_info->fs_mutex); |
1415 | mark_inode_dirty(inode); | 1414 | btrfs_btree_balance_dirty(root); |
1416 | } | 1415 | } |
1417 | 1416 | ||
1418 | /* | 1417 | /* |
@@ -1777,10 +1776,15 @@ static int prepare_pages(struct btrfs_root *root, | |||
1777 | err = -ENOMEM; | 1776 | err = -ENOMEM; |
1778 | goto failed_release; | 1777 | goto failed_release; |
1779 | } | 1778 | } |
1779 | cancel_dirty_page(pages[i], PAGE_CACHE_SIZE); | ||
1780 | wait_on_page_writeback(pages[i]); | ||
1780 | offset = pos & (PAGE_CACHE_SIZE -1); | 1781 | offset = pos & (PAGE_CACHE_SIZE -1); |
1781 | this_write = min(PAGE_CACHE_SIZE - offset, write_bytes); | 1782 | this_write = min(PAGE_CACHE_SIZE - offset, write_bytes); |
1782 | create_empty_buffers(pages[i], root->fs_info->sb->s_blocksize, | 1783 | if (!page_has_buffers(pages[i])) { |
1783 | (1 << BH_Uptodate)); | 1784 | create_empty_buffers(pages[i], |
1785 | root->fs_info->sb->s_blocksize, | ||
1786 | (1 << BH_Uptodate)); | ||
1787 | } | ||
1784 | head = page_buffers(pages[i]); | 1788 | head = page_buffers(pages[i]); |
1785 | bh = head; | 1789 | bh = head; |
1786 | do { | 1790 | do { |
@@ -1820,7 +1824,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1820 | struct inode *inode = file->f_path.dentry->d_inode; | 1824 | struct inode *inode = file->f_path.dentry->d_inode; |
1821 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1825 | struct btrfs_root *root = BTRFS_I(inode)->root; |
1822 | struct page *pages[8]; | 1826 | struct page *pages[8]; |
1823 | struct page *pinned[2] = { NULL, NULL }; | 1827 | struct page *pinned[2]; |
1824 | unsigned long first_index; | 1828 | unsigned long first_index; |
1825 | unsigned long last_index; | 1829 | unsigned long last_index; |
1826 | u64 start_pos; | 1830 | u64 start_pos; |
@@ -1829,6 +1833,8 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1829 | struct btrfs_trans_handle *trans; | 1833 | struct btrfs_trans_handle *trans; |
1830 | struct btrfs_key ins; | 1834 | struct btrfs_key ins; |
1831 | 1835 | ||
1836 | pinned[0] = NULL; | ||
1837 | pinned[1] = NULL; | ||
1832 | if (file->f_flags & O_DIRECT) | 1838 | if (file->f_flags & O_DIRECT) |
1833 | return -EINVAL; | 1839 | return -EINVAL; |
1834 | pos = *ppos; | 1840 | pos = *ppos; |
@@ -1858,6 +1864,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1858 | if (!PageUptodate(pinned[0])) { | 1864 | if (!PageUptodate(pinned[0])) { |
1859 | ret = mpage_readpage(pinned[0], btrfs_get_block); | 1865 | ret = mpage_readpage(pinned[0], btrfs_get_block); |
1860 | BUG_ON(ret); | 1866 | BUG_ON(ret); |
1867 | wait_on_page_locked(pinned[0]); | ||
1861 | } else { | 1868 | } else { |
1862 | unlock_page(pinned[0]); | 1869 | unlock_page(pinned[0]); |
1863 | } | 1870 | } |
@@ -1869,6 +1876,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1869 | if (!PageUptodate(pinned[1])) { | 1876 | if (!PageUptodate(pinned[1])) { |
1870 | ret = mpage_readpage(pinned[1], btrfs_get_block); | 1877 | ret = mpage_readpage(pinned[1], btrfs_get_block); |
1871 | BUG_ON(ret); | 1878 | BUG_ON(ret); |
1879 | wait_on_page_locked(pinned[1]); | ||
1872 | } else { | 1880 | } else { |
1873 | unlock_page(pinned[1]); | 1881 | unlock_page(pinned[1]); |
1874 | } | 1882 | } |
@@ -1940,6 +1948,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf, | |||
1940 | num_written += write_bytes; | 1948 | num_written += write_bytes; |
1941 | 1949 | ||
1942 | balance_dirty_pages_ratelimited(inode->i_mapping); | 1950 | balance_dirty_pages_ratelimited(inode->i_mapping); |
1951 | btrfs_btree_balance_dirty(root); | ||
1943 | cond_resched(); | 1952 | cond_resched(); |
1944 | } | 1953 | } |
1945 | out_unlock: | 1954 | out_unlock: |
@@ -2165,6 +2174,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen) | |||
2165 | iput(inode); | 2174 | iput(inode); |
2166 | 2175 | ||
2167 | mutex_unlock(&root->fs_info->fs_mutex); | 2176 | mutex_unlock(&root->fs_info->fs_mutex); |
2177 | btrfs_btree_balance_dirty(root); | ||
2168 | return 0; | 2178 | return 0; |
2169 | } | 2179 | } |
2170 | 2180 | ||
@@ -2220,6 +2230,7 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | |||
2220 | ret = btrfs_commit_transaction(trans, root); | 2230 | ret = btrfs_commit_transaction(trans, root); |
2221 | BUG_ON(ret); | 2231 | BUG_ON(ret); |
2222 | mutex_unlock(&root->fs_info->fs_mutex); | 2232 | mutex_unlock(&root->fs_info->fs_mutex); |
2233 | btrfs_btree_balance_dirty(root); | ||
2223 | return 0; | 2234 | return 0; |
2224 | } | 2235 | } |
2225 | 2236 | ||
@@ -2295,6 +2306,7 @@ out: | |||
2295 | mutex_unlock(&root->fs_info->fs_mutex); | 2306 | mutex_unlock(&root->fs_info->fs_mutex); |
2296 | out_nolock: | 2307 | out_nolock: |
2297 | btrfs_free_path(path); | 2308 | btrfs_free_path(path); |
2309 | btrfs_btree_balance_dirty(root); | ||
2298 | 2310 | ||
2299 | return ret; | 2311 | return ret; |
2300 | } | 2312 | } |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index bdbf514c111f..8bbe9107ff7e 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -199,8 +199,9 @@ struct dirty_root { | |||
199 | struct btrfs_root *root; | 199 | struct btrfs_root *root; |
200 | }; | 200 | }; |
201 | 201 | ||
202 | int add_dirty_roots(struct btrfs_trans_handle *trans, | 202 | static int add_dirty_roots(struct btrfs_trans_handle *trans, |
203 | struct radix_tree_root *radix, struct list_head *list) | 203 | struct radix_tree_root *radix, |
204 | struct list_head *list) | ||
204 | { | 205 | { |
205 | struct dirty_root *dirty; | 206 | struct dirty_root *dirty; |
206 | struct btrfs_root *gang[8]; | 207 | struct btrfs_root *gang[8]; |
@@ -246,7 +247,8 @@ int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
246 | return 0; | 247 | return 0; |
247 | } | 248 | } |
248 | 249 | ||
249 | int drop_dirty_roots(struct btrfs_root *tree_root, struct list_head *list) | 250 | static int drop_dirty_roots(struct btrfs_root *tree_root, |
251 | struct list_head *list) | ||
250 | { | 252 | { |
251 | struct dirty_root *dirty; | 253 | struct dirty_root *dirty; |
252 | struct btrfs_trans_handle *trans; | 254 | struct btrfs_trans_handle *trans; |