diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-06-22 14:16:25 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-06-22 14:16:25 -0400 |
commit | 5eda7b5e9b0bed864dd18284c7df9b3c8207dad7 (patch) | |
tree | 9efe48de46e77f2b7b97a2ce3ee93c9da6451671 /fs/btrfs | |
parent | 54aa1f4dfdacd60a19c4471220b24e581be6f774 (diff) |
Btrfs: Add the ability to find and remove dead roots after a crash.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.h | 17 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 44 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 3 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 2 | ||||
-rw-r--r-- | fs/btrfs/root-tree.c | 75 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 54 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 1 |
7 files changed, 164 insertions, 32 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 77071f273977..fb6fffb71dd0 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -122,12 +122,12 @@ struct btrfs_super_block { | |||
122 | u8 fsid[16]; /* FS specific uuid */ | 122 | u8 fsid[16]; /* FS specific uuid */ |
123 | __le64 blocknr; /* this block number */ | 123 | __le64 blocknr; /* this block number */ |
124 | __le64 magic; | 124 | __le64 magic; |
125 | __le32 blocksize; | ||
126 | __le64 generation; | 125 | __le64 generation; |
127 | __le64 root; | 126 | __le64 root; |
128 | __le64 total_blocks; | 127 | __le64 total_blocks; |
129 | __le64 blocks_used; | 128 | __le64 blocks_used; |
130 | __le64 root_dir_objectid; | 129 | __le64 root_dir_objectid; |
130 | __le32 blocksize; | ||
131 | } __attribute__ ((__packed__)); | 131 | } __attribute__ ((__packed__)); |
132 | 132 | ||
133 | /* | 133 | /* |
@@ -226,10 +226,12 @@ struct btrfs_root_item { | |||
226 | struct btrfs_inode_item inode; | 226 | struct btrfs_inode_item inode; |
227 | __le64 root_dirid; | 227 | __le64 root_dirid; |
228 | __le64 blocknr; | 228 | __le64 blocknr; |
229 | __le32 flags; | ||
230 | __le64 block_limit; | 229 | __le64 block_limit; |
231 | __le64 blocks_used; | 230 | __le64 blocks_used; |
231 | __le32 flags; | ||
232 | __le32 refs; | 232 | __le32 refs; |
233 | struct btrfs_disk_key drop_progress; | ||
234 | u8 drop_level; | ||
233 | } __attribute__ ((__packed__)); | 235 | } __attribute__ ((__packed__)); |
234 | 236 | ||
235 | #define BTRFS_FILE_EXTENT_REG 0 | 237 | #define BTRFS_FILE_EXTENT_REG 0 |
@@ -800,6 +802,16 @@ static inline void btrfs_set_root_refs(struct btrfs_root_item *item, u32 val) | |||
800 | item->refs = cpu_to_le32(val); | 802 | item->refs = cpu_to_le32(val); |
801 | } | 803 | } |
802 | 804 | ||
805 | static inline u32 btrfs_root_flags(struct btrfs_root_item *item) | ||
806 | { | ||
807 | return le32_to_cpu(item->flags); | ||
808 | } | ||
809 | |||
810 | static inline void btrfs_set_root_flags(struct btrfs_root_item *item, u32 val) | ||
811 | { | ||
812 | item->flags = cpu_to_le32(val); | ||
813 | } | ||
814 | |||
803 | static inline u64 btrfs_super_blocknr(struct btrfs_super_block *s) | 815 | static inline u64 btrfs_super_blocknr(struct btrfs_super_block *s) |
804 | { | 816 | { |
805 | return le64_to_cpu(s->blocknr); | 817 | return le64_to_cpu(s->blocknr); |
@@ -1076,6 +1088,7 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1076 | *item); | 1088 | *item); |
1077 | int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct | 1089 | int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct |
1078 | btrfs_root_item *item, struct btrfs_key *key); | 1090 | btrfs_root_item *item, struct btrfs_key *key); |
1091 | int btrfs_find_dead_roots(struct btrfs_root *root); | ||
1079 | /* dir-item.c */ | 1092 | /* dir-item.c */ |
1080 | int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root | 1093 | int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root |
1081 | *root, const char *name, int name_len, u64 dir, | 1094 | *root, const char *name, int name_len, u64 dir, |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 865a284aa06c..d7615e1578cc 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -326,8 +326,8 @@ static int find_and_setup_root(int blocksize, | |||
326 | return 0; | 326 | return 0; |
327 | } | 327 | } |
328 | 328 | ||
329 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | 329 | struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, |
330 | struct btrfs_key *location) | 330 | struct btrfs_key *location) |
331 | { | 331 | { |
332 | struct btrfs_root *root; | 332 | struct btrfs_root *root; |
333 | struct btrfs_root *tree_root = fs_info->tree_root; | 333 | struct btrfs_root *tree_root = fs_info->tree_root; |
@@ -336,11 +336,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | |||
336 | u64 highest_inode; | 336 | u64 highest_inode; |
337 | int ret = 0; | 337 | int ret = 0; |
338 | 338 | ||
339 | root = radix_tree_lookup(&fs_info->fs_roots_radix, | 339 | root = kzalloc(sizeof(*root), GFP_NOFS); |
340 | (unsigned long)location->objectid); | ||
341 | if (root) | ||
342 | return root; | ||
343 | root = kmalloc(sizeof(*root), GFP_NOFS); | ||
344 | if (!root) | 340 | if (!root) |
345 | return ERR_PTR(-ENOMEM); | 341 | return ERR_PTR(-ENOMEM); |
346 | if (location->offset == (u64)-1) { | 342 | if (location->offset == (u64)-1) { |
@@ -383,6 +379,28 @@ out: | |||
383 | BUG_ON(!root->node); | 379 | BUG_ON(!root->node); |
384 | insert: | 380 | insert: |
385 | root->ref_cows = 1; | 381 | root->ref_cows = 1; |
382 | ret = btrfs_find_highest_inode(root, &highest_inode); | ||
383 | if (ret == 0) { | ||
384 | root->highest_inode = highest_inode; | ||
385 | root->last_inode_alloc = highest_inode; | ||
386 | } | ||
387 | return root; | ||
388 | } | ||
389 | |||
390 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | ||
391 | struct btrfs_key *location) | ||
392 | { | ||
393 | struct btrfs_root *root; | ||
394 | int ret; | ||
395 | |||
396 | root = radix_tree_lookup(&fs_info->fs_roots_radix, | ||
397 | (unsigned long)location->objectid); | ||
398 | if (root) | ||
399 | return root; | ||
400 | |||
401 | root = btrfs_read_fs_root_no_radix(fs_info, location); | ||
402 | if (IS_ERR(root)) | ||
403 | return root; | ||
386 | ret = radix_tree_insert(&fs_info->fs_roots_radix, | 404 | ret = radix_tree_insert(&fs_info->fs_roots_radix, |
387 | (unsigned long)root->root_key.objectid, | 405 | (unsigned long)root->root_key.objectid, |
388 | root); | 406 | root); |
@@ -391,11 +409,6 @@ insert: | |||
391 | kfree(root); | 409 | kfree(root); |
392 | return ERR_PTR(ret); | 410 | return ERR_PTR(ret); |
393 | } | 411 | } |
394 | ret = btrfs_find_highest_inode(root, &highest_inode); | ||
395 | if (ret == 0) { | ||
396 | root->highest_inode = highest_inode; | ||
397 | root->last_inode_alloc = highest_inode; | ||
398 | } | ||
399 | return root; | 412 | return root; |
400 | } | 413 | } |
401 | 414 | ||
@@ -489,6 +502,9 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
489 | btrfs_read_block_groups(extent_root); | 502 | btrfs_read_block_groups(extent_root); |
490 | 503 | ||
491 | fs_info->generation = btrfs_super_generation(disk_super) + 1; | 504 | fs_info->generation = btrfs_super_generation(disk_super) + 1; |
505 | ret = btrfs_find_dead_roots(tree_root); | ||
506 | if (ret) | ||
507 | goto fail_tree_root; | ||
492 | mutex_unlock(&fs_info->fs_mutex); | 508 | mutex_unlock(&fs_info->fs_mutex); |
493 | return tree_root; | 509 | return tree_root; |
494 | 510 | ||
@@ -538,7 +554,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root | |||
538 | return 0; | 554 | return 0; |
539 | } | 555 | } |
540 | 556 | ||
541 | static int free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | 557 | int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) |
542 | { | 558 | { |
543 | radix_tree_delete(&fs_info->fs_roots_radix, | 559 | radix_tree_delete(&fs_info->fs_roots_radix, |
544 | (unsigned long)root->root_key.objectid); | 560 | (unsigned long)root->root_key.objectid); |
@@ -565,7 +581,7 @@ static int del_fs_roots(struct btrfs_fs_info *fs_info) | |||
565 | if (!ret) | 581 | if (!ret) |
566 | break; | 582 | break; |
567 | for (i = 0; i < ret; i++) | 583 | for (i = 0; i < ret; i++) |
568 | free_fs_root(fs_info, gang[i]); | 584 | btrfs_free_fs_root(fs_info, gang[i]); |
569 | } | 585 | } |
570 | return 0; | 586 | return 0; |
571 | } | 587 | } |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 7b76ccc48754..c4a695ac44f6 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -65,6 +65,8 @@ int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, | |||
65 | char *result); | 65 | char *result); |
66 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | 66 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, |
67 | struct btrfs_key *location); | 67 | struct btrfs_key *location); |
68 | struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, | ||
69 | struct btrfs_key *location); | ||
68 | u64 bh_blocknr(struct buffer_head *bh); | 70 | u64 bh_blocknr(struct buffer_head *bh); |
69 | int btrfs_insert_dev_radix(struct btrfs_root *root, | 71 | int btrfs_insert_dev_radix(struct btrfs_root *root, |
70 | struct block_device *bdev, | 72 | struct block_device *bdev, |
@@ -75,4 +77,5 @@ int btrfs_map_bh_to_logical(struct btrfs_root *root, struct buffer_head *bh, | |||
75 | u64 logical); | 77 | u64 logical); |
76 | int btrfs_releasepage(struct page *page, gfp_t flags); | 78 | int btrfs_releasepage(struct page *page, gfp_t flags); |
77 | void btrfs_btree_balance_dirty(struct btrfs_root *root); | 79 | void btrfs_btree_balance_dirty(struct btrfs_root *root); |
80 | int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); | ||
78 | #endif | 81 | #endif |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6d031daa7779..9d2a0a3f674d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2028,6 +2028,8 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen) | |||
2028 | 2028 | ||
2029 | btrfs_set_root_blocknr(&root_item, bh_blocknr(subvol)); | 2029 | btrfs_set_root_blocknr(&root_item, bh_blocknr(subvol)); |
2030 | btrfs_set_root_refs(&root_item, 1); | 2030 | btrfs_set_root_refs(&root_item, 1); |
2031 | memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress)); | ||
2032 | root_item.drop_level = 0; | ||
2031 | brelse(subvol); | 2033 | brelse(subvol); |
2032 | subvol = NULL; | 2034 | subvol = NULL; |
2033 | 2035 | ||
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index ac0fae7780ff..737e5a38d17e 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include "ctree.h" | 20 | #include "ctree.h" |
21 | #include "transaction.h" | ||
21 | #include "disk-io.h" | 22 | #include "disk-io.h" |
22 | #include "print-tree.h" | 23 | #include "print-tree.h" |
23 | 24 | ||
@@ -32,7 +33,7 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, | |||
32 | 33 | ||
33 | search_key.objectid = objectid; | 34 | search_key.objectid = objectid; |
34 | search_key.flags = (u32)-1; | 35 | search_key.flags = (u32)-1; |
35 | search_key.offset = (u32)-1; | 36 | search_key.offset = (u64)-1; |
36 | 37 | ||
37 | path = btrfs_alloc_path(); | 38 | path = btrfs_alloc_path(); |
38 | BUG_ON(!path); | 39 | BUG_ON(!path); |
@@ -50,6 +51,7 @@ int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, | |||
50 | memcpy(item, btrfs_item_ptr(l, slot, struct btrfs_root_item), | 51 | memcpy(item, btrfs_item_ptr(l, slot, struct btrfs_root_item), |
51 | sizeof(*item)); | 52 | sizeof(*item)); |
52 | btrfs_disk_key_to_cpu(key, &l->items[slot].key); | 53 | btrfs_disk_key_to_cpu(key, &l->items[slot].key); |
54 | printk("find last finds key %Lu %u %Lu slot %d search for obj %Lu\n", key->objectid, key->flags, key->offset, slot, objectid); | ||
53 | ret = 0; | 55 | ret = 0; |
54 | out: | 56 | out: |
55 | btrfs_release_path(root, path); | 57 | btrfs_release_path(root, path); |
@@ -93,6 +95,67 @@ int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root | |||
93 | return ret; | 95 | return ret; |
94 | } | 96 | } |
95 | 97 | ||
98 | int btrfs_find_dead_roots(struct btrfs_root *root) | ||
99 | { | ||
100 | struct btrfs_root *dead_root; | ||
101 | struct btrfs_item *item; | ||
102 | struct btrfs_root_item *ri; | ||
103 | struct btrfs_key key; | ||
104 | struct btrfs_path *path; | ||
105 | int ret; | ||
106 | u32 nritems; | ||
107 | struct btrfs_leaf *leaf; | ||
108 | int slot; | ||
109 | |||
110 | key.objectid = 0; | ||
111 | key.flags = 0; | ||
112 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | ||
113 | key.offset = 0; | ||
114 | path = btrfs_alloc_path(); | ||
115 | if (!path) | ||
116 | return -ENOMEM; | ||
117 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
118 | if (ret < 0) | ||
119 | goto err; | ||
120 | while(1) { | ||
121 | leaf = btrfs_buffer_leaf(path->nodes[0]); | ||
122 | nritems = btrfs_header_nritems(&leaf->header); | ||
123 | slot = path->slots[0]; | ||
124 | if (slot >= nritems) { | ||
125 | ret = btrfs_next_leaf(root, path); | ||
126 | if (ret) | ||
127 | break; | ||
128 | leaf = btrfs_buffer_leaf(path->nodes[0]); | ||
129 | nritems = btrfs_header_nritems(&leaf->header); | ||
130 | slot = path->slots[0]; | ||
131 | } | ||
132 | item = leaf->items + slot; | ||
133 | btrfs_disk_key_to_cpu(&key, &item->key); | ||
134 | if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY) | ||
135 | goto next; | ||
136 | ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item); | ||
137 | if (btrfs_root_refs(ri) != 0) | ||
138 | goto next; | ||
139 | dead_root = btrfs_read_fs_root_no_radix(root->fs_info, &key); | ||
140 | if (IS_ERR(root)) { | ||
141 | ret = PTR_ERR(root); | ||
142 | goto err; | ||
143 | } | ||
144 | printk("found dead root %Lu %u %Lu\n", key.objectid, key.flags, key.offset); | ||
145 | ret = btrfs_add_dead_root(dead_root, | ||
146 | &root->fs_info->dead_roots); | ||
147 | if (ret) | ||
148 | goto err; | ||
149 | next: | ||
150 | slot++; | ||
151 | path->slots[0]++; | ||
152 | } | ||
153 | ret = 0; | ||
154 | err: | ||
155 | btrfs_free_path(path); | ||
156 | return ret; | ||
157 | } | ||
158 | |||
96 | int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 159 | int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
97 | struct btrfs_key *key) | 160 | struct btrfs_key *key) |
98 | { | 161 | { |
@@ -111,14 +174,8 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
111 | path->slots[0], struct btrfs_root_item); | 174 | path->slots[0], struct btrfs_root_item); |
112 | 175 | ||
113 | refs = btrfs_root_refs(ri); | 176 | refs = btrfs_root_refs(ri); |
114 | BUG_ON(refs == 0); | 177 | BUG_ON(refs != 0); |
115 | if (refs == 1) { | 178 | ret = btrfs_del_item(trans, root, path); |
116 | ret = btrfs_del_item(trans, root, path); | ||
117 | } else { | ||
118 | btrfs_set_root_refs(ri, refs - 1); | ||
119 | WARN_ON(1); | ||
120 | mark_buffer_dirty(path->nodes[0]); | ||
121 | } | ||
122 | out: | 179 | out: |
123 | btrfs_release_path(root, path); | 180 | btrfs_release_path(root, path); |
124 | btrfs_free_path(path); | 181 | btrfs_free_path(path); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 321f8852755b..85a2a5e27148 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -85,11 +85,15 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, | |||
85 | 85 | ||
86 | if (root != root->fs_info->tree_root && root->last_trans < | 86 | if (root != root->fs_info->tree_root && root->last_trans < |
87 | running_trans_id) { | 87 | running_trans_id) { |
88 | radix_tree_tag_set(&root->fs_info->fs_roots_radix, | 88 | if (root->root_item.refs != 0) { |
89 | (unsigned long)root->root_key.objectid, | 89 | radix_tree_tag_set(&root->fs_info->fs_roots_radix, |
90 | BTRFS_ROOT_TRANS_TAG); | 90 | (unsigned long)root->root_key.objectid, |
91 | root->commit_root = root->node; | 91 | BTRFS_ROOT_TRANS_TAG); |
92 | get_bh(root->node); | 92 | root->commit_root = root->node; |
93 | get_bh(root->node); | ||
94 | } else { | ||
95 | WARN_ON(1); | ||
96 | } | ||
93 | } | 97 | } |
94 | root->last_trans = running_trans_id; | 98 | root->last_trans = running_trans_id; |
95 | h->transid = running_trans_id; | 99 | h->transid = running_trans_id; |
@@ -208,8 +212,24 @@ struct dirty_root { | |||
208 | struct btrfs_key snap_key; | 212 | struct btrfs_key snap_key; |
209 | struct buffer_head *commit_root; | 213 | struct buffer_head *commit_root; |
210 | struct btrfs_root *root; | 214 | struct btrfs_root *root; |
215 | int free_on_drop; | ||
211 | }; | 216 | }; |
212 | 217 | ||
218 | int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list) | ||
219 | { | ||
220 | struct dirty_root *dirty; | ||
221 | |||
222 | dirty = kmalloc(sizeof(*dirty), GFP_NOFS); | ||
223 | if (!dirty) | ||
224 | return -ENOMEM; | ||
225 | memcpy(&dirty->snap_key, &root->root_key, sizeof(root->root_key)); | ||
226 | dirty->commit_root = root->node; | ||
227 | dirty->root = root; | ||
228 | dirty->free_on_drop = 1; | ||
229 | list_add(&dirty->list, dead_list); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
213 | static int add_dirty_roots(struct btrfs_trans_handle *trans, | 233 | static int add_dirty_roots(struct btrfs_trans_handle *trans, |
214 | struct radix_tree_root *radix, | 234 | struct radix_tree_root *radix, |
215 | struct list_head *list) | 235 | struct list_head *list) |
@@ -217,9 +237,11 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
217 | struct dirty_root *dirty; | 237 | struct dirty_root *dirty; |
218 | struct btrfs_root *gang[8]; | 238 | struct btrfs_root *gang[8]; |
219 | struct btrfs_root *root; | 239 | struct btrfs_root *root; |
240 | struct btrfs_root_item tmp_item; | ||
220 | int i; | 241 | int i; |
221 | int ret; | 242 | int ret; |
222 | int err = 0; | 243 | int err = 0; |
244 | u32 refs; | ||
223 | 245 | ||
224 | while(1) { | 246 | while(1) { |
225 | ret = radix_tree_gang_lookup_tag(radix, (void **)gang, 0, | 247 | ret = radix_tree_gang_lookup_tag(radix, (void **)gang, 0, |
@@ -246,6 +268,9 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
246 | dirty->commit_root = root->commit_root; | 268 | dirty->commit_root = root->commit_root; |
247 | root->commit_root = NULL; | 269 | root->commit_root = NULL; |
248 | dirty->root = root; | 270 | dirty->root = root; |
271 | dirty->free_on_drop = 0; | ||
272 | memcpy(&tmp_item, &root->root_item, sizeof(tmp_item)); | ||
273 | |||
249 | root->root_key.offset = root->fs_info->generation; | 274 | root->root_key.offset = root->fs_info->generation; |
250 | btrfs_set_root_blocknr(&root->root_item, | 275 | btrfs_set_root_blocknr(&root->root_item, |
251 | bh_blocknr(root->node)); | 276 | bh_blocknr(root->node)); |
@@ -254,7 +279,18 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
254 | &root->root_item); | 279 | &root->root_item); |
255 | if (err) | 280 | if (err) |
256 | break; | 281 | break; |
257 | list_add(&dirty->list, list); | 282 | |
283 | refs = btrfs_root_refs(&tmp_item); | ||
284 | btrfs_set_root_refs(&tmp_item, refs - 1); | ||
285 | err = btrfs_update_root(trans, root->fs_info->tree_root, | ||
286 | &dirty->snap_key, | ||
287 | &tmp_item); | ||
288 | |||
289 | BUG_ON(err); | ||
290 | if (refs == 1) | ||
291 | list_add(&dirty->list, list); | ||
292 | else | ||
293 | kfree(dirty); | ||
258 | } | 294 | } |
259 | } | 295 | } |
260 | return err; | 296 | return err; |
@@ -270,16 +306,20 @@ static int drop_dirty_roots(struct btrfs_root *tree_root, | |||
270 | mutex_lock(&tree_root->fs_info->fs_mutex); | 306 | mutex_lock(&tree_root->fs_info->fs_mutex); |
271 | dirty = list_entry(list->next, struct dirty_root, list); | 307 | dirty = list_entry(list->next, struct dirty_root, list); |
272 | list_del_init(&dirty->list); | 308 | list_del_init(&dirty->list); |
309 | |||
273 | trans = btrfs_start_transaction(tree_root, 1); | 310 | trans = btrfs_start_transaction(tree_root, 1); |
311 | printk("deleting root %Lu %u %Lu\n", dirty->snap_key.objectid, dirty->snap_key.flags, dirty->snap_key.offset); | ||
274 | ret = btrfs_drop_snapshot(trans, dirty->root, | 312 | ret = btrfs_drop_snapshot(trans, dirty->root, |
275 | dirty->commit_root); | 313 | dirty->commit_root); |
276 | BUG_ON(ret); | 314 | BUG_ON(ret); |
277 | |||
278 | ret = btrfs_del_root(trans, tree_root, &dirty->snap_key); | 315 | ret = btrfs_del_root(trans, tree_root, &dirty->snap_key); |
279 | if (ret) | 316 | if (ret) |
280 | break; | 317 | break; |
281 | ret = btrfs_end_transaction(trans, tree_root); | 318 | ret = btrfs_end_transaction(trans, tree_root); |
282 | BUG_ON(ret); | 319 | BUG_ON(ret); |
320 | |||
321 | if (dirty->free_on_drop) | ||
322 | kfree(dirty->root); | ||
283 | kfree(dirty); | 323 | kfree(dirty); |
284 | mutex_unlock(&tree_root->fs_info->fs_mutex); | 324 | mutex_unlock(&tree_root->fs_info->fs_mutex); |
285 | btrfs_btree_balance_dirty(tree_root); | 325 | btrfs_btree_balance_dirty(tree_root); |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 5fb1d322aa10..ebf44f3e1118 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -69,5 +69,6 @@ void btrfs_transaction_flush_work(struct btrfs_root *root); | |||
69 | void btrfs_transaction_queue_work(struct btrfs_root *root, int delay); | 69 | void btrfs_transaction_queue_work(struct btrfs_root *root, int delay); |
70 | void btrfs_init_transaction_sys(void); | 70 | void btrfs_init_transaction_sys(void); |
71 | void btrfs_exit_transaction_sys(void); | 71 | void btrfs_exit_transaction_sys(void); |
72 | int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list); | ||
72 | 73 | ||
73 | #endif | 74 | #endif |