Merge branch 'for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs fixes from Chris Mason: "Some fixes for btrfs send/recv and fsync from Filipe and Robbie Ko. Bonus points to Filipe for already having xfstests in place for many of these" * 'for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: Btrfs: remove unused function btrfs_add_delayed_qgroup_reserve() Btrfs: improve performance on fsync against new inode after rename/unlink Btrfs: be more precise on errors when getting an inode from disk Btrfs: send, don't bug on inconsistent snapshots Btrfs: send, avoid incorrect leaf accesses when sending utimes operations Btrfs: send, fix invalid leaf accesses due to incorrect utimes operations Btrfs: send, fix warning due to late freeing of orphan_dir_info structures Btrfs: incremental send, fix premature rmdir operations Btrfs: incremental send, fix invalid paths for rename operations Btrfs: send, add missing error check for calls to path_loop() Btrfs: send, fix failure to move directories with the same name around Btrfs: add missing check for writeback errors on fsync
This commit is contained in:
@@ -3435,10 +3435,10 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
found_key.offset = 0;
|
||||
inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
|
||||
ret = PTR_ERR_OR_ZERO(inode);
|
||||
if (ret && ret != -ESTALE)
|
||||
if (ret && ret != -ENOENT)
|
||||
goto out;
|
||||
|
||||
if (ret == -ESTALE && root == root->fs_info->tree_root) {
|
||||
if (ret == -ENOENT && root == root->fs_info->tree_root) {
|
||||
struct btrfs_root *dead_root;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
int is_dead_root = 0;
|
||||
@@ -3474,7 +3474,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
* Inode is already gone but the orphan item is still there,
|
||||
* kill the orphan item.
|
||||
*/
|
||||
if (ret == -ESTALE) {
|
||||
if (ret == -ENOENT) {
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
if (IS_ERR(trans)) {
|
||||
ret = PTR_ERR(trans);
|
||||
@@ -3633,7 +3633,7 @@ static noinline int acls_after_inode_item(struct extent_buffer *leaf,
|
||||
/*
|
||||
* read an inode from the btree into the in-memory inode
|
||||
*/
|
||||
static void btrfs_read_locked_inode(struct inode *inode)
|
||||
static int btrfs_read_locked_inode(struct inode *inode)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
struct extent_buffer *leaf;
|
||||
@@ -3652,14 +3652,19 @@ static void btrfs_read_locked_inode(struct inode *inode)
|
||||
filled = true;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
if (!path) {
|
||||
ret = -ENOMEM;
|
||||
goto make_bad;
|
||||
}
|
||||
|
||||
memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
|
||||
|
||||
ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
if (ret > 0)
|
||||
ret = -ENOENT;
|
||||
goto make_bad;
|
||||
}
|
||||
|
||||
leaf = path->nodes[0];
|
||||
|
||||
@@ -3812,11 +3817,12 @@ cache_acl:
|
||||
}
|
||||
|
||||
btrfs_update_iflags(inode);
|
||||
return;
|
||||
return 0;
|
||||
|
||||
make_bad:
|
||||
btrfs_free_path(path);
|
||||
make_bad_inode(inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4204,6 +4210,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
int err = 0;
|
||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||
struct btrfs_trans_handle *trans;
|
||||
u64 last_unlink_trans;
|
||||
|
||||
if (inode->i_size > BTRFS_EMPTY_DIR_SIZE)
|
||||
return -ENOTEMPTY;
|
||||
@@ -4226,11 +4233,27 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
last_unlink_trans = BTRFS_I(inode)->last_unlink_trans;
|
||||
|
||||
/* now the directory is empty */
|
||||
err = btrfs_unlink_inode(trans, root, dir, d_inode(dentry),
|
||||
dentry->d_name.name, dentry->d_name.len);
|
||||
if (!err)
|
||||
if (!err) {
|
||||
btrfs_i_size_write(inode, 0);
|
||||
/*
|
||||
* Propagate the last_unlink_trans value of the deleted dir to
|
||||
* its parent directory. This is to prevent an unrecoverable
|
||||
* log tree in the case we do something like this:
|
||||
* 1) create dir foo
|
||||
* 2) create snapshot under dir foo
|
||||
* 3) delete the snapshot
|
||||
* 4) rmdir foo
|
||||
* 5) mkdir foo
|
||||
* 6) fsync foo or some file inside foo
|
||||
*/
|
||||
if (last_unlink_trans >= trans->transid)
|
||||
BTRFS_I(dir)->last_unlink_trans = last_unlink_trans;
|
||||
}
|
||||
out:
|
||||
btrfs_end_transaction(trans, root);
|
||||
btrfs_btree_balance_dirty(root);
|
||||
@@ -5606,7 +5629,9 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (inode->i_state & I_NEW) {
|
||||
btrfs_read_locked_inode(inode);
|
||||
int ret;
|
||||
|
||||
ret = btrfs_read_locked_inode(inode);
|
||||
if (!is_bad_inode(inode)) {
|
||||
inode_tree_add(inode);
|
||||
unlock_new_inode(inode);
|
||||
@@ -5615,7 +5640,8 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
|
||||
} else {
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
inode = ERR_PTR(-ESTALE);
|
||||
ASSERT(ret < 0);
|
||||
inode = ERR_PTR(ret < 0 ? ret : -ESTALE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user