diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-22 15:59:16 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-22 15:59:16 -0400 |
commit | 79154b1b5bcf87903db7ff16a30b360b78d6fe4f (patch) | |
tree | 7c752c350abd28060c5bd7aa364323051aecac90 | |
parent | e20d96d64f9cf9288ffecc9ad4714e91c3b97ca8 (diff) |
Btrfs: transaction rework
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/Makefile | 2 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 4 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 115 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 8 | ||||
-rw-r--r-- | fs/btrfs/super.c | 18 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 199 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 35 |
7 files changed, 235 insertions, 146 deletions
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index 1a0fb7422393..be7d74cdca04 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile | |||
@@ -3,7 +3,7 @@ ifneq ($(KERNELRELEASE),) | |||
3 | 3 | ||
4 | obj-m := btrfs.o | 4 | obj-m := btrfs.o |
5 | btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ | 5 | btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ |
6 | hash.o file-item.o inode-item.o inode-map.o disk-io.o | 6 | hash.o file-item.o inode-item.o inode-map.o disk-io.o transaction.o |
7 | 7 | ||
8 | #btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ | 8 | #btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ |
9 | # root-tree.o dir-item.o hash.o file-item.o inode-item.o \ | 9 | # root-tree.o dir-item.o hash.o file-item.o inode-item.o \ |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 7748eecd9304..4c19a3f12afd 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/fs.h> | 5 | #include <linux/fs.h> |
6 | 6 | ||
7 | struct btrfs_trans_handle; | 7 | struct btrfs_trans_handle; |
8 | struct btrfs_transaction; | ||
8 | 9 | ||
9 | #define BTRFS_MAGIC "_BtRfS_M" | 10 | #define BTRFS_MAGIC "_BtRfS_M" |
10 | 11 | ||
@@ -224,10 +225,11 @@ struct btrfs_fs_info { | |||
224 | u64 last_inode_alloc; | 225 | u64 last_inode_alloc; |
225 | u64 last_inode_alloc_dirid; | 226 | u64 last_inode_alloc_dirid; |
226 | u64 generation; | 227 | u64 generation; |
227 | struct btrfs_trans_handle *running_transaction; | 228 | struct btrfs_transaction *running_transaction; |
228 | struct btrfs_super_block *disk_super; | 229 | struct btrfs_super_block *disk_super; |
229 | struct buffer_head *sb_buffer; | 230 | struct buffer_head *sb_buffer; |
230 | struct super_block *sb; | 231 | struct super_block *sb; |
232 | struct mutex trans_mutex; | ||
231 | }; | 233 | }; |
232 | 234 | ||
233 | /* | 235 | /* |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index df2061a735cd..9cacca0c525c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -50,89 +50,6 @@ int clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
50 | return 0; | 50 | return 0; |
51 | } | 51 | } |
52 | 52 | ||
53 | int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | ||
54 | struct buffer_head *buf) | ||
55 | { | ||
56 | mark_buffer_dirty(buf); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int __commit_transaction(struct btrfs_trans_handle *trans, struct | ||
61 | btrfs_root *root) | ||
62 | { | ||
63 | filemap_write_and_wait(root->fs_info->sb->s_bdev->bd_inode->i_mapping); | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int commit_tree_roots(struct btrfs_trans_handle *trans, | ||
68 | struct btrfs_fs_info *fs_info) | ||
69 | { | ||
70 | int ret; | ||
71 | u64 old_extent_block; | ||
72 | struct btrfs_root *tree_root = fs_info->tree_root; | ||
73 | struct btrfs_root *extent_root = fs_info->extent_root; | ||
74 | struct btrfs_root *inode_root = fs_info->inode_root; | ||
75 | |||
76 | btrfs_set_root_blocknr(&inode_root->root_item, | ||
77 | inode_root->node->b_blocknr); | ||
78 | ret = btrfs_update_root(trans, tree_root, | ||
79 | &inode_root->root_key, | ||
80 | &inode_root->root_item); | ||
81 | BUG_ON(ret); | ||
82 | while(1) { | ||
83 | old_extent_block = btrfs_root_blocknr(&extent_root->root_item); | ||
84 | if (old_extent_block == extent_root->node->b_blocknr) | ||
85 | break; | ||
86 | btrfs_set_root_blocknr(&extent_root->root_item, | ||
87 | extent_root->node->b_blocknr); | ||
88 | ret = btrfs_update_root(trans, tree_root, | ||
89 | &extent_root->root_key, | ||
90 | &extent_root->root_item); | ||
91 | BUG_ON(ret); | ||
92 | } | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct | ||
97 | btrfs_root *root, struct btrfs_super_block *s) | ||
98 | { | ||
99 | int ret = 0; | ||
100 | struct buffer_head *snap = root->commit_root; | ||
101 | struct btrfs_key snap_key; | ||
102 | |||
103 | if (root->commit_root == root->node) | ||
104 | return 0; | ||
105 | |||
106 | memcpy(&snap_key, &root->root_key, sizeof(snap_key)); | ||
107 | root->root_key.offset++; | ||
108 | |||
109 | btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr); | ||
110 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, | ||
111 | &root->root_key, &root->root_item); | ||
112 | BUG_ON(ret); | ||
113 | |||
114 | ret = commit_tree_roots(trans, root->fs_info); | ||
115 | BUG_ON(ret); | ||
116 | |||
117 | ret = __commit_transaction(trans, root); | ||
118 | BUG_ON(ret); | ||
119 | |||
120 | write_ctree_super(trans, root, s); | ||
121 | btrfs_finish_extent_commit(trans, root->fs_info->extent_root); | ||
122 | btrfs_finish_extent_commit(trans, root->fs_info->tree_root); | ||
123 | |||
124 | root->commit_root = root->node; | ||
125 | get_bh(root->node); | ||
126 | ret = btrfs_drop_snapshot(trans, root, snap); | ||
127 | BUG_ON(ret); | ||
128 | |||
129 | ret = btrfs_del_root(trans, root->fs_info->tree_root, &snap_key); | ||
130 | BUG_ON(ret); | ||
131 | root->fs_info->generation = root->root_key.offset + 1; | ||
132 | |||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | static int __setup_root(struct btrfs_super_block *super, | 53 | static int __setup_root(struct btrfs_super_block *super, |
137 | struct btrfs_root *root, | 54 | struct btrfs_root *root, |
138 | struct btrfs_fs_info *fs_info, | 55 | struct btrfs_fs_info *fs_info, |
@@ -197,6 +114,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
197 | fs_info->disk_super = disk_super; | 114 | fs_info->disk_super = disk_super; |
198 | fs_info->sb_buffer = sb_buffer; | 115 | fs_info->sb_buffer = sb_buffer; |
199 | fs_info->sb = sb; | 116 | fs_info->sb = sb; |
117 | mutex_init(&fs_info->trans_mutex); | ||
200 | memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert)); | 118 | memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert)); |
201 | memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert)); | 119 | memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert)); |
202 | 120 | ||
@@ -225,7 +143,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
225 | } | 143 | } |
226 | 144 | ||
227 | int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root | 145 | int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root |
228 | *root, struct btrfs_super_block *s) | 146 | *root) |
229 | { | 147 | { |
230 | return 0; | 148 | return 0; |
231 | #if 0 | 149 | #if 0 |
@@ -242,34 +160,19 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root | |||
242 | #endif | 160 | #endif |
243 | } | 161 | } |
244 | 162 | ||
245 | static int drop_cache(struct btrfs_root *root) | ||
246 | { | ||
247 | return 0; | ||
248 | #if 0 | ||
249 | while(!list_empty(&root->fs_info->cache)) { | ||
250 | struct buffer_head *b = list_entry(root->fs_info->cache.next, | ||
251 | struct buffer_head, | ||
252 | cache); | ||
253 | list_del_init(&b->cache); | ||
254 | btrfs_block_release(root, b); | ||
255 | } | ||
256 | return 0; | ||
257 | #endif | ||
258 | } | ||
259 | |||
260 | int close_ctree(struct btrfs_root *root) | 163 | int close_ctree(struct btrfs_root *root) |
261 | { | 164 | { |
262 | int ret; | 165 | int ret; |
263 | struct btrfs_trans_handle *trans; | 166 | struct btrfs_trans_handle *trans; |
264 | 167 | ||
265 | trans = root->fs_info->running_transaction; | 168 | trans = btrfs_start_transaction(root, 1); |
266 | btrfs_commit_transaction(trans, root, root->fs_info->disk_super); | 169 | btrfs_commit_transaction(trans, root); |
267 | ret = commit_tree_roots(trans, root->fs_info); | 170 | /* run commit again to drop the original snapshot */ |
268 | BUG_ON(ret); | 171 | trans = btrfs_start_transaction(root, 1); |
269 | ret = __commit_transaction(trans, root); | 172 | btrfs_commit_transaction(trans, root); |
173 | ret = btrfs_write_and_wait_transaction(NULL, root); | ||
270 | BUG_ON(ret); | 174 | BUG_ON(ret); |
271 | write_ctree_super(trans, root, root->fs_info->disk_super); | 175 | write_ctree_super(NULL, root); |
272 | drop_cache(root); | ||
273 | 176 | ||
274 | if (root->node) | 177 | if (root->node) |
275 | btrfs_block_release(root, root->node); | 178 | btrfs_block_release(root, root->node); |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 7f4bb729b734..099f7eea0ec7 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -28,14 +28,14 @@ int dirty_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
28 | struct buffer_head *buf); | 28 | struct buffer_head *buf); |
29 | int clean_tree_block(struct btrfs_trans_handle *trans, | 29 | int clean_tree_block(struct btrfs_trans_handle *trans, |
30 | struct btrfs_root *root, struct buffer_head *buf); | 30 | struct btrfs_root *root, struct buffer_head *buf); |
31 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, struct btrfs_root | 31 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
32 | *root, struct btrfs_super_block *s); | 32 | struct btrfs_root *root); |
33 | struct btrfs_root *open_ctree(struct super_block *sb, | 33 | struct btrfs_root *open_ctree(struct super_block *sb, |
34 | struct buffer_head *sb_buffer, | 34 | struct buffer_head *sb_buffer, |
35 | struct btrfs_super_block *disk_super); | 35 | struct btrfs_super_block *disk_super); |
36 | int close_ctree(struct btrfs_root *root); | 36 | int close_ctree(struct btrfs_root *root); |
37 | void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf); | 37 | void btrfs_block_release(struct btrfs_root *root, struct buffer_head *buf); |
38 | int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 38 | int write_ctree_super(struct btrfs_trans_handle *trans, |
39 | struct btrfs_super_block *s); | 39 | struct btrfs_root *root); |
40 | int mkfs(int fd, u64 num_blocks, u32 blocksize); | 40 | int mkfs(int fd, u64 num_blocks, u32 blocksize); |
41 | #endif | 41 | #endif |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index ccc056aad692..620430825840 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -141,7 +141,6 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
141 | struct btrfs_inode_item *inode_item; | 141 | struct btrfs_inode_item *inode_item; |
142 | struct btrfs_root *root = btrfs_sb(inode->i_sb); | 142 | struct btrfs_root *root = btrfs_sb(inode->i_sb); |
143 | int ret; | 143 | int ret; |
144 | printk("read locked inode %lu\n", inode->i_ino); | ||
145 | btrfs_init_path(&path); | 144 | btrfs_init_path(&path); |
146 | ret = btrfs_lookup_inode(NULL, root, &path, inode->i_ino, 0); | 145 | ret = btrfs_lookup_inode(NULL, root, &path, inode->i_ino, 0); |
147 | if (ret) { | 146 | if (ret) { |
@@ -152,7 +151,6 @@ printk("read locked inode %lu\n", inode->i_ino); | |||
152 | path.slots[0], | 151 | path.slots[0], |
153 | struct btrfs_inode_item); | 152 | struct btrfs_inode_item); |
154 | 153 | ||
155 | printk("found locked inode %lu\n", inode->i_ino); | ||
156 | inode->i_mode = btrfs_inode_mode(inode_item); | 154 | inode->i_mode = btrfs_inode_mode(inode_item); |
157 | inode->i_nlink = btrfs_inode_nlink(inode_item); | 155 | inode->i_nlink = btrfs_inode_nlink(inode_item); |
158 | inode->i_uid = btrfs_inode_uid(inode_item); | 156 | inode->i_uid = btrfs_inode_uid(inode_item); |
@@ -166,7 +164,6 @@ printk("found locked inode %lu\n", inode->i_ino); | |||
166 | inode->i_ctime.tv_nsec = btrfs_timespec_nsec(&inode_item->ctime); | 164 | inode->i_ctime.tv_nsec = btrfs_timespec_nsec(&inode_item->ctime); |
167 | inode->i_blocks = btrfs_inode_nblocks(inode_item); | 165 | inode->i_blocks = btrfs_inode_nblocks(inode_item); |
168 | inode->i_generation = btrfs_inode_generation(inode_item); | 166 | inode->i_generation = btrfs_inode_generation(inode_item); |
169 | printk("about to release\n"); | ||
170 | btrfs_release_path(root, &path); | 167 | btrfs_release_path(root, &path); |
171 | switch (inode->i_mode & S_IFMT) { | 168 | switch (inode->i_mode & S_IFMT) { |
172 | #if 0 | 169 | #if 0 |
@@ -176,19 +173,15 @@ printk("about to release\n"); | |||
176 | break; | 173 | break; |
177 | #endif | 174 | #endif |
178 | case S_IFREG: | 175 | case S_IFREG: |
179 | printk("inode %lu now a file\n", inode->i_ino); | ||
180 | break; | 176 | break; |
181 | case S_IFDIR: | 177 | case S_IFDIR: |
182 | printk("inode %lu now a directory\n", inode->i_ino); | ||
183 | inode->i_op = &btrfs_dir_inode_operations; | 178 | inode->i_op = &btrfs_dir_inode_operations; |
184 | inode->i_fop = &btrfs_dir_file_operations; | 179 | inode->i_fop = &btrfs_dir_file_operations; |
185 | break; | 180 | break; |
186 | case S_IFLNK: | 181 | case S_IFLNK: |
187 | printk("inode %lu now a link\n", inode->i_ino); | ||
188 | // inode->i_op = &page_symlink_inode_operations; | 182 | // inode->i_op = &page_symlink_inode_operations; |
189 | break; | 183 | break; |
190 | } | 184 | } |
191 | printk("returning!\n"); | ||
192 | return; | 185 | return; |
193 | } | 186 | } |
194 | 187 | ||
@@ -232,7 +225,6 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
232 | return ERR_PTR(ret); | 225 | return ERR_PTR(ret); |
233 | inode = NULL; | 226 | inode = NULL; |
234 | if (ino) { | 227 | if (ino) { |
235 | printk("lookup on %.*s returns %lu\n", dentry->d_name.len, dentry->d_name.name, ino); | ||
236 | inode = iget(dir->i_sb, ino); | 228 | inode = iget(dir->i_sb, ino); |
237 | if (!inode) | 229 | if (!inode) |
238 | return ERR_PTR(-EACCES); | 230 | return ERR_PTR(-EACCES); |
@@ -257,7 +249,6 @@ static int btrfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
257 | int over; | 249 | int over; |
258 | 250 | ||
259 | key.objectid = inode->i_ino; | 251 | key.objectid = inode->i_ino; |
260 | printk("readdir on dir %Lu pos %Lu\n", key.objectid, filp->f_pos); | ||
261 | key.flags = 0; | 252 | key.flags = 0; |
262 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); | 253 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); |
263 | key.offset = filp->f_pos; | 254 | key.offset = filp->f_pos; |
@@ -266,15 +257,12 @@ printk("readdir on dir %Lu pos %Lu\n", key.objectid, filp->f_pos); | |||
266 | if (ret < 0) { | 257 | if (ret < 0) { |
267 | goto err; | 258 | goto err; |
268 | } | 259 | } |
269 | printk("first ret %d\n", ret); | ||
270 | advance = filp->f_pos > 0 && ret != 0; | 260 | advance = filp->f_pos > 0 && ret != 0; |
271 | while(1) { | 261 | while(1) { |
272 | leaf = btrfs_buffer_leaf(path.nodes[0]); | 262 | leaf = btrfs_buffer_leaf(path.nodes[0]); |
273 | nritems = btrfs_header_nritems(&leaf->header); | 263 | nritems = btrfs_header_nritems(&leaf->header); |
274 | slot = path.slots[0]; | 264 | slot = path.slots[0]; |
275 | printk("leaf %Lu nritems %lu slot %d\n", path.nodes[0]->b_blocknr, nritems, slot); | ||
276 | if (advance) { | 265 | if (advance) { |
277 | printk("advancing!\n"); | ||
278 | if (slot == nritems -1) { | 266 | if (slot == nritems -1) { |
279 | ret = btrfs_next_leaf(root, &path); | 267 | ret = btrfs_next_leaf(root, &path); |
280 | if (ret) | 268 | if (ret) |
@@ -282,7 +270,6 @@ printk("advancing!\n"); | |||
282 | leaf = btrfs_buffer_leaf(path.nodes[0]); | 270 | leaf = btrfs_buffer_leaf(path.nodes[0]); |
283 | nritems = btrfs_header_nritems(&leaf->header); | 271 | nritems = btrfs_header_nritems(&leaf->header); |
284 | slot = path.slots[0]; | 272 | slot = path.slots[0]; |
285 | printk("2leaf %Lu nritems %lu slot %d\n", path.nodes[0]->b_blocknr, nritems, slot); | ||
286 | } else { | 273 | } else { |
287 | slot++; | 274 | slot++; |
288 | path.slots[0]++; | 275 | path.slots[0]++; |
@@ -290,15 +277,11 @@ printk("2leaf %Lu nritems %lu slot %d\n", path.nodes[0]->b_blocknr, nritems, slo | |||
290 | } | 277 | } |
291 | advance = 1; | 278 | advance = 1; |
292 | item = leaf->items + slot; | 279 | item = leaf->items + slot; |
293 | printk("item key %Lu %u %Lu\n", btrfs_disk_key_objectid(&item->key), | ||
294 | btrfs_disk_key_flags(&item->key), btrfs_disk_key_offset(&item->key)); | ||
295 | if (btrfs_disk_key_objectid(&item->key) != key.objectid) | 280 | if (btrfs_disk_key_objectid(&item->key) != key.objectid) |
296 | break; | 281 | break; |
297 | if (btrfs_disk_key_type(&item->key) != BTRFS_DIR_ITEM_KEY) | 282 | if (btrfs_disk_key_type(&item->key) != BTRFS_DIR_ITEM_KEY) |
298 | continue; | 283 | continue; |
299 | di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); | 284 | di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); |
300 | printk("filldir name %.*s, objectid %Lu\n", btrfs_dir_name_len(di), | ||
301 | (const char *)(di + 1), btrfs_dir_objectid(di)); | ||
302 | over = filldir(dirent, (const char *)(di + 1), | 285 | over = filldir(dirent, (const char *)(di + 1), |
303 | btrfs_dir_name_len(di), | 286 | btrfs_dir_name_len(di), |
304 | btrfs_disk_key_offset(&item->key), | 287 | btrfs_disk_key_offset(&item->key), |
@@ -307,7 +290,6 @@ printk("filldir name %.*s, objectid %Lu\n", btrfs_dir_name_len(di), | |||
307 | break; | 290 | break; |
308 | filp->f_pos = btrfs_disk_key_offset(&item->key) + 1; | 291 | filp->f_pos = btrfs_disk_key_offset(&item->key) + 1; |
309 | } | 292 | } |
310 | printk("filldir all done\n"); | ||
311 | ret = 0; | 293 | ret = 0; |
312 | err: | 294 | err: |
313 | btrfs_release_path(root, &path); | 295 | btrfs_release_path(root, &path); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c new file mode 100644 index 000000000000..8dc1c170f10f --- /dev/null +++ b/fs/btrfs/transaction.c | |||
@@ -0,0 +1,199 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/fs.h> | ||
3 | #include "ctree.h" | ||
4 | #include "disk-io.h" | ||
5 | #include "transaction.h" | ||
6 | |||
7 | |||
8 | static void put_transaction(struct btrfs_transaction *transaction) | ||
9 | { | ||
10 | transaction->use_count--; | ||
11 | if (transaction->use_count == 0) | ||
12 | kfree(transaction); | ||
13 | } | ||
14 | |||
15 | static int join_transaction(struct btrfs_root *root) | ||
16 | { | ||
17 | struct btrfs_transaction *cur_trans; | ||
18 | cur_trans = root->fs_info->running_transaction; | ||
19 | if (!cur_trans) { | ||
20 | cur_trans = kmalloc(sizeof(*cur_trans), GFP_NOFS); | ||
21 | BUG_ON(!cur_trans); | ||
22 | root->fs_info->running_transaction = cur_trans; | ||
23 | cur_trans->num_writers = 0; | ||
24 | cur_trans->transid = root->root_key.offset + 1; | ||
25 | init_waitqueue_head(&cur_trans->writer_wait); | ||
26 | init_waitqueue_head(&cur_trans->commit_wait); | ||
27 | cur_trans->in_commit = 0; | ||
28 | cur_trans->use_count = 0; | ||
29 | cur_trans->commit_done = 0; | ||
30 | } | ||
31 | cur_trans->num_writers++; | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | ||
36 | int num_blocks) | ||
37 | { | ||
38 | struct btrfs_trans_handle *h = kmalloc(sizeof(*h), GFP_NOFS); | ||
39 | int ret; | ||
40 | |||
41 | mutex_lock(&root->fs_info->trans_mutex); | ||
42 | ret = join_transaction(root); | ||
43 | BUG_ON(ret); | ||
44 | h->transid = root->fs_info->running_transaction->transid; | ||
45 | h->transaction = root->fs_info->running_transaction; | ||
46 | h->blocks_reserved = num_blocks; | ||
47 | h->blocks_used = 0; | ||
48 | root->fs_info->running_transaction->use_count++; | ||
49 | mutex_unlock(&root->fs_info->trans_mutex); | ||
50 | return h; | ||
51 | } | ||
52 | |||
53 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | ||
54 | struct btrfs_root *root) | ||
55 | { | ||
56 | struct btrfs_transaction *cur_trans; | ||
57 | mutex_lock(&root->fs_info->trans_mutex); | ||
58 | cur_trans = root->fs_info->running_transaction; | ||
59 | WARN_ON(cur_trans->num_writers <= 1); | ||
60 | if (waitqueue_active(&cur_trans->writer_wait)) | ||
61 | wake_up(&cur_trans->writer_wait); | ||
62 | cur_trans->num_writers--; | ||
63 | put_transaction(cur_trans); | ||
64 | mutex_unlock(&root->fs_info->trans_mutex); | ||
65 | kfree(trans); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | |||
70 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | ||
71 | struct btrfs_root *root) | ||
72 | { | ||
73 | filemap_write_and_wait(root->fs_info->sb->s_bdev->bd_inode->i_mapping); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, | ||
78 | struct btrfs_root *root) | ||
79 | { | ||
80 | int ret; | ||
81 | u64 old_extent_block; | ||
82 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
83 | struct btrfs_root *tree_root = fs_info->tree_root; | ||
84 | struct btrfs_root *extent_root = fs_info->extent_root; | ||
85 | struct btrfs_root *inode_root = fs_info->inode_root; | ||
86 | |||
87 | btrfs_set_root_blocknr(&inode_root->root_item, | ||
88 | inode_root->node->b_blocknr); | ||
89 | ret = btrfs_update_root(trans, tree_root, | ||
90 | &inode_root->root_key, | ||
91 | &inode_root->root_item); | ||
92 | BUG_ON(ret); | ||
93 | while(1) { | ||
94 | old_extent_block = btrfs_root_blocknr(&extent_root->root_item); | ||
95 | if (old_extent_block == extent_root->node->b_blocknr) | ||
96 | break; | ||
97 | btrfs_set_root_blocknr(&extent_root->root_item, | ||
98 | extent_root->node->b_blocknr); | ||
99 | ret = btrfs_update_root(trans, tree_root, | ||
100 | &extent_root->root_key, | ||
101 | &extent_root->root_item); | ||
102 | BUG_ON(ret); | ||
103 | } | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int wait_for_commit(struct btrfs_root *root, | ||
108 | struct btrfs_transaction *commit) | ||
109 | { | ||
110 | DEFINE_WAIT(wait); | ||
111 | commit->use_count++; | ||
112 | while(!commit->commit_done) { | ||
113 | prepare_to_wait(&commit->commit_wait, &wait, | ||
114 | TASK_UNINTERRUPTIBLE); | ||
115 | if (commit->commit_done) | ||
116 | break; | ||
117 | mutex_unlock(&root->fs_info->trans_mutex); | ||
118 | schedule(); | ||
119 | mutex_lock(&root->fs_info->trans_mutex); | ||
120 | } | ||
121 | finish_wait(&commit->commit_wait, &wait); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | ||
126 | struct btrfs_root *root) | ||
127 | { | ||
128 | int ret = 0; | ||
129 | struct buffer_head *snap = root->commit_root; | ||
130 | struct btrfs_key snap_key; | ||
131 | struct btrfs_transaction *cur_trans; | ||
132 | DEFINE_WAIT(wait); | ||
133 | |||
134 | mutex_lock(&root->fs_info->trans_mutex); | ||
135 | if (trans->transaction->in_commit) { | ||
136 | cur_trans = trans->transaction; | ||
137 | trans->transaction->use_count++; | ||
138 | btrfs_end_transaction(trans, root); | ||
139 | ret = wait_for_commit(root, cur_trans); | ||
140 | BUG_ON(ret); | ||
141 | put_transaction(cur_trans); | ||
142 | mutex_unlock(&root->fs_info->trans_mutex); | ||
143 | return 0; | ||
144 | } | ||
145 | while (trans->transaction->num_writers > 1) { | ||
146 | prepare_to_wait(&trans->transaction->writer_wait, &wait, | ||
147 | TASK_UNINTERRUPTIBLE); | ||
148 | if (trans->transaction->num_writers <= 1) | ||
149 | break; | ||
150 | mutex_unlock(&root->fs_info->trans_mutex); | ||
151 | schedule(); | ||
152 | mutex_lock(&root->fs_info->trans_mutex); | ||
153 | } | ||
154 | finish_wait(&trans->transaction->writer_wait, &wait); | ||
155 | |||
156 | cur_trans = root->fs_info->running_transaction; | ||
157 | root->fs_info->running_transaction = NULL; | ||
158 | mutex_unlock(&root->fs_info->trans_mutex); | ||
159 | |||
160 | memcpy(&snap_key, &root->root_key, sizeof(snap_key)); | ||
161 | root->root_key.offset++; | ||
162 | |||
163 | if (btrfs_root_blocknr(&root->root_item) != root->node->b_blocknr) { | ||
164 | btrfs_set_root_blocknr(&root->root_item, root->node->b_blocknr); | ||
165 | ret = btrfs_insert_root(trans, root->fs_info->tree_root, | ||
166 | &root->root_key, &root->root_item); | ||
167 | BUG_ON(ret); | ||
168 | } | ||
169 | |||
170 | ret = btrfs_commit_tree_roots(trans, root); | ||
171 | BUG_ON(ret); | ||
172 | |||
173 | ret = btrfs_write_and_wait_transaction(trans, root); | ||
174 | BUG_ON(ret); | ||
175 | |||
176 | write_ctree_super(trans, root); | ||
177 | btrfs_finish_extent_commit(trans, root->fs_info->extent_root); | ||
178 | btrfs_finish_extent_commit(trans, root->fs_info->tree_root); | ||
179 | put_transaction(cur_trans); | ||
180 | kfree(trans); | ||
181 | |||
182 | if (root->node != root->commit_root) { | ||
183 | trans = btrfs_start_transaction(root, 1); | ||
184 | root->commit_root = root->node; | ||
185 | get_bh(root->node); | ||
186 | ret = btrfs_drop_snapshot(trans, root, snap); | ||
187 | BUG_ON(ret); | ||
188 | |||
189 | ret = btrfs_del_root(trans, root->fs_info->tree_root, | ||
190 | &snap_key); | ||
191 | BUG_ON(ret); | ||
192 | root->fs_info->generation = root->root_key.offset + 1; | ||
193 | ret = btrfs_end_transaction(trans, root); | ||
194 | BUG_ON(ret); | ||
195 | } | ||
196 | |||
197 | return ret; | ||
198 | } | ||
199 | |||
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 9ab27b7491c5..7e6c08a0accd 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -1,27 +1,30 @@ | |||
1 | #ifndef __TRANSACTION__ | 1 | #ifndef __TRANSACTION__ |
2 | #define __TRANSACTION__ | 2 | #define __TRANSACTION__ |
3 | 3 | ||
4 | struct btrfs_transaction { | ||
5 | u64 transid; | ||
6 | unsigned long num_writers; | ||
7 | int in_commit; | ||
8 | int use_count; | ||
9 | int commit_done; | ||
10 | wait_queue_head_t writer_wait; | ||
11 | wait_queue_head_t commit_wait; | ||
12 | }; | ||
13 | |||
4 | struct btrfs_trans_handle { | 14 | struct btrfs_trans_handle { |
5 | u64 transid; | 15 | u64 transid; |
6 | unsigned long blocks_reserved; | 16 | unsigned long blocks_reserved; |
7 | unsigned long blocks_used; | 17 | unsigned long blocks_used; |
18 | struct btrfs_transaction *transaction; | ||
8 | }; | 19 | }; |
9 | 20 | ||
10 | static inline struct btrfs_trans_handle * | ||
11 | btrfs_start_transaction(struct btrfs_root *root, int num_blocks) | ||
12 | { | ||
13 | struct btrfs_trans_handle *h = kmalloc(sizeof(*h), GFP_NOFS); | ||
14 | h->transid = root->root_key.offset; | ||
15 | h->blocks_reserved = num_blocks; | ||
16 | h->blocks_used = 0; | ||
17 | return h; | ||
18 | } | ||
19 | |||
20 | static inline void btrfs_free_transaction(struct btrfs_root *root, | ||
21 | struct btrfs_trans_handle *handle) | ||
22 | { | ||
23 | memset(handle, 0, sizeof(*handle)); | ||
24 | kfree(handle); | ||
25 | } | ||
26 | 21 | ||
22 | int btrfs_end_transaction(struct btrfs_trans_handle *trans, | ||
23 | struct btrfs_root *root); | ||
24 | struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | ||
25 | int num_blocks); | ||
26 | int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, | ||
27 | struct btrfs_root *root); | ||
28 | int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans, | ||
29 | struct btrfs_root *root); | ||
27 | #endif | 30 | #endif |