Commit 032f2f90 authored by Zizhi Wo's avatar Zizhi Wo Committed by Long Li
Browse files

xfs: Fix agf_longest update error

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I9TDTA


CVE: NA

--------------------------------

A concurrent file creation and little writing could unexpectedly return
-ENOSPC error since there is a race window that the allocator could get the
wrong agf->agf_longest.

Write file process steps:
1) Find the entry that best meets the conditions, then calculate the start
address and length of the remaining part of the entry after allocation.
2) Delete this entry and update the agf->agf_longest.
3) Insert the remaining unused parts of this entry based on the
calculations in 1), and update the agf->agf_longest again if necessary.

Create file process steps:
1) Check whether there are free inodes in the inode chunk.
2) If there is no free inode, check whether there has space for creating
inode chunks, perform the no-lock judgment first.
3) If the judgment succeeds, the judgment is performed again with agf lock
held. Otherwire, an error is returned directly.

If the write process is in step 2) but not go to 3) yet, the create file
process goes to 2) at this time, it will be mistaken for no space,
resulting in the file system still has space but the file creation fails.
Because in the previous code, if numrec == 0, longest will be temporarily
set to 0 in write process step 2), and we have fixed it in commit
628ab796d8b1 ("xfs: Fix file creation failure") to update the longest in
advance.

But we don't fix it all. If numrec is not 0 in xfs_allocbt_update_lastrec,
xfs will update the agf_longest to the -current- longest node currently.
However, this is not true because the value of the node may be smaller than
the remaining part of the original longest extent after part of it is
deleted. The agf_longest updated at this moment is not accurate.

Fix it by comparing cur->bc_free_longest with the -current- longest node
and taking the maximum value as the agf_longest.

Fixes: 1da177e4 ("Linux-2.6.12-rc2")
Fixes: 628ab796d8b1 ("xfs: Fix file creation failure")
Signed-off-by: default avatarZizhi Wo <wozizhi@huawei.com>
Signed-off-by: default avatarLong Li <leo.lilong@huawei.com>
parent fb979312
Loading
Loading
Loading
Loading
+10 −10
Original line number Diff line number Diff line
@@ -141,12 +141,6 @@ xfs_allocbt_update_lastrec(
			return;
		ASSERT(ptr == numrecs + 1);

		if (numrecs) {
			xfs_alloc_rec_t *rrp;

			rrp = XFS_ALLOC_REC_ADDR(cur->bc_mp, block, numrecs);
			len = rrp->ar_blockcount;
		} else {
		/*
		 * Update in advance to prevent file creation failure
		 * for concurrent processes even though there is no
@@ -155,6 +149,12 @@ xfs_allocbt_update_lastrec(
		 * less than bc_free_longest will be inserted later.
		 */
		len = cpu_to_be32(cur->bc_free_longest);
		if (numrecs) {
			xfs_alloc_rec_t *rrp;

			rrp = XFS_ALLOC_REC_ADDR(cur->bc_mp, block, numrecs);
			len = cpu_to_be32(max_t(xfs_extlen_t, cur->bc_free_longest,
						be32_to_cpu(rrp->ar_blockcount)));
		}

		break;