]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
xfs: apply rt extent alignment constraints to CoW extsize hint
authorDarrick J. Wong <djwong@kernel.org>
Thu, 21 Nov 2024 00:21:03 +0000 (16:21 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 23 Dec 2024 21:06:14 +0000 (13:06 -0800)
The copy-on-write extent size hint is subject to the same alignment
constraints as the regular extent size hint.  Since we're in the process
of adding reflink (and therefore CoW) to the realtime device, we must
apply the same scattered rextsize alignment validation strategies to
both hints to deal with the possibility of rextsize changing.

Therefore, fix the inode validator to perform rextsize alignment checks
on regular realtime files, and to remove misaligned directory hints.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_inode_buf.c
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_ioctl.c

index 4273d096fb0a9c3b5369c4156f19adfd80e6268b..f24fa628fecf1e1b01cb21c91170b40d85437290 100644 (file)
@@ -910,11 +910,29 @@ xfs_inode_validate_cowextsize(
        bool                            rt_flag;
        bool                            hint_flag;
        uint32_t                        cowextsize_bytes;
+       uint32_t                        blocksize_bytes;
 
        rt_flag = (flags & XFS_DIFLAG_REALTIME);
        hint_flag = (flags2 & XFS_DIFLAG2_COWEXTSIZE);
        cowextsize_bytes = XFS_FSB_TO_B(mp, cowextsize);
 
+       /*
+        * Similar to extent size hints, a directory can be configured to
+        * propagate realtime status and a CoW extent size hint to newly
+        * created files even if there is no realtime device, and the hints on
+        * disk can become misaligned if the sysadmin changes the rt extent
+        * size while adding the realtime device.
+        *
+        * Therefore, we can only enforce the rextsize alignment check against
+        * regular realtime files, and rely on callers to decide when alignment
+        * checks are appropriate, and fix things up as needed.
+        */
+
+       if (rt_flag)
+               blocksize_bytes = XFS_FSB_TO_B(mp, mp->m_sb.sb_rextsize);
+       else
+               blocksize_bytes = mp->m_sb.sb_blocksize;
+
        if (hint_flag && !xfs_has_reflink(mp))
                return __this_address;
 
@@ -928,16 +946,13 @@ xfs_inode_validate_cowextsize(
        if (mode && !hint_flag && cowextsize != 0)
                return __this_address;
 
-       if (hint_flag && rt_flag)
-               return __this_address;
-
-       if (cowextsize_bytes % mp->m_sb.sb_blocksize)
+       if (cowextsize_bytes % blocksize_bytes)
                return __this_address;
 
        if (cowextsize > XFS_MAX_BMBT_EXTLEN)
                return __this_address;
 
-       if (cowextsize > mp->m_sb.sb_agblocks / 2)
+       if (!rt_flag && cowextsize > mp->m_sb.sb_agblocks / 2)
                return __this_address;
 
        return NULL;
index a174f64b8bb250372018a9b31c30985ab8f5907d..70283c6419fd30e63d81468c8a6c8b3ee410f1de 100644 (file)
@@ -157,6 +157,20 @@ xfs_inode_item_precommit(
        if (flags & XFS_ILOG_IVERSION)
                flags = ((flags & ~XFS_ILOG_IVERSION) | XFS_ILOG_CORE);
 
+       /*
+        * Inode verifiers do not check that the CoW extent size hint is an
+        * integer multiple of the rt extent size on a directory with both
+        * rtinherit and cowextsize 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_diflags2 & XFS_DIFLAG2_COWEXTSIZE) &&
+           xfs_extlen_to_rtxmod(ip->i_mount, ip->i_cowextsize) > 0) {
+               ip->i_diflags2 &= ~XFS_DIFLAG2_COWEXTSIZE;
+               ip->i_cowextsize = 0;
+               flags |= XFS_ILOG_CORE;
+       }
+
        if (!iip->ili_item.li_buf) {
                struct xfs_buf  *bp;
                int             error;
index 4caf29cc59b9efbe908a172111d6468af507b611..726282e74d546d3627ec83d32c588b84aad4ce3c 100644 (file)
@@ -469,8 +469,21 @@ xfs_fill_fsxattr(
                }
        }
 
-       if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE)
-               fa->fsx_cowextsize = XFS_FSB_TO_B(mp, ip->i_cowextsize);
+       if (ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE) {
+               /*
+                * Don't let a misaligned CoW extent size hint on a directory
+                * escape to userspace if it won't pass the setattr checks
+                * later.
+                */
+               if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
+                   ip->i_cowextsize % mp->m_sb.sb_rextsize > 0) {
+                       fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE;
+                       fa->fsx_cowextsize = 0;
+               } else {
+                       fa->fsx_cowextsize = XFS_FSB_TO_B(mp, ip->i_cowextsize);
+               }
+       }
+
        fa->fsx_projid = ip->i_projid;
        if (ifp && !xfs_need_iread_extents(ifp))
                fa->fsx_nextents = xfs_iext_count(ifp);