diff options
author | Josef Bacik <josef@redhat.com> | 2011-01-31 16:22:42 -0500 |
---|---|---|
committer | Josef Bacik <josef@redhat.com> | 2011-03-17 14:21:26 -0400 |
commit | 66b4ffd110f9b48b8d8c1319ee446b53b8d073bf (patch) | |
tree | 690b14cda46b47c0d71be15a82019c35729afa75 /fs | |
parent | 3893e33b0bebee2f67d96b6c15259dc884523c20 (diff) |
Btrfs: handle errors in btrfs_orphan_cleanup
If we cannot truncate an inode for some reason we will never delete the orphan
item associated with that inode, which means that we will loop forever in
btrfs_orphan_cleanup. Instead of doing this just return error so we fail to
mount. It sucks, but hey it's better than hanging. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 15 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 3 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 47 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 4 | ||||
-rw-r--r-- | fs/btrfs/relocation.c | 2 |
6 files changed, 50 insertions, 23 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 34142d5647df..841330f3d68d 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -2529,7 +2529,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans, | |||
2529 | struct inode *inode); | 2529 | struct inode *inode); |
2530 | int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); | 2530 | int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); |
2531 | int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); | 2531 | int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); |
2532 | void btrfs_orphan_cleanup(struct btrfs_root *root); | 2532 | int btrfs_orphan_cleanup(struct btrfs_root *root); |
2533 | void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans, | 2533 | void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans, |
2534 | struct btrfs_pending_snapshot *pending, | 2534 | struct btrfs_pending_snapshot *pending, |
2535 | u64 *bytes_to_reserve); | 2535 | u64 *bytes_to_reserve); |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e1aa8d607bc7..495b1ac45f8c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -2058,9 +2058,14 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
2058 | 2058 | ||
2059 | if (!(sb->s_flags & MS_RDONLY)) { | 2059 | if (!(sb->s_flags & MS_RDONLY)) { |
2060 | down_read(&fs_info->cleanup_work_sem); | 2060 | down_read(&fs_info->cleanup_work_sem); |
2061 | btrfs_orphan_cleanup(fs_info->fs_root); | 2061 | err = btrfs_orphan_cleanup(fs_info->fs_root); |
2062 | btrfs_orphan_cleanup(fs_info->tree_root); | 2062 | if (!err) |
2063 | err = btrfs_orphan_cleanup(fs_info->tree_root); | ||
2063 | up_read(&fs_info->cleanup_work_sem); | 2064 | up_read(&fs_info->cleanup_work_sem); |
2065 | if (err) { | ||
2066 | close_ctree(tree_root); | ||
2067 | return ERR_PTR(err); | ||
2068 | } | ||
2064 | } | 2069 | } |
2065 | 2070 | ||
2066 | return tree_root; | 2071 | return tree_root; |
@@ -2435,8 +2440,12 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) | |||
2435 | 2440 | ||
2436 | root_objectid = gang[ret - 1]->root_key.objectid + 1; | 2441 | root_objectid = gang[ret - 1]->root_key.objectid + 1; |
2437 | for (i = 0; i < ret; i++) { | 2442 | for (i = 0; i < ret; i++) { |
2443 | int err; | ||
2444 | |||
2438 | root_objectid = gang[i]->root_key.objectid; | 2445 | root_objectid = gang[i]->root_key.objectid; |
2439 | btrfs_orphan_cleanup(gang[i]); | 2446 | err = btrfs_orphan_cleanup(gang[i]); |
2447 | if (err) | ||
2448 | return err; | ||
2440 | } | 2449 | } |
2441 | root_objectid++; | 2450 | root_objectid++; |
2442 | } | 2451 | } |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 27376c97d85f..a8f4e8d2ba60 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -7619,7 +7619,8 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root) | |||
7619 | 7619 | ||
7620 | reloc_root = btrfs_read_fs_root_no_name(root->fs_info, &location); | 7620 | reloc_root = btrfs_read_fs_root_no_name(root->fs_info, &location); |
7621 | BUG_ON(!reloc_root); | 7621 | BUG_ON(!reloc_root); |
7622 | btrfs_orphan_cleanup(reloc_root); | 7622 | ret = btrfs_orphan_cleanup(reloc_root); |
7623 | BUG_ON(ret); | ||
7623 | return 0; | 7624 | return 0; |
7624 | } | 7625 | } |
7625 | 7626 | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index d83025063ee7..0600265cb9b0 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2284,7 +2284,7 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode) | |||
2284 | * this cleans up any orphans that may be left on the list from the last use | 2284 | * this cleans up any orphans that may be left on the list from the last use |
2285 | * of this root. | 2285 | * of this root. |
2286 | */ | 2286 | */ |
2287 | void btrfs_orphan_cleanup(struct btrfs_root *root) | 2287 | int btrfs_orphan_cleanup(struct btrfs_root *root) |
2288 | { | 2288 | { |
2289 | struct btrfs_path *path; | 2289 | struct btrfs_path *path; |
2290 | struct extent_buffer *leaf; | 2290 | struct extent_buffer *leaf; |
@@ -2294,10 +2294,13 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
2294 | int ret = 0, nr_unlink = 0, nr_truncate = 0; | 2294 | int ret = 0, nr_unlink = 0, nr_truncate = 0; |
2295 | 2295 | ||
2296 | if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED)) | 2296 | if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED)) |
2297 | return; | 2297 | return 0; |
2298 | 2298 | ||
2299 | path = btrfs_alloc_path(); | 2299 | path = btrfs_alloc_path(); |
2300 | BUG_ON(!path); | 2300 | if (!path) { |
2301 | ret = -ENOMEM; | ||
2302 | goto out; | ||
2303 | } | ||
2301 | path->reada = -1; | 2304 | path->reada = -1; |
2302 | 2305 | ||
2303 | key.objectid = BTRFS_ORPHAN_OBJECTID; | 2306 | key.objectid = BTRFS_ORPHAN_OBJECTID; |
@@ -2306,11 +2309,8 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
2306 | 2309 | ||
2307 | while (1) { | 2310 | while (1) { |
2308 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 2311 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
2309 | if (ret < 0) { | 2312 | if (ret < 0) |
2310 | printk(KERN_ERR "Error searching slot for orphan: %d" | 2313 | goto out; |
2311 | "\n", ret); | ||
2312 | break; | ||
2313 | } | ||
2314 | 2314 | ||
2315 | /* | 2315 | /* |
2316 | * if ret == 0 means we found what we were searching for, which | 2316 | * if ret == 0 means we found what we were searching for, which |
@@ -2318,6 +2318,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
2318 | * find the key and see if we have stuff that matches | 2318 | * find the key and see if we have stuff that matches |
2319 | */ | 2319 | */ |
2320 | if (ret > 0) { | 2320 | if (ret > 0) { |
2321 | ret = 0; | ||
2321 | if (path->slots[0] == 0) | 2322 | if (path->slots[0] == 0) |
2322 | break; | 2323 | break; |
2323 | path->slots[0]--; | 2324 | path->slots[0]--; |
@@ -2345,7 +2346,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
2345 | found_key.type = BTRFS_INODE_ITEM_KEY; | 2346 | found_key.type = BTRFS_INODE_ITEM_KEY; |
2346 | found_key.offset = 0; | 2347 | found_key.offset = 0; |
2347 | inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL); | 2348 | inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL); |
2348 | BUG_ON(IS_ERR(inode)); | 2349 | if (IS_ERR(inode)) { |
2350 | ret = PTR_ERR(inode); | ||
2351 | goto out; | ||
2352 | } | ||
2349 | 2353 | ||
2350 | /* | 2354 | /* |
2351 | * add this inode to the orphan list so btrfs_orphan_del does | 2355 | * add this inode to the orphan list so btrfs_orphan_del does |
@@ -2363,7 +2367,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
2363 | */ | 2367 | */ |
2364 | if (is_bad_inode(inode)) { | 2368 | if (is_bad_inode(inode)) { |
2365 | trans = btrfs_start_transaction(root, 0); | 2369 | trans = btrfs_start_transaction(root, 0); |
2366 | BUG_ON(IS_ERR(trans)); | 2370 | if (IS_ERR(trans)) { |
2371 | ret = PTR_ERR(trans); | ||
2372 | goto out; | ||
2373 | } | ||
2367 | btrfs_orphan_del(trans, inode); | 2374 | btrfs_orphan_del(trans, inode); |
2368 | btrfs_end_transaction(trans, root); | 2375 | btrfs_end_transaction(trans, root); |
2369 | iput(inode); | 2376 | iput(inode); |
@@ -2378,16 +2385,16 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
2378 | continue; | 2385 | continue; |
2379 | } | 2386 | } |
2380 | nr_truncate++; | 2387 | nr_truncate++; |
2381 | btrfs_truncate(inode); | 2388 | ret = btrfs_truncate(inode); |
2382 | } else { | 2389 | } else { |
2383 | nr_unlink++; | 2390 | nr_unlink++; |
2384 | } | 2391 | } |
2385 | 2392 | ||
2386 | /* this will do delete_inode and everything for us */ | 2393 | /* this will do delete_inode and everything for us */ |
2387 | iput(inode); | 2394 | iput(inode); |
2395 | if (ret) | ||
2396 | goto out; | ||
2388 | } | 2397 | } |
2389 | btrfs_free_path(path); | ||
2390 | |||
2391 | root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE; | 2398 | root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE; |
2392 | 2399 | ||
2393 | if (root->orphan_block_rsv) | 2400 | if (root->orphan_block_rsv) |
@@ -2396,14 +2403,20 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
2396 | 2403 | ||
2397 | if (root->orphan_block_rsv || root->orphan_item_inserted) { | 2404 | if (root->orphan_block_rsv || root->orphan_item_inserted) { |
2398 | trans = btrfs_join_transaction(root, 1); | 2405 | trans = btrfs_join_transaction(root, 1); |
2399 | BUG_ON(IS_ERR(trans)); | 2406 | if (!IS_ERR(trans)) |
2400 | btrfs_end_transaction(trans, root); | 2407 | btrfs_end_transaction(trans, root); |
2401 | } | 2408 | } |
2402 | 2409 | ||
2403 | if (nr_unlink) | 2410 | if (nr_unlink) |
2404 | printk(KERN_INFO "btrfs: unlinked %d orphans\n", nr_unlink); | 2411 | printk(KERN_INFO "btrfs: unlinked %d orphans\n", nr_unlink); |
2405 | if (nr_truncate) | 2412 | if (nr_truncate) |
2406 | printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate); | 2413 | printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate); |
2414 | |||
2415 | out: | ||
2416 | if (ret) | ||
2417 | printk(KERN_CRIT "btrfs: could not do orphan cleanup %d\n", ret); | ||
2418 | btrfs_free_path(path); | ||
2419 | return ret; | ||
2407 | } | 2420 | } |
2408 | 2421 | ||
2409 | /* | 2422 | /* |
@@ -4156,8 +4169,10 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
4156 | if (!IS_ERR(inode) && root != sub_root) { | 4169 | if (!IS_ERR(inode) && root != sub_root) { |
4157 | down_read(&root->fs_info->cleanup_work_sem); | 4170 | down_read(&root->fs_info->cleanup_work_sem); |
4158 | if (!(inode->i_sb->s_flags & MS_RDONLY)) | 4171 | if (!(inode->i_sb->s_flags & MS_RDONLY)) |
4159 | btrfs_orphan_cleanup(sub_root); | 4172 | ret = btrfs_orphan_cleanup(sub_root); |
4160 | up_read(&root->fs_info->cleanup_work_sem); | 4173 | up_read(&root->fs_info->cleanup_work_sem); |
4174 | if (ret) | ||
4175 | inode = ERR_PTR(ret); | ||
4161 | } | 4176 | } |
4162 | 4177 | ||
4163 | return inode; | 4178 | return inode; |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 5fdb2abc4fa7..ad9b8c0e930b 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -409,7 +409,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
409 | if (ret) | 409 | if (ret) |
410 | goto fail; | 410 | goto fail; |
411 | 411 | ||
412 | btrfs_orphan_cleanup(pending_snapshot->snap); | 412 | ret = btrfs_orphan_cleanup(pending_snapshot->snap); |
413 | if (ret) | ||
414 | goto fail; | ||
413 | 415 | ||
414 | parent = dget_parent(dentry); | 416 | parent = dget_parent(dentry); |
415 | inode = btrfs_lookup_dentry(parent->d_inode, dentry); | 417 | inode = btrfs_lookup_dentry(parent->d_inode, dentry); |
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index 31ade5802ae8..c863c8447015 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -4209,7 +4209,7 @@ out: | |||
4209 | if (IS_ERR(fs_root)) | 4209 | if (IS_ERR(fs_root)) |
4210 | err = PTR_ERR(fs_root); | 4210 | err = PTR_ERR(fs_root); |
4211 | else | 4211 | else |
4212 | btrfs_orphan_cleanup(fs_root); | 4212 | err = btrfs_orphan_cleanup(fs_root); |
4213 | } | 4213 | } |
4214 | return err; | 4214 | return err; |
4215 | } | 4215 | } |