Commit 7aac7190 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client fixes from Trond Myklebust:
 "Stable patches:

   - Revert "SUNRPC: Don't allow waiting for exiting tasks" as it is
     breaking ltp tests

  Bugfixes:

   - Another set of fixes to the tracking of NFSv4 server capabilities
     when crossing filesystem boundaries

   - Localio fix to restore credentials and prevent triggering a
     BUG_ON()

   - Fix to prevent flapping of the localio on/off trigger

   - Protections against 'eof page pollution' as demonstrated in
     xfstests generic/363

   - Series of patches to ensure correct ordering of O_DIRECT i/o and
     truncate, fallocate and copy functions

   - Fix a NULL pointer check in flexfiles reads that regresses 6.17

   - Correct a typo that breaks flexfiles layout segment processing"

* tag 'nfs-for-6.17-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv4/flexfiles: Fix layout merge mirror check.
  SUNRPC: call xs_sock_process_cmsg for all cmsg
  Revert "SUNRPC: Don't allow waiting for exiting tasks"
  NFS: Fix the marking of the folio as up to date
  NFS: nfs_invalidate_folio() must observe the offset and size arguments
  NFSv4.2: Serialise O_DIRECT i/o and copy range
  NFSv4.2: Serialise O_DIRECT i/o and clone range
  NFSv4.2: Serialise O_DIRECT i/o and fallocate()
  NFS: Serialise O_DIRECT i/o and truncate()
  NFSv4.2: Protect copy offload and clone against 'eof page pollution'
  NFS: Protect against 'eof page pollution'
  flexfiles/pNFS: fix NULL checks on result of ff_layout_choose_ds_for_read
  nfs/localio: avoid bouncing LOCALIO if nfs_client_is_local()
  nfs/localio: restore creds before releasing pageio data
  NFSv4: Clear the NFS_CAP_XATTR flag if not supported by the server
  NFSv4: Clear NFS_CAP_OPEN_XOR and NFS_CAP_DELEGTIME if not supported
  NFSv4: Clear the NFS_CAP_FS_LOCATIONS flag if it is not set
  NFSv4: Don't clear capabilities that won't be reset
parents 1b5d4661 dd2fa824
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -888,6 +888,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,

	if (fsinfo->xattr_support)
		server->caps |= NFS_CAP_XATTR;
	else
		server->caps &= ~NFS_CAP_XATTR;
#endif
}

+37 −3
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/gfp.h>
#include <linux/rmap.h>
#include <linux/swap.h>
#include <linux/compaction.h>

@@ -280,6 +281,37 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
}
EXPORT_SYMBOL_GPL(nfs_file_fsync);

void nfs_truncate_last_folio(struct address_space *mapping, loff_t from,
			     loff_t to)
{
	struct folio *folio;

	if (from >= to)
		return;

	folio = filemap_lock_folio(mapping, from >> PAGE_SHIFT);
	if (IS_ERR(folio))
		return;

	if (folio_mkclean(folio))
		folio_mark_dirty(folio);

	if (folio_test_uptodate(folio)) {
		loff_t fpos = folio_pos(folio);
		size_t offset = from - fpos;
		size_t end = folio_size(folio);

		if (to - fpos < end)
			end = to - fpos;
		folio_zero_segment(folio, offset, end);
		trace_nfs_size_truncate_folio(mapping->host, to);
	}

	folio_unlock(folio);
	folio_put(folio);
}
EXPORT_SYMBOL_GPL(nfs_truncate_last_folio);

/*
 * Decide whether a read/modify/write cycle may be more efficient
 * then a modify/write/read cycle when writing to a page in the
@@ -356,6 +388,7 @@ static int nfs_write_begin(const struct kiocb *iocb,

	dfprintk(PAGECACHE, "NFS: write_begin(%pD2(%lu), %u@%lld)\n",
		file, mapping->host->i_ino, len, (long long) pos);
	nfs_truncate_last_folio(mapping, i_size_read(mapping->host), pos);

	fgp |= fgf_set_order(len);
start:
@@ -442,9 +475,10 @@ static void nfs_invalidate_folio(struct folio *folio, size_t offset,
	dfprintk(PAGECACHE, "NFS: invalidate_folio(%lu, %zu, %zu)\n",
		 folio->index, offset, length);

	if (offset != 0 || length < folio_size(folio))
		return;
	/* Cancel any unstarted writes on this page */
	if (offset != 0 || length < folio_size(folio))
		nfs_wb_folio(inode, folio);
	else
		nfs_wb_folio_cancel(inode, folio);
	folio_wait_private_2(folio); /* [DEPRECATED] */
	trace_nfs_invalidate_folio(inode, folio_pos(folio) + offset, length);
+13 −8
Original line number Diff line number Diff line
@@ -293,7 +293,7 @@ ff_lseg_match_mirrors(struct pnfs_layout_segment *l1,
		struct pnfs_layout_segment *l2)
{
	const struct nfs4_ff_layout_segment *fl1 = FF_LAYOUT_LSEG(l1);
	const struct nfs4_ff_layout_segment *fl2 = FF_LAYOUT_LSEG(l1);
	const struct nfs4_ff_layout_segment *fl2 = FF_LAYOUT_LSEG(l2);
	u32 i;

	if (fl1->mirror_array_cnt != fl2->mirror_array_cnt)
@@ -773,8 +773,11 @@ ff_layout_choose_ds_for_read(struct pnfs_layout_segment *lseg,
			continue;

		if (check_device &&
		    nfs4_test_deviceid_unavailable(&mirror->mirror_ds->id_node))
		    nfs4_test_deviceid_unavailable(&mirror->mirror_ds->id_node)) {
			// reinitialize the error state in case if this is the last iteration
			ds = ERR_PTR(-EINVAL);
			continue;
		}

		*best_idx = idx;
		break;
@@ -804,7 +807,7 @@ ff_layout_choose_best_ds_for_read(struct pnfs_layout_segment *lseg,
	struct nfs4_pnfs_ds *ds;

	ds = ff_layout_choose_valid_ds_for_read(lseg, start_idx, best_idx);
	if (ds)
	if (!IS_ERR(ds))
		return ds;
	return ff_layout_choose_any_ds_for_read(lseg, start_idx, best_idx);
}
@@ -818,7 +821,7 @@ ff_layout_get_ds_for_read(struct nfs_pageio_descriptor *pgio,

	ds = ff_layout_choose_best_ds_for_read(lseg, pgio->pg_mirror_idx,
					       best_idx);
	if (ds || !pgio->pg_mirror_idx)
	if (!IS_ERR(ds) || !pgio->pg_mirror_idx)
		return ds;
	return ff_layout_choose_best_ds_for_read(lseg, 0, best_idx);
}
@@ -868,7 +871,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
	req->wb_nio = 0;

	ds = ff_layout_get_ds_for_read(pgio, &ds_idx);
	if (!ds) {
	if (IS_ERR(ds)) {
		if (!ff_layout_no_fallback_to_mds(pgio->pg_lseg))
			goto out_mds;
		pnfs_generic_pg_cleanup(pgio);
@@ -1072,11 +1075,13 @@ static void ff_layout_resend_pnfs_read(struct nfs_pgio_header *hdr)
{
	u32 idx = hdr->pgio_mirror_idx + 1;
	u32 new_idx = 0;
	struct nfs4_pnfs_ds *ds;

	if (ff_layout_choose_any_ds_for_read(hdr->lseg, idx, &new_idx))
		ff_layout_send_layouterror(hdr->lseg);
	else
	ds = ff_layout_choose_any_ds_for_read(hdr->lseg, idx, &new_idx);
	if (IS_ERR(ds))
		pnfs_error_mark_layout_for_return(hdr->inode, hdr->lseg);
	else
		ff_layout_send_layouterror(hdr->lseg);
	pnfs_read_resend_pnfs(hdr, new_idx);
}

+10 −3
Original line number Diff line number Diff line
@@ -716,6 +716,7 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
{
	struct inode *inode = d_inode(dentry);
	struct nfs_fattr *fattr;
	loff_t oldsize = i_size_read(inode);
	int error = 0;

	nfs_inc_stats(inode, NFSIOS_VFSSETATTR);
@@ -731,7 +732,7 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
		if (error)
			return error;

		if (attr->ia_size == i_size_read(inode))
		if (attr->ia_size == oldsize)
			attr->ia_valid &= ~ATTR_SIZE;
	}

@@ -767,8 +768,10 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
	trace_nfs_setattr_enter(inode);

	/* Write all dirty data */
	if (S_ISREG(inode->i_mode))
	if (S_ISREG(inode->i_mode)) {
		nfs_file_block_o_direct(NFS_I(inode));
		nfs_sync_inode(inode);
	}

	fattr = nfs_alloc_fattr_with_label(NFS_SERVER(inode));
	if (fattr == NULL) {
@@ -777,8 +780,12 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
	}

	error = NFS_PROTO(inode)->setattr(dentry, fattr, attr);
	if (error == 0)
	if (error == 0) {
		if (attr->ia_valid & ATTR_SIZE)
			nfs_truncate_last_folio(inode->i_mapping, oldsize,
						attr->ia_size);
		error = nfs_refresh_inode(inode, fattr);
	}
	nfs_free_fattr(fattr);
out:
	trace_nfs_setattr_exit(inode, error);
+12 −0
Original line number Diff line number Diff line
@@ -437,6 +437,8 @@ int nfs_file_release(struct inode *, struct file *);
int nfs_lock(struct file *, int, struct file_lock *);
int nfs_flock(struct file *, int, struct file_lock *);
int nfs_check_flags(int);
void nfs_truncate_last_folio(struct address_space *mapping, loff_t from,
			     loff_t to);

/* inode.c */
extern struct workqueue_struct *nfsiod_workqueue;
@@ -530,6 +532,16 @@ static inline bool nfs_file_io_is_buffered(struct nfs_inode *nfsi)
	return test_bit(NFS_INO_ODIRECT, &nfsi->flags) == 0;
}

/* Must be called with exclusively locked inode->i_rwsem */
static inline void nfs_file_block_o_direct(struct nfs_inode *nfsi)
{
	if (test_bit(NFS_INO_ODIRECT, &nfsi->flags)) {
		clear_bit(NFS_INO_ODIRECT, &nfsi->flags);
		inode_dio_wait(&nfsi->vfs_inode);
	}
}


/* namespace.c */
#define NFS_PATH_CANONICAL 1
extern char *nfs_path(char **p, struct dentry *dentry,
Loading