Commit dfb07e99 authored by Dan Aloni's avatar Dan Aloni Committed by Anna Schumaker
Browse files

nfs: add 'noalignwrite' option for lock-less 'lost writes' prevention



There are some applications that write to predefined non-overlapping
file offsets from multiple clients and therefore don't need to rely on
file locking. However, if these applications want non-aligned offsets
and sizes they need to either use locks or risk data corruption, as the
NFS client defaults to extending writes to whole pages.

This commit adds a new mount option `noalignwrite`, which allows to turn
that off and avoid the need of locking, as long as these applications
don't overlap on offsets.

Signed-off-by: default avatarDan Aloni <dan.aloni@vastdata.com>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Reviewed-by: default avatarSagi Grimberg <sagi@grimberg.me>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAnna Schumaker <anna.schumaker@oracle.com>
parent 6d26c5e4
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ enum nfs_param {
	Opt_bsize,
	Opt_clientaddr,
	Opt_cto,
	Opt_alignwrite,
	Opt_fg,
	Opt_fscache,
	Opt_fscache_flag,
@@ -149,6 +150,7 @@ static const struct fs_parameter_spec nfs_fs_parameters[] = {
	fsparam_u32   ("bsize",		Opt_bsize),
	fsparam_string("clientaddr",	Opt_clientaddr),
	fsparam_flag_no("cto",		Opt_cto),
	fsparam_flag_no("alignwrite",	Opt_alignwrite),
	fsparam_flag  ("fg",		Opt_fg),
	fsparam_flag_no("fsc",		Opt_fscache_flag),
	fsparam_string("fsc",		Opt_fscache),
@@ -592,6 +594,12 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
		else
			ctx->flags |= NFS_MOUNT_TRUNK_DISCOVERY;
		break;
	case Opt_alignwrite:
		if (result.negated)
			ctx->flags |= NFS_MOUNT_NO_ALIGNWRITE;
		else
			ctx->flags &= ~NFS_MOUNT_NO_ALIGNWRITE;
		break;
	case Opt_ac:
		if (result.negated)
			ctx->flags |= NFS_MOUNT_NOAC;
+3 −0
Original line number Diff line number Diff line
@@ -551,6 +551,9 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
	else
		seq_puts(m, ",local_lock=posix");

	if (nfss->flags & NFS_MOUNT_NO_ALIGNWRITE)
		seq_puts(m, ",noalignwrite");

	if (nfss->flags & NFS_MOUNT_WRITE_EAGER) {
		if (nfss->flags & NFS_MOUNT_WRITE_WAIT)
			seq_puts(m, ",write=wait");
+3 −0
Original line number Diff line number Diff line
@@ -1295,7 +1295,10 @@ static int nfs_can_extend_write(struct file *file, struct folio *folio,
	struct file_lock_context *flctx = locks_inode_context(inode);
	struct file_lock *fl;
	int ret;
	unsigned int mntflags = NFS_SERVER(inode)->flags;

	if (mntflags & NFS_MOUNT_NO_ALIGNWRITE)
		return 0;
	if (file->f_flags & O_DSYNC)
		return 0;
	if (!nfs_folio_write_uptodate(folio, pagelen))
+1 −0
Original line number Diff line number Diff line
@@ -158,6 +158,7 @@ struct nfs_server {
#define NFS_MOUNT_WRITE_WAIT		0x02000000
#define NFS_MOUNT_TRUNK_DISCOVERY	0x04000000
#define NFS_MOUNT_SHUTDOWN			0x08000000
#define NFS_MOUNT_NO_ALIGNWRITE		0x10000000

	unsigned int		fattr_valid;	/* Valid attributes */
	unsigned int		caps;		/* server capabilities */