mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 19:00:25 +00:00
Btrfs: add orphan before truncating pagecache
Running xfstests 83 in a loop would sometimes fail the fsck. This happens because if we invalidate a page that already has an ordered extent setup for it we will complete the ordered extent ourselves, assuming that the truncate will clean everything up. The problem with this is there is plenty of time for the truncate to fail after we've done this work. So to fix this we need to add the orphan item first to make sure the cleanup gets done properly, and then we can truncate the pagecache and all that stuff and be safe. This fixes the btrfsck failures I was seeing while running 83 in a loop. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com>
This commit is contained in:
parent
72bcd99d45
commit
f3fe820c20
1 changed files with 38 additions and 15 deletions
|
@ -2478,6 +2478,18 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
nr_truncate++;
|
nr_truncate++;
|
||||||
|
|
||||||
|
/* 1 for the orphan item deletion. */
|
||||||
|
trans = btrfs_start_transaction(root, 1);
|
||||||
|
if (IS_ERR(trans)) {
|
||||||
|
ret = PTR_ERR(trans);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = btrfs_orphan_add(trans, inode);
|
||||||
|
btrfs_end_transaction(trans, root);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
ret = btrfs_truncate(inode);
|
ret = btrfs_truncate(inode);
|
||||||
} else {
|
} else {
|
||||||
nr_unlink++;
|
nr_unlink++;
|
||||||
|
@ -3783,9 +3795,34 @@ static int btrfs_setsize(struct inode *inode, loff_t newsize)
|
||||||
set_bit(BTRFS_INODE_ORDERED_DATA_CLOSE,
|
set_bit(BTRFS_INODE_ORDERED_DATA_CLOSE,
|
||||||
&BTRFS_I(inode)->runtime_flags);
|
&BTRFS_I(inode)->runtime_flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1 for the orphan item we're going to add
|
||||||
|
* 1 for the orphan item deletion.
|
||||||
|
*/
|
||||||
|
trans = btrfs_start_transaction(root, 2);
|
||||||
|
if (IS_ERR(trans))
|
||||||
|
return PTR_ERR(trans);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to do this in case we fail at _any_ point during the
|
||||||
|
* actual truncate. Once we do the truncate_setsize we could
|
||||||
|
* invalidate pages which forces any outstanding ordered io to
|
||||||
|
* be instantly completed which will give us extents that need
|
||||||
|
* to be truncated. If we fail to get an orphan inode down we
|
||||||
|
* could have left over extents that were never meant to live,
|
||||||
|
* so we need to garuntee from this point on that everything
|
||||||
|
* will be consistent.
|
||||||
|
*/
|
||||||
|
ret = btrfs_orphan_add(trans, inode);
|
||||||
|
btrfs_end_transaction(trans, root);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* we don't support swapfiles, so vmtruncate shouldn't fail */
|
/* we don't support swapfiles, so vmtruncate shouldn't fail */
|
||||||
truncate_setsize(inode, newsize);
|
truncate_setsize(inode, newsize);
|
||||||
ret = btrfs_truncate(inode);
|
ret = btrfs_truncate(inode);
|
||||||
|
if (ret && inode->i_nlink)
|
||||||
|
btrfs_orphan_del(NULL, inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -6929,11 +6966,9 @@ static int btrfs_truncate(struct inode *inode)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1 for the truncate slack space
|
* 1 for the truncate slack space
|
||||||
* 1 for the orphan item we're going to add
|
|
||||||
* 1 for the orphan item deletion
|
|
||||||
* 1 for updating the inode.
|
* 1 for updating the inode.
|
||||||
*/
|
*/
|
||||||
trans = btrfs_start_transaction(root, 4);
|
trans = btrfs_start_transaction(root, 2);
|
||||||
if (IS_ERR(trans)) {
|
if (IS_ERR(trans)) {
|
||||||
err = PTR_ERR(trans);
|
err = PTR_ERR(trans);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -6944,12 +6979,6 @@ static int btrfs_truncate(struct inode *inode)
|
||||||
min_size);
|
min_size);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
|
||||||
ret = btrfs_orphan_add(trans, inode);
|
|
||||||
if (ret) {
|
|
||||||
btrfs_end_transaction(trans, root);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* setattr is responsible for setting the ordered_data_close flag,
|
* setattr is responsible for setting the ordered_data_close flag,
|
||||||
* but that is only tested during the last file release. That
|
* but that is only tested during the last file release. That
|
||||||
|
@ -7018,12 +7047,6 @@ static int btrfs_truncate(struct inode *inode)
|
||||||
ret = btrfs_orphan_del(trans, inode);
|
ret = btrfs_orphan_del(trans, inode);
|
||||||
if (ret)
|
if (ret)
|
||||||
err = ret;
|
err = ret;
|
||||||
} else if (ret && inode->i_nlink > 0) {
|
|
||||||
/*
|
|
||||||
* Failed to do the truncate, remove us from the in memory
|
|
||||||
* orphan list.
|
|
||||||
*/
|
|
||||||
ret = btrfs_orphan_del(NULL, inode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trans) {
|
if (trans) {
|
||||||
|
|
Loading…
Reference in a new issue