diff mbox series

[02/14] xfs: allow newer INCOMPAT/RO_COMPAT feature bits to protect ATTRI log items

Message ID 170404840436.1756514.8950160514368962094.stgit@frogsfrogsfrogs (mailing list archive)
State Superseded
Headers show
Series [01/14] xfs: require XFS_SB_FEAT_INCOMPAT_LOG_XATTRS for attr log intent item recovery | expand

Commit Message

Darrick J. Wong Dec. 31, 2023, 8:45 p.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

Log recovery (which can include replaying ATTRI intent items) occurs on
rw and ro mounts.  Dirty logs containing these log items must be
protected from being replayed by older kernels.  The log incompat
feature XFS_SB_FEAT_INCOMPAT_LOG_XATTRS provides this protection.

However, adding this flag to the filesystem introduces performance
problems of its own -- each time we do, we must force the log and write
the primary superblock before writing any ATTRI log items.  This was ok
when the only users were developers using the debug knob, but this sucks
for regular users.  We'd like to avoid that.

If a filesystem has ro-compat or incompat feature bits set that weren't
defined at the time that ATTRI log items were defined, then any kernel
that doesn't know about ATTRI items will reject that filesystem.  This
provides the same protection as the log-incompat feature, but at a much
lower cost because most ro-compat and incompat features are set on a
permanent basis.

Avoid the performance hit by detecting these feature bits and skipping
the xfs_add_incompat_log_feature calls.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/libxfs/xfs_attr.c   |    6 +++++-
 fs/xfs/libxfs/xfs_attr.h   |   23 +++++++++++++++++++++++
 fs/xfs/libxfs/xfs_format.h |    6 +++++-
 fs/xfs/xfs_attr_item.c     |    3 ++-
 fs/xfs/xfs_xattr.c         |   10 +++++++++-
 5 files changed, 44 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index b002ddd5f05a2..2e5550ab1454f 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -885,9 +885,13 @@  xfs_attr_defer_add(
 	struct xfs_da_args	*args,
 	unsigned int		op_flags)
 {
-
 	struct xfs_attr_intent	*new;
 
+	/* ATTRI log items must be protected from older kernels */
+	if (args->op_flags & XFS_DA_OP_LOGGED)
+		ASSERT(xfs_attri_can_use_without_log_assistance(args->dp->i_mount) ||
+		       xfs_sb_version_haslogxattrs(&args->dp->i_mount->m_sb));
+
 	new = kmem_cache_zalloc(xfs_attr_intent_cache, GFP_NOFS | __GFP_NOFAIL);
 	new->xattri_op_flags = op_flags;
 	new->xattri_da_args = args;
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index e4f55008552b4..273e8dff76c07 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -620,4 +620,27 @@  void xfs_attr_intent_destroy_cache(void);
 
 int xfs_attr_sf_totsize(struct xfs_inode *dp);
 
+/*
+ * Decide if this filesystem has a new enough permanent feature set to protect
+ * attri log items from being replayed on a kernel that does not have
+ * XFS_SB_FEAT_INCOMPAT_LOG_XATTRS set.
+ */
+static inline bool
+xfs_attri_can_use_without_log_assistance(
+	struct xfs_mount	*mp)
+{
+	if (!xfs_sb_is_v5(&mp->m_sb))
+		return false;
+
+	if (xfs_sb_has_incompat_feature(&mp->m_sb,
+				~(XFS_SB_FEAT_INCOMPAT_FTYPE |
+				  XFS_SB_FEAT_INCOMPAT_SPINODES |
+				  XFS_SB_FEAT_INCOMPAT_META_UUID |
+				  XFS_SB_FEAT_INCOMPAT_BIGTIME |
+				  XFS_SB_FEAT_INCOMPAT_NREXT64)))
+		return true;
+
+	return false;
+}
+
 #endif	/* __XFS_ATTR_H__ */
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index ec25010b57797..8b952909ce1e2 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -390,7 +390,11 @@  xfs_sb_has_incompat_feature(
 	return (sbp->sb_features_incompat & feature) != 0;
 }
 
-#define XFS_SB_FEAT_INCOMPAT_LOG_XATTRS   (1 << 0)	/* Delayed Attributes */
+/*
+ * Log contains ATTRI log intent items which are not otherwise protected by
+ * an INCOMPAT/RO_COMPAT feature flag.
+ */
+#define XFS_SB_FEAT_INCOMPAT_LOG_XATTRS   (1 << 0)
 
 /*
  * Log contains SXI log intent items which are not otherwise protected by
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
index c023962141556..c95cef827179c 100644
--- a/fs/xfs/xfs_attr_item.c
+++ b/fs/xfs/xfs_attr_item.c
@@ -469,7 +469,8 @@  xfs_attri_validate(
 	unsigned int			op = attrp->alfi_op_flags &
 					     XFS_ATTRI_OP_FLAGS_TYPE_MASK;
 
-	if (!xfs_sb_version_haslogxattrs(&mp->m_sb))
+	if (!xfs_sb_version_haslogxattrs(&mp->m_sb) &&
+	    !xfs_attri_can_use_without_log_assistance(mp))
 		return false;
 
 	if (attrp->__pad != 0)
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 1920ca49b08d6..5246539ad2174 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -33,6 +33,13 @@  xfs_attr_grab_log_assist(
 {
 	int			error = 0;
 
+	/*
+	 * As a performance optimization, skip the log force and super write
+	 * if the filesystem featureset already protects the attri log items.
+	 */
+	if (xfs_attri_can_use_without_log_assistance(mp))
+		return 0;
+
 	/*
 	 * Protect ourselves from an idle log clearing the logged xattrs log
 	 * incompat feature bit.
@@ -76,7 +83,8 @@  static inline void
 xfs_attr_rele_log_assist(
 	struct xfs_mount	*mp)
 {
-	xlog_drop_incompat_feat(mp->m_log, XLOG_INCOMPAT_FEAT_XATTRS);
+	if (!xfs_attri_can_use_without_log_assistance(mp))
+		xlog_drop_incompat_feat(mp->m_log, XLOG_INCOMPAT_FEAT_XATTRS);
 }
 
 static inline bool