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:
+1
-2
@@ -181,8 +181,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
|
|||||||
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
|
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
|
||||||
seqlock_init(&clp->cl_boot_lock);
|
seqlock_init(&clp->cl_boot_lock);
|
||||||
ktime_get_real_ts64(&clp->cl_nfssvc_boot);
|
ktime_get_real_ts64(&clp->cl_nfssvc_boot);
|
||||||
clp->cl_uuid.net = NULL;
|
nfs_uuid_init(&clp->cl_uuid);
|
||||||
clp->cl_uuid.dom = NULL;
|
|
||||||
spin_lock_init(&clp->cl_localio_lock);
|
spin_lock_init(&clp->cl_localio_lock);
|
||||||
#endif /* CONFIG_NFS_LOCALIO */
|
#endif /* CONFIG_NFS_LOCALIO */
|
||||||
|
|
||||||
|
|||||||
+47
-23
@@ -205,12 +205,15 @@ void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
|
|||||||
nfs_fscache_invalidate(inode, 0);
|
nfs_fscache_invalidate(inode, 0);
|
||||||
flags &= ~NFS_INO_REVAL_FORCED;
|
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) {
|
/* pairs with nfs_clear_invalid_mapping()'s smp_load_acquire() */
|
||||||
nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
|
smp_store_release(&nfsi->cache_validity, flags);
|
||||||
nfs_ooo_clear(nfsi);
|
|
||||||
} else if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
|
if (inode->i_mapping->nrpages == 0 ||
|
||||||
|
nfsi->cache_validity & NFS_INO_INVALID_DATA) {
|
||||||
nfs_ooo_clear(nfsi);
|
nfs_ooo_clear(nfsi);
|
||||||
}
|
}
|
||||||
trace_nfs_set_cache_invalid(inode, 0);
|
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)
|
void nfs_update_delegated_atime(struct inode *inode)
|
||||||
{
|
{
|
||||||
spin_lock(&inode->i_lock);
|
spin_lock(&inode->i_lock);
|
||||||
if (nfs_have_delegated_atime(inode)) {
|
if (nfs_have_delegated_atime(inode))
|
||||||
inode_update_timestamps(inode, S_ATIME);
|
nfs_update_timestamps(inode, ATTR_ATIME);
|
||||||
NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_ATIME;
|
|
||||||
}
|
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfs_update_delegated_mtime_locked(struct inode *inode)
|
void nfs_update_delegated_mtime_locked(struct inode *inode)
|
||||||
{
|
{
|
||||||
if (nfs_have_delegated_mtime(inode)) {
|
if (nfs_have_delegated_mtime(inode))
|
||||||
inode_update_timestamps(inode, S_CTIME | S_MTIME);
|
nfs_update_timestamps(inode, ATTR_MTIME);
|
||||||
NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_CTIME |
|
|
||||||
NFS_INO_INVALID_MTIME);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfs_update_delegated_mtime(struct inode *inode)
|
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;
|
attr->ia_valid &= ~ATTR_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nfs_have_delegated_mtime(inode)) {
|
if (nfs_have_delegated_mtime(inode) && attr->ia_valid & ATTR_MTIME) {
|
||||||
if (attr->ia_valid & ATTR_MTIME) {
|
spin_lock(&inode->i_lock);
|
||||||
nfs_update_delegated_mtime(inode);
|
nfs_update_timestamps(inode, attr->ia_valid);
|
||||||
attr->ia_valid &= ~ATTR_MTIME;
|
spin_unlock(&inode->i_lock);
|
||||||
}
|
attr->ia_valid &= ~(ATTR_MTIME | ATTR_ATIME);
|
||||||
if (attr->ia_valid & ATTR_ATIME) {
|
} else if (nfs_have_delegated_atime(inode) &&
|
||||||
nfs_update_delegated_atime(inode);
|
attr->ia_valid & ATTR_ATIME &&
|
||||||
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 */
|
/* 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);
|
TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
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);
|
spin_lock(&inode->i_lock);
|
||||||
if (test_bit(NFS_INO_INVALIDATING, bitlock)) {
|
if (test_bit(NFS_INO_INVALIDATING, bitlock)) {
|
||||||
spin_unlock(&inode->i_lock);
|
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->gencount = nfs_inc_attr_generation_counter();
|
||||||
fattr->owner_name = NULL;
|
fattr->owner_name = NULL;
|
||||||
fattr->group_name = NULL;
|
fattr->group_name = NULL;
|
||||||
|
fattr->mdsthreshold = NULL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfs_fattr_init);
|
EXPORT_SYMBOL_GPL(nfs_fattr_init);
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -205,7 +205,8 @@ void nfs_local_probe(struct nfs_client *clp)
|
|||||||
nfs_local_disable(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))
|
if (nfs_server_uuid_is_local(clp))
|
||||||
nfs_local_enable(clp);
|
nfs_local_enable(clp);
|
||||||
nfs_uuid_end(&clp->cl_uuid);
|
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;
|
adjust_flags |= NFS_INO_INVALID_MODE;
|
||||||
if (sattr->ia_valid & (ATTR_UID | ATTR_GID))
|
if (sattr->ia_valid & (ATTR_UID | ATTR_GID))
|
||||||
adjust_flags |= NFS_INO_INVALID_OTHER;
|
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 {
|
do {
|
||||||
nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label),
|
nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label),
|
||||||
|
|||||||
+9
-1
@@ -885,7 +885,15 @@ static int nfs_request_mount(struct fs_context *fc,
|
|||||||
* Now ask the mount server to map our export path
|
* Now ask the mount server to map our export path
|
||||||
* to a file handle.
|
* 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) {
|
if (status != 0) {
|
||||||
dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n",
|
dfprintk(MOUNT, "NFS: unable to mount server %s, error %d\n",
|
||||||
request.hostname, status);
|
request.hostname, status);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/rculist.h>
|
#include <linux/list.h>
|
||||||
#include <linux/nfslocalio.h>
|
#include <linux/nfslocalio.h>
|
||||||
#include <net/netns/generic.h>
|
#include <net/netns/generic.h>
|
||||||
|
|
||||||
@@ -20,15 +20,27 @@ static DEFINE_SPINLOCK(nfs_uuid_lock);
|
|||||||
*/
|
*/
|
||||||
static LIST_HEAD(nfs_uuids);
|
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->net = NULL;
|
||||||
nfs_uuid->dom = 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);
|
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);
|
spin_unlock(&nfs_uuid_lock);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfs_uuid_begin);
|
EXPORT_SYMBOL_GPL(nfs_uuid_begin);
|
||||||
|
|
||||||
@@ -36,7 +48,8 @@ void nfs_uuid_end(nfs_uuid_t *nfs_uuid)
|
|||||||
{
|
{
|
||||||
if (nfs_uuid->net == NULL) {
|
if (nfs_uuid->net == NULL) {
|
||||||
spin_lock(&nfs_uuid_lock);
|
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);
|
spin_unlock(&nfs_uuid_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ typedef struct {
|
|||||||
struct auth_domain *dom; /* auth_domain for localio */
|
struct auth_domain *dom; /* auth_domain for localio */
|
||||||
} nfs_uuid_t;
|
} 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_end(nfs_uuid_t *);
|
||||||
void nfs_uuid_is_local(const uuid_t *, struct list_head *,
|
void nfs_uuid_is_local(const uuid_t *, struct list_head *,
|
||||||
struct net *, struct auth_domain *, struct module *);
|
struct net *, struct auth_domain *, struct module *);
|
||||||
|
|||||||
@@ -2459,6 +2459,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
|
|||||||
case -EHOSTUNREACH:
|
case -EHOSTUNREACH:
|
||||||
case -EADDRINUSE:
|
case -EADDRINUSE:
|
||||||
case -ENOBUFS:
|
case -ENOBUFS:
|
||||||
|
case -ENOTCONN:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk("%s: connect returned unhandled error %d\n",
|
printk("%s: connect returned unhandled error %d\n",
|
||||||
|
|||||||
Reference in New Issue
Block a user