diff options
author | Josef Bacik <jwhiter@redhat.com> | 2007-08-10 16:22:09 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-08-10 16:22:09 -0400 |
commit | 15ee9bc7ed171248d1405df5854da5fa91bfdc39 (patch) | |
tree | 5f29f51e1c14a6b35b2019a2ada5bb80fb97e2bd | |
parent | f2183bde1a918d338337955c8e8ba29bd8f5e7b1 (diff) |
Btrfs: delay commits during fsync to allow more writers
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/btrfs_inode.h | 5 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 1 | ||||
-rw-r--r-- | fs/btrfs/file.c | 22 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 2 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 44 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 7 |
7 files changed, 66 insertions, 16 deletions
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 6bce46be49ff..f446f161f736 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h | |||
@@ -25,6 +25,11 @@ struct btrfs_inode { | |||
25 | struct btrfs_block_group_cache *block_group; | 25 | struct btrfs_block_group_cache *block_group; |
26 | struct btrfs_key location; | 26 | struct btrfs_key location; |
27 | struct inode vfs_inode; | 27 | struct inode vfs_inode; |
28 | |||
29 | /* | ||
30 | * transid of the trans_handle that last modified this inode | ||
31 | */ | ||
32 | u64 last_trans; | ||
28 | }; | 33 | }; |
29 | static inline struct btrfs_inode *BTRFS_I(struct inode *inode) | 34 | static inline struct btrfs_inode *BTRFS_I(struct inode *inode) |
30 | { | 35 | { |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index d3cd564b3b3f..c7f5161271d3 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -301,6 +301,7 @@ struct btrfs_fs_info { | |||
301 | struct radix_tree_root extent_map_radix; | 301 | struct radix_tree_root extent_map_radix; |
302 | struct radix_tree_root extent_ins_radix; | 302 | struct radix_tree_root extent_ins_radix; |
303 | u64 generation; | 303 | u64 generation; |
304 | u64 last_trans_committed; | ||
304 | struct btrfs_transaction *running_transaction; | 305 | struct btrfs_transaction *running_transaction; |
305 | struct btrfs_super_block *disk_super; | 306 | struct btrfs_super_block *disk_super; |
306 | struct btrfs_super_block super_copy; | 307 | struct btrfs_super_block super_copy; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 192211274ce5..b2f79878d51a 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -435,6 +435,7 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
435 | INIT_LIST_HEAD(&fs_info->dead_roots); | 435 | INIT_LIST_HEAD(&fs_info->dead_roots); |
436 | sb_set_blocksize(sb, 4096); | 436 | sb_set_blocksize(sb, 4096); |
437 | fs_info->running_transaction = NULL; | 437 | fs_info->running_transaction = NULL; |
438 | fs_info->last_trans_committed = 0; | ||
438 | fs_info->tree_root = tree_root; | 439 | fs_info->tree_root = tree_root; |
439 | fs_info->extent_root = extent_root; | 440 | fs_info->extent_root = extent_root; |
440 | fs_info->sb = sb; | 441 | fs_info->sb = sb; |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 00b118a2db69..6933ab11a5cd 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -694,22 +694,36 @@ static int btrfs_sync_file(struct file *file, | |||
694 | { | 694 | { |
695 | struct inode *inode = dentry->d_inode; | 695 | struct inode *inode = dentry->d_inode; |
696 | struct btrfs_root *root = BTRFS_I(inode)->root; | 696 | struct btrfs_root *root = BTRFS_I(inode)->root; |
697 | int ret; | 697 | int ret = 0; |
698 | struct btrfs_trans_handle *trans; | 698 | struct btrfs_trans_handle *trans; |
699 | 699 | ||
700 | /* | 700 | /* |
701 | * FIXME, use inode generation number to check if we can skip the | 701 | * check the transaction that last modified this inode |
702 | * commit | 702 | * and see if its already been committed |
703 | */ | 703 | */ |
704 | mutex_lock(&root->fs_info->fs_mutex); | 704 | mutex_lock(&root->fs_info->fs_mutex); |
705 | if (!BTRFS_I(inode)->last_trans) | ||
706 | goto out; | ||
707 | mutex_lock(&root->fs_info->trans_mutex); | ||
708 | if (BTRFS_I(inode)->last_trans <= | ||
709 | root->fs_info->last_trans_committed) { | ||
710 | BTRFS_I(inode)->last_trans = 0; | ||
711 | mutex_unlock(&root->fs_info->trans_mutex); | ||
712 | goto out; | ||
713 | } | ||
714 | mutex_unlock(&root->fs_info->trans_mutex); | ||
715 | |||
716 | /* | ||
717 | * ok we haven't committed the transaction yet, lets do a commit | ||
718 | */ | ||
705 | trans = btrfs_start_transaction(root, 1); | 719 | trans = btrfs_start_transaction(root, 1); |
706 | if (!trans) { | 720 | if (!trans) { |
707 | ret = -ENOMEM; | 721 | ret = -ENOMEM; |
708 | goto out; | 722 | goto out; |
709 | } | 723 | } |
710 | ret = btrfs_commit_transaction(trans, root); | 724 | ret = btrfs_commit_transaction(trans, root); |
711 | mutex_unlock(&root->fs_info->fs_mutex); | ||
712 | out: | 725 | out: |
726 | mutex_unlock(&root->fs_info->fs_mutex); | ||
713 | return ret > 0 ? EIO : ret; | 727 | return ret > 0 ? EIO : ret; |
714 | } | 728 | } |
715 | 729 | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5c05ecbc5726..398484179d82 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -193,6 +193,7 @@ static int btrfs_update_inode(struct btrfs_trans_handle *trans, | |||
193 | 193 | ||
194 | fill_inode_item(inode_item, inode); | 194 | fill_inode_item(inode_item, inode); |
195 | btrfs_mark_buffer_dirty(path->nodes[0]); | 195 | btrfs_mark_buffer_dirty(path->nodes[0]); |
196 | btrfs_set_inode_last_trans(trans, inode); | ||
196 | ret = 0; | 197 | ret = 0; |
197 | failed: | 198 | failed: |
198 | btrfs_release_path(root, path); | 199 | btrfs_release_path(root, path); |
@@ -2234,6 +2235,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) | |||
2234 | ei = kmem_cache_alloc(btrfs_inode_cachep, GFP_NOFS); | 2235 | ei = kmem_cache_alloc(btrfs_inode_cachep, GFP_NOFS); |
2235 | if (!ei) | 2236 | if (!ei) |
2236 | return NULL; | 2237 | return NULL; |
2238 | ei->last_trans = 0; | ||
2237 | return &ei->vfs_inode; | 2239 | return &ei->vfs_inode; |
2238 | } | 2240 | } |
2239 | 2241 | ||
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index c9d52dc83e48..18abea802794 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -55,7 +55,8 @@ static int join_transaction(struct btrfs_root *root) | |||
55 | BUG_ON(!cur_trans); | 55 | BUG_ON(!cur_trans); |
56 | root->fs_info->generation++; | 56 | root->fs_info->generation++; |
57 | root->fs_info->running_transaction = cur_trans; | 57 | root->fs_info->running_transaction = cur_trans; |
58 | cur_trans->num_writers = 0; | 58 | cur_trans->num_writers = 1; |
59 | cur_trans->num_joined = 0; | ||
59 | cur_trans->transid = root->fs_info->generation; | 60 | cur_trans->transid = root->fs_info->generation; |
60 | init_waitqueue_head(&cur_trans->writer_wait); | 61 | init_waitqueue_head(&cur_trans->writer_wait); |
61 | init_waitqueue_head(&cur_trans->commit_wait); | 62 | init_waitqueue_head(&cur_trans->commit_wait); |
@@ -65,8 +66,11 @@ static int join_transaction(struct btrfs_root *root) | |||
65 | cur_trans->start_time = get_seconds(); | 66 | cur_trans->start_time = get_seconds(); |
66 | list_add_tail(&cur_trans->list, &root->fs_info->trans_list); | 67 | list_add_tail(&cur_trans->list, &root->fs_info->trans_list); |
67 | init_bit_radix(&cur_trans->dirty_pages); | 68 | init_bit_radix(&cur_trans->dirty_pages); |
69 | } else { | ||
70 | cur_trans->num_writers++; | ||
71 | cur_trans->num_joined++; | ||
68 | } | 72 | } |
69 | cur_trans->num_writers++; | 73 | |
70 | return 0; | 74 | return 0; |
71 | } | 75 | } |
72 | 76 | ||
@@ -428,12 +432,14 @@ static int drop_dirty_roots(struct btrfs_root *tree_root, | |||
428 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 432 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
429 | struct btrfs_root *root) | 433 | struct btrfs_root *root) |
430 | { | 434 | { |
431 | int ret = 0; | 435 | unsigned long joined = 0; |
436 | unsigned long timeout = 1; | ||
432 | struct btrfs_transaction *cur_trans; | 437 | struct btrfs_transaction *cur_trans; |
433 | struct btrfs_transaction *prev_trans = NULL; | 438 | struct btrfs_transaction *prev_trans = NULL; |
434 | struct list_head dirty_fs_roots; | 439 | struct list_head dirty_fs_roots; |
435 | struct radix_tree_root pinned_copy; | 440 | struct radix_tree_root pinned_copy; |
436 | DEFINE_WAIT(wait); | 441 | DEFINE_WAIT(wait); |
442 | int ret; | ||
437 | 443 | ||
438 | init_bit_radix(&pinned_copy); | 444 | init_bit_radix(&pinned_copy); |
439 | INIT_LIST_HEAD(&dirty_fs_roots); | 445 | INIT_LIST_HEAD(&dirty_fs_roots); |
@@ -448,7 +454,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
448 | mutex_unlock(&root->fs_info->fs_mutex); | 454 | mutex_unlock(&root->fs_info->fs_mutex); |
449 | ret = wait_for_commit(root, cur_trans); | 455 | ret = wait_for_commit(root, cur_trans); |
450 | BUG_ON(ret); | 456 | BUG_ON(ret); |
457 | |||
458 | mutex_lock(&root->fs_info->trans_mutex); | ||
451 | put_transaction(cur_trans); | 459 | put_transaction(cur_trans); |
460 | mutex_unlock(&root->fs_info->trans_mutex); | ||
461 | |||
452 | mutex_lock(&root->fs_info->fs_mutex); | 462 | mutex_lock(&root->fs_info->fs_mutex); |
453 | return 0; | 463 | return 0; |
454 | } | 464 | } |
@@ -463,26 +473,35 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
463 | mutex_unlock(&root->fs_info->trans_mutex); | 473 | mutex_unlock(&root->fs_info->trans_mutex); |
464 | 474 | ||
465 | wait_for_commit(root, prev_trans); | 475 | wait_for_commit(root, prev_trans); |
466 | put_transaction(prev_trans); | ||
467 | 476 | ||
468 | mutex_lock(&root->fs_info->fs_mutex); | 477 | mutex_lock(&root->fs_info->fs_mutex); |
469 | mutex_lock(&root->fs_info->trans_mutex); | 478 | mutex_lock(&root->fs_info->trans_mutex); |
479 | put_transaction(prev_trans); | ||
470 | } | 480 | } |
471 | } | 481 | } |
472 | while (trans->transaction->num_writers > 1) { | 482 | |
483 | do { | ||
484 | joined = cur_trans->num_joined; | ||
473 | WARN_ON(cur_trans != trans->transaction); | 485 | WARN_ON(cur_trans != trans->transaction); |
474 | prepare_to_wait(&trans->transaction->writer_wait, &wait, | 486 | prepare_to_wait(&cur_trans->writer_wait, &wait, |
475 | TASK_UNINTERRUPTIBLE); | 487 | TASK_UNINTERRUPTIBLE); |
476 | if (trans->transaction->num_writers <= 1) | 488 | |
477 | break; | 489 | if (cur_trans->num_writers > 1) |
490 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
491 | else | ||
492 | timeout = 1; | ||
493 | |||
478 | mutex_unlock(&root->fs_info->fs_mutex); | 494 | mutex_unlock(&root->fs_info->fs_mutex); |
479 | mutex_unlock(&root->fs_info->trans_mutex); | 495 | mutex_unlock(&root->fs_info->trans_mutex); |
480 | schedule(); | 496 | |
497 | schedule_timeout(timeout); | ||
498 | |||
481 | mutex_lock(&root->fs_info->fs_mutex); | 499 | mutex_lock(&root->fs_info->fs_mutex); |
482 | mutex_lock(&root->fs_info->trans_mutex); | 500 | mutex_lock(&root->fs_info->trans_mutex); |
483 | finish_wait(&trans->transaction->writer_wait, &wait); | 501 | finish_wait(&cur_trans->writer_wait, &wait); |
484 | } | 502 | } while (cur_trans->num_writers > 1 || |
485 | finish_wait(&trans->transaction->writer_wait, &wait); | 503 | (cur_trans->num_joined != joined)); |
504 | |||
486 | WARN_ON(cur_trans != trans->transaction); | 505 | WARN_ON(cur_trans != trans->transaction); |
487 | ret = add_dirty_roots(trans, &root->fs_info->fs_roots_radix, | 506 | ret = add_dirty_roots(trans, &root->fs_info->fs_roots_radix, |
488 | &dirty_fs_roots); | 507 | &dirty_fs_roots); |
@@ -511,6 +530,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
511 | btrfs_finish_extent_commit(trans, root, &pinned_copy); | 530 | btrfs_finish_extent_commit(trans, root, &pinned_copy); |
512 | mutex_lock(&root->fs_info->trans_mutex); | 531 | mutex_lock(&root->fs_info->trans_mutex); |
513 | cur_trans->commit_done = 1; | 532 | cur_trans->commit_done = 1; |
533 | root->fs_info->last_trans_committed = cur_trans->transid; | ||
514 | wake_up(&cur_trans->commit_wait); | 534 | wake_up(&cur_trans->commit_wait); |
515 | put_transaction(cur_trans); | 535 | put_transaction(cur_trans); |
516 | put_transaction(cur_trans); | 536 | put_transaction(cur_trans); |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index d5f491d3757e..e451783a1a4d 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -23,6 +23,7 @@ | |||
23 | struct btrfs_transaction { | 23 | struct btrfs_transaction { |
24 | u64 transid; | 24 | u64 transid; |
25 | unsigned long num_writers; | 25 | unsigned long num_writers; |
26 | unsigned long num_joined; | ||
26 | int in_commit; | 27 | int in_commit; |
27 | int use_count; | 28 | int use_count; |
28 | int commit_done; | 29 | int commit_done; |
@@ -57,6 +58,12 @@ static inline void btrfs_update_inode_block_group(struct | |||
57 | BTRFS_I(inode)->block_group = trans->block_group; | 58 | BTRFS_I(inode)->block_group = trans->block_group; |
58 | } | 59 | } |
59 | 60 | ||
61 | static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans, | ||
62 | struct inode *inode) | ||
63 | { | ||
64 | BTRFS_I(inode)->last_trans = trans->transaction->transid; | ||
65 | } | ||
66 | |||
60 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | 67 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, |
61 | struct btrfs_root *root); | 68 | struct btrfs_root *root); |
62 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | 69 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, |