Commit ff7afaec authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'nfs-for-6.12-3' of git://git.linux-nfs.org/projects/anna/linux-nfs

Pull NFS client fixes from Anna Schumaker:
 "These are mostly fixes that came up during the nfs bakeathon the other
  week.

  Stable Fixes:
   - Fix KMSAN warning in decode_getfattr_attrs()

  Other Bugfixes:
   - Handle -ENOTCONN in xs_tcp_setup_socked()
   - NFSv3: only use NFS timeout for MOUNT when protocols are compatible
   - Fix attribute delegation behavior on exclusive create and a/mtime
     changes
   - Fix localio to cope with racing nfs_local_probe()
   - Avoid i_lock contention in fs_clear_invalid_mapping()"

* tag 'nfs-for-6.12-3' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  nfs: avoid i_lock contention in nfs_clear_invalid_mapping
  nfs_common: fix localio to cope with racing nfs_local_probe()
  NFS: Further fixes to attribute delegation a/mtime changes
  NFS: Fix attribute delegation behaviour on exclusive create
  nfs: Fix KMSAN warning in decode_getfattr_attrs()
  NFSv3: only use NFS timeout for MOUNT when protocols are compatible
  sunrpc: handle -ENOTCONN in xs_tcp_setup_socket()
parents f43b1569 867da60d
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -181,8 +181,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
	seqlock_init(&clp->cl_boot_lock);
	ktime_get_real_ts64(&clp->cl_nfssvc_boot);
	clp->cl_uuid.net = NULL;
	clp->cl_uuid.dom = NULL;
	nfs_uuid_init(&clp->cl_uuid);
	spin_lock_init(&clp->cl_localio_lock);
#endif /* CONFIG_NFS_LOCALIO */

+47 −23
Original line number Diff line number Diff line
@@ -205,12 +205,15 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
		nfs_fscache_invalidate(inode, 0);
	flags &= ~NFS_INO_REVAL_FORCED;

	nfsi->cache_validity |= flags;
	flags |= nfsi->cache_validity;
	if (inode->i_mapping->nrpages == 0)
		flags &= ~NFS_INO_INVALID_DATA;

	if (inode->i_mapping->nrpages == 0) {
		nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
		nfs_ooo_clear(nfsi);
	} else if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
	/* pairs with nfs_clear_invalid_mapping()'s smp_load_acquire() */
	smp_store_release(&nfsi->cache_validity, flags);

	if (inode->i_mapping->nrpages == 0 ||
	    nfsi->cache_validity & NFS_INO_INVALID_DATA) {
		nfs_ooo_clear(nfsi);
	}
	trace_nfs_set_cache_invalid(inode, 0);
@@ -628,23 +631,35 @@ nfs_fattr_fixup_delegated(struct inode *inode, struct nfs_fattr *fattr)
	}
}

static void nfs_update_timestamps(struct inode *inode, unsigned int ia_valid)
{
	enum file_time_flags time_flags = 0;
	unsigned int cache_flags = 0;

	if (ia_valid & ATTR_MTIME) {
		time_flags |= S_MTIME | S_CTIME;
		cache_flags |= NFS_INO_INVALID_CTIME | NFS_INO_INVALID_MTIME;
	}
	if (ia_valid & ATTR_ATIME) {
		time_flags |= S_ATIME;
		cache_flags |= NFS_INO_INVALID_ATIME;
	}
	inode_update_timestamps(inode, time_flags);
	NFS_I(inode)->cache_validity &= ~cache_flags;
}

void nfs_update_delegated_atime(struct inode *inode)
{
	spin_lock(&inode->i_lock);
	if (nfs_have_delegated_atime(inode)) {
		inode_update_timestamps(inode, S_ATIME);
		NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_ATIME;
	}
	if (nfs_have_delegated_atime(inode))
		nfs_update_timestamps(inode, ATTR_ATIME);
	spin_unlock(&inode->i_lock);
}

void nfs_update_delegated_mtime_locked(struct inode *inode)
{
	if (nfs_have_delegated_mtime(inode)) {
		inode_update_timestamps(inode, S_CTIME | S_MTIME);
		NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_CTIME |
						  NFS_INO_INVALID_MTIME);
	}
	if (nfs_have_delegated_mtime(inode))
		nfs_update_timestamps(inode, ATTR_MTIME);
}

void nfs_update_delegated_mtime(struct inode *inode)
@@ -682,16 +697,17 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
			attr->ia_valid &= ~ATTR_SIZE;
	}

	if (nfs_have_delegated_mtime(inode)) {
		if (attr->ia_valid & ATTR_MTIME) {
			nfs_update_delegated_mtime(inode);
			attr->ia_valid &= ~ATTR_MTIME;
		}
		if (attr->ia_valid & ATTR_ATIME) {
	if (nfs_have_delegated_mtime(inode) && attr->ia_valid & ATTR_MTIME) {
		spin_lock(&inode->i_lock);
		nfs_update_timestamps(inode, attr->ia_valid);
		spin_unlock(&inode->i_lock);
		attr->ia_valid &= ~(ATTR_MTIME | ATTR_ATIME);
	} else if (nfs_have_delegated_atime(inode) &&
		   attr->ia_valid & ATTR_ATIME &&
		   !(attr->ia_valid & ATTR_MTIME)) {
		nfs_update_delegated_atime(inode);
		attr->ia_valid &= ~ATTR_ATIME;
	}
	}

	/* Optimization: if the end result is no change, don't RPC */
	if (((attr->ia_valid & NFS_VALID_ATTRS) & ~(ATTR_FILE|ATTR_OPEN)) == 0)
@@ -1408,6 +1424,13 @@ int nfs_clear_invalid_mapping(struct address_space *mapping)
					 TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
		if (ret)
			goto out;
		smp_rmb(); /* pairs with smp_wmb() below */
		if (test_bit(NFS_INO_INVALIDATING, bitlock))
			continue;
		/* pairs with nfs_set_cache_invalid()'s smp_store_release() */
		if (!(smp_load_acquire(&nfsi->cache_validity) & NFS_INO_INVALID_DATA))
			goto out;
		/* Slow-path that double-checks with spinlock held */
		spin_lock(&inode->i_lock);
		if (test_bit(NFS_INO_INVALIDATING, bitlock)) {
			spin_unlock(&inode->i_lock);
@@ -1633,6 +1656,7 @@ void nfs_fattr_init(struct nfs_fattr *fattr)
	fattr->gencount = nfs_inc_attr_generation_counter();
	fattr->owner_name = NULL;
	fattr->group_name = NULL;
	fattr->mdsthreshold = NULL;
}
EXPORT_SYMBOL_GPL(nfs_fattr_init);

+2 −1
Original line number Diff line number Diff line
@@ -205,7 +205,8 @@ void nfs_local_probe(struct nfs_client *clp)
		nfs_local_disable(clp);
	}

	nfs_uuid_begin(&clp->cl_uuid);
	if (!nfs_uuid_begin(&clp->cl_uuid))
		return;
	if (nfs_server_uuid_is_local(clp))
		nfs_local_enable(clp);
	nfs_uuid_end(&clp->cl_uuid);
+4 −0
Original line number Diff line number Diff line
@@ -3452,6 +3452,10 @@ static int nfs4_do_setattr(struct inode *inode, const struct cred *cred,
		adjust_flags |= NFS_INO_INVALID_MODE;
	if (sattr->ia_valid & (ATTR_UID | ATTR_GID))
		adjust_flags |= NFS_INO_INVALID_OTHER;
	if (sattr->ia_valid & ATTR_ATIME)
		adjust_flags |= NFS_INO_INVALID_ATIME;
	if (sattr->ia_valid & ATTR_MTIME)
		adjust_flags |= NFS_INO_INVALID_MTIME;

	do {
		nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label),
+9 −1
Original line number Diff line number Diff line
@@ -885,7 +885,15 @@ static int nfs_request_mount(struct fs_context *fc,
	 * Now ask the mount server to map our export path
	 * to a file handle.
	 */
	if ((request.protocol == XPRT_TRANSPORT_UDP) ==
	    !(ctx->flags & NFS_MOUNT_TCP))
		/*
		 * NFS protocol and mount protocol are both UDP or neither UDP
		 * so timeouts are compatible.  Use NFS timeouts for MOUNT
		 */
		status = nfs_mount(&request, ctx->timeo, ctx->retrans);
	else
		status = nfs_mount(&request, NFS_UNSPEC_TIMEO, NFS_UNSPEC_RETRANS);
	if (status != 0) {
		dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n",
				request.hostname, status);
Loading