Commit 5d894321 authored by John Garry's avatar John Garry Committed by Darrick J. Wong
Browse files

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: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Acked-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarJohn Garry <john.g.garry@oracle.com>
parent bfecc409
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -1336,7 +1336,8 @@ void bdev_statx(struct path *path, struct kstat *stat,

		generic_fill_statx_atomic_writes(stat,
			queue_atomic_write_unit_min_bytes(bd_queue),
			queue_atomic_write_unit_max_bytes(bd_queue));
			queue_atomic_write_unit_max_bytes(bd_queue),
			0);
	}

	stat->blksize = bdev_io_min(bdev);
+1 −1
Original line number Diff line number Diff line
@@ -5692,7 +5692,7 @@ int ext4_getattr(struct mnt_idmap *idmap, const struct path *path,
			awu_max = sbi->s_awu_max;
		}

		generic_fill_statx_atomic_writes(stat, awu_min, awu_max);
		generic_fill_statx_atomic_writes(stat, awu_min, awu_max, 0);
	}

	flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
+5 −1
Original line number Diff line number Diff line
@@ -136,13 +136,15 @@ EXPORT_SYMBOL(generic_fill_statx_attr);
 * @stat:	Where to fill in the attribute flags
 * @unit_min:	Minimum supported atomic write length in bytes
 * @unit_max:	Maximum supported atomic write length in bytes
 * @unit_max_opt: Optimised maximum supported atomic write length in bytes
 *
 * Fill in the STATX{_ATTR}_WRITE_ATOMIC flags in the kstat structure from
 * atomic write unit_min and unit_max values.
 */
void generic_fill_statx_atomic_writes(struct kstat *stat,
				      unsigned int unit_min,
				      unsigned int unit_max)
				      unsigned int unit_max,
				      unsigned int unit_max_opt)
{
	/* Confirm that the request type is known */
	stat->result_mask |= STATX_WRITE_ATOMIC;
@@ -153,6 +155,7 @@ void generic_fill_statx_atomic_writes(struct kstat *stat,
	if (unit_min) {
		stat->atomic_write_unit_min = unit_min;
		stat->atomic_write_unit_max = unit_max;
		stat->atomic_write_unit_max_opt = unit_max_opt;
		/* Initially only allow 1x segment */
		stat->atomic_write_segments_max = 1;

@@ -732,6 +735,7 @@ cp_statx(const struct kstat *stat, struct statx __user *buffer)
	tmp.stx_atomic_write_unit_min = stat->atomic_write_unit_min;
	tmp.stx_atomic_write_unit_max = stat->atomic_write_unit_max;
	tmp.stx_atomic_write_segments_max = stat->atomic_write_segments_max;
	tmp.stx_atomic_write_unit_max_opt = stat->atomic_write_unit_max_opt;

	return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
+1 −1
Original line number Diff line number Diff line
@@ -610,7 +610,7 @@ xfs_report_atomic_write(

	if (xfs_inode_can_atomicwrite(ip))
		unit_min = unit_max = ip->i_mount->m_sb.sb_blocksize;
	generic_fill_statx_atomic_writes(stat, unit_min, unit_max);
	generic_fill_statx_atomic_writes(stat, unit_min, unit_max, 0);
}

STATIC int
+2 −1
Original line number Diff line number Diff line
@@ -3475,7 +3475,8 @@ void generic_fillattr(struct mnt_idmap *, u32, struct inode *, struct kstat *);
void generic_fill_statx_attr(struct inode *inode, struct kstat *stat);
void generic_fill_statx_atomic_writes(struct kstat *stat,
				      unsigned int unit_min,
				      unsigned int unit_max);
				      unsigned int unit_max,
				      unsigned int unit_max_opt);
extern int vfs_getattr_nosec(const struct path *, struct kstat *, u32, unsigned int);
extern int vfs_getattr(const struct path *, struct kstat *, u32, unsigned int);
void __inode_add_bytes(struct inode *inode, loff_t bytes);
Loading