summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-09-01 10:47:30 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-12-15 17:28:59 -0800
commit93dda3ad1c4e1a0e5a0130ef176977266fdec1fc (patch)
tree166a3b0b18f558c07629493d77f43b90172846b5 /fs
parentea7ddde15643d6711c865c21950990aee849f60b (diff)
xfs: create a log incompat flag for atomic extent swapping
Create a log incompat flag so that we only attempt to process swap extent log items if the filesystem supports it. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/libxfs/xfs_format.h17
-rw-r--r--fs/xfs/libxfs/xfs_fs.h1
-rw-r--r--fs/xfs/libxfs/xfs_sb.c5
-rw-r--r--fs/xfs/xfs_log_recover.c1
-rw-r--r--fs/xfs/xfs_mount.c23
-rw-r--r--fs/xfs/xfs_mount.h33
6 files changed, 55 insertions, 25 deletions
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index ccf7c369fdc2..592a1505d2e8 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -388,6 +388,7 @@ xfs_sb_has_incompat_feature(
return (sbp->sb_features_incompat & feature) != 0;
}
+#define XFS_SB_FEAT_INCOMPAT_LOG_ATOMIC_SWAP (1 << 0)
#define XFS_SB_FEAT_INCOMPAT_LOG_ALL 0
#define XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_LOG_ALL
static inline bool
@@ -398,22 +399,6 @@ xfs_sb_has_incompat_log_feature(
return (sbp->sb_features_log_incompat & feature) != 0;
}
-static inline void
-xfs_sb_remove_incompat_log_features(
- struct xfs_sb *sbp)
-{
- sbp->sb_features_log_incompat &= ~XFS_SB_FEAT_INCOMPAT_LOG_ALL;
-}
-
-static inline void
-xfs_sb_add_incompat_log_features(
- struct xfs_sb *sbp,
- unsigned int features)
-{
- sbp->sb_features_log_incompat |= features;
-}
-
-
static inline bool
xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino)
{
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 98f53eb619cf..16ca677d4985 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -252,6 +252,7 @@ typedef struct xfs_fsop_resblks {
#define XFS_FSOP_GEOM_FLAGS_REFLINK (1 << 20) /* files can share blocks */
#define XFS_FSOP_GEOM_FLAGS_BIGTIME (1 << 21) /* 64-bit nsec timestamps */
#define XFS_FSOP_GEOM_FLAGS_INOBTCNT (1 << 22) /* inobt btree counter */
+#define XFS_FSOP_GEOM_FLAGS_ATOMIC_SWAP (1 << 23) /* atomic swapext */
/*
* Minimum and maximum sizes need for growth checks.
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index 901d219e16de..3c8afd2cd1b1 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -124,6 +124,9 @@ xfs_sb_version_to_features(
features |= XFS_FEAT_BIGTIME;
if (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR)
features |= XFS_FEAT_NEEDSREPAIR;
+
+ if (sbp->sb_features_log_incompat & XFS_SB_FEAT_INCOMPAT_LOG_ATOMIC_SWAP)
+ features |= XFS_FEAT_ATOMIC_SWAP;
return features;
}
@@ -1135,6 +1138,8 @@ xfs_fs_geometry(
} else {
geo->logsectsize = BBSIZE;
}
+ if (xfs_can_atomicswap(mp))
+ geo->flags |= XFS_FSOP_GEOM_FLAGS_ATOMIC_SWAP;
geo->rtsectsize = sbp->sb_blocksize;
geo->dirblocksize = xfs_dir2_dirblock_bytes(sbp);
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 53366cc0bc9e..1bc081f3e466 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3344,6 +3344,7 @@ xlog_do_recover(
xfs_buf_relse(bp);
/* re-initialise in-core superblock and geometry structures */
+ mp->m_features &= ~XFS_FEAT_INCOMPAT_LOG_ALL;
mp->m_features |= xfs_sb_version_to_features(sbp);
xfs_reinit_percpu_counters(mp);
error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi);
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 804adb6cf650..490bf1266661 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1278,13 +1278,15 @@ xfs_force_summary_recalc(
int
xfs_add_incompat_log_feature(
struct xfs_mount *mp,
- uint32_t feature)
+ uint64_t mount_feature,
+ uint32_t sb_feature)
{
struct xfs_dsb *dsb;
int error;
- ASSERT(hweight32(feature) == 1);
- ASSERT(!(feature & XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN));
+ ASSERT(hweight32(sb_feature) == 1);
+ ASSERT(!(sb_feature & XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN));
+ ASSERT(!(mount_feature & ~XFS_FEAT_INCOMPAT_LOG_ALL));
/*
* Force the log to disk and kick the background AIL thread to reduce
@@ -1309,7 +1311,7 @@ xfs_add_incompat_log_feature(
goto rele;
}
- if (xfs_sb_has_incompat_log_feature(&mp->m_sb, feature))
+ if (xfs_sb_has_incompat_log_feature(&mp->m_sb, sb_feature))
goto rele;
/*
@@ -1319,7 +1321,7 @@ xfs_add_incompat_log_feature(
*/
dsb = mp->m_sb_bp->b_addr;
xfs_sb_to_disk(dsb, &mp->m_sb);
- dsb->sb_features_log_incompat |= cpu_to_be32(feature);
+ dsb->sb_features_log_incompat |= cpu_to_be32(sb_feature);
error = xfs_bwrite(mp->m_sb_bp);
if (error)
goto shutdown;
@@ -1328,7 +1330,10 @@ xfs_add_incompat_log_feature(
* Add the feature bits to the incore superblock before we unlock the
* buffer.
*/
- xfs_sb_add_incompat_log_features(&mp->m_sb, feature);
+ spin_lock(&mp->m_sb_lock);
+ mp->m_features |= mount_feature;
+ mp->m_sb.sb_features_log_incompat |= sb_feature;
+ spin_unlock(&mp->m_sb_lock);
xfs_buf_relse(mp->m_sb_bp);
/* Log the superblock to disk. */
@@ -1369,14 +1374,18 @@ xfs_clear_incompat_log_features(
*/
xfs_buf_lock(mp->m_sb_bp);
xfs_buf_hold(mp->m_sb_bp);
+ spin_lock(&mp->m_sb_lock);
if (xfs_sb_has_incompat_log_feature(&mp->m_sb,
XFS_SB_FEAT_INCOMPAT_LOG_ALL)) {
xfs_info(mp, "Clearing log incompat feature flags.");
- xfs_sb_remove_incompat_log_features(&mp->m_sb);
+ mp->m_features &= ~XFS_FEAT_INCOMPAT_LOG_ALL;
+ mp->m_sb.sb_features_log_incompat &=
+ ~XFS_SB_FEAT_INCOMPAT_LOG_ALL;
ret = true;
}
+ spin_unlock(&mp->m_sb_lock);
xfs_buf_relse(mp->m_sb_bp);
return ret;
}
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index b9a93d782175..504b504ebfe1 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -299,6 +299,7 @@ typedef struct xfs_mount {
#define XFS_FEAT_INOBTCNT (1ULL << 23) /* inobt block counts */
#define XFS_FEAT_BIGTIME (1ULL << 24) /* large timestamps */
#define XFS_FEAT_NEEDSREPAIR (1ULL << 25) /* needs xfs_repair */
+#define XFS_FEAT_ATOMIC_SWAP (1ULL << 26) /* extent swap log items */
/* Mount features */
#define XFS_FEAT_NOATTR2 (1ULL << 48) /* disable attr2 creation */
@@ -334,6 +335,24 @@ static inline void xfs_add_ ## name (struct xfs_mount *mp) \
xfs_sb_version_add ## name(&mp->m_sb); \
}
+/*
+ * Log incompat features are added one at a time, but they are all cleared when
+ * the log is cleaned.
+ */
+#define XFS_FEAT_INCOMPAT_LOG_ALL (XFS_FEAT_ATOMIC_SWAP)
+
+int xfs_add_incompat_log_feature(struct xfs_mount *mp, uint64_t mount_feature,
+ uint32_t sb_feature);
+bool xfs_clear_incompat_log_features(struct xfs_mount *mp);
+
+#define __XFS_LOG_FEAT(name, NAME) \
+ __XFS_HAS_FEAT(name, NAME); \
+static inline int xfs_add_ ## name (struct xfs_mount *mp) \
+{ \
+ return xfs_add_incompat_log_feature((mp), XFS_FEAT_ ## NAME, \
+ XFS_SB_FEAT_INCOMPAT_LOG_ ## NAME); \
+}
+
/* Superblock features */
__XFS_ADD_FEAT(attr, ATTR)
__XFS_HAS_FEAT(nlink, NLINK)
@@ -361,6 +380,18 @@ __XFS_HAS_FEAT(realtime, REALTIME)
__XFS_HAS_FEAT(inobtcounts, INOBTCNT)
__XFS_HAS_FEAT(bigtime, BIGTIME)
__XFS_HAS_FEAT(needsrepair, NEEDSREPAIR)
+__XFS_LOG_FEAT(atomicswap, ATOMIC_SWAP)
+
+/*
+ * Decide if this filesystem can use log-assisted ("atomic") extent swapping.
+ * The atomic swap log intent items depend on the block mapping log intent
+ * items introduced with reflink and rmap. Realtime is not supported yet.
+ */
+static inline bool xfs_can_atomicswap(struct xfs_mount *mp)
+{
+ return (xfs_has_reflink(mp) || xfs_has_rmapbt(mp)) &&
+ !xfs_has_realtime(mp);
+}
/*
* Mount features
@@ -521,8 +552,6 @@ int xfs_zero_extent(struct xfs_inode *ip, xfs_fsblock_t start_fsb,
struct xfs_error_cfg * xfs_error_get_cfg(struct xfs_mount *mp,
int error_class, int error);
void xfs_force_summary_recalc(struct xfs_mount *mp);
-int xfs_add_incompat_log_feature(struct xfs_mount *mp, uint32_t feature);
-bool xfs_clear_incompat_log_features(struct xfs_mount *mp);
void xfs_mod_delalloc(struct xfs_mount *mp, int64_t delta);
#endif /* __XFS_MOUNT_H__ */