btrfs: Support busy loop of write and delete
Reproduce: while true; do dd if=/dev/zero of=/mnt/btrfs/file count=[75% fs_size] rm /mnt/btrfs/file done Then we can see above loop failed on NO_SPACE. It it long-term problem since very beginning, because delayed-iput after rm are not run. We already have commit_transaction() in alloc_space code, but it is not triggered in above case. This patch trigger commit_transaction() to run delayed-iput and reflash pinned-space to to make write success. It is based on previous fix of delayed-iput in commit_transaction(), need to be applied on top of: btrfs: Fix NO_SPACE bug caused by delayed-iput Signed-off-by: Zhao Lei <zhaolei@cn.fujitsu.com> Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
parent
d7c151717a
commit
c99f1b0c6c
@ -3858,14 +3858,14 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
|
|||||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||||
u64 used;
|
u64 used;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int committed = 0;
|
int need_commit = 2;
|
||||||
int have_pinned_space = 1;
|
int have_pinned_space;
|
||||||
|
|
||||||
/* make sure bytes are sectorsize aligned */
|
/* make sure bytes are sectorsize aligned */
|
||||||
bytes = ALIGN(bytes, root->sectorsize);
|
bytes = ALIGN(bytes, root->sectorsize);
|
||||||
|
|
||||||
if (btrfs_is_free_space_inode(inode)) {
|
if (btrfs_is_free_space_inode(inode)) {
|
||||||
committed = 1;
|
need_commit = 0;
|
||||||
ASSERT(current->journal_info);
|
ASSERT(current->journal_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3915,8 +3915,10 @@ alloc:
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (ret != -ENOSPC)
|
if (ret != -ENOSPC)
|
||||||
return ret;
|
return ret;
|
||||||
else
|
else {
|
||||||
|
have_pinned_space = 1;
|
||||||
goto commit_trans;
|
goto commit_trans;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data_sinfo)
|
if (!data_sinfo)
|
||||||
@ -3930,23 +3932,23 @@ alloc:
|
|||||||
* allocation, and no removed chunk in current transaction,
|
* allocation, and no removed chunk in current transaction,
|
||||||
* don't bother committing the transaction.
|
* don't bother committing the transaction.
|
||||||
*/
|
*/
|
||||||
if (percpu_counter_compare(&data_sinfo->total_bytes_pinned,
|
have_pinned_space = percpu_counter_compare(
|
||||||
used + bytes -
|
&data_sinfo->total_bytes_pinned,
|
||||||
data_sinfo->total_bytes) < 0)
|
used + bytes - data_sinfo->total_bytes);
|
||||||
have_pinned_space = 0;
|
|
||||||
spin_unlock(&data_sinfo->lock);
|
spin_unlock(&data_sinfo->lock);
|
||||||
|
|
||||||
/* commit the current transaction and try again */
|
/* commit the current transaction and try again */
|
||||||
commit_trans:
|
commit_trans:
|
||||||
if (!committed &&
|
if (need_commit &&
|
||||||
!atomic_read(&root->fs_info->open_ioctl_trans)) {
|
!atomic_read(&root->fs_info->open_ioctl_trans)) {
|
||||||
committed = 1;
|
need_commit--;
|
||||||
|
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
if (IS_ERR(trans))
|
if (IS_ERR(trans))
|
||||||
return PTR_ERR(trans);
|
return PTR_ERR(trans);
|
||||||
if (have_pinned_space ||
|
if (have_pinned_space >= 0 ||
|
||||||
trans->transaction->have_free_bgs) {
|
trans->transaction->have_free_bgs ||
|
||||||
|
need_commit > 0) {
|
||||||
ret = btrfs_commit_transaction(trans, root);
|
ret = btrfs_commit_transaction(trans, root);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user