mirror of
https://github.com/torvalds/linux.git
synced 2026-01-12 00:42:35 +08:00
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()
This commit is contained in:
@@ -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 */
|
||||
|
||||
|
||||
@@ -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,15 +697,16 @@ 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) {
|
||||
nfs_update_delegated_atime(inode);
|
||||
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 */
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
status = nfs_mount(&request, ctx->timeo, ctx->retrans);
|
||||
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);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/nfslocalio.h>
|
||||
#include <net/netns/generic.h>
|
||||
|
||||
@@ -20,15 +20,27 @@ static DEFINE_SPINLOCK(nfs_uuid_lock);
|
||||
*/
|
||||
static LIST_HEAD(nfs_uuids);
|
||||
|
||||
void nfs_uuid_begin(nfs_uuid_t *nfs_uuid)
|
||||
void nfs_uuid_init(nfs_uuid_t *nfs_uuid)
|
||||
{
|
||||
nfs_uuid->net = NULL;
|
||||
nfs_uuid->dom = NULL;
|
||||
uuid_gen(&nfs_uuid->uuid);
|
||||
INIT_LIST_HEAD(&nfs_uuid->list);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_uuid_init);
|
||||
|
||||
bool nfs_uuid_begin(nfs_uuid_t *nfs_uuid)
|
||||
{
|
||||
spin_lock(&nfs_uuid_lock);
|
||||
list_add_tail_rcu(&nfs_uuid->list, &nfs_uuids);
|
||||
/* Is this nfs_uuid already in use? */
|
||||
if (!list_empty(&nfs_uuid->list)) {
|
||||
spin_unlock(&nfs_uuid_lock);
|
||||
return false;
|
||||
}
|
||||
uuid_gen(&nfs_uuid->uuid);
|
||||
list_add_tail(&nfs_uuid->list, &nfs_uuids);
|
||||
spin_unlock(&nfs_uuid_lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_uuid_begin);
|
||||
|
||||
@@ -36,7 +48,8 @@ void nfs_uuid_end(nfs_uuid_t *nfs_uuid)
|
||||
{
|
||||
if (nfs_uuid->net == NULL) {
|
||||
spin_lock(&nfs_uuid_lock);
|
||||
list_del_init(&nfs_uuid->list);
|
||||
if (nfs_uuid->net == NULL)
|
||||
list_del_init(&nfs_uuid->list);
|
||||
spin_unlock(&nfs_uuid_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ typedef struct {
|
||||
struct auth_domain *dom; /* auth_domain for localio */
|
||||
} nfs_uuid_t;
|
||||
|
||||
void nfs_uuid_begin(nfs_uuid_t *);
|
||||
void nfs_uuid_init(nfs_uuid_t *);
|
||||
bool nfs_uuid_begin(nfs_uuid_t *);
|
||||
void nfs_uuid_end(nfs_uuid_t *);
|
||||
void nfs_uuid_is_local(const uuid_t *, struct list_head *,
|
||||
struct net *, struct auth_domain *, struct module *);
|
||||
|
||||
@@ -2459,6 +2459,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
|
||||
case -EHOSTUNREACH:
|
||||
case -EADDRINUSE:
|
||||
case -ENOBUFS:
|
||||
case -ENOTCONN:
|
||||
break;
|
||||
default:
|
||||
printk("%s: connect returned unhandled error %d\n",
|
||||
|
||||
Reference in New Issue
Block a user