Commit 60f0560f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'nfs-for-6.11-2' of git://git.linux-nfs.org/projects/anna/linux-nfs

Pull NFS client fixes from Anna Schumaker:

 - Fix rpcrdma refcounting in xa_alloc

 - Fix rpcrdma usage of XA_FLAGS_ALLOC

 - Fix requesting FATTR4_WORD2_OPEN_ARGUMENTS

 - Fix attribute bitmap decoder to handle a 3rd word

 - Add reschedule points when returning delegations to avoid soft lockups

 - Fix clearing layout segments in layoutreturn

 - Avoid unnecessary rescanning of the per-server delegation list

* tag 'nfs-for-6.11-2' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  NFS: Avoid unnecessary rescanning of the per-server delegation list
  NFSv4: Fix clearing of layout segments in layoutreturn
  NFSv4: Add missing rescheduling points in nfs_client_return_marked_delegations
  nfs: fix bitmap decoder to handle a 3rd word
  nfs: fix the fetch of FATTR4_OPEN_ARGUMENTS
  rpcrdma: Trace connection registration and unregistration
  rpcrdma: Use XA_FLAGS_ALLOC instead of XA_FLAGS_ALLOC1
  rpcrdma: Device kref is over-incremented on error from xa_alloc
parents 66ace9a8 f92214e4
...@@ -118,7 +118,9 @@ static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) ...@@ -118,7 +118,9 @@ static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
if (likely(attrlen > 0)) if (likely(attrlen > 0))
bitmap[0] = ntohl(*p++); bitmap[0] = ntohl(*p++);
if (attrlen > 1) if (attrlen > 1)
bitmap[1] = ntohl(*p); bitmap[1] = ntohl(*p++);
if (attrlen > 2)
bitmap[2] = ntohl(*p);
return 0; return 0;
} }
...@@ -446,7 +448,7 @@ static __be32 decode_recallany_args(struct svc_rqst *rqstp, ...@@ -446,7 +448,7 @@ static __be32 decode_recallany_args(struct svc_rqst *rqstp,
void *argp) void *argp)
{ {
struct cb_recallanyargs *args = argp; struct cb_recallanyargs *args = argp;
uint32_t bitmap[2]; uint32_t bitmap[3];
__be32 *p, status; __be32 *p, status;
p = xdr_inline_decode(xdr, 4); p = xdr_inline_decode(xdr, 4);
......
...@@ -647,6 +647,9 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server, ...@@ -647,6 +647,9 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server,
prev = delegation; prev = delegation;
continue; continue;
} }
inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL)
continue;
if (prev) { if (prev) {
struct inode *tmp = nfs_delegation_grab_inode(prev); struct inode *tmp = nfs_delegation_grab_inode(prev);
...@@ -657,12 +660,6 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server, ...@@ -657,12 +660,6 @@ static int nfs_server_return_marked_delegations(struct nfs_server *server,
} }
} }
inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL) {
rcu_read_unlock();
iput(to_put);
goto restart;
}
delegation = nfs_start_delegation_return_locked(NFS_I(inode)); delegation = nfs_start_delegation_return_locked(NFS_I(inode));
rcu_read_unlock(); rcu_read_unlock();
...@@ -1184,7 +1181,6 @@ static int nfs_server_reap_unclaimed_delegations(struct nfs_server *server, ...@@ -1184,7 +1181,6 @@ static int nfs_server_reap_unclaimed_delegations(struct nfs_server *server,
struct inode *inode; struct inode *inode;
restart: restart:
rcu_read_lock(); rcu_read_lock();
restart_locked:
list_for_each_entry_rcu(delegation, &server->delegations, super_list) { list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
if (test_bit(NFS_DELEGATION_INODE_FREEING, if (test_bit(NFS_DELEGATION_INODE_FREEING,
&delegation->flags) || &delegation->flags) ||
...@@ -1195,7 +1191,7 @@ static int nfs_server_reap_unclaimed_delegations(struct nfs_server *server, ...@@ -1195,7 +1191,7 @@ static int nfs_server_reap_unclaimed_delegations(struct nfs_server *server,
continue; continue;
inode = nfs_delegation_grab_inode(delegation); inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL) if (inode == NULL)
goto restart_locked; continue;
delegation = nfs_start_delegation_return_locked(NFS_I(inode)); delegation = nfs_start_delegation_return_locked(NFS_I(inode));
rcu_read_unlock(); rcu_read_unlock();
if (delegation != NULL) { if (delegation != NULL) {
...@@ -1318,7 +1314,6 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server, ...@@ -1318,7 +1314,6 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
restart: restart:
rcu_read_lock(); rcu_read_lock();
restart_locked:
list_for_each_entry_rcu(delegation, &server->delegations, super_list) { list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
if (test_bit(NFS_DELEGATION_INODE_FREEING, if (test_bit(NFS_DELEGATION_INODE_FREEING,
&delegation->flags) || &delegation->flags) ||
...@@ -1330,7 +1325,7 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server, ...@@ -1330,7 +1325,7 @@ static int nfs_server_reap_expired_delegations(struct nfs_server *server,
continue; continue;
inode = nfs_delegation_grab_inode(delegation); inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL) if (inode == NULL)
goto restart_locked; continue;
spin_lock(&delegation->lock); spin_lock(&delegation->lock);
cred = get_cred_rcu(delegation->cred); cred = get_cred_rcu(delegation->cred);
nfs4_stateid_copy(&stateid, &delegation->stateid); nfs4_stateid_copy(&stateid, &delegation->stateid);
......
...@@ -3931,7 +3931,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f ...@@ -3931,7 +3931,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
FATTR4_WORD0_CASE_INSENSITIVE | FATTR4_WORD0_CASE_INSENSITIVE |
FATTR4_WORD0_CASE_PRESERVING; FATTR4_WORD0_CASE_PRESERVING;
if (minorversion) if (minorversion)
bitmask[2] = FATTR4_WORD2_SUPPATTR_EXCLCREAT; bitmask[2] = FATTR4_WORD2_SUPPATTR_EXCLCREAT |
FATTR4_WORD2_OPEN_ARGUMENTS;
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
if (status == 0) { if (status == 0) {
...@@ -9997,6 +9998,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) ...@@ -9997,6 +9998,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
fallthrough; fallthrough;
default: default:
task->tk_status = 0; task->tk_status = 0;
lrp->res.lrs_present = 0;
fallthrough; fallthrough;
case 0: case 0:
break; break;
...@@ -10010,9 +10012,11 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) ...@@ -10010,9 +10012,11 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
task->tk_status = 0; task->tk_status = 0;
break; break;
case -NFS4ERR_DELAY: case -NFS4ERR_DELAY:
if (nfs4_async_handle_error(task, server, NULL, NULL) != -EAGAIN) if (nfs4_async_handle_error(task, server, NULL, NULL) ==
break; -EAGAIN)
goto out_restart; goto out_restart;
lrp->res.lrs_present = 0;
break;
} }
return; return;
out_restart: out_restart:
......
...@@ -1284,10 +1284,9 @@ void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo, ...@@ -1284,10 +1284,9 @@ void pnfs_layoutreturn_free_lsegs(struct pnfs_layout_hdr *lo,
LIST_HEAD(freeme); LIST_HEAD(freeme);
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
if (!pnfs_layout_is_valid(lo) || if (!nfs4_stateid_match_other(&lo->plh_stateid, arg_stateid))
!nfs4_stateid_match_other(&lo->plh_stateid, arg_stateid))
goto out_unlock; goto out_unlock;
if (stateid) { if (stateid && pnfs_layout_is_valid(lo)) {
u32 seq = be32_to_cpu(arg_stateid->seqid); u32 seq = be32_to_cpu(arg_stateid->seqid);
pnfs_mark_matching_lsegs_invalid(lo, &freeme, range, seq); pnfs_mark_matching_lsegs_invalid(lo, &freeme, range, seq);
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -228,6 +229,7 @@ static int __nfs_list_for_each_server(struct list_head *head, ...@@ -228,6 +229,7 @@ static int __nfs_list_for_each_server(struct list_head *head,
ret = fn(server, data); ret = fn(server, data);
if (ret) if (ret)
goto out; goto out;
cond_resched();
rcu_read_lock(); rcu_read_lock();
} }
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -2277,6 +2277,42 @@ DEFINE_CLIENT_DEVICE_EVENT(rpcrdma_client_remove_one); ...@@ -2277,6 +2277,42 @@ DEFINE_CLIENT_DEVICE_EVENT(rpcrdma_client_remove_one);
DEFINE_CLIENT_DEVICE_EVENT(rpcrdma_client_wait_on); DEFINE_CLIENT_DEVICE_EVENT(rpcrdma_client_wait_on);
DEFINE_CLIENT_DEVICE_EVENT(rpcrdma_client_remove_one_done); DEFINE_CLIENT_DEVICE_EVENT(rpcrdma_client_remove_one_done);
DECLARE_EVENT_CLASS(rpcrdma_client_register_class,
TP_PROTO(
const struct ib_device *device,
const struct rpcrdma_notification *rn
),
TP_ARGS(device, rn),
TP_STRUCT__entry(
__string(name, device->name)
__field(void *, callback)
__field(u32, index)
),
TP_fast_assign(
__assign_str(name);
__entry->callback = rn->rn_done;
__entry->index = rn->rn_index;
),
TP_printk("device=%s index=%u done callback=%pS\n",
__get_str(name), __entry->index, __entry->callback
)
);
#define DEFINE_CLIENT_REGISTER_EVENT(name) \
DEFINE_EVENT(rpcrdma_client_register_class, name, \
TP_PROTO( \
const struct ib_device *device, \
const struct rpcrdma_notification *rn \
), \
TP_ARGS(device, rn))
DEFINE_CLIENT_REGISTER_EVENT(rpcrdma_client_register);
DEFINE_CLIENT_REGISTER_EVENT(rpcrdma_client_unregister);
#endif /* _TRACE_RPCRDMA_H */ #endif /* _TRACE_RPCRDMA_H */
#include <trace/define_trace.h> #include <trace/define_trace.h>
...@@ -62,10 +62,11 @@ int rpcrdma_rn_register(struct ib_device *device, ...@@ -62,10 +62,11 @@ int rpcrdma_rn_register(struct ib_device *device,
if (!rd || test_bit(RPCRDMA_RD_F_REMOVING, &rd->rd_flags)) if (!rd || test_bit(RPCRDMA_RD_F_REMOVING, &rd->rd_flags))
return -ENETUNREACH; return -ENETUNREACH;
kref_get(&rd->rd_kref);
if (xa_alloc(&rd->rd_xa, &rn->rn_index, rn, xa_limit_32b, GFP_KERNEL) < 0) if (xa_alloc(&rd->rd_xa, &rn->rn_index, rn, xa_limit_32b, GFP_KERNEL) < 0)
return -ENOMEM; return -ENOMEM;
kref_get(&rd->rd_kref);
rn->rn_done = done; rn->rn_done = done;
trace_rpcrdma_client_register(device, rn);
return 0; return 0;
} }
...@@ -91,6 +92,7 @@ void rpcrdma_rn_unregister(struct ib_device *device, ...@@ -91,6 +92,7 @@ void rpcrdma_rn_unregister(struct ib_device *device,
if (!rd) if (!rd)
return; return;
trace_rpcrdma_client_unregister(device, rn);
xa_erase(&rd->rd_xa, rn->rn_index); xa_erase(&rd->rd_xa, rn->rn_index);
kref_put(&rd->rd_kref, rpcrdma_rn_release); kref_put(&rd->rd_kref, rpcrdma_rn_release);
} }
...@@ -111,7 +113,7 @@ static int rpcrdma_add_one(struct ib_device *device) ...@@ -111,7 +113,7 @@ static int rpcrdma_add_one(struct ib_device *device)
return -ENOMEM; return -ENOMEM;
kref_init(&rd->rd_kref); kref_init(&rd->rd_kref);
xa_init_flags(&rd->rd_xa, XA_FLAGS_ALLOC1); xa_init_flags(&rd->rd_xa, XA_FLAGS_ALLOC);
rd->rd_device = device; rd->rd_device = device;
init_completion(&rd->rd_done); init_completion(&rd->rd_done);
ib_set_client_data(device, &rpcrdma_ib_client, rd); ib_set_client_data(device, &rpcrdma_ib_client, rd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment