From e8051c837bd96ad1eabdd46504363431dc5fddc5 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 16 Jul 2014 10:31:56 -0400 Subject: nfsd: eliminate nfsd4_init_callback It's just an obfuscated INIT_WORK call. Just make the work_func_t a non-static symbol and use a normal INIT_WORK call. Signed-off-by: Jeff Layton Reviewed-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 2c73cae9899..30a71cb4600 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -1011,7 +1011,8 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) run_nfsd4_cb(cb); } -static void nfsd4_do_callback_rpc(struct work_struct *w) +void +nfsd4_do_callback_rpc(struct work_struct *w) { struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work); struct nfs4_client *clp = cb->cb_clp; @@ -1031,11 +1032,6 @@ static void nfsd4_do_callback_rpc(struct work_struct *w) cb->cb_ops, cb); } -void nfsd4_init_callback(struct nfsd4_callback *cb) -{ - INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc); -} - void nfsd4_cb_recall(struct nfs4_delegation *dp) { struct nfsd4_callback *cb = &dp->dl_recall; -- cgit v1.2.3-70-g09d2 From 02e1215f9f72ad8c087e21a5701bea0ac18fafd4 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 16 Jul 2014 10:31:57 -0400 Subject: nfsd: Avoid taking state_lock while holding inode lock in nfsd_break_one_deleg state_lock is a heavily contended global lock. We don't want to grab that while simultaneously holding the inode->i_lock. Add a new per-nfs4_file lock that we can use to protect the per-nfs4_file delegation list. Hold that while walking the list in the break_deleg callback and queue the workqueue job for each one. The workqueue job can then take the state_lock and do the list manipulations without the i_lock being held prior to starting the rpc call. Signed-off-by: Trond Myklebust Signed-off-by: Jeff Layton Reviewed-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 25 ++++++++++++++++++---- fs/nfsd/nfs4state.c | 58 +++++++++++++++++++++++++++++++++----------------- fs/nfsd/state.h | 4 +++- 3 files changed, 62 insertions(+), 25 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 30a71cb4600..a88a93e09d6 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -933,7 +933,7 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp) set_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags); /* * Note this won't actually result in a null callback; - * instead, nfsd4_do_callback_rpc() will detect the killed + * instead, nfsd4_run_cb_null() will detect the killed * client, destroy the rpc client, and stop: */ do_probe_callback(clp); @@ -1011,10 +1011,9 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) run_nfsd4_cb(cb); } -void -nfsd4_do_callback_rpc(struct work_struct *w) +static void +nfsd4_run_callback_rpc(struct nfsd4_callback *cb) { - struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work); struct nfs4_client *clp = cb->cb_clp; struct rpc_clnt *clnt; @@ -1032,6 +1031,24 @@ nfsd4_do_callback_rpc(struct work_struct *w) cb->cb_ops, cb); } +void +nfsd4_run_cb_null(struct work_struct *w) +{ + struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, + cb_work); + nfsd4_run_callback_rpc(cb); +} + +void +nfsd4_run_cb_recall(struct work_struct *w) +{ + struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, + cb_work); + + nfsd4_prepare_cb_recall(cb->cb_op); + nfsd4_run_callback_rpc(cb); +} + void nfsd4_cb_recall(struct nfs4_delegation *dp) { struct nfsd4_callback *cb = &dp->dl_recall; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 56ea4f12803..bdf8ac3393b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -254,6 +254,8 @@ static void nfsd4_free_file(struct nfs4_file *f) static inline void put_nfs4_file(struct nfs4_file *fi) { + might_lock(&state_lock); + if (atomic_dec_and_lock(&fi->fi_ref, &state_lock)) { hlist_del(&fi->fi_hash); spin_unlock(&state_lock); @@ -554,6 +556,8 @@ static void block_delegations(struct knfsd_fh *fh) u32 hash; struct bloom_pair *bd = &blocked_delegations; + lockdep_assert_held(&state_lock); + hash = arch_fast_hash(&fh->fh_base, fh->fh_size, 0); __set_bit(hash&255, bd->set[bd->new]); @@ -592,7 +596,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); dp->dl_time = 0; atomic_set(&dp->dl_count, 1); - INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); + INIT_WORK(&dp->dl_recall.cb_work, nfsd4_run_cb_recall); return dp; } @@ -640,7 +644,9 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) lockdep_assert_held(&state_lock); dp->dl_stid.sc_type = NFS4_DELEG_STID; + spin_lock(&fp->fi_lock); list_add(&dp->dl_perfile, &fp->fi_delegations); + spin_unlock(&fp->fi_lock); list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); } @@ -648,14 +654,18 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) static void unhash_delegation(struct nfs4_delegation *dp) { + struct nfs4_file *fp = dp->dl_file; + spin_lock(&state_lock); list_del_init(&dp->dl_perclnt); - list_del_init(&dp->dl_perfile); list_del_init(&dp->dl_recall_lru); + spin_lock(&fp->fi_lock); + list_del_init(&dp->dl_perfile); + spin_unlock(&fp->fi_lock); spin_unlock(&state_lock); - if (dp->dl_file) { - nfs4_put_deleg_lease(dp->dl_file); - put_nfs4_file(dp->dl_file); + if (fp) { + nfs4_put_deleg_lease(fp); + put_nfs4_file(fp); dp->dl_file = NULL; } } @@ -1677,7 +1687,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, spin_unlock(&nn->client_lock); return NULL; } - INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); + INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_run_cb_null); clp->cl_time = get_seconds(); clear_bit(0, &clp->cl_cb_slot_busy); copy_verf(clp, verf); @@ -3079,30 +3089,38 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) return ret; } -static void nfsd_break_one_deleg(struct nfs4_delegation *dp) +void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp) { struct nfs4_client *clp = dp->dl_stid.sc_client; struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); - lockdep_assert_held(&state_lock); - /* We're assuming the state code never drops its reference - * without first removing the lease. Since we're in this lease - * callback (and since the lease code is serialized by the kernel - * lock) we know the server hasn't removed the lease yet, we know - * it's safe to take a reference: */ - atomic_inc(&dp->dl_count); - + /* + * We can't do this in nfsd_break_deleg_cb because it is + * already holding inode->i_lock + */ + spin_lock(&state_lock); + block_delegations(&dp->dl_fh); /* * If the dl_time != 0, then we know that it has already been * queued for a lease break. Don't queue it again. */ if (dp->dl_time == 0) { - list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); dp->dl_time = get_seconds(); + list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); } + spin_unlock(&state_lock); +} - block_delegations(&dp->dl_fh); - +static void nfsd_break_one_deleg(struct nfs4_delegation *dp) +{ + /* + * We're assuming the state code never drops its reference + * without first removing the lease. Since we're in this lease + * callback (and since the lease code is serialized by the kernel + * lock) we know the server hasn't removed the lease yet, we know + * it's safe to take a reference. + */ + atomic_inc(&dp->dl_count); nfsd4_cb_recall(dp); } @@ -3127,11 +3145,11 @@ static void nfsd_break_deleg_cb(struct file_lock *fl) */ fl->fl_break_time = 0; - spin_lock(&state_lock); fp->fi_had_conflict = true; + spin_lock(&fp->fi_lock); list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) nfsd_break_one_deleg(dp); - spin_unlock(&state_lock); + spin_unlock(&fp->fi_lock); } static diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 20857142773..81b7522e3f6 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -436,7 +436,8 @@ extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, extern __be32 nfs4_check_open_reclaim(clientid_t *clid, struct nfsd4_compound_state *cstate, struct nfsd_net *nn); extern int set_callback_cred(void); -void nfsd4_do_callback_rpc(struct work_struct *w); +void nfsd4_run_cb_null(struct work_struct *w); +void nfsd4_run_cb_recall(struct work_struct *w); extern void nfsd4_probe_callback(struct nfs4_client *clp); extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); @@ -444,6 +445,7 @@ extern void nfsd4_cb_recall(struct nfs4_delegation *dp); extern int nfsd4_create_callback_queue(void); extern void nfsd4_destroy_callback_queue(void); extern void nfsd4_shutdown_callback(struct nfs4_client *); +extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp); extern void nfs4_put_delegation(struct nfs4_delegation *dp); extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn); -- cgit v1.2.3-70-g09d2 From 3c45ddf823d679a820adddd53b52c6699c9a05ac Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 16 Jul 2014 15:38:32 -0400 Subject: svcrdma: Select NFSv4.1 backchannel transport based on forward channel The current code always selects XPRT_TRANSPORT_BC_TCP for the back channel, even when the forward channel was not TCP (eg, RDMA). When a 4.1 mount is attempted with RDMA, the server panics in the TCP BC code when trying to send CB_NULL. Instead, construct the transport protocol number from the forward channel transport or'd with XPRT_TRANSPORT_BC. Transports that do not support bi-directional RPC will not have registered a "BC" transport, causing create_backchannel_client() to fail immediately. Fixes: https://bugzilla.linux-nfs.org/show_bug.cgi?id=265 Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 3 ++- include/linux/sunrpc/svc_xprt.h | 1 + net/sunrpc/svcsock.c | 2 ++ net/sunrpc/xprt.c | 2 +- net/sunrpc/xprtrdma/svc_rdma_transport.c | 1 + 5 files changed, 7 insertions(+), 2 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index a88a93e09d6..564d7230461 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -689,7 +689,8 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c clp->cl_cb_session = ses; args.bc_xprt = conn->cb_xprt; args.prognumber = clp->cl_cb_session->se_cb_prog; - args.protocol = XPRT_TRANSPORT_BC_TCP; + args.protocol = conn->cb_xprt->xpt_class->xcl_ident | + XPRT_TRANSPORT_BC; args.authflavor = ses->se_cb_sec.flavor; } /* Create RPC client */ diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 7235040a19b..5d9d6f84b38 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -33,6 +33,7 @@ struct svc_xprt_class { struct svc_xprt_ops *xcl_ops; struct list_head xcl_list; u32 xcl_max_payload; + int xcl_ident; }; /* diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index b507cd327d9..b2437ee9365 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -692,6 +692,7 @@ static struct svc_xprt_class svc_udp_class = { .xcl_owner = THIS_MODULE, .xcl_ops = &svc_udp_ops, .xcl_max_payload = RPCSVC_MAXPAYLOAD_UDP, + .xcl_ident = XPRT_TRANSPORT_UDP, }; static void svc_udp_init(struct svc_sock *svsk, struct svc_serv *serv) @@ -1292,6 +1293,7 @@ static struct svc_xprt_class svc_tcp_class = { .xcl_owner = THIS_MODULE, .xcl_ops = &svc_tcp_ops, .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, + .xcl_ident = XPRT_TRANSPORT_TCP, }; void svc_init_xprt_sock(void) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index c3b2b3369e5..51c63165073 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -1306,7 +1306,7 @@ struct rpc_xprt *xprt_create_transport(struct xprt_create *args) } } spin_unlock(&xprt_list_lock); - printk(KERN_ERR "RPC: transport (%d) not supported\n", args->ident); + dprintk("RPC: transport (%d) not supported\n", args->ident); return ERR_PTR(-EIO); found: diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index e7323fbbd34..06a5d923510 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -92,6 +92,7 @@ struct svc_xprt_class svc_rdma_class = { .xcl_owner = THIS_MODULE, .xcl_ops = &svc_rdma_ops, .xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP, + .xcl_ident = XPRT_TRANSPORT_RDMA, }; struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt) -- cgit v1.2.3-70-g09d2 From fc8e5a644c2041273a1cee7c6299713ccee319ab Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Wed, 23 Jul 2014 20:12:31 +0530 Subject: nfsd4: convert comma to semicolon Replace a comma between expression statements by a semicolon. This changes the semantics of the code, but given the current indentation appears to be what is intended. A simplified version of the Coccinelle semantic patch that performs this transformation is as follows: // @r@ expression e1,e2; @@ e1 -, +; e2; // Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 564d7230461..c393d6ca3fc 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -678,7 +678,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c (clp->cl_cred.cr_flavor >= RPC_AUTH_GSS_KRB5)) return -EINVAL; args.client_name = clp->cl_cred.cr_principal; - args.prognumber = conn->cb_prog, + args.prognumber = conn->cb_prog; args.protocol = XPRT_TRANSPORT_TCP; args.authflavor = clp->cl_cred.cr_flavor; clp->cl_cb_ident = conn->cb_ident; -- cgit v1.2.3-70-g09d2 From 650ecc8f8ff29a7f0990704f09df232b505b200d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 25 Jul 2014 07:34:27 -0400 Subject: nfsd: remove dl_fh field from struct nfs4_delegation Now that the nfs4_file has a filehandle in it, we no longer need to keep a per-delegation copy of it. Switch to using the one in the nfs4_file instead. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 2 +- fs/nfsd/nfs4state.c | 3 +-- fs/nfsd/state.h | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index c393d6ca3fc..e9813389687 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -337,7 +337,7 @@ static void encode_cb_recall4args(struct xdr_stream *xdr, p = xdr_reserve_space(xdr, 4); *p++ = xdr_zero; /* truncate */ - encode_nfs_fh4(xdr, &dp->dl_fh); + encode_nfs_fh4(xdr, &dp->dl_file->fi_fhandle); hdr->nops++; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ecfddca9b84..b0f83beeca7 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -604,7 +604,6 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh) INIT_LIST_HEAD(&dp->dl_perclnt); INIT_LIST_HEAD(&dp->dl_recall_lru); dp->dl_type = NFS4_OPEN_DELEGATE_READ; - fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); INIT_WORK(&dp->dl_recall.cb_work, nfsd4_run_cb_recall); return dp; out_dec: @@ -3097,7 +3096,7 @@ void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp) struct nfs4_client *clp = dp->dl_stid.sc_client; struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); - block_delegations(&dp->dl_fh); + block_delegations(&dp->dl_file->fi_fhandle); /* * We can't do this in nfsd_break_deleg_cb because it is diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 0097d477152..39747736e83 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -96,7 +96,6 @@ struct nfs4_delegation { u32 dl_type; time_t dl_time; /* For recall: */ - struct knfsd_fh dl_fh; int dl_retries; struct nfsd4_callback dl_recall; }; -- cgit v1.2.3-70-g09d2 From 6011695da2d7c588f2dfe57c318758f0bf1154dd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 29 Jul 2014 21:34:06 -0400 Subject: nfsd: Add reference counting to the lock and open stateids When we remove the client_mutex, we'll need to be able to ensure that these objects aren't destroyed while we're not holding locks. Add a ->free() callback to the struct nfs4_stid, so that we can release a reference to the stid without caring about the contents. Signed-off-by: Trond Myklebust Reviewed-by: Christoph Hellwig Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 2 +- fs/nfsd/nfs4state.c | 103 ++++++++++++++++++++++++++----------------------- fs/nfsd/state.h | 3 +- 3 files changed, 58 insertions(+), 50 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index e9813389687..8574c708cf8 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -905,7 +905,7 @@ static void nfsd4_cb_recall_release(void *calldata) spin_lock(&clp->cl_lock); list_del(&cb->cb_per_client); spin_unlock(&clp->cl_lock); - nfs4_put_delegation(dp); + nfs4_put_stid(&dp->dl_stid); } } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b0f83beeca7..60ab22b6e09 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -71,6 +71,7 @@ static u64 current_sessionid = 1; /* forward declarations */ static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner); +static void nfs4_free_ol_stateid(struct nfs4_stid *stid); /* Locking: */ @@ -463,8 +464,8 @@ static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) __nfs4_file_put_access(fp, O_RDONLY); } -static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct -kmem_cache *slab) +static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, + struct kmem_cache *slab) { struct idr *stateids = &cl->cl_stateids; struct nfs4_stid *stid; @@ -500,7 +501,26 @@ out_free: static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp) { - return openlockstateid(nfs4_alloc_stid(clp, stateid_slab)); + struct nfs4_stid *stid; + struct nfs4_ol_stateid *stp; + + stid = nfs4_alloc_stid(clp, stateid_slab); + if (!stid) + return NULL; + + stp = openlockstateid(stid); + stp->st_stid.sc_free = nfs4_free_ol_stateid; + return stp; +} + +static void nfs4_free_deleg(struct nfs4_stid *stid) +{ + struct nfs4_delegation *dp = delegstateid(stid); + + if (dp->dl_file) + put_nfs4_file(dp->dl_file); + kmem_cache_free(deleg_slab, stid); + atomic_long_dec(&num_delegations); } /* @@ -594,6 +614,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh) dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); if (dp == NULL) goto out_dec; + + dp->dl_stid.sc_free = nfs4_free_deleg; /* * delegation seqid's are never incremented. The 4.1 special * meaning of seqid 0 isn't meaningful, really, but let's avoid @@ -611,28 +633,15 @@ out_dec: return NULL; } -static void remove_stid(struct nfs4_stid *s) -{ - struct idr *stateids = &s->sc_client->cl_stateids; - - idr_remove(stateids, s->sc_stateid.si_opaque.so_id); -} - -static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s) -{ - kmem_cache_free(slab, s); -} - void -nfs4_put_delegation(struct nfs4_delegation *dp) +nfs4_put_stid(struct nfs4_stid *s) { - if (atomic_dec_and_test(&dp->dl_stid.sc_count)) { - if (dp->dl_file) - put_nfs4_file(dp->dl_file); - remove_stid(&dp->dl_stid); - nfs4_free_stid(deleg_slab, &dp->dl_stid); - atomic_long_dec(&num_delegations); - } + struct nfs4_client *clp = s->sc_client; + + if (!atomic_dec_and_test(&s->sc_count)) + return; + idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); + s->sc_free(s); } static void nfs4_put_deleg_lease(struct nfs4_file *fp) @@ -689,7 +698,7 @@ static void destroy_delegation(struct nfs4_delegation *dp) spin_lock(&state_lock); unhash_delegation_locked(dp); spin_unlock(&state_lock); - nfs4_put_delegation(dp); + nfs4_put_stid(&dp->dl_stid); } static void revoke_delegation(struct nfs4_delegation *dp) @@ -699,7 +708,7 @@ static void revoke_delegation(struct nfs4_delegation *dp) WARN_ON(!list_empty(&dp->dl_recall_lru)); if (clp->cl_minorversion == 0) - nfs4_put_delegation(dp); + nfs4_put_stid(&dp->dl_stid); else { dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; spin_lock(&clp->cl_lock); @@ -885,17 +894,14 @@ static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) list_del(&stp->st_perstateowner); } -static void close_generic_stateid(struct nfs4_ol_stateid *stp) +static void nfs4_free_ol_stateid(struct nfs4_stid *stid) { - release_all_access(stp); -} + struct nfs4_ol_stateid *stp = openlockstateid(stid); -static void free_generic_stateid(struct nfs4_ol_stateid *stp) -{ + release_all_access(stp); if (stp->st_file) put_nfs4_file(stp->st_file); - remove_stid(&stp->st_stid); - nfs4_free_stid(stateid_slab, &stp->st_stid); + kmem_cache_free(stateid_slab, stid); } static void __release_lock_stateid(struct nfs4_ol_stateid *stp) @@ -908,8 +914,7 @@ static void __release_lock_stateid(struct nfs4_ol_stateid *stp) file = find_any_file(stp->st_file); if (file) filp_close(file, (fl_owner_t)lockowner(stp->st_stateowner)); - close_generic_stateid(stp); - free_generic_stateid(stp); + nfs4_put_stid(&stp->st_stid); } static void unhash_lockowner(struct nfs4_lockowner *lo) @@ -966,13 +971,12 @@ static void unhash_open_stateid(struct nfs4_ol_stateid *stp) { unhash_generic_stateid(stp); release_open_stateid_locks(stp); - close_generic_stateid(stp); } static void release_open_stateid(struct nfs4_ol_stateid *stp) { unhash_open_stateid(stp); - free_generic_stateid(stp); + nfs4_put_stid(&stp->st_stid); } static void unhash_openowner(struct nfs4_openowner *oo) @@ -993,7 +997,7 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo) struct nfs4_ol_stateid *s = oo->oo_last_closed_stid; if (s) { - free_generic_stateid(s); + nfs4_put_stid(&s->st_stid); oo->oo_last_closed_stid = NULL; } } @@ -1467,12 +1471,12 @@ destroy_client(struct nfs4_client *clp) while (!list_empty(&reaplist)) { dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); list_del_init(&dp->dl_recall_lru); - nfs4_put_delegation(dp); + nfs4_put_stid(&dp->dl_stid); } while (!list_empty(&clp->cl_revoked)) { dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); list_del_init(&dp->dl_recall_lru); - nfs4_put_delegation(dp); + nfs4_put_stid(&dp->dl_stid); } while (!list_empty(&clp->cl_openowners)) { oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); @@ -3588,7 +3592,7 @@ out_unlock: spin_unlock(&state_lock); out: if (status) { - nfs4_put_delegation(dp); + nfs4_put_stid(&dp->dl_stid); return ERR_PTR(status); } return dp; @@ -3818,7 +3822,7 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status) if (open->op_file) nfsd4_free_file(open->op_file); if (open->op_stp) - free_generic_stateid(open->op_stp); + nfs4_put_stid(&open->op_stp->st_stid); } __be32 @@ -4266,7 +4270,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, spin_lock(&cl->cl_lock); list_del_init(&dp->dl_recall_lru); spin_unlock(&cl->cl_lock); - nfs4_put_delegation(dp); + nfs4_put_stid(s); ret = nfs_ok; break; default: @@ -4477,19 +4481,22 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) unhash_open_stateid(s); if (clp->cl_minorversion) { - free_generic_stateid(s); if (list_empty(&oo->oo_owner.so_stateids)) release_openowner(oo); + nfs4_put_stid(&s->st_stid); } else { + /* + * In the 4.0 case we need to keep the owners around a + * little while to handle CLOSE replay. We still do need + * to release any file access that is held by them + * before returning however. + */ + release_all_access(s); if (s->st_file) { put_nfs4_file(s->st_file); s->st_file = NULL; } oo->oo_last_closed_stid = s; - /* - * In the 4.0 case we need to keep the owners around a - * little while to handle CLOSE replay. - */ if (list_empty(&oo->oo_owner.so_stateids)) move_to_close_lru(oo, clp->net); } @@ -5665,7 +5672,7 @@ nfs4_state_shutdown_net(struct net *net) list_for_each_safe(pos, next, &reaplist) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); list_del_init(&dp->dl_recall_lru); - nfs4_put_delegation(dp); + nfs4_put_stid(&dp->dl_stid); } nfsd4_client_tracking_exit(net); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 39747736e83..32c466265ac 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -85,6 +85,7 @@ struct nfs4_stid { unsigned char sc_type; stateid_t sc_stateid; struct nfs4_client *sc_client; + void (*sc_free)(struct nfs4_stid *); }; struct nfs4_delegation { @@ -429,6 +430,7 @@ extern __be32 nfs4_preprocess_stateid_op(struct net *net, stateid_t *stateid, int flags, struct file **filp); extern void nfs4_lock_state(void); extern void nfs4_unlock_state(void); +void nfs4_put_stid(struct nfs4_stid *s); void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *); extern void nfs4_release_reclaim(struct nfsd_net *); extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, @@ -446,7 +448,6 @@ extern int nfsd4_create_callback_queue(void); extern void nfsd4_destroy_callback_queue(void); extern void nfsd4_shutdown_callback(struct nfs4_client *); extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp); -extern void nfs4_put_delegation(struct nfs4_delegation *dp); extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn); extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn); -- cgit v1.2.3-70-g09d2 From 11b9164adad7cd119b82b1f2c911a6d9bc67f1cc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 29 Jul 2014 21:34:08 -0400 Subject: nfsd: Add a struct nfs4_file field to struct nfs4_stid All stateids are associated with a nfs4_file. Let's consolidate. Replace delegation->dl_file with the dl_stid.sc_file, and nfs4_ol_stateid->st_file with st_stid.sc_file. Signed-off-by: Trond Myklebust Reviewed-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 2 +- fs/nfsd/nfs4state.c | 69 +++++++++++++++++++++++++------------------------- fs/nfsd/state.h | 3 +-- 3 files changed, 36 insertions(+), 38 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 8574c708cf8..e0be57b0f79 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -337,7 +337,7 @@ static void encode_cb_recall4args(struct xdr_stream *xdr, p = xdr_reserve_space(xdr, 4); *p++ = xdr_zero; /* truncate */ - encode_nfs_fh4(xdr, &dp->dl_file->fi_fhandle); + encode_nfs_fh4(xdr, &dp->dl_stid.sc_file->fi_fhandle); hdr->nops++; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 60ab22b6e09..344cd1ac3f6 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -515,10 +515,6 @@ static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp) static void nfs4_free_deleg(struct nfs4_stid *stid) { - struct nfs4_delegation *dp = delegstateid(stid); - - if (dp->dl_file) - put_nfs4_file(dp->dl_file); kmem_cache_free(deleg_slab, stid); atomic_long_dec(&num_delegations); } @@ -636,12 +632,15 @@ out_dec: void nfs4_put_stid(struct nfs4_stid *s) { + struct nfs4_file *fp = s->sc_file; struct nfs4_client *clp = s->sc_client; if (!atomic_dec_and_test(&s->sc_count)) return; idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); s->sc_free(s); + if (fp) + put_nfs4_file(fp); } static void nfs4_put_deleg_lease(struct nfs4_file *fp) @@ -677,7 +676,7 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) static void unhash_delegation_locked(struct nfs4_delegation *dp) { - struct nfs4_file *fp = dp->dl_file; + struct nfs4_file *fp = dp->dl_stid.sc_file; lockdep_assert_held(&state_lock); @@ -864,7 +863,7 @@ reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) /* Recalculate per-file deny mode if there was a change */ if (change) - recalculate_deny_mode(stp->st_file); + recalculate_deny_mode(stp->st_stid.sc_file); } /* release all access and file references for a given stateid */ @@ -872,21 +871,21 @@ static void release_all_access(struct nfs4_ol_stateid *stp) { int i; - struct nfs4_file *fp = stp->st_file; + struct nfs4_file *fp = stp->st_stid.sc_file; if (fp && stp->st_deny_bmap != 0) recalculate_deny_mode(fp); for (i = 1; i < 4; i++) { if (test_access(i, stp)) - nfs4_file_put_access(stp->st_file, i); + nfs4_file_put_access(stp->st_stid.sc_file, i); clear_access(i, stp); } } static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) { - struct nfs4_file *fp = stp->st_file; + struct nfs4_file *fp = stp->st_stid.sc_file; spin_lock(&fp->fi_lock); list_del(&stp->st_perfile); @@ -899,8 +898,6 @@ static void nfs4_free_ol_stateid(struct nfs4_stid *stid) struct nfs4_ol_stateid *stp = openlockstateid(stid); release_all_access(stp); - if (stp->st_file) - put_nfs4_file(stp->st_file); kmem_cache_free(stateid_slab, stid); } @@ -911,7 +908,7 @@ static void __release_lock_stateid(struct nfs4_ol_stateid *stp) list_del(&stp->st_locks); unhash_generic_stateid(stp); unhash_stid(&stp->st_stid); - file = find_any_file(stp->st_file); + file = find_any_file(stp->st_stid.sc_file); if (file) filp_close(file, (fl_owner_t)lockowner(stp->st_stateowner)); nfs4_put_stid(&stp->st_stid); @@ -2976,7 +2973,7 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); stp->st_stateowner = &oo->oo_owner; get_nfs4_file(fp); - stp->st_file = fp; + stp->st_stid.sc_file = fp; stp->st_access_bmap = 0; stp->st_deny_bmap = 0; stp->st_openstp = NULL; @@ -3097,10 +3094,10 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp) { - struct nfs4_client *clp = dp->dl_stid.sc_client; - struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, + nfsd_net_id); - block_delegations(&dp->dl_file->fi_fhandle); + block_delegations(&dp->dl_stid.sc_file->fi_fhandle); /* * We can't do this in nfsd_break_deleg_cb because it is @@ -3508,7 +3505,7 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag) static int nfs4_setlease(struct nfs4_delegation *dp) { - struct nfs4_file *fp = dp->dl_file; + struct nfs4_file *fp = dp->dl_stid.sc_file; struct file_lock *fl; struct file *filp; int status = 0; @@ -3573,7 +3570,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, get_nfs4_file(fp); spin_lock(&state_lock); spin_lock(&fp->fi_lock); - dp->dl_file = fp; + dp->dl_stid.sc_file = fp; if (!fp->fi_lease) { spin_unlock(&fp->fi_lock); spin_unlock(&state_lock); @@ -3669,7 +3666,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, default: goto out_no_deleg; } - dp = nfs4_set_delegation(clp, fh, stp->st_file); + dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file); if (IS_ERR(dp)) goto out_no_deleg; @@ -3959,7 +3956,7 @@ laundromat_main(struct work_struct *laundry) static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) { - if (!nfsd_fh_match(&fhp->fh_handle, &stp->st_file->fi_fhandle)) + if (!nfsd_fh_match(&fhp->fh_handle, &stp->st_stid.sc_file->fi_fhandle)) return nfserr_bad_stateid; return nfs_ok; } @@ -4167,7 +4164,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, if (status) goto out; if (filpp) { - file = dp->dl_file->fi_deleg_file; + file = dp->dl_stid.sc_file->fi_deleg_file; if (!file) { WARN_ON_ONCE(1); status = nfserr_serverfault; @@ -4189,10 +4186,12 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, if (status) goto out; if (filpp) { + struct nfs4_file *fp = stp->st_stid.sc_file; + if (flags & RD_STATE) - file = find_readable_file(stp->st_file); + file = find_readable_file(fp); else - file = find_writeable_file(stp->st_file); + file = find_writeable_file(fp); } break; default: @@ -4212,7 +4211,7 @@ nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp) { struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); - if (check_for_locks(stp->st_file, lo)) + if (check_for_locks(stp->st_stid.sc_file, lo)) return nfserr_locks_held; release_lockowner_if_empty(lo); return nfs_ok; @@ -4403,7 +4402,7 @@ static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 a { if (!test_access(access, stp)) return; - nfs4_file_put_access(stp->st_file, access); + nfs4_file_put_access(stp->st_stid.sc_file, access); clear_access(access, stp); } @@ -4492,9 +4491,9 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) * before returning however. */ release_all_access(s); - if (s->st_file) { - put_nfs4_file(s->st_file); - s->st_file = NULL; + if (s->st_stid.sc_file) { + put_nfs4_file(s->st_stid.sc_file); + s->st_stid.sc_file = NULL; } oo->oo_last_closed_stid = s; if (list_empty(&oo->oo_owner.so_stateids)) @@ -4695,7 +4694,7 @@ alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); stp->st_stateowner = &lo->lo_owner; get_nfs4_file(fp); - stp->st_file = fp; + stp->st_stid.sc_file = fp; stp->st_access_bmap = 0; stp->st_deny_bmap = open_stp->st_deny_bmap; stp->st_openstp = open_stp; @@ -4712,7 +4711,7 @@ find_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp) struct nfs4_ol_stateid *lst; list_for_each_entry(lst, &lo->lo_owner.so_stateids, st_perstateowner) { - if (lst->st_file == fp) + if (lst->st_stid.sc_file == fp) return lst; } return NULL; @@ -4728,7 +4727,7 @@ check_lock_length(u64 offset, u64 length) static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) { - struct nfs4_file *fp = lock_stp->st_file; + struct nfs4_file *fp = lock_stp->st_stid.sc_file; lockdep_assert_held(&fp->fi_lock); @@ -4740,7 +4739,7 @@ static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) { - struct nfs4_file *fi = ost->st_file; + struct nfs4_file *fi = ost->st_stid.sc_file; struct nfs4_openowner *oo = openowner(ost->st_stateowner); struct nfs4_client *cl = oo->oo_owner.so_client; struct inode *inode = cstate->current_fh.fh_dentry->d_inode; @@ -4865,7 +4864,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, goto out; } - fp = lock_stp->st_file; + fp = lock_stp->st_stid.sc_file; locks_init_lock(file_lock); switch (lock->lk_type) { case NFS4_READ_LT: @@ -5065,7 +5064,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, &stp, nn); if (status) goto out; - filp = find_any_file(stp->st_file); + filp = find_any_file(stp->st_stid.sc_file); if (!filp) { status = nfserr_lock_range; goto out; @@ -5188,7 +5187,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, lo = lockowner(sop); /* see if there are still any locks associated with it */ list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { - if (check_for_locks(stp->st_file, lo)) + if (check_for_locks(stp->st_stid.sc_file, lo)) goto out; } diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 32c466265ac..af1d9c42e93 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -85,6 +85,7 @@ struct nfs4_stid { unsigned char sc_type; stateid_t sc_stateid; struct nfs4_client *sc_client; + struct nfs4_file *sc_file; void (*sc_free)(struct nfs4_stid *); }; @@ -93,7 +94,6 @@ struct nfs4_delegation { struct list_head dl_perfile; struct list_head dl_perclnt; struct list_head dl_recall_lru; /* delegation recalled */ - struct nfs4_file *dl_file; u32 dl_type; time_t dl_time; /* For recall: */ @@ -407,7 +407,6 @@ struct nfs4_ol_stateid { struct list_head st_perstateowner; struct list_head st_locks; struct nfs4_stateowner * st_stateowner; - struct nfs4_file * st_file; unsigned char st_access_bmap; unsigned char st_deny_bmap; struct nfs4_ol_stateid * st_openstp; -- cgit v1.2.3-70-g09d2 From 444b6e910d2a637cc144c74b15efd1b61bf737bb Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 23 Sep 2014 08:58:48 +0200 Subject: nfsd: fix nfsd4_cb_recall_done error handling For any error that is not EBADHANDLE or NFS4ERR_BAD_STATEID, nfsd4_cb_recall_done first marks the connection down, then retries until dl_retries hits zero, then marks the connection down again and sets cb_done. This changes the code to only retry for EBADHANDLE or NFS4ERR_BAD_STATEID, and factors setting cb_done into a single point in the function. Signed-off-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index e0be57b0f79..795e218a2a9 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -874,24 +874,21 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) return; switch (task->tk_status) { case 0: - cb->cb_done = true; - return; + break; case -EBADHANDLE: case -NFS4ERR_BAD_STATEID: /* Race: client probably got cb_recall * before open reply granting delegation */ - break; + if (dp->dl_retries--) { + rpc_delay(task, 2*HZ); + task->tk_status = 0; + rpc_restart_call_prepare(task); + return; + } default: /* Network partition? */ nfsd4_mark_cb_down(clp, task->tk_status); } - if (dp->dl_retries--) { - rpc_delay(task, 2*HZ); - task->tk_status = 0; - rpc_restart_call_prepare(task); - return; - } - nfsd4_mark_cb_down(clp, task->tk_status); cb->cb_done = true; } -- cgit v1.2.3-70-g09d2 From 341b51df1fef0a39d792fb1c7d7856cf142627ab Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Tue, 23 Sep 2014 08:58:49 +0200 Subject: nfsd: do not clear rpc_resp in nfsd4_cb_done_sequence This is incorrect when a callback is has to be restarted, in which case the XDR decoding of the second iteration will see a NULL cb argument. [hch: updated description] Signed-off-by: Benny Halevy Signed-off-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 795e218a2a9..fc07084e822 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -847,9 +847,6 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) rpc_wake_up_next(&clp->cl_cb_waitq); dprintk("%s: freed slot, new seqid=%d\n", __func__, clp->cl_cb_session->se_cb_seq_nr); - - /* We're done looking into the sequence information */ - task->tk_msg.rpc_resp = NULL; } } -- cgit v1.2.3-70-g09d2 From 2faf3b43507556bd80e5274270db1fce1408f4ff Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 24 Sep 2014 12:19:16 +0200 Subject: nfsd: remove nfsd4_callback.cb_op We can always get at the private data by using container_of, no need for a void pointer. Also introduce a little to_delegation helper to avoid opencoding the container_of everywhere. Signed-off-by: Christoph Hellwig Reviewed-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 17 +++++++++-------- fs/nfsd/state.h | 1 - 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index fc07084e822..06e07e18ea7 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -55,6 +55,9 @@ enum { NFSPROC4_CLNT_CB_SEQUENCE, }; +#define to_delegation(cb) \ + container_of(cb, struct nfs4_delegation, dl_recall) + struct nfs4_cb_compound_hdr { /* args */ u32 ident; /* minorversion 0 only */ @@ -494,7 +497,7 @@ static void nfs4_xdr_enc_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr, static void nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, struct xdr_stream *xdr, const struct nfsd4_callback *cb) { - const struct nfs4_delegation *args = cb->cb_op; + const struct nfs4_delegation *dp = to_delegation(cb); struct nfs4_cb_compound_hdr hdr = { .ident = cb->cb_clp->cl_cb_ident, .minorversion = cb->cb_minorversion, @@ -502,7 +505,7 @@ static void nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, struct xdr_stream *xdr, encode_cb_compound4args(xdr, &hdr); encode_cb_sequence4args(xdr, cb, &hdr); - encode_cb_recall4args(xdr, args, &hdr); + encode_cb_recall4args(xdr, dp, &hdr); encode_cb_nops(&hdr); } @@ -755,7 +758,6 @@ static void do_probe_callback(struct nfs4_client *clp) { struct nfsd4_callback *cb = &clp->cl_cb_null; - cb->cb_op = NULL; cb->cb_clp = clp; cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL]; @@ -850,11 +852,10 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) } } - static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) { struct nfsd4_callback *cb = calldata; - struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); + struct nfs4_delegation *dp = to_delegation(cb); struct nfs4_client *clp = cb->cb_clp; struct rpc_clnt *current_rpc_client = clp->cl_cb_client; @@ -893,9 +894,10 @@ static void nfsd4_cb_recall_release(void *calldata) { struct nfsd4_callback *cb = calldata; struct nfs4_client *clp = cb->cb_clp; - struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); if (cb->cb_done) { + struct nfs4_delegation *dp = to_delegation(cb); + spin_lock(&clp->cl_lock); list_del(&cb->cb_per_client); spin_unlock(&clp->cl_lock); @@ -1040,7 +1042,7 @@ nfsd4_run_cb_recall(struct work_struct *w) struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work); - nfsd4_prepare_cb_recall(cb->cb_op); + nfsd4_prepare_cb_recall(to_delegation(cb)); nfsd4_run_callback_rpc(cb); } @@ -1050,7 +1052,6 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp) struct nfs4_client *clp = dp->dl_stid.sc_client; dp->dl_retries = 1; - cb->cb_op = dp; cb->cb_clp = clp; cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL]; cb->cb_msg.rpc_argp = cb; diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 62a82ab06cf..57d2db63a1e 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -62,7 +62,6 @@ typedef struct { (s)->si_generation struct nfsd4_callback { - void *cb_op; struct nfs4_client *cb_clp; struct list_head cb_per_client; u32 cb_minorversion; -- cgit v1.2.3-70-g09d2 From 326129d02aea8efa1dfd1a210653a744e7c85239 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 24 Sep 2014 12:19:17 +0200 Subject: nfsd: introduce a generic nfsd4_cb Add a helper to queue up a callback. CB_NULL has a bit of special casing because it is special in the specification, but all other new callback operations will be able to share code with this and a few more changes to refactor the callback code. Signed-off-by: Christoph Hellwig Reviewed-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 43 ++++++++++--------------------------------- fs/nfsd/nfs4state.c | 4 +++- fs/nfsd/state.h | 10 +++++++++- 3 files changed, 22 insertions(+), 35 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 06e07e18ea7..03d9f4f298e 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -49,12 +49,6 @@ static void nfsd4_mark_cb_fault(struct nfs4_client *, int reason); /* Index of predefined Linux callback client operations */ -enum { - NFSPROC4_CLNT_CB_NULL = 0, - NFSPROC4_CLNT_CB_RECALL, - NFSPROC4_CLNT_CB_SEQUENCE, -}; - #define to_delegation(cb) \ container_of(cb, struct nfs4_delegation, dl_recall) @@ -749,24 +743,9 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = { static struct workqueue_struct *callback_wq; -static void run_nfsd4_cb(struct nfsd4_callback *cb) -{ - queue_work(callback_wq, &cb->cb_work); -} - static void do_probe_callback(struct nfs4_client *clp) { - struct nfsd4_callback *cb = &clp->cl_cb_null; - - cb->cb_clp = clp; - - cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL]; - cb->cb_msg.rpc_argp = NULL; - cb->cb_msg.rpc_resp = NULL; - - cb->cb_ops = &nfsd4_cb_probe_ops; - - run_nfsd4_cb(cb); + return nfsd4_cb(&clp->cl_cb_null, clp, NFSPROC4_CLNT_CB_NULL); } /* @@ -1005,7 +984,7 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) } /* Yay, the callback channel's back! Restart any callbacks: */ list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client) - run_nfsd4_cb(cb); + queue_work(callback_wq, &cb->cb_work); } static void @@ -1046,21 +1025,19 @@ nfsd4_run_cb_recall(struct work_struct *w) nfsd4_run_callback_rpc(cb); } -void nfsd4_cb_recall(struct nfs4_delegation *dp) +void nfsd4_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, + enum nfsd4_cb_op op) { - struct nfsd4_callback *cb = &dp->dl_recall; - struct nfs4_client *clp = dp->dl_stid.sc_client; - - dp->dl_retries = 1; cb->cb_clp = clp; - cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL]; + cb->cb_msg.rpc_proc = &nfs4_cb_procedures[op]; cb->cb_msg.rpc_argp = cb; cb->cb_msg.rpc_resp = cb; - - cb->cb_ops = &nfsd4_cb_recall_ops; - + if (op == NFSPROC4_CLNT_CB_NULL) + cb->cb_ops = &nfsd4_cb_probe_ops; + else + cb->cb_ops = &nfsd4_cb_recall_ops; INIT_LIST_HEAD(&cb->cb_per_client); cb->cb_done = true; - run_nfsd4_cb(&dp->dl_recall); + queue_work(callback_wq, &cb->cb_work); } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ec24272529a..ae9846b976b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3388,7 +3388,9 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp) * it's safe to take a reference. */ atomic_inc(&dp->dl_stid.sc_count); - nfsd4_cb_recall(dp); + dp->dl_retries = 1; + nfsd4_cb(&dp->dl_recall, dp->dl_stid.sc_client, + NFSPROC4_CLNT_CB_RECALL); } /* Called from break_lease() with i_lock held. */ diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 57d2db63a1e..5fb6ab17f38 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -517,6 +517,13 @@ static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) #define RD_STATE 0x00000010 #define WR_STATE 0x00000020 +enum nfsd4_cb_op { + NFSPROC4_CLNT_CB_NULL = 0, + NFSPROC4_CLNT_CB_RECALL, + NFSPROC4_CLNT_CB_SEQUENCE, +}; + + struct nfsd4_compound_state; struct nfsd_net; @@ -536,7 +543,8 @@ void nfsd4_run_cb_recall(struct work_struct *w); extern void nfsd4_probe_callback(struct nfs4_client *clp); extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); -extern void nfsd4_cb_recall(struct nfs4_delegation *dp); +extern void nfsd4_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, + enum nfsd4_cb_op op); extern int nfsd4_create_callback_queue(void); extern void nfsd4_destroy_callback_queue(void); extern void nfsd4_shutdown_callback(struct nfs4_client *); -- cgit v1.2.3-70-g09d2 From f0b5de1b6b8b66552bcc7ae692f45940d411cf05 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 24 Sep 2014 12:19:18 +0200 Subject: nfsd: split nfsd4_callback initialization and use Split out initializing the nfs4_callback structure from using it. For the NULL callback this gets rid of tons of pointless re-initializations. Note that I don't quite understand what protects us from running multiple NULL callbacks at the same time, but at least this chance doesn't make it worse.. Signed-off-by: Christoph Hellwig Reviewed-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 14 ++++++-------- fs/nfsd/nfs4state.c | 8 +++++--- fs/nfsd/state.h | 3 ++- 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 03d9f4f298e..d97e2009e31 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -743,11 +743,6 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = { static struct workqueue_struct *callback_wq; -static void do_probe_callback(struct nfs4_client *clp) -{ - return nfsd4_cb(&clp->cl_cb_null, clp, NFSPROC4_CLNT_CB_NULL); -} - /* * Poke the callback thread to process any updates to the callback * parameters, and send a null probe. @@ -756,7 +751,7 @@ void nfsd4_probe_callback(struct nfs4_client *clp) { clp->cl_cb_state = NFSD4_CB_UNKNOWN; set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags); - do_probe_callback(clp); + nfsd4_run_cb(&clp->cl_cb_null); } void nfsd4_probe_callback_sync(struct nfs4_client *clp) @@ -912,7 +907,7 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp) * instead, nfsd4_run_cb_null() will detect the killed * client, destroy the rpc client, and stop: */ - do_probe_callback(clp); + nfsd4_run_cb(&clp->cl_cb_null); flush_workqueue(callback_wq); } @@ -1025,7 +1020,7 @@ nfsd4_run_cb_recall(struct work_struct *w) nfsd4_run_callback_rpc(cb); } -void nfsd4_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, +void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, enum nfsd4_cb_op op) { cb->cb_clp = clp; @@ -1038,6 +1033,9 @@ void nfsd4_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, cb->cb_ops = &nfsd4_cb_recall_ops; INIT_LIST_HEAD(&cb->cb_per_client); cb->cb_done = true; +} +void nfsd4_run_cb(struct nfsd4_callback *cb) +{ queue_work(callback_wq, &cb->cb_work); } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ae9846b976b..a0ead0c5726 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -645,6 +645,9 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh) INIT_LIST_HEAD(&dp->dl_perclnt); INIT_LIST_HEAD(&dp->dl_recall_lru); dp->dl_type = NFS4_OPEN_DELEGATE_READ; + dp->dl_retries = 1; + nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, + NFSPROC4_CLNT_CB_RECALL); INIT_WORK(&dp->dl_recall.cb_work, nfsd4_run_cb_recall); return dp; out_dec: @@ -1869,6 +1872,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, free_client(clp); return NULL; } + nfsd4_init_cb(&clp->cl_cb_null, clp, NFSPROC4_CLNT_CB_NULL); INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_run_cb_null); clp->cl_time = get_seconds(); clear_bit(0, &clp->cl_cb_slot_busy); @@ -3388,9 +3392,7 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp) * it's safe to take a reference. */ atomic_inc(&dp->dl_stid.sc_count); - dp->dl_retries = 1; - nfsd4_cb(&dp->dl_recall, dp->dl_stid.sc_client, - NFSPROC4_CLNT_CB_RECALL); + nfsd4_run_cb(&dp->dl_recall); } /* Called from break_lease() with i_lock held. */ diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 5fb6ab17f38..3c3a1903b4f 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -543,8 +543,9 @@ void nfsd4_run_cb_recall(struct work_struct *w); extern void nfsd4_probe_callback(struct nfs4_client *clp); extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); -extern void nfsd4_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, +extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, enum nfsd4_cb_op op); +extern void nfsd4_run_cb(struct nfsd4_callback *cb); extern int nfsd4_create_callback_queue(void); extern void nfsd4_destroy_callback_queue(void); extern void nfsd4_shutdown_callback(struct nfs4_client *); -- cgit v1.2.3-70-g09d2 From 0162ac2b978e18792fa8cf3c0b4304321b4a3983 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 24 Sep 2014 12:19:19 +0200 Subject: nfsd: introduce nfsd4_callback_ops Add a higher level abstraction than the rpc_ops for callback operations. Signed-off-by: Christoph Hellwig Reviewed-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4callback.c | 91 ++++++++++++++++---------------------------------- fs/nfsd/nfs4state.c | 51 +++++++++++++++++++++++++--- fs/nfsd/state.h | 12 ++++--- 3 files changed, 83 insertions(+), 71 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index d97e2009e31..4fe4be1ee82 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -824,18 +824,8 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) dprintk("%s: freed slot, new seqid=%d\n", __func__, clp->cl_cb_session->se_cb_seq_nr); } -} -static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) -{ - struct nfsd4_callback *cb = calldata; - struct nfs4_delegation *dp = to_delegation(cb); - struct nfs4_client *clp = cb->cb_clp; - struct rpc_clnt *current_rpc_client = clp->cl_cb_client; - - nfsd4_cb_done(task, calldata); - - if (current_rpc_client != task->tk_client) { + if (clp->cl_cb_client != task->tk_client) { /* We're shutting down or changing cl_cb_client; leave * it to nfsd4_process_cb_update to restart the call if * necessary. */ @@ -844,45 +834,42 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) if (cb->cb_done) return; - switch (task->tk_status) { + + switch (cb->cb_ops->done(cb, task)) { case 0: + task->tk_status = 0; + rpc_restart_call_prepare(task); + return; + case 1: break; - case -EBADHANDLE: - case -NFS4ERR_BAD_STATEID: - /* Race: client probably got cb_recall - * before open reply granting delegation */ - if (dp->dl_retries--) { - rpc_delay(task, 2*HZ); - task->tk_status = 0; - rpc_restart_call_prepare(task); - return; - } - default: + case -1: /* Network partition? */ nfsd4_mark_cb_down(clp, task->tk_status); + break; + default: + BUG(); } cb->cb_done = true; } -static void nfsd4_cb_recall_release(void *calldata) +static void nfsd4_cb_release(void *calldata) { struct nfsd4_callback *cb = calldata; struct nfs4_client *clp = cb->cb_clp; if (cb->cb_done) { - struct nfs4_delegation *dp = to_delegation(cb); - spin_lock(&clp->cl_lock); list_del(&cb->cb_per_client); spin_unlock(&clp->cl_lock); - nfs4_put_stid(&dp->dl_stid); + + cb->cb_ops->release(cb); } } -static const struct rpc_call_ops nfsd4_cb_recall_ops = { +static const struct rpc_call_ops nfsd4_cb_ops = { .rpc_call_prepare = nfsd4_cb_prepare, - .rpc_call_done = nfsd4_cb_recall_done, - .rpc_release = nfsd4_cb_recall_release, + .rpc_call_done = nfsd4_cb_done, + .rpc_release = nfsd4_cb_release, }; int nfsd4_create_callback_queue(void) @@ -911,12 +898,6 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp) flush_workqueue(callback_wq); } -static void nfsd4_release_cb(struct nfsd4_callback *cb) -{ - if (cb->cb_ops->rpc_release) - cb->cb_ops->rpc_release(cb); -} - /* requires cl_lock: */ static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp) { @@ -983,54 +964,40 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) } static void -nfsd4_run_callback_rpc(struct nfsd4_callback *cb) +nfsd4_run_cb_work(struct work_struct *work) { + struct nfsd4_callback *cb = + container_of(work, struct nfsd4_callback, cb_work); struct nfs4_client *clp = cb->cb_clp; struct rpc_clnt *clnt; + if (cb->cb_ops && cb->cb_ops->prepare) + cb->cb_ops->prepare(cb); + if (clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK) nfsd4_process_cb_update(cb); clnt = clp->cl_cb_client; if (!clnt) { /* Callback channel broken, or client killed; give up: */ - nfsd4_release_cb(cb); + if (cb->cb_ops && cb->cb_ops->release) + cb->cb_ops->release(cb); return; } cb->cb_msg.rpc_cred = clp->cl_cb_cred; rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN, - cb->cb_ops, cb); -} - -void -nfsd4_run_cb_null(struct work_struct *w) -{ - struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, - cb_work); - nfsd4_run_callback_rpc(cb); -} - -void -nfsd4_run_cb_recall(struct work_struct *w) -{ - struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, - cb_work); - - nfsd4_prepare_cb_recall(to_delegation(cb)); - nfsd4_run_callback_rpc(cb); + cb->cb_ops ? &nfsd4_cb_ops : &nfsd4_cb_probe_ops, cb); } void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, - enum nfsd4_cb_op op) + struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op) { cb->cb_clp = clp; cb->cb_msg.rpc_proc = &nfs4_cb_procedures[op]; cb->cb_msg.rpc_argp = cb; cb->cb_msg.rpc_resp = cb; - if (op == NFSPROC4_CLNT_CB_NULL) - cb->cb_ops = &nfsd4_cb_probe_ops; - else - cb->cb_ops = &nfsd4_cb_recall_ops; + cb->cb_ops = ops; + INIT_WORK(&cb->cb_work, nfsd4_run_cb_work); INIT_LIST_HEAD(&cb->cb_per_client); cb->cb_done = true; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index a0ead0c5726..551f32d7f5c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -96,6 +96,8 @@ static struct kmem_cache *deleg_slab; static void free_session(struct nfsd4_session *); +static struct nfsd4_callback_ops nfsd4_cb_recall_ops; + static bool is_session_dead(struct nfsd4_session *ses) { return ses->se_flags & NFS4_SESSION_DEAD; @@ -647,8 +649,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh) dp->dl_type = NFS4_OPEN_DELEGATE_READ; dp->dl_retries = 1; nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, - NFSPROC4_CLNT_CB_RECALL); - INIT_WORK(&dp->dl_recall.cb_work, nfsd4_run_cb_recall); + &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); return dp; out_dec: atomic_long_dec(&num_delegations); @@ -1872,8 +1873,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, free_client(clp); return NULL; } - nfsd4_init_cb(&clp->cl_cb_null, clp, NFSPROC4_CLNT_CB_NULL); - INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_run_cb_null); + nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); clp->cl_time = get_seconds(); clear_bit(0, &clp->cl_cb_slot_busy); copy_verf(clp, verf); @@ -3360,8 +3360,12 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) return ret; } -void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp) +#define cb_to_delegation(cb) \ + container_of(cb, struct nfs4_delegation, dl_recall) + +static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) { + struct nfs4_delegation *dp = cb_to_delegation(cb); struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, nfsd_net_id); @@ -3382,6 +3386,43 @@ void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp) spin_unlock(&state_lock); } +static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, + struct rpc_task *task) +{ + struct nfs4_delegation *dp = cb_to_delegation(cb); + + switch (task->tk_status) { + case 0: + return 1; + case -EBADHANDLE: + case -NFS4ERR_BAD_STATEID: + /* + * Race: client probably got cb_recall before open reply + * granting delegation. + */ + if (dp->dl_retries--) { + rpc_delay(task, 2 * HZ); + return 0; + } + /*FALLTHRU*/ + default: + return -1; + } +} + +static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) +{ + struct nfs4_delegation *dp = cb_to_delegation(cb); + + nfs4_put_stid(&dp->dl_stid); +} + +static struct nfsd4_callback_ops nfsd4_cb_recall_ops = { + .prepare = nfsd4_cb_recall_prepare, + .done = nfsd4_cb_recall_done, + .release = nfsd4_cb_recall_release, +}; + static void nfsd_break_one_deleg(struct nfs4_delegation *dp) { /* diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 3c3a1903b4f..bf52dc7b15e 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -66,11 +66,17 @@ struct nfsd4_callback { struct list_head cb_per_client; u32 cb_minorversion; struct rpc_message cb_msg; - const struct rpc_call_ops *cb_ops; + struct nfsd4_callback_ops *cb_ops; struct work_struct cb_work; bool cb_done; }; +struct nfsd4_callback_ops { + void (*prepare)(struct nfsd4_callback *); + int (*done)(struct nfsd4_callback *, struct rpc_task *); + void (*release)(struct nfsd4_callback *); +}; + /* * A core object that represents a "common" stateid. These are generally * embedded within the different (more specific) stateid objects and contain @@ -538,13 +544,11 @@ extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, extern __be32 nfs4_check_open_reclaim(clientid_t *clid, struct nfsd4_compound_state *cstate, struct nfsd_net *nn); extern int set_callback_cred(void); -void nfsd4_run_cb_null(struct work_struct *w); -void nfsd4_run_cb_recall(struct work_struct *w); extern void nfsd4_probe_callback(struct nfs4_client *clp); extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, - enum nfsd4_cb_op op); + struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op); extern void nfsd4_run_cb(struct nfsd4_callback *cb); extern int nfsd4_create_callback_queue(void); extern void nfsd4_destroy_callback_queue(void); -- cgit v1.2.3-70-g09d2 From 34549ab09e62db9703811c6ed4715f2ffa1fd7fb Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 1 Oct 2014 08:05:22 -0400 Subject: nfsd: eliminate "to_delegation" define We now have cb_to_delegation and to_delegation, which do the same thing and are defined separately in different .c files. Move the cb_to_delegation definition into a header file and eliminate the redundant to_delegation definition. Reviewed-by: Christoph Hellwig Signed-off-by: Jeff Layton --- fs/nfsd/nfs4callback.c | 5 +---- fs/nfsd/nfs4state.c | 3 --- fs/nfsd/state.h | 3 +++ 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'fs/nfsd/nfs4callback.c') diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 4fe4be1ee82..ed2b1151b17 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -49,9 +49,6 @@ static void nfsd4_mark_cb_fault(struct nfs4_client *, int reason); /* Index of predefined Linux callback client operations */ -#define to_delegation(cb) \ - container_of(cb, struct nfs4_delegation, dl_recall) - struct nfs4_cb_compound_hdr { /* args */ u32 ident; /* minorversion 0 only */ @@ -491,7 +488,7 @@ static void nfs4_xdr_enc_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr, static void nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, struct xdr_stream *xdr, const struct nfsd4_callback *cb) { - const struct nfs4_delegation *dp = to_delegation(cb); + const struct nfs4_delegation *dp = cb_to_delegation(cb); struct nfs4_cb_compound_hdr hdr = { .ident = cb->cb_clp->cl_cb_ident, .minorversion = cb->cb_minorversion, diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 551f32d7f5c..5c0cac17306 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3360,9 +3360,6 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) return ret; } -#define cb_to_delegation(cb) \ - container_of(cb, struct nfs4_delegation, dl_recall) - static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) { struct nfs4_delegation *dp = cb_to_delegation(cb); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index bf52dc7b15e..0a47c6a6b30 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -132,6 +132,9 @@ struct nfs4_delegation { struct nfsd4_callback dl_recall; }; +#define cb_to_delegation(cb) \ + container_of(cb, struct nfs4_delegation, dl_recall) + /* client delegation callback info */ struct nfs4_cb_conn { /* SETCLIENTID info */ -- cgit v1.2.3-70-g09d2