Implement support for userspace controlled write-streams. Add a new i_write_stream field in xfs inode (note: existing hole is used), and use that to implement write stream management file operations. Signed-off-by: Kanchan Joshi --- fs/xfs/xfs_file.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_icache.c | 1 + fs/xfs/xfs_inode.h | 3 +++ fs/xfs/xfs_iomap.c | 1 + 4 files changed, 59 insertions(+) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 43d088a3bceb..f3b137407a60 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -2021,6 +2021,57 @@ xfs_file_mmap_prepare( return 0; } +static struct block_device * +xfs_file_get_bdev( + struct inode *inode) +{ + struct xfs_inode *ip = XFS_I(inode); + struct xfs_mount *mp = ip->i_mount; + + if (XFS_IS_REALTIME_INODE(ip)) + return mp->m_rtdev_targp->bt_bdev; + + return mp->m_ddev_targp->bt_bdev; +} + +static int +xfs_file_get_max_write_streams( + struct file *file) +{ + struct block_device *bdev = xfs_file_get_bdev(file_inode(file)); + + if (bdev) + return bdev_max_write_streams(bdev); + + return 0; +} + +static int +xfs_file_get_write_stream( + struct file *file) +{ + struct xfs_inode *ip = XFS_I(file_inode(file)); + + return READ_ONCE(ip->i_write_stream); +} + +static int +xfs_file_set_write_stream( + struct file *file, + unsigned long stream) +{ + struct xfs_inode *ip = XFS_I(file_inode(file)); + int max_streams = xfs_file_get_max_write_streams(file); + + if (stream > max_streams) + return -EINVAL; + xfs_ilock(ip, XFS_ILOCK_EXCL); + WRITE_ONCE(ip->i_write_stream, stream); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + return 0; +} + const struct file_operations xfs_file_operations = { .llseek = xfs_file_llseek, .read_iter = xfs_file_read_iter, @@ -2040,6 +2091,9 @@ const struct file_operations xfs_file_operations = { .fallocate = xfs_file_fallocate, .fadvise = xfs_file_fadvise, .remap_file_range = xfs_file_remap_range, + .get_max_write_streams = xfs_file_get_max_write_streams, + .get_write_stream = xfs_file_get_write_stream, + .set_write_stream = xfs_file_set_write_stream, .fop_flags = FOP_MMAP_SYNC | FOP_BUFFER_RASYNC | FOP_BUFFER_WASYNC | FOP_DIO_PARALLEL_WRITE | FOP_DONTCACHE, diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index dbaab4ae709f..fc9c6794b7db 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -130,6 +130,7 @@ xfs_inode_alloc( spin_lock_init(&ip->i_ioend_lock); ip->i_next_unlinked = NULLAGINO; ip->i_prev_unlinked = 0; + ip->i_write_stream = 0; return ip; } diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index bd6d33557194..be3580fec318 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -38,6 +38,9 @@ typedef struct xfs_inode { struct xfs_ifork i_df; /* data fork */ struct xfs_ifork i_af; /* attribute fork */ + /* Write stream information */ + uint8_t i_write_stream; /* for placement, 0 = none */ + /* Transaction and locking information. */ struct xfs_inode_log_item *i_itemp; /* logging information */ struct rw_semaphore i_lock; /* inode lock */ diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index be86d43044df..7988c9e16635 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -148,6 +148,7 @@ xfs_bmbt_to_iomap( else iomap->bdev = target->bt_bdev; iomap->flags = iomap_flags; + iomap->write_stream = ip->i_write_stream; /* * If the inode is dirty for datasync purposes, let iomap know so it -- 2.25.1