aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-01-31 16:22:42 -0500
committerJosef Bacik <josef@redhat.com>2011-03-17 14:21:26 -0400
commit66b4ffd110f9b48b8d8c1319ee446b53b8d073bf (patch)
tree690b14cda46b47c0d71be15a82019c35729afa75 /fs/btrfs/inode.c
parent3893e33b0bebee2f67d96b6c15259dc884523c20 (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/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c47
1 files changed, 31 insertions, 16 deletions
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 */
2287void btrfs_orphan_cleanup(struct btrfs_root *root) 2287int 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
2415out:
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;