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>
This commit is contained in:
parent
3893e33b0b
commit
66b4ffd110
@ -2529,7 +2529,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans,
|
|||||||
struct inode *inode);
|
struct inode *inode);
|
||||||
int btrfs_orphan_add(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);
|
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,
|
void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_pending_snapshot *pending,
|
struct btrfs_pending_snapshot *pending,
|
||||||
u64 *bytes_to_reserve);
|
u64 *bytes_to_reserve);
|
||||||
|
@ -2058,9 +2058,14 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
|||||||
|
|
||||||
if (!(sb->s_flags & MS_RDONLY)) {
|
if (!(sb->s_flags & MS_RDONLY)) {
|
||||||
down_read(&fs_info->cleanup_work_sem);
|
down_read(&fs_info->cleanup_work_sem);
|
||||||
btrfs_orphan_cleanup(fs_info->fs_root);
|
err = btrfs_orphan_cleanup(fs_info->fs_root);
|
||||||
btrfs_orphan_cleanup(fs_info->tree_root);
|
if (!err)
|
||||||
|
err = btrfs_orphan_cleanup(fs_info->tree_root);
|
||||||
up_read(&fs_info->cleanup_work_sem);
|
up_read(&fs_info->cleanup_work_sem);
|
||||||
|
if (err) {
|
||||||
|
close_ctree(tree_root);
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tree_root;
|
return tree_root;
|
||||||
@ -2435,8 +2440,12 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
|
|||||||
|
|
||||||
root_objectid = gang[ret - 1]->root_key.objectid + 1;
|
root_objectid = gang[ret - 1]->root_key.objectid + 1;
|
||||||
for (i = 0; i < ret; i++) {
|
for (i = 0; i < ret; i++) {
|
||||||
|
int err;
|
||||||
|
|
||||||
root_objectid = gang[i]->root_key.objectid;
|
root_objectid = gang[i]->root_key.objectid;
|
||||||
btrfs_orphan_cleanup(gang[i]);
|
err = btrfs_orphan_cleanup(gang[i]);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
root_objectid++;
|
root_objectid++;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
reloc_root = btrfs_read_fs_root_no_name(root->fs_info, &location);
|
||||||
BUG_ON(!reloc_root);
|
BUG_ON(!reloc_root);
|
||||||
btrfs_orphan_cleanup(reloc_root);
|
ret = btrfs_orphan_cleanup(reloc_root);
|
||||||
|
BUG_ON(ret);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
* this cleans up any orphans that may be left on the list from the last use
|
||||||
* of this root.
|
* of this root.
|
||||||
*/
|
*/
|
||||||
void btrfs_orphan_cleanup(struct btrfs_root *root)
|
int btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||||
{
|
{
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
struct extent_buffer *leaf;
|
struct extent_buffer *leaf;
|
||||||
@ -2294,10 +2294,13 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
|||||||
int ret = 0, nr_unlink = 0, nr_truncate = 0;
|
int ret = 0, nr_unlink = 0, nr_truncate = 0;
|
||||||
|
|
||||||
if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED))
|
if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
BUG_ON(!path);
|
if (!path) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
path->reada = -1;
|
path->reada = -1;
|
||||||
|
|
||||||
key.objectid = BTRFS_ORPHAN_OBJECTID;
|
key.objectid = BTRFS_ORPHAN_OBJECTID;
|
||||||
@ -2306,11 +2309,8 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
printk(KERN_ERR "Error searching slot for orphan: %d"
|
goto out;
|
||||||
"\n", ret);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if ret == 0 means we found what we were searching for, which
|
* if ret == 0 means we found what we were searching for, which
|
||||||
@ -2318,6 +2318,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
|||||||
* find the key and see if we have stuff that matches
|
* find the key and see if we have stuff that matches
|
||||||
*/
|
*/
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
|
ret = 0;
|
||||||
if (path->slots[0] == 0)
|
if (path->slots[0] == 0)
|
||||||
break;
|
break;
|
||||||
path->slots[0]--;
|
path->slots[0]--;
|
||||||
@ -2345,7 +2346,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
|||||||
found_key.type = BTRFS_INODE_ITEM_KEY;
|
found_key.type = BTRFS_INODE_ITEM_KEY;
|
||||||
found_key.offset = 0;
|
found_key.offset = 0;
|
||||||
inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
|
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
|
* add this inode to the orphan list so btrfs_orphan_del does
|
||||||
@ -2363,7 +2367,10 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
|||||||
*/
|
*/
|
||||||
if (is_bad_inode(inode)) {
|
if (is_bad_inode(inode)) {
|
||||||
trans = btrfs_start_transaction(root, 0);
|
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_orphan_del(trans, inode);
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
iput(inode);
|
iput(inode);
|
||||||
@ -2378,16 +2385,16 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
nr_truncate++;
|
nr_truncate++;
|
||||||
btrfs_truncate(inode);
|
ret = btrfs_truncate(inode);
|
||||||
} else {
|
} else {
|
||||||
nr_unlink++;
|
nr_unlink++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this will do delete_inode and everything for us */
|
/* this will do delete_inode and everything for us */
|
||||||
iput(inode);
|
iput(inode);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
btrfs_free_path(path);
|
|
||||||
|
|
||||||
root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE;
|
root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE;
|
||||||
|
|
||||||
if (root->orphan_block_rsv)
|
if (root->orphan_block_rsv)
|
||||||
@ -2396,14 +2403,20 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
|
|||||||
|
|
||||||
if (root->orphan_block_rsv || root->orphan_item_inserted) {
|
if (root->orphan_block_rsv || root->orphan_item_inserted) {
|
||||||
trans = btrfs_join_transaction(root, 1);
|
trans = btrfs_join_transaction(root, 1);
|
||||||
BUG_ON(IS_ERR(trans));
|
if (!IS_ERR(trans))
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nr_unlink)
|
if (nr_unlink)
|
||||||
printk(KERN_INFO "btrfs: unlinked %d orphans\n", nr_unlink);
|
printk(KERN_INFO "btrfs: unlinked %d orphans\n", nr_unlink);
|
||||||
if (nr_truncate)
|
if (nr_truncate)
|
||||||
printk(KERN_INFO "btrfs: truncated %d orphans\n", 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4156,8 +4169,10 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
|
|||||||
if (!IS_ERR(inode) && root != sub_root) {
|
if (!IS_ERR(inode) && root != sub_root) {
|
||||||
down_read(&root->fs_info->cleanup_work_sem);
|
down_read(&root->fs_info->cleanup_work_sem);
|
||||||
if (!(inode->i_sb->s_flags & MS_RDONLY))
|
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);
|
up_read(&root->fs_info->cleanup_work_sem);
|
||||||
|
if (ret)
|
||||||
|
inode = ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return inode;
|
return inode;
|
||||||
|
@ -409,7 +409,9 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
btrfs_orphan_cleanup(pending_snapshot->snap);
|
ret = btrfs_orphan_cleanup(pending_snapshot->snap);
|
||||||
|
if (ret)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
parent = dget_parent(dentry);
|
parent = dget_parent(dentry);
|
||||||
inode = btrfs_lookup_dentry(parent->d_inode, dentry);
|
inode = btrfs_lookup_dentry(parent->d_inode, dentry);
|
||||||
|
@ -4209,7 +4209,7 @@ out:
|
|||||||
if (IS_ERR(fs_root))
|
if (IS_ERR(fs_root))
|
||||||
err = PTR_ERR(fs_root);
|
err = PTR_ERR(fs_root);
|
||||||
else
|
else
|
||||||
btrfs_orphan_cleanup(fs_root);
|
err = btrfs_orphan_cleanup(fs_root);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user