Commit 75b9c727 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull xfs fixes from Darrick Wong:
 "This week's pile mitigates some decades-old problems in how extent
  size hints interact with realtime volumes, fixes some failures in
  online shrink, and fixes a problem where directory and symlink
  shrinking on extremely fragmented filesystems could fail.

  The most user-notable change here is to point users at our (new) IRC
  channel on OFTC. Freedom isn't free, it costs folks like you and me;
  and if you don't kowtow, they'll expel everyone and take over your
  channel. (Ok, ok, that didn't fit the song lyrics...)

  Summary:

   - Fix a bug where unmapping operations end earlier than expected,
     which can cause chaos on multi-block directory and symlink shrink
     operations.

   - Fix an erroneous assert that can trigger if we try to transition a
     bmap structure from btree format to extents format with zero
     extents. This was exposed by xfs/538"

* tag 'xfs-5.13-fixes-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: bunmapi has unnecessary AG lock ordering issues
  xfs: btree format inode forks can have zero extents
  xfs: add new IRC channel to MAINTAINERS
  xfs: validate extsz hints against rt extent size when rtinherit is set
  xfs: standardize extent size hint validation
  xfs: check free AG space when making per-AG reservations
parents df8c66c4 0fe0bbe0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -20014,6 +20014,7 @@ F: arch/x86/xen/*swiotlb*
F:	drivers/xen/*swiotlb*
XFS FILESYSTEM
C:	irc://irc.oftc.net/xfs
M:	Darrick J. Wong <djwong@kernel.org>
M:	linux-xfs@vger.kernel.org
L:	linux-xfs@vger.kernel.org
+15 −3
Original line number Diff line number Diff line
@@ -325,10 +325,22 @@ xfs_ag_resv_init(
		error2 = xfs_alloc_pagf_init(mp, tp, pag->pag_agno, 0);
		if (error2)
			return error2;
		ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved +
		       xfs_perag_resv(pag, XFS_AG_RESV_RMAPBT)->ar_reserved <=
		       pag->pagf_freeblks + pag->pagf_flcount);

		/*
		 * If there isn't enough space in the AG to satisfy the
		 * reservation, let the caller know that there wasn't enough
		 * space.  Callers are responsible for deciding what to do
		 * next, since (in theory) we can stumble along with
		 * insufficient reservation if data blocks are being freed to
		 * replenish the AG's free space.
		 */
		if (!error &&
		    xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved +
		    xfs_perag_resv(pag, XFS_AG_RESV_RMAPBT)->ar_reserved >
		    pag->pagf_freeblks + pag->pagf_flcount)
			error = -ENOSPC;
	}

	return error;
}

+0 −12
Original line number Diff line number Diff line
@@ -605,7 +605,6 @@ xfs_bmap_btree_to_extents(

	ASSERT(cur);
	ASSERT(whichfork != XFS_COW_FORK);
	ASSERT(!xfs_need_iread_extents(ifp));
	ASSERT(ifp->if_format == XFS_DINODE_FMT_BTREE);
	ASSERT(be16_to_cpu(rblock->bb_level) == 1);
	ASSERT(be16_to_cpu(rblock->bb_numrecs) == 1);
@@ -5350,7 +5349,6 @@ __xfs_bunmapi(
	xfs_fsblock_t		sum;
	xfs_filblks_t		len = *rlen;	/* length to unmap in file */
	xfs_fileoff_t		max_len;
	xfs_agnumber_t		prev_agno = NULLAGNUMBER, agno;
	xfs_fileoff_t		end;
	struct xfs_iext_cursor	icur;
	bool			done = false;
@@ -5442,16 +5440,6 @@ __xfs_bunmapi(
		del = got;
		wasdel = isnullstartblock(del.br_startblock);

		/*
		 * Make sure we don't touch multiple AGF headers out of order
		 * in a single transaction, as that could cause AB-BA deadlocks.
		 */
		if (!wasdel && !isrt) {
			agno = XFS_FSB_TO_AGNO(mp, del.br_startblock);
			if (prev_agno != NULLAGNUMBER && prev_agno > agno)
				break;
			prev_agno = agno;
		}
		if (got.br_startoff < start) {
			del.br_startoff = start;
			del.br_blockcount -= start - got.br_startoff;
+42 −4
Original line number Diff line number Diff line
@@ -559,8 +559,17 @@ xfs_dinode_calc_crc(
/*
 * Validate di_extsize hint.
 *
 * The rules are documented at xfs_ioctl_setattr_check_extsize().
 * These functions must be kept in sync with each other.
 * 1. Extent size hint is only valid for directories and regular files.
 * 2. FS_XFLAG_EXTSIZE is only valid for regular files.
 * 3. FS_XFLAG_EXTSZINHERIT is only valid for directories.
 * 4. Hint cannot be larger than MAXTEXTLEN.
 * 5. Can be changed on directories at any time.
 * 6. Hint value of 0 turns off hints, clears inode flags.
 * 7. Extent size must be a multiple of the appropriate block size.
 *    For realtime files, this is the rt extent size.
 * 8. For non-realtime files, the extent size hint must be limited
 *    to half the AG size to avoid alignment extending the extent beyond the
 *    limits of the AG.
 */
xfs_failaddr_t
xfs_inode_validate_extsize(
@@ -580,6 +589,28 @@ xfs_inode_validate_extsize(
	inherit_flag = (flags & XFS_DIFLAG_EXTSZINHERIT);
	extsize_bytes = XFS_FSB_TO_B(mp, extsize);

	/*
	 * This comment describes a historic gap in this verifier function.
	 *
	 * On older kernels, the extent size hint verifier doesn't check that
	 * the extent size hint is an integer multiple of the realtime extent
	 * size on a directory with both RTINHERIT and EXTSZINHERIT flags set.
	 * The verifier has always enforced the alignment rule for regular
	 * files with the REALTIME flag set.
	 *
	 * If a directory with a misaligned extent size hint is allowed to
	 * propagate that hint into a new regular realtime file, the result
	 * is that the inode cluster buffer verifier will trigger a corruption
	 * shutdown the next time it is run.
	 *
	 * Unfortunately, there could be filesystems with these misconfigured
	 * directories in the wild, so we cannot add a check to this verifier
	 * at this time because that will result a new source of directory
	 * corruption errors when reading an existing filesystem.  Instead, we
	 * permit the misconfiguration to pass through the verifiers so that
	 * callers of this function can correct and mitigate externally.
	 */

	if (rt_flag)
		blocksize_bytes = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog;
	else
@@ -616,8 +647,15 @@ xfs_inode_validate_extsize(
/*
 * Validate di_cowextsize hint.
 *
 * The rules are documented at xfs_ioctl_setattr_check_cowextsize().
 * These functions must be kept in sync with each other.
 * 1. CoW extent size hint can only be set if reflink is enabled on the fs.
 *    The inode does not have to have any shared blocks, but it must be a v3.
 * 2. FS_XFLAG_COWEXTSIZE is only valid for directories and regular files;
 *    for a directory, the hint is propagated to new files.
 * 3. Can be changed on files & directories at any time.
 * 4. Hint value of 0 turns off hints, clears inode flags.
 * 5. Extent size must be a multiple of the appropriate block size.
 * 6. The extent size hint must be limited to half the AG size to avoid
 *    alignment extending the extent beyond the limits of the AG.
 */
xfs_failaddr_t
xfs_inode_validate_cowextsize(
+17 −0
Original line number Diff line number Diff line
@@ -142,6 +142,23 @@ xfs_trans_log_inode(
		flags |= XFS_ILOG_CORE;
	}

	/*
	 * Inode verifiers on older kernels don't check that the extent size
	 * hint is an integer multiple of the rt extent size on a directory
	 * with both rtinherit and extszinherit flags set.  If we're logging a
	 * directory that is misconfigured in this way, clear the hint.
	 */
	if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
	    (ip->i_diflags & XFS_DIFLAG_EXTSZINHERIT) &&
	    (ip->i_extsize % ip->i_mount->m_sb.sb_rextsize) > 0) {
		xfs_info_once(ip->i_mount,
	"Correcting misaligned extent size hint in inode 0x%llx.", ip->i_ino);
		ip->i_diflags &= ~(XFS_DIFLAG_EXTSIZE |
				   XFS_DIFLAG_EXTSZINHERIT);
		ip->i_extsize = 0;
		flags |= XFS_ILOG_CORE;
	}

	/*
	 * Record the specific change for fdatasync optimisation. This allows
	 * fdatasync to skip log forces for inodes that are only timestamp
Loading