diff options
author | Filipe Manana <fdmanana@suse.com> | 2016-06-06 06:51:25 -0400 |
---|---|---|
committer | Filipe Manana <fdmanana@suse.com> | 2016-08-01 02:32:03 -0400 |
commit | 67710892ec983aa79ad1e2a2642fe8e3a4a194ea (patch) | |
tree | 251f0feaddfbbf6e98690943d470972d7b37c3d6 | |
parent | 951555856b88aa47bc238de6b4c6e97bfd9d36df (diff) |
Btrfs: be more precise on errors when getting an inode from disk
When we attempt to read an inode from disk, we end up always returning an
-ESTALE error to the caller regardless of the actual failure reason, which
can be an out of memory problem (when allocating a path), some error found
when reading from the fs/subvolume btree (like a genuine IO error) or the
inode does not exists. So lets start returning the real error code to the
callers so that they don't treat all -ESTALE errors as meaning that the
inode does not exists (such as during orphan cleanup). This will also be
needed for a subsequent patch in the same series dealing with a special
fsync case.
Signed-off-by: Filipe Manana <fdmanana@suse.com>
-rw-r--r-- | fs/btrfs/inode.c | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3e61bd1f3f65..f9686541997b 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -3428,10 +3428,10 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) | |||
3428 | found_key.offset = 0; | 3428 | found_key.offset = 0; |
3429 | inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL); | 3429 | inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL); |
3430 | ret = PTR_ERR_OR_ZERO(inode); | 3430 | ret = PTR_ERR_OR_ZERO(inode); |
3431 | if (ret && ret != -ESTALE) | 3431 | if (ret && ret != -ENOENT) |
3432 | goto out; | 3432 | goto out; |
3433 | 3433 | ||
3434 | if (ret == -ESTALE && root == root->fs_info->tree_root) { | 3434 | if (ret == -ENOENT && root == root->fs_info->tree_root) { |
3435 | struct btrfs_root *dead_root; | 3435 | struct btrfs_root *dead_root; |
3436 | struct btrfs_fs_info *fs_info = root->fs_info; | 3436 | struct btrfs_fs_info *fs_info = root->fs_info; |
3437 | int is_dead_root = 0; | 3437 | int is_dead_root = 0; |
@@ -3467,7 +3467,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) | |||
3467 | * Inode is already gone but the orphan item is still there, | 3467 | * Inode is already gone but the orphan item is still there, |
3468 | * kill the orphan item. | 3468 | * kill the orphan item. |
3469 | */ | 3469 | */ |
3470 | if (ret == -ESTALE) { | 3470 | if (ret == -ENOENT) { |
3471 | trans = btrfs_start_transaction(root, 1); | 3471 | trans = btrfs_start_transaction(root, 1); |
3472 | if (IS_ERR(trans)) { | 3472 | if (IS_ERR(trans)) { |
3473 | ret = PTR_ERR(trans); | 3473 | ret = PTR_ERR(trans); |
@@ -3626,7 +3626,7 @@ static noinline int acls_after_inode_item(struct extent_buffer *leaf, | |||
3626 | /* | 3626 | /* |
3627 | * read an inode from the btree into the in-memory inode | 3627 | * read an inode from the btree into the in-memory inode |
3628 | */ | 3628 | */ |
3629 | static void btrfs_read_locked_inode(struct inode *inode) | 3629 | static int btrfs_read_locked_inode(struct inode *inode) |
3630 | { | 3630 | { |
3631 | struct btrfs_path *path; | 3631 | struct btrfs_path *path; |
3632 | struct extent_buffer *leaf; | 3632 | struct extent_buffer *leaf; |
@@ -3645,14 +3645,19 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
3645 | filled = true; | 3645 | filled = true; |
3646 | 3646 | ||
3647 | path = btrfs_alloc_path(); | 3647 | path = btrfs_alloc_path(); |
3648 | if (!path) | 3648 | if (!path) { |
3649 | ret = -ENOMEM; | ||
3649 | goto make_bad; | 3650 | goto make_bad; |
3651 | } | ||
3650 | 3652 | ||
3651 | memcpy(&location, &BTRFS_I(inode)->location, sizeof(location)); | 3653 | memcpy(&location, &BTRFS_I(inode)->location, sizeof(location)); |
3652 | 3654 | ||
3653 | ret = btrfs_lookup_inode(NULL, root, path, &location, 0); | 3655 | ret = btrfs_lookup_inode(NULL, root, path, &location, 0); |
3654 | if (ret) | 3656 | if (ret) { |
3657 | if (ret > 0) | ||
3658 | ret = -ENOENT; | ||
3655 | goto make_bad; | 3659 | goto make_bad; |
3660 | } | ||
3656 | 3661 | ||
3657 | leaf = path->nodes[0]; | 3662 | leaf = path->nodes[0]; |
3658 | 3663 | ||
@@ -3805,11 +3810,12 @@ cache_acl: | |||
3805 | } | 3810 | } |
3806 | 3811 | ||
3807 | btrfs_update_iflags(inode); | 3812 | btrfs_update_iflags(inode); |
3808 | return; | 3813 | return 0; |
3809 | 3814 | ||
3810 | make_bad: | 3815 | make_bad: |
3811 | btrfs_free_path(path); | 3816 | btrfs_free_path(path); |
3812 | make_bad_inode(inode); | 3817 | make_bad_inode(inode); |
3818 | return ret; | ||
3813 | } | 3819 | } |
3814 | 3820 | ||
3815 | /* | 3821 | /* |
@@ -5595,7 +5601,9 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, | |||
5595 | return ERR_PTR(-ENOMEM); | 5601 | return ERR_PTR(-ENOMEM); |
5596 | 5602 | ||
5597 | if (inode->i_state & I_NEW) { | 5603 | if (inode->i_state & I_NEW) { |
5598 | btrfs_read_locked_inode(inode); | 5604 | int ret; |
5605 | |||
5606 | ret = btrfs_read_locked_inode(inode); | ||
5599 | if (!is_bad_inode(inode)) { | 5607 | if (!is_bad_inode(inode)) { |
5600 | inode_tree_add(inode); | 5608 | inode_tree_add(inode); |
5601 | unlock_new_inode(inode); | 5609 | unlock_new_inode(inode); |
@@ -5604,7 +5612,8 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, | |||
5604 | } else { | 5612 | } else { |
5605 | unlock_new_inode(inode); | 5613 | unlock_new_inode(inode); |
5606 | iput(inode); | 5614 | iput(inode); |
5607 | inode = ERR_PTR(-ESTALE); | 5615 | ASSERT(ret < 0); |
5616 | inode = ERR_PTR(ret < 0 ? ret : -ESTALE); | ||
5608 | } | 5617 | } |
5609 | } | 5618 | } |
5610 | 5619 | ||