Implement support for FS_IOC_WRITE_STREAM ioctl. For FS_WRITE_STREAM_OP_GET_MAX, available write streams are reported based on the capability of the underlying block device. For FS_WRITE_STREAM_OP_{SET/GET}, add a new i_write_stream field in xfs inode. This value is propagated to the iomap during block mapping. Signed-off-by: Kanchan Joshi --- fs/xfs/xfs_icache.c | 1 + fs/xfs/xfs_inode.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ fs/xfs/xfs_inode.h | 6 ++++++ fs/xfs/xfs_ioctl.c | 34 +++++++++++++++++++++++++++++++++ fs/xfs/xfs_iomap.c | 1 + 5 files changed, 88 insertions(+) diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index a7a09e7eec81..2ad8d02152f4 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.c b/fs/xfs/xfs_inode.c index 50c0404f9064..9b88b2d1cf9a 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -47,6 +47,52 @@ struct kmem_cache *xfs_inode_cache; +int +xfs_inode_max_write_streams( + struct xfs_inode *ip) +{ + struct xfs_mount *mp = ip->i_mount; + struct block_device *bdev; + + if (XFS_IS_REALTIME_INODE(ip)) + bdev = mp->m_rtdev_targp ? mp->m_rtdev_targp->bt_bdev : NULL; + else + bdev = mp->m_ddev_targp->bt_bdev; + + if (!bdev) + return 0; + + return bdev_max_write_streams(bdev); +} + +uint8_t +xfs_inode_get_write_stream( + struct xfs_inode *ip) +{ + uint8_t stream_id; + + xfs_ilock(ip, XFS_ILOCK_SHARED); + stream_id = ip->i_write_stream; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + return stream_id; +} + +int +xfs_inode_set_write_stream( + struct xfs_inode *ip, + uint8_t stream_id) +{ + if (stream_id > xfs_inode_max_write_streams(ip)) + return -EINVAL; + + xfs_ilock(ip, XFS_ILOCK_EXCL); + ip->i_write_stream = stream_id; + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + return 0; +} + /* * These two are wrapper routines around the xfs_ilock() routine used to * centralize some grungy code. They are used in places that wish to lock the diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index bd6d33557194..9f6cab729924 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; + /* Transaction and locking information. */ struct xfs_inode_log_item *i_itemp; /* logging information */ struct rw_semaphore i_lock; /* inode lock */ @@ -676,4 +679,7 @@ int xfs_icreate_dqalloc(const struct xfs_icreate_args *args, struct xfs_dquot **udqpp, struct xfs_dquot **gdqpp, struct xfs_dquot **pdqpp); +int xfs_inode_max_write_streams(struct xfs_inode *ip); +uint8_t xfs_inode_get_write_stream(struct xfs_inode *ip); +int xfs_inode_set_write_stream(struct xfs_inode *ip, uint8_t stream_id); #endif /* __XFS_INODE_H__ */ diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index facffdc8dca8..091d6a8b5f57 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -1160,6 +1160,38 @@ xfs_ioctl_fs_counts( return 0; } +static int +xfs_ioc_write_stream( + struct file *filp, + void __user *arg) +{ + struct inode *inode = file_inode(filp); + struct xfs_inode *ip = XFS_I(inode); + struct fs_write_stream ws = { }; + + if (copy_from_user(&ws, arg, sizeof(ws))) + return -EFAULT; + + switch (ws.op_flags) { + case FS_WRITE_STREAM_OP_GET_MAX: + ws.max_streams = xfs_inode_max_write_streams(ip); + goto copy_out; + case FS_WRITE_STREAM_OP_GET: + ws.stream_id = xfs_inode_get_write_stream(ip); + goto copy_out; + case FS_WRITE_STREAM_OP_SET: + return xfs_inode_set_write_stream(ip, ws.stream_id); + default: + return -EINVAL; + } + return 0; + +copy_out: + if (copy_to_user(arg, &ws, sizeof(ws))) + return -EFAULT; + return 0; +} + /* * These long-unused ioctls were removed from the official ioctl API in 5.17, * but retain these definitions so that we can log warnings about them. @@ -1425,6 +1457,8 @@ xfs_file_ioctl( return xfs_ioc_health_monitor(filp, arg); case XFS_IOC_VERIFY_MEDIA: return xfs_ioc_verify_media(filp, arg); + case FS_IOC_WRITE_STREAM: + return xfs_ioc_write_stream(filp, arg); default: return -ENOTTY; 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