aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-06-22 14:16:25 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-06-22 14:16:25 -0400
commit5eda7b5e9b0bed864dd18284c7df9b3c8207dad7 (patch)
tree9efe48de46e77f2b7b97a2ce3ee93c9da6451671 /fs/btrfs
parent54aa1f4dfdacd60a19c4471220b24e581be6f774 (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.h17
-rw-r--r--fs/btrfs/disk-io.c44
-rw-r--r--fs/btrfs/disk-io.h3
-rw-r--r--fs/btrfs/inode.c2
-rw-r--r--fs/btrfs/root-tree.c75
-rw-r--r--fs/btrfs/transaction.c54
-rw-r--r--fs/btrfs/transaction.h1
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
805static inline u32 btrfs_root_flags(struct btrfs_root_item *item)
806{
807 return le32_to_cpu(item->flags);
808}
809
810static inline void btrfs_set_root_flags(struct btrfs_root_item *item, u32 val)
811{
812 item->flags = cpu_to_le32(val);
813}
814
803static inline u64 btrfs_super_blocknr(struct btrfs_super_block *s) 815static 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);
1077int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct 1089int 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);
1091int btrfs_find_dead_roots(struct btrfs_root *root);
1079/* dir-item.c */ 1092/* dir-item.c */
1080int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root 1093int 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
329struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, 329struct 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);
384insert: 380insert:
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
390struct 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
541static int free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) 557int 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);
66struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, 66struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
67 struct btrfs_key *location); 67 struct btrfs_key *location);
68struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info,
69 struct btrfs_key *location);
68u64 bh_blocknr(struct buffer_head *bh); 70u64 bh_blocknr(struct buffer_head *bh);
69int btrfs_insert_dev_radix(struct btrfs_root *root, 71int 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);
76int btrfs_releasepage(struct page *page, gfp_t flags); 78int btrfs_releasepage(struct page *page, gfp_t flags);
77void btrfs_btree_balance_dirty(struct btrfs_root *root); 79void btrfs_btree_balance_dirty(struct btrfs_root *root);
80int 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);
54printk("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;
54out: 56out:
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
98int 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 }
144printk("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;
149next:
150 slot++;
151 path->slots[0]++;
152 }
153 ret = 0;
154err:
155 btrfs_free_path(path);
156 return ret;
157}
158
96int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, 159int 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 }
122out: 179out:
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
218int 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
213static int add_dirty_roots(struct btrfs_trans_handle *trans, 233static 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);
311printk("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);
69void btrfs_transaction_queue_work(struct btrfs_root *root, int delay); 69void btrfs_transaction_queue_work(struct btrfs_root *root, int delay);
70void btrfs_init_transaction_sys(void); 70void btrfs_init_transaction_sys(void);
71void btrfs_exit_transaction_sys(void); 71void btrfs_exit_transaction_sys(void);
72int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list);
72 73
73#endif 74#endif