Commit 0efdc097 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull xfs fixes from Chandan Babu:

 - Do not call out v1 inodes with non-zero di_nlink field as being
   corrupt

 - Change xfs_finobt_count_blocks() to count "free inode btree" blocks
   rather than "inode btree" blocks

 - Don't report the number of trimmed bytes via FITRIM because the
   underlying storage isn't required to do anything and failed discard
   IOs aren't reported to the caller anyway

 - Fix incorrect setting of rm_owner field in an rmap query

 - Report missing disk offset range in an fsmap query

 - Obtain m_growlock when extending realtime section of the filesystem

 - Reset rootdir extent size hint after extending realtime section of
   the filesystem

* tag 'xfs-6.11-fixes-4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: reset rootdir extent size hint after growfsrt
  xfs: take m_growlock when running growfsrt
  xfs: Fix missing interval for missing_owner in xfs fsmap
  xfs: use XFS_BUF_DADDR_NULL for daddrs in getfsmap code
  xfs: Fix the owner setting issue for rmap query in xfs fsmap
  xfs: don't bother reporting blocks trimmed via FITRIM
  xfs: xfs_finobt_count_blocks() walks the wrong btree
  xfs: fix folio dirtying for XFILE_ALLOC callers
  xfs: fix di_onlink checking for V1/V2 inodes
parents 35667a29 a24cae8f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -749,7 +749,7 @@ xfs_finobt_count_blocks(
	if (error)
		return error;

	cur = xfs_inobt_init_cursor(pag, tp, agbp);
	cur = xfs_finobt_init_cursor(pag, tp, agbp);
	error = xfs_btree_count_blocks(cur, tree_blocks);
	xfs_btree_del_cursor(cur, error);
	xfs_trans_brelse(tp, agbp);
+10 −4
Original line number Diff line number Diff line
@@ -514,12 +514,18 @@ xfs_dinode_verify(
			return __this_address;
	}

	if (dip->di_version > 1) {
	/*
	 * Historical note: xfsprogs in the 3.2 era set up its incore inodes to
	 * have di_nlink track the link count, even if the actual filesystem
	 * only supported V1 inodes (i.e. di_onlink).  When writing out the
	 * ondisk inode, it would set both the ondisk di_nlink and di_onlink to
	 * the the incore di_nlink value, which is why we cannot check for
	 * di_nlink==0 on a V1 inode.  V2/3 inodes would get written out with
	 * di_onlink==0, so we can check that.
	 */
	if (dip->di_version >= 2) {
		if (dip->di_onlink)
			return __this_address;
	} else {
		if (dip->di_nlink)
			return __this_address;
	}

	/* don't allow invalid i_size */
+1 −1
Original line number Diff line number Diff line
@@ -293,7 +293,7 @@ xfile_get_folio(
	 * (potentially last) reference in xfile_put_folio.
	 */
	if (flags & XFILE_ALLOC)
		folio_set_dirty(folio);
		folio_mark_dirty(folio);
	return folio;
}

+11 −25
Original line number Diff line number Diff line
@@ -158,8 +158,7 @@ static int
xfs_trim_gather_extents(
	struct xfs_perag	*pag,
	struct xfs_trim_cur	*tcur,
	struct xfs_busy_extents	*extents,
	uint64_t		*blocks_trimmed)
	struct xfs_busy_extents	*extents)
{
	struct xfs_mount	*mp = pag->pag_mount;
	struct xfs_trans	*tp;
@@ -280,7 +279,6 @@ xfs_trim_gather_extents(

		xfs_extent_busy_insert_discard(pag, fbno, flen,
				&extents->extent_list);
		*blocks_trimmed += flen;
next_extent:
		if (tcur->by_bno)
			error = xfs_btree_increment(cur, 0, &i);
@@ -327,8 +325,7 @@ xfs_trim_perag_extents(
	struct xfs_perag	*pag,
	xfs_agblock_t		start,
	xfs_agblock_t		end,
	xfs_extlen_t		minlen,
	uint64_t		*blocks_trimmed)
	xfs_extlen_t		minlen)
{
	struct xfs_trim_cur	tcur = {
		.start		= start,
@@ -354,8 +351,7 @@ xfs_trim_perag_extents(
		extents->owner = extents;
		INIT_LIST_HEAD(&extents->extent_list);

		error = xfs_trim_gather_extents(pag, &tcur, extents,
				blocks_trimmed);
		error = xfs_trim_gather_extents(pag, &tcur, extents);
		if (error) {
			kfree(extents);
			break;
@@ -389,8 +385,7 @@ xfs_trim_datadev_extents(
	struct xfs_mount	*mp,
	xfs_daddr_t		start,
	xfs_daddr_t		end,
	xfs_extlen_t		minlen,
	uint64_t		*blocks_trimmed)
	xfs_extlen_t		minlen)
{
	xfs_agnumber_t		start_agno, end_agno;
	xfs_agblock_t		start_agbno, end_agbno;
@@ -411,8 +406,7 @@ xfs_trim_datadev_extents(

		if (start_agno == end_agno)
			agend = end_agbno;
		error = xfs_trim_perag_extents(pag, start_agbno, agend, minlen,
				blocks_trimmed);
		error = xfs_trim_perag_extents(pag, start_agbno, agend, minlen);
		if (error)
			last_error = error;

@@ -431,9 +425,6 @@ struct xfs_trim_rtdev {
	/* list of rt extents to free */
	struct list_head	extent_list;

	/* pointer to count of blocks trimmed */
	uint64_t		*blocks_trimmed;

	/* minimum length that caller allows us to trim */
	xfs_rtblock_t		minlen_fsb;

@@ -551,7 +542,6 @@ xfs_trim_gather_rtextent(
	busyp->length = rlen;
	INIT_LIST_HEAD(&busyp->list);
	list_add_tail(&busyp->list, &tr->extent_list);
	*tr->blocks_trimmed += rlen;

	tr->restart_rtx = rec->ar_startext + rec->ar_extcount;
	return 0;
@@ -562,13 +552,11 @@ xfs_trim_rtdev_extents(
	struct xfs_mount	*mp,
	xfs_daddr_t		start,
	xfs_daddr_t		end,
	xfs_daddr_t		minlen,
	uint64_t		*blocks_trimmed)
	xfs_daddr_t		minlen)
{
	struct xfs_rtalloc_rec	low = { };
	struct xfs_rtalloc_rec	high = { };
	struct xfs_trim_rtdev	tr = {
		.blocks_trimmed	= blocks_trimmed,
		.minlen_fsb	= XFS_BB_TO_FSB(mp, minlen),
	};
	struct xfs_trans	*tp;
@@ -634,7 +622,7 @@ xfs_trim_rtdev_extents(
	return error;
}
#else
# define xfs_trim_rtdev_extents(m,s,e,n,b)	(-EOPNOTSUPP)
# define xfs_trim_rtdev_extents(...)	(-EOPNOTSUPP)
#endif /* CONFIG_XFS_RT */

/*
@@ -661,7 +649,6 @@ xfs_ioc_trim(
	xfs_daddr_t		start, end;
	xfs_extlen_t		minlen;
	xfs_rfsblock_t		max_blocks;
	uint64_t		blocks_trimmed = 0;
	int			error, last_error = 0;

	if (!capable(CAP_SYS_ADMIN))
@@ -706,15 +693,13 @@ xfs_ioc_trim(
	end = start + BTOBBT(range.len) - 1;

	if (bdev_max_discard_sectors(mp->m_ddev_targp->bt_bdev)) {
		error = xfs_trim_datadev_extents(mp, start, end, minlen,
				&blocks_trimmed);
		error = xfs_trim_datadev_extents(mp, start, end, minlen);
		if (error)
			last_error = error;
	}

	if (rt_bdev && !xfs_trim_should_stop()) {
		error = xfs_trim_rtdev_extents(mp, start, end, minlen,
				&blocks_trimmed);
		error = xfs_trim_rtdev_extents(mp, start, end, minlen);
		if (error)
			last_error = error;
	}
@@ -722,7 +707,8 @@ xfs_ioc_trim(
	if (last_error)
		return last_error;

	range.len = XFS_FSB_TO_B(mp, blocks_trimmed);
	range.len = min_t(unsigned long long, range.len,
			  XFS_FSB_TO_B(mp, max_blocks));
	if (copy_to_user(urange, &range, sizeof(range)))
		return -EFAULT;
	return 0;
+26 −4
Original line number Diff line number Diff line
@@ -71,7 +71,7 @@ xfs_fsmap_owner_to_rmap(
	switch (src->fmr_owner) {
	case 0:			/* "lowest owner id possible" */
	case -1ULL:		/* "highest owner id possible" */
		dest->rm_owner = 0;
		dest->rm_owner = src->fmr_owner;
		break;
	case XFS_FMR_OWN_FREE:
		dest->rm_owner = XFS_RMAP_OWN_NULL;
@@ -162,6 +162,7 @@ struct xfs_getfsmap_info {
	xfs_daddr_t		next_daddr;	/* next daddr we expect */
	/* daddr of low fsmap key when we're using the rtbitmap */
	xfs_daddr_t		low_daddr;
	xfs_daddr_t		end_daddr;	/* daddr of high fsmap key */
	u64			missing_owner;	/* owner of holes */
	u32			dev;		/* device id */
	/*
@@ -182,6 +183,7 @@ struct xfs_getfsmap_dev {
	int			(*fn)(struct xfs_trans *tp,
				      const struct xfs_fsmap *keys,
				      struct xfs_getfsmap_info *info);
	sector_t		nr_sectors;
};

/* Compare two getfsmap device handlers. */
@@ -252,7 +254,7 @@ xfs_getfsmap_rec_before_start(
	const struct xfs_rmap_irec	*rec,
	xfs_daddr_t			rec_daddr)
{
	if (info->low_daddr != -1ULL)
	if (info->low_daddr != XFS_BUF_DADDR_NULL)
		return rec_daddr < info->low_daddr;
	if (info->low.rm_blockcount)
		return xfs_rmap_compare(rec, &info->low) < 0;
@@ -294,6 +296,18 @@ xfs_getfsmap_helper(
		return 0;
	}

	/*
	 * For an info->last query, we're looking for a gap between the last
	 * mapping emitted and the high key specified by userspace.  If the
	 * user's query spans less than 1 fsblock, then info->high and
	 * info->low will have the same rm_startblock, which causes rec_daddr
	 * and next_daddr to be the same.  Therefore, use the end_daddr that
	 * we calculated from userspace's high key to synthesize the record.
	 * Note that if the btree query found a mapping, there won't be a gap.
	 */
	if (info->last && info->end_daddr != XFS_BUF_DADDR_NULL)
		rec_daddr = info->end_daddr;

	/* Are we just counting mappings? */
	if (info->head->fmh_count == 0) {
		if (info->head->fmh_entries == UINT_MAX)
@@ -904,17 +918,21 @@ xfs_getfsmap(

	/* Set up our device handlers. */
	memset(handlers, 0, sizeof(handlers));
	handlers[0].nr_sectors = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
	handlers[0].dev = new_encode_dev(mp->m_ddev_targp->bt_dev);
	if (use_rmap)
		handlers[0].fn = xfs_getfsmap_datadev_rmapbt;
	else
		handlers[0].fn = xfs_getfsmap_datadev_bnobt;
	if (mp->m_logdev_targp != mp->m_ddev_targp) {
		handlers[1].nr_sectors = XFS_FSB_TO_BB(mp,
						       mp->m_sb.sb_logblocks);
		handlers[1].dev = new_encode_dev(mp->m_logdev_targp->bt_dev);
		handlers[1].fn = xfs_getfsmap_logdev;
	}
#ifdef CONFIG_XFS_RT
	if (mp->m_rtdev_targp) {
		handlers[2].nr_sectors = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
		handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev);
		handlers[2].fn = xfs_getfsmap_rtdev_rtbitmap;
	}
@@ -946,6 +964,7 @@ xfs_getfsmap(

	info.next_daddr = head->fmh_keys[0].fmr_physical +
			  head->fmh_keys[0].fmr_length;
	info.end_daddr = XFS_BUF_DADDR_NULL;
	info.fsmap_recs = fsmap_recs;
	info.head = head;

@@ -966,8 +985,11 @@ xfs_getfsmap(
		 * low key, zero out the low key so that we get
		 * everything from the beginning.
		 */
		if (handlers[i].dev == head->fmh_keys[1].fmr_device)
		if (handlers[i].dev == head->fmh_keys[1].fmr_device) {
			dkeys[1] = head->fmh_keys[1];
			info.end_daddr = min(handlers[i].nr_sectors - 1,
					     dkeys[1].fmr_physical);
		}
		if (handlers[i].dev > head->fmh_keys[0].fmr_device)
			memset(&dkeys[0], 0, sizeof(struct xfs_fsmap));

@@ -983,7 +1005,7 @@ xfs_getfsmap(
		info.dev = handlers[i].dev;
		info.last = false;
		info.pag = NULL;
		info.low_daddr = -1ULL;
		info.low_daddr = XFS_BUF_DADDR_NULL;
		info.low.rm_blockcount = 0;
		error = handlers[i].fn(tp, dkeys, &info);
		if (error)
Loading