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/transaction.c | |
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/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 54 |
1 files changed, 47 insertions, 7 deletions
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); |