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 Signed-off-by: Anuj Gupta --- 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