Skip to content

Commit

Permalink
Btrfs: handle errors in btrfs_orphan_cleanup
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Josef Bacik committed Mar 17, 2011
1 parent 3893e33 commit 66b4ffd
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 23 deletions.
2 changes: 1 addition & 1 deletion fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -2529,7 +2529,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans,
struct inode *inode);
int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode);
int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
void btrfs_orphan_cleanup(struct btrfs_root *root);
int btrfs_orphan_cleanup(struct btrfs_root *root);
void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_pending_snapshot *pending,
u64 *bytes_to_reserve);
Expand Down
15 changes: 12 additions & 3 deletions fs/btrfs/disk-io.c
Original file line number Diff line number Diff line change
Expand Up @@ -2058,9 +2058,14 @@ struct btrfs_root *open_ctree(struct super_block *sb,

if (!(sb->s_flags & MS_RDONLY)) {
down_read(&fs_info->cleanup_work_sem);
btrfs_orphan_cleanup(fs_info->fs_root);
btrfs_orphan_cleanup(fs_info->tree_root);
err = btrfs_orphan_cleanup(fs_info->fs_root);
if (!err)
err = btrfs_orphan_cleanup(fs_info->tree_root);
up_read(&fs_info->cleanup_work_sem);
if (err) {
close_ctree(tree_root);
return ERR_PTR(err);
}
}

return tree_root;
Expand Down Expand Up @@ -2435,8 +2440,12 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)

root_objectid = gang[ret - 1]->root_key.objectid + 1;
for (i = 0; i < ret; i++) {
int err;

root_objectid = gang[i]->root_key.objectid;
btrfs_orphan_cleanup(gang[i]);
err = btrfs_orphan_cleanup(gang[i]);
if (err)
return err;
}
root_objectid++;
}
Expand Down
3 changes: 2 additions & 1 deletion fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -7619,7 +7619,8 @@ int btrfs_cleanup_reloc_trees(struct btrfs_root *root)

reloc_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
BUG_ON(!reloc_root);
btrfs_orphan_cleanup(reloc_root);
ret = btrfs_orphan_cleanup(reloc_root);
BUG_ON(ret);
return 0;
}

Expand Down
47 changes: 31 additions & 16 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2284,7 +2284,7 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode)
* this cleans up any orphans that may be left on the list from the last use
* of this root.
*/
void btrfs_orphan_cleanup(struct btrfs_root *root)
int btrfs_orphan_cleanup(struct btrfs_root *root)
{
struct btrfs_path *path;
struct extent_buffer *leaf;
Expand All @@ -2294,10 +2294,13 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
int ret = 0, nr_unlink = 0, nr_truncate = 0;

if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED))
return;
return 0;

path = btrfs_alloc_path();
BUG_ON(!path);
if (!path) {
ret = -ENOMEM;
goto out;
}
path->reada = -1;

key.objectid = BTRFS_ORPHAN_OBJECTID;
Expand All @@ -2306,18 +2309,16 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)

while (1) {
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0) {
printk(KERN_ERR "Error searching slot for orphan: %d"
"\n", ret);
break;
}
if (ret < 0)
goto out;

/*
* if ret == 0 means we found what we were searching for, which
* is weird, but possible, so only screw with path if we didnt
* find the key and see if we have stuff that matches
*/
if (ret > 0) {
ret = 0;
if (path->slots[0] == 0)
break;
path->slots[0]--;
Expand Down Expand Up @@ -2345,7 +2346,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
found_key.type = BTRFS_INODE_ITEM_KEY;
found_key.offset = 0;
inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
BUG_ON(IS_ERR(inode));
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
goto out;
}

/*
* add this inode to the orphan list so btrfs_orphan_del does
Expand All @@ -2363,7 +2367,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
*/
if (is_bad_inode(inode)) {
trans = btrfs_start_transaction(root, 0);
BUG_ON(IS_ERR(trans));
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
}
btrfs_orphan_del(trans, inode);
btrfs_end_transaction(trans, root);
iput(inode);
Expand All @@ -2378,16 +2385,16 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
continue;
}
nr_truncate++;
btrfs_truncate(inode);
ret = btrfs_truncate(inode);
} else {
nr_unlink++;
}

/* this will do delete_inode and everything for us */
iput(inode);
if (ret)
goto out;
}
btrfs_free_path(path);

root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE;

if (root->orphan_block_rsv)
Expand All @@ -2396,14 +2403,20 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)

if (root->orphan_block_rsv || root->orphan_item_inserted) {
trans = btrfs_join_transaction(root, 1);
BUG_ON(IS_ERR(trans));
btrfs_end_transaction(trans, root);
if (!IS_ERR(trans))
btrfs_end_transaction(trans, root);
}

if (nr_unlink)
printk(KERN_INFO "btrfs: unlinked %d orphans\n", nr_unlink);
if (nr_truncate)
printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate);

out:
if (ret)
printk(KERN_CRIT "btrfs: could not do orphan cleanup %d\n", ret);
btrfs_free_path(path);
return ret;
}

/*
Expand Down Expand Up @@ -4156,8 +4169,10 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
if (!IS_ERR(inode) && root != sub_root) {
down_read(&root->fs_info->cleanup_work_sem);
if (!(inode->i_sb->s_flags & MS_RDONLY))
btrfs_orphan_cleanup(sub_root);
ret = btrfs_orphan_cleanup(sub_root);
up_read(&root->fs_info->cleanup_work_sem);
if (ret)
inode = ERR_PTR(ret);
}

return inode;
Expand Down
4 changes: 3 additions & 1 deletion fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
if (ret)
goto fail;

btrfs_orphan_cleanup(pending_snapshot->snap);
ret = btrfs_orphan_cleanup(pending_snapshot->snap);
if (ret)
goto fail;

parent = dget_parent(dentry);
inode = btrfs_lookup_dentry(parent->d_inode, dentry);
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/relocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -4209,7 +4209,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
if (IS_ERR(fs_root))
err = PTR_ERR(fs_root);
else
btrfs_orphan_cleanup(fs_root);
err = btrfs_orphan_cleanup(fs_root);
}
return err;
}
Expand Down

0 comments on commit 66b4ffd

Please sign in to comment.