[PATCH v4 6/6] xfs: introduce software write streams

Kanchan Joshi <[email protected]>
Newsgroups org.kernel.vger.linux-xfs,org.kernel.vger.linux-block,org.kernel.vger.linux-fsdevel
Message-ID <[email protected]>
Even when the underlying block device does not advertise write streams,
XFS can choose do so, as that enables logical spatial isolation and
dynamic AG-set based concurrency for the standard storage, excluding
rtvolume.

Use AG count based heuristic to derive AG set size and software streams.
Larger filesystem (i.e., more AGs) get wider fanout (i.e., larger AG-set).

XFS_SW_WRITE_STREAMS_MAX bounds the software fallback. The mount-time
write stream bitmap allocation now also falls back to it when the data device
reports no hardware streams.

Signed-off-by: Kanchan Joshi <[email protected]>
Signed-off-by: Anuj Gupta <[email protected]>
---
 fs/xfs/xfs_inode.c | 22 +++++++++++++++++++++-
 fs/xfs/xfs_mount.h |  2 ++
 fs/xfs/xfs_super.c | 12 ++++++------
 3 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index aafc3ffa6e0a..638bee3e4ac2 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -53,6 +53,9 @@ xfs_inode_max_write_streams(
 	struct xfs_inode	*ip)
 {
 	struct block_device	*bdev;
+	struct xfs_mount	*mp = ip->i_mount;
+	int nr_streams;
+	xfs_agnumber_t nr_ags, ag_set_size;
 	bool			is_filestream, is_realtime;
 
 	xfs_ilock(ip, XFS_ILOCK_SHARED);
@@ -64,7 +67,24 @@ xfs_inode_max_write_streams(
 	if (!bdev || is_filestream || is_realtime)
 		return 0;
 
-	return bdev_max_write_streams(bdev);
+	nr_streams = bdev_max_write_streams(bdev);
+	if (nr_streams > 0)
+		return nr_streams;
+	/*
+	 * Enable software-only streams if hardware streams are not available.
+	 * This helps to
+	 * - improve isolation; reduce allocation interleaving.
+	 * - improve concurrency using AG-set based steering within and across streams.
+	 */
+	nr_ags = mp->m_sb.sb_agcount;
+	if (nr_ags >= 16)
+		ag_set_size = 4;
+	else if (nr_ags >= 8)
+		ag_set_size = 2;
+	else
+		ag_set_size = 1;
+	nr_streams = nr_ags / ag_set_size;
+	return min_t(uint16_t, nr_streams, XFS_SW_WRITE_STREAMS_MAX);
 }
 
 uint16_t
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 1376963fb7e8..ad51115594d3 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -45,6 +45,8 @@ enum {
 
 #define XFS_ERR_RETRY_FOREVER	-1
 
+#define XFS_SW_WRITE_STREAMS_MAX	16
+
 /*
  * Although retry_timeout is in jiffies which is normally an unsigned long,
  * we limit the retry timeout to 86400 seconds, or one day.  So even a
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 0e2bf6f7b378..d698be504c45 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1711,12 +1711,12 @@ xfs_fs_fill_super(
 		return error;
 
 	nr_streams = bdev_max_write_streams(mp->m_ddev_targp->bt_bdev);
-	if (nr_streams) {
-		mp->m_streams_in_use = bitmap_zalloc(nr_streams, GFP_KERNEL);
-		if (!mp->m_streams_in_use) {
-			error = -ENOMEM;
-			goto out_shutdown_devices;
-		}
+	if (!nr_streams)
+		nr_streams = XFS_SW_WRITE_STREAMS_MAX;
+	mp->m_streams_in_use = bitmap_zalloc(nr_streams, GFP_KERNEL);
+	if (!mp->m_streams_in_use) {
+		error = -ENOMEM;
+		goto out_shutdown_devices;
 	}
 
 	if (xfs_debugfs) {
-- 
2.25.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.