Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fs: add atomic write unit max opt to statx

XFS will be able to support large atomic writes (atomic write > 1x block)
in future. This will be achieved by using different operating methods,
depending on the size of the write.

Specifically a new method of operation based in FS atomic extent remapping
will be supported in addition to the current HW offload-based method.

The FS method will generally be appreciably slower performing than the
HW-offload method. However the FS method will be typically able to
contribute to achieving a larger atomic write unit max limit.

XFS will support a hybrid mode, where HW offload method will be used when
possible, i.e. HW offload is used when the length of the write is
supported, and for other times FS-based atomic writes will be used.

As such, there is an atomic write length at which the user may experience
appreciably slower performance.

Advertise this limit in a new statx field, stx_atomic_write_unit_max_opt.

When zero, it means that there is no such performance boundary.

Masks STATX{_ATTR}_WRITE_ATOMIC can be used to get this new field. This is
ok for older kernels which don't support this new field, as they would
report 0 in this field (from zeroing in cp_statx()) already. Furthermore
those older kernels don't support large atomic writes - apart from block
fops, but there would be consistent performance there for atomic writes
in range [unit min, unit max].

Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Acked-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: John Garry <john.g.garry@oracle.com>

authored by

John Garry and committed by
Darrick J. Wong
5d894321 bfecc409

+18 -7
+2 -1
block/bdev.c
··· 1336 1336 1337 1337 generic_fill_statx_atomic_writes(stat, 1338 1338 queue_atomic_write_unit_min_bytes(bd_queue), 1339 - queue_atomic_write_unit_max_bytes(bd_queue)); 1339 + queue_atomic_write_unit_max_bytes(bd_queue), 1340 + 0); 1340 1341 } 1341 1342 1342 1343 stat->blksize = bdev_io_min(bdev);
+1 -1
fs/ext4/inode.c
··· 5692 5692 awu_max = sbi->s_awu_max; 5693 5693 } 5694 5694 5695 - generic_fill_statx_atomic_writes(stat, awu_min, awu_max); 5695 + generic_fill_statx_atomic_writes(stat, awu_min, awu_max, 0); 5696 5696 } 5697 5697 5698 5698 flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
+5 -1
fs/stat.c
··· 136 136 * @stat: Where to fill in the attribute flags 137 137 * @unit_min: Minimum supported atomic write length in bytes 138 138 * @unit_max: Maximum supported atomic write length in bytes 139 + * @unit_max_opt: Optimised maximum supported atomic write length in bytes 139 140 * 140 141 * Fill in the STATX{_ATTR}_WRITE_ATOMIC flags in the kstat structure from 141 142 * atomic write unit_min and unit_max values. 142 143 */ 143 144 void generic_fill_statx_atomic_writes(struct kstat *stat, 144 145 unsigned int unit_min, 145 - unsigned int unit_max) 146 + unsigned int unit_max, 147 + unsigned int unit_max_opt) 146 148 { 147 149 /* Confirm that the request type is known */ 148 150 stat->result_mask |= STATX_WRITE_ATOMIC; ··· 155 153 if (unit_min) { 156 154 stat->atomic_write_unit_min = unit_min; 157 155 stat->atomic_write_unit_max = unit_max; 156 + stat->atomic_write_unit_max_opt = unit_max_opt; 158 157 /* Initially only allow 1x segment */ 159 158 stat->atomic_write_segments_max = 1; 160 159 ··· 735 732 tmp.stx_atomic_write_unit_min = stat->atomic_write_unit_min; 736 733 tmp.stx_atomic_write_unit_max = stat->atomic_write_unit_max; 737 734 tmp.stx_atomic_write_segments_max = stat->atomic_write_segments_max; 735 + tmp.stx_atomic_write_unit_max_opt = stat->atomic_write_unit_max_opt; 738 736 739 737 return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0; 740 738 }
+1 -1
fs/xfs/xfs_iops.c
··· 610 610 611 611 if (xfs_inode_can_atomicwrite(ip)) 612 612 unit_min = unit_max = ip->i_mount->m_sb.sb_blocksize; 613 - generic_fill_statx_atomic_writes(stat, unit_min, unit_max); 613 + generic_fill_statx_atomic_writes(stat, unit_min, unit_max, 0); 614 614 } 615 615 616 616 STATIC int
+2 -1
include/linux/fs.h
··· 3475 3475 void generic_fill_statx_attr(struct inode *inode, struct kstat *stat); 3476 3476 void generic_fill_statx_atomic_writes(struct kstat *stat, 3477 3477 unsigned int unit_min, 3478 - unsigned int unit_max); 3478 + unsigned int unit_max, 3479 + unsigned int unit_max_opt); 3479 3480 extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int); 3480 3481 extern int vfs_getattr(const struct path *, struct kstat *, u32, unsigned int); 3481 3482 void __inode_add_bytes(struct inode *inode, loff_t bytes);
+1
include/linux/stat.h
··· 57 57 u32 dio_read_offset_align; 58 58 u32 atomic_write_unit_min; 59 59 u32 atomic_write_unit_max; 60 + u32 atomic_write_unit_max_opt; 60 61 u32 atomic_write_segments_max; 61 62 }; 62 63
+6 -2
include/uapi/linux/stat.h
··· 182 182 /* File offset alignment for direct I/O reads */ 183 183 __u32 stx_dio_read_offset_align; 184 184 185 - /* 0xb8 */ 186 - __u64 __spare3[9]; /* Spare space for future expansion */ 185 + /* Optimised max atomic write unit in bytes */ 186 + __u32 stx_atomic_write_unit_max_opt; 187 + __u32 __spare2[1]; 188 + 189 + /* 0xc0 */ 190 + __u64 __spare3[8]; /* Spare space for future expansion */ 187 191 188 192 /* 0x100 */ 189 193 };