diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
| -rw-r--r-- | fs/btrfs/transaction.c | 59 |
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) | |||
| 55 | static noinline int join_transaction(struct btrfs_root *root, int nofail) | 56 | static 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); |
| 60 | loop: | 62 | loop: |
| 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); |
