block allocations for the refcount btree

Christoph Hellwig
2016-02-10T09:30:18Z

I've been chasing asserts about reserved blocks when testing the reflink
feature over NFS. I was right with my suspicion that the full allocator
recursion from xfs_refcountbt_alloc_block was the culprit, but I should
have read the assert before jumping to conclusions: we're running out
of space reservations, not log reservations.

The problem is that we need reserve the space for these normal allocator
block pools used by the refcount btree, which we may use up for allocations
and frees given that we use the normal space allocator for it.

This means we need a reservation for each transaction that truncates
extents, including those allocated in xfs_trans_roll. The patch below
demonstrates a local hack that makes things work for me so far, but
I don't think it's a viable solution.

Darrick, Dave - can you explain the design decisions behind the
refcount btree block allocations to me? This whole area still seems
to be in constant flux, so it seems there are lots of tradeoffs to make.

diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 338c457..3b8a25e 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -967,7 +967,7 @@ xfs_free_eofblocks(
}
}

- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
+ error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 2, 0);
if (error) {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
xfs_trans_cancel(tp);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index d1311ef..ec530d7 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1783,7 +1783,7 @@ xfs_inactive_truncate(
int error;

tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
+ error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 2, 0);
if (error) {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
xfs_trans_cancel(tp);
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index ab3619c..a8c55bd 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -871,7 +871,7 @@ xfs_setattr_size(
truncate_setsize(inode, newsize);

tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
+ error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 2, 0);
if (error)
goto out_trans_cancel;

diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 4d63836..a661430 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -4144,7 +4144,7 @@ xlog_recover_process_efi(
}

tp = xfs_trans_alloc(mp, 0);
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
+ error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 2, 0);
if (error)
goto abort_error;
efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents);
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index 3640c6e..33ff98f 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -237,7 +237,7 @@ xfs_qm_scall_trunc_qfile(
xfs_ilock(ip, XFS_IOLOCK_EXCL);

tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE);
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
+ error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 2, 0);
if (error) {
xfs_trans_cancel(tp);
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 9503ccc..585a94a 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -1026,7 +1026,7 @@ xfs_reflink_update_dest(
return 0;

tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
+ error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 2, 0);

/*
* check for running out of space
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c
index b44284c..7538f39 100644
--- a/fs/xfs/xfs_symlink.c
+++ b/fs/xfs/xfs_symlink.c
@@ -456,7 +456,7 @@ xfs_inactive_symlink_rmt(
ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2);

tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
- error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
+ error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 2, 0);
if (error) {
xfs_trans_cancel(tp);
return error;
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 748b16a..2ef46de 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -1065,7 +1065,7 @@ __xfs_trans_roll(
* the prior and the next transactions.
*/
tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
- error = xfs_trans_reserve(trans, &tres, 0, 0);
+ error = xfs_trans_reserve(trans, &tres, 2, 0);
/*
* Ensure that the inode is in the new transaction and locked.
*/