aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/transaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r--fs/btrfs/transaction.c59
1 files changed, 41 insertions, 18 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 36422254ef67..1791c6e3d834 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -28,6 +28,7 @@
28#include "locking.h" 28#include "locking.h"
29#include "tree-log.h" 29#include "tree-log.h"
30#include "inode-map.h" 30#include "inode-map.h"
31#include "volumes.h"
31 32
32#define BTRFS_ROOT_TRANS_TAG 0 33#define BTRFS_ROOT_TRANS_TAG 0
33 34
@@ -55,48 +56,49 @@ static noinline void switch_commit_root(struct btrfs_root *root)
55static noinline int join_transaction(struct btrfs_root *root, int nofail) 56static noinline int join_transaction(struct btrfs_root *root, int nofail)
56{ 57{
57 struct btrfs_transaction *cur_trans; 58 struct btrfs_transaction *cur_trans;
59 struct btrfs_fs_info *fs_info = root->fs_info;
58 60
59 spin_lock(&root->fs_info->trans_lock); 61 spin_lock(&fs_info->trans_lock);
60loop: 62loop:
61 /* The file system has been taken offline. No new transactions. */ 63 /* The file system has been taken offline. No new transactions. */
62 if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { 64 if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
63 spin_unlock(&root->fs_info->trans_lock); 65 spin_unlock(&fs_info->trans_lock);
64 return -EROFS; 66 return -EROFS;
65 } 67 }
66 68
67 if (root->fs_info->trans_no_join) { 69 if (fs_info->trans_no_join) {
68 if (!nofail) { 70 if (!nofail) {
69 spin_unlock(&root->fs_info->trans_lock); 71 spin_unlock(&fs_info->trans_lock);
70 return -EBUSY; 72 return -EBUSY;
71 } 73 }
72 } 74 }
73 75
74 cur_trans = root->fs_info->running_transaction; 76 cur_trans = fs_info->running_transaction;
75 if (cur_trans) { 77 if (cur_trans) {
76 if (cur_trans->aborted) { 78 if (cur_trans->aborted) {
77 spin_unlock(&root->fs_info->trans_lock); 79 spin_unlock(&fs_info->trans_lock);
78 return cur_trans->aborted; 80 return cur_trans->aborted;
79 } 81 }
80 atomic_inc(&cur_trans->use_count); 82 atomic_inc(&cur_trans->use_count);
81 atomic_inc(&cur_trans->num_writers); 83 atomic_inc(&cur_trans->num_writers);
82 cur_trans->num_joined++; 84 cur_trans->num_joined++;
83 spin_unlock(&root->fs_info->trans_lock); 85 spin_unlock(&fs_info->trans_lock);
84 return 0; 86 return 0;
85 } 87 }
86 spin_unlock(&root->fs_info->trans_lock); 88 spin_unlock(&fs_info->trans_lock);
87 89
88 cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); 90 cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS);
89 if (!cur_trans) 91 if (!cur_trans)
90 return -ENOMEM; 92 return -ENOMEM;
91 93
92 spin_lock(&root->fs_info->trans_lock); 94 spin_lock(&fs_info->trans_lock);
93 if (root->fs_info->running_transaction) { 95 if (fs_info->running_transaction) {
94 /* 96 /*
95 * someone started a transaction after we unlocked. Make sure 97 * someone started a transaction after we unlocked. Make sure
96 * to redo the trans_no_join checks above 98 * to redo the trans_no_join checks above
97 */ 99 */
98 kmem_cache_free(btrfs_transaction_cachep, cur_trans); 100 kmem_cache_free(btrfs_transaction_cachep, cur_trans);
99 cur_trans = root->fs_info->running_transaction; 101 cur_trans = fs_info->running_transaction;
100 goto loop; 102 goto loop;
101 } 103 }
102 104
@@ -121,20 +123,38 @@ loop:
121 cur_trans->delayed_refs.flushing = 0; 123 cur_trans->delayed_refs.flushing = 0;
122 cur_trans->delayed_refs.run_delayed_start = 0; 124 cur_trans->delayed_refs.run_delayed_start = 0;
123 cur_trans->delayed_refs.seq = 1; 125 cur_trans->delayed_refs.seq = 1;
126
127 /*
128 * although the tree mod log is per file system and not per transaction,
129 * the log must never go across transaction boundaries.
130 */
131 smp_mb();
132 if (!list_empty(&fs_info->tree_mod_seq_list)) {
133 printk(KERN_ERR "btrfs: tree_mod_seq_list not empty when "
134 "creating a fresh transaction\n");
135 WARN_ON(1);
136 }
137 if (!RB_EMPTY_ROOT(&fs_info->tree_mod_log)) {
138 printk(KERN_ERR "btrfs: tree_mod_log rb tree not empty when "
139 "creating a fresh transaction\n");
140 WARN_ON(1);
141 }
142 atomic_set(&fs_info->tree_mod_seq, 0);
143
124 init_waitqueue_head(&cur_trans->delayed_refs.seq_wait); 144 init_waitqueue_head(&cur_trans->delayed_refs.seq_wait);
125 spin_lock_init(&cur_trans->commit_lock); 145 spin_lock_init(&cur_trans->commit_lock);
126 spin_lock_init(&cur_trans->delayed_refs.lock); 146 spin_lock_init(&cur_trans->delayed_refs.lock);
127 INIT_LIST_HEAD(&cur_trans->delayed_refs.seq_head); 147 INIT_LIST_HEAD(&cur_trans->delayed_refs.seq_head);
128 148
129 INIT_LIST_HEAD(&cur_trans->pending_snapshots); 149 INIT_LIST_HEAD(&cur_trans->pending_snapshots);
130 list_add_tail(&cur_trans->list, &root->fs_info->trans_list); 150 list_add_tail(&cur_trans->list, &fs_info->trans_list);
131 extent_io_tree_init(&cur_trans->dirty_pages, 151 extent_io_tree_init(&cur_trans->dirty_pages,
132 root->fs_info->btree_inode->i_mapping); 152 fs_info->btree_inode->i_mapping);
133 root->fs_info->generation++; 153 fs_info->generation++;
134 cur_trans->transid = root->fs_info->generation; 154 cur_trans->transid = fs_info->generation;
135 root->fs_info->running_transaction = cur_trans; 155 fs_info->running_transaction = cur_trans;
136 cur_trans->aborted = 0; 156 cur_trans->aborted = 0;
137 spin_unlock(&root->fs_info->trans_lock); 157 spin_unlock(&fs_info->trans_lock);
138 158
139 return 0; 159 return 0;
140} 160}
@@ -758,6 +778,9 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
758 if (ret) 778 if (ret)
759 return ret; 779 return ret;
760 780
781 ret = btrfs_run_dev_stats(trans, root->fs_info);
782 BUG_ON(ret);
783
761 while (!list_empty(&fs_info->dirty_cowonly_roots)) { 784 while (!list_empty(&fs_info->dirty_cowonly_roots)) {
762 next = fs_info->dirty_cowonly_roots.next; 785 next = fs_info->dirty_cowonly_roots.next;
763 list_del_init(next); 786 list_del_init(next);