Commit c99f1b0c authored by Zhao Lei's avatar Zhao Lei Committed by Chris Mason

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: default avatarZhao Lei <zhaolei@cn.fujitsu.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent d7c15171
...@@ -3858,14 +3858,14 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes) ...@@ -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 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes) ...@@ -3915,8 +3915,10 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
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 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes) ...@@ -3930,23 +3932,23 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
* 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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment