Commit f6a7b4ec authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'xfs-6.12-fixes-6' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Carlos Maiolino:

 - fix a sysbot reported crash on filestreams

 - Reduce cpu time spent searching for extents in a very fragmented FS

 - Check for delayed allocations before setting extsize

* tag 'xfs-6.12-fixes-6' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: streamline xfs_filestream_pick_ag
  xfs: fix finding a last resort AG in xfs_filestream_pick_ag
  xfs: Reduce unnecessary searches when searching for the best extents
  xfs: Check for delayed allocations before setting extsize
parents 11066801 81a1e1c3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1923,7 +1923,7 @@ xfs_alloc_ag_vextent_size(
				error = -EFSCORRUPTED;
				goto error0;
			}
			if (flen < bestrlen)
			if (flen <= bestrlen)
				break;
			busy = xfs_alloc_compute_aligned(args, fbno, flen,
					&rbno, &rlen, &busy_gen);
+48 −51
Original line number Diff line number Diff line
@@ -64,26 +64,32 @@ xfs_filestream_pick_ag(
	struct xfs_perag	*pag;
	struct xfs_perag	*max_pag = NULL;
	xfs_extlen_t		minlen = *longest;
	xfs_extlen_t		free = 0, minfree, maxfree = 0;
	xfs_extlen_t		minfree, maxfree = 0;
	xfs_agnumber_t		agno;
	bool			first_pass = true;
	int			err;

	/* 2% of an AG's blocks must be free for it to be chosen. */
	minfree = mp->m_sb.sb_agblocks / 50;

restart:
	for_each_perag_wrap(mp, start_agno, agno, pag) {
		int		err;

		trace_xfs_filestream_scan(pag, pino);

		*longest = 0;
		err = xfs_bmap_longest_free_extent(pag, NULL, longest);
		if (err) {
			if (err != -EAGAIN)
				break;
			if (err == -EAGAIN) {
				/* Couldn't lock the AGF, skip this AG. */
				err = 0;
				continue;
			}
			xfs_perag_rele(pag);
			if (max_pag)
				xfs_perag_rele(max_pag);
			return err;
		}

		/* Keep track of the AG with the most free blocks. */
		if (pag->pagf_freeblks > maxfree) {
@@ -107,8 +113,9 @@ xfs_filestream_pick_ag(
			     !(flags & XFS_PICK_USERDATA) ||
			     (flags & XFS_PICK_LOWSPACE))) {
				/* Break out, retaining the reference on the AG. */
				free = pag->pagf_freeblks;
				break;
				if (max_pag)
					xfs_perag_rele(max_pag);
				goto done;
			}
		}

@@ -116,18 +123,10 @@ xfs_filestream_pick_ag(
		atomic_dec(&pag->pagf_fstrms);
	}

	if (err) {
		xfs_perag_rele(pag);
		if (max_pag)
			xfs_perag_rele(max_pag);
		return err;
	}

	if (!pag) {
	/*
		 * Allow a second pass to give xfs_bmap_longest_free_extent()
		 * another attempt at locking AGFs that it might have skipped
		 * over before we fail.
	 * Allow a second pass to give xfs_bmap_longest_free_extent() another
	 * attempt at locking AGFs that it might have skipped over before we
	 * fail.
	 */
	if (first_pass) {
		first_pass = false;
@@ -135,8 +134,8 @@ xfs_filestream_pick_ag(
	}

	/*
		 * We must be low on data space, so run a final lowspace
		 * optimised selection pass if we haven't already.
	 * We must be low on data space, so run a final lowspace optimised
	 * selection pass if we haven't already.
	 */
	if (!(flags & XFS_PICK_LOWSPACE)) {
		flags |= XFS_PICK_LOWSPACE;
@@ -144,29 +143,27 @@ xfs_filestream_pick_ag(
	}

	/*
		 * No unassociated AGs are available, so select the AG with the
		 * most free space, regardless of whether it's already in use by
		 * another filestream. It none suit, just use whatever AG we can
		 * grab.
	 * No unassociated AGs are available, so select the AG with the most
	 * free space, regardless of whether it's already in use by another
	 * filestream. It none suit, just use whatever AG we can grab.
	 */
	if (!max_pag) {
			for_each_perag_wrap(args->mp, 0, start_agno, args->pag)
		for_each_perag_wrap(args->mp, 0, start_agno, pag) {
			max_pag = pag;
			break;
			atomic_inc(&args->pag->pagf_fstrms);
			*longest = 0;
		} else {
			pag = max_pag;
			free = maxfree;
			atomic_inc(&pag->pagf_fstrms);
		}
	} else if (max_pag) {
		xfs_perag_rele(max_pag);

		/* Bail if there are no AGs at all to select from. */
		if (!max_pag)
			return -ENOSPC;
	}

	trace_xfs_filestream_pick(pag, pino, free);
	pag = max_pag;
	atomic_inc(&pag->pagf_fstrms);
done:
	trace_xfs_filestream_pick(pag, pino);
	args->pag = pag;
	return 0;

}

static struct xfs_inode *
+1 −1
Original line number Diff line number Diff line
@@ -1409,7 +1409,7 @@ xfs_inactive(

	if (S_ISREG(VFS_I(ip)->i_mode) &&
	    (ip->i_disk_size != 0 || XFS_ISIZE(ip) != 0 ||
	     ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0))
	     xfs_inode_has_filedata(ip)))
		truncate = 1;

	if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) {
+5 −0
Original line number Diff line number Diff line
@@ -292,6 +292,11 @@ static inline bool xfs_is_cow_inode(struct xfs_inode *ip)
	return xfs_is_reflink_inode(ip) || xfs_is_always_cow_inode(ip);
}

static inline bool xfs_inode_has_filedata(const struct xfs_inode *ip)
{
	return ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0;
}

/*
 * Check if an inode has any data in the COW fork.  This might be often false
 * even for inodes with the reflink flag when there is no pending COW operation.
+2 −2
Original line number Diff line number Diff line
@@ -481,7 +481,7 @@ xfs_ioctl_setattr_xflags(

	if (rtflag != XFS_IS_REALTIME_INODE(ip)) {
		/* Can't change realtime flag if any extents are allocated. */
		if (ip->i_df.if_nextents || ip->i_delayed_blks)
		if (xfs_inode_has_filedata(ip))
			return -EINVAL;

		/*
@@ -602,7 +602,7 @@ xfs_ioctl_setattr_check_extsize(
	if (!fa->fsx_valid)
		return 0;

	if (S_ISREG(VFS_I(ip)->i_mode) && ip->i_df.if_nextents &&
	if (S_ISREG(VFS_I(ip)->i_mode) && xfs_inode_has_filedata(ip) &&
	    XFS_FSB_TO_B(mp, ip->i_extsize) != fa->fsx_extsize)
		return -EINVAL;

Loading