Skip to content

Commit 38f080f

Browse files
committed
NFSD: Move callback_wq into struct nfs4_client
Commit 8838203 ("nfsd: update workqueue creation") made the callback_wq single-threaded, presumably to protect modifications of cl_cb_client. See documenting comment for nfsd4_process_cb_update(). However, cl_cb_client is per-lease. There's no other reason that all callback operations need to be dispatched via a single thread. The single threading here means all client callbacks can be blocked by a problem with one client. Change the NFSv4 callback client so it serializes per-lease instead of serializing all NFSv4 callback operations on the server. Reported-by: Dai Ngo <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent 56c35f4 commit 38f080f

File tree

3 files changed

+18
-31
lines changed

3 files changed

+18
-31
lines changed

fs/nfsd/nfs4callback.c

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -978,12 +978,12 @@ static int max_cb_time(struct net *net)
978978
return max(((u32)nn->nfsd4_lease)/10, 1u) * HZ;
979979
}
980980

981-
static struct workqueue_struct *callback_wq;
982-
983981
static bool nfsd4_queue_cb(struct nfsd4_callback *cb)
984982
{
985-
trace_nfsd_cb_queue(cb->cb_clp, cb);
986-
return queue_work(callback_wq, &cb->cb_work);
983+
struct nfs4_client *clp = cb->cb_clp;
984+
985+
trace_nfsd_cb_queue(clp, cb);
986+
return queue_work(clp->cl_callback_wq, &cb->cb_work);
987987
}
988988

989989
static void nfsd41_cb_inflight_begin(struct nfs4_client *clp)
@@ -1153,7 +1153,7 @@ void nfsd4_probe_callback(struct nfs4_client *clp)
11531153
void nfsd4_probe_callback_sync(struct nfs4_client *clp)
11541154
{
11551155
nfsd4_probe_callback(clp);
1156-
flush_workqueue(callback_wq);
1156+
flush_workqueue(clp->cl_callback_wq);
11571157
}
11581158

11591159
void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
@@ -1372,19 +1372,6 @@ static const struct rpc_call_ops nfsd4_cb_ops = {
13721372
.rpc_release = nfsd4_cb_release,
13731373
};
13741374

1375-
int nfsd4_create_callback_queue(void)
1376-
{
1377-
callback_wq = alloc_ordered_workqueue("nfsd4_callbacks", 0);
1378-
if (!callback_wq)
1379-
return -ENOMEM;
1380-
return 0;
1381-
}
1382-
1383-
void nfsd4_destroy_callback_queue(void)
1384-
{
1385-
destroy_workqueue(callback_wq);
1386-
}
1387-
13881375
/* must be called under the state lock */
13891376
void nfsd4_shutdown_callback(struct nfs4_client *clp)
13901377
{
@@ -1398,7 +1385,7 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp)
13981385
* client, destroy the rpc client, and stop:
13991386
*/
14001387
nfsd4_run_cb(&clp->cl_cb_null);
1401-
flush_workqueue(callback_wq);
1388+
flush_workqueue(clp->cl_callback_wq);
14021389
nfsd41_cb_inflight_wait_complete(clp);
14031390
}
14041391

@@ -1420,9 +1407,9 @@ static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp)
14201407

14211408
/*
14221409
* Note there isn't a lot of locking in this code; instead we depend on
1423-
* the fact that it is run from the callback_wq, which won't run two
1424-
* work items at once. So, for example, callback_wq handles all access
1425-
* of cl_cb_client and all calls to rpc_create or rpc_shutdown_client.
1410+
* the fact that it is run from clp->cl_callback_wq, which won't run two
1411+
* work items at once. So, for example, clp->cl_callback_wq handles all
1412+
* access of cl_cb_client and all calls to rpc_create or rpc_shutdown_client.
14261413
*/
14271414
static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
14281415
{

fs/nfsd/nfs4state.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2233,6 +2233,10 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name,
22332233
GFP_KERNEL);
22342234
if (!clp->cl_ownerstr_hashtbl)
22352235
goto err_no_hashtbl;
2236+
clp->cl_callback_wq = alloc_ordered_workqueue("nfsd4_callbacks", 0);
2237+
if (!clp->cl_callback_wq)
2238+
goto err_no_callback_wq;
2239+
22362240
for (i = 0; i < OWNER_HASH_SIZE; i++)
22372241
INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]);
22382242
INIT_LIST_HEAD(&clp->cl_sessions);
@@ -2255,6 +2259,8 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name,
22552259
spin_lock_init(&clp->cl_lock);
22562260
rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
22572261
return clp;
2262+
err_no_callback_wq:
2263+
kfree(clp->cl_ownerstr_hashtbl);
22582264
err_no_hashtbl:
22592265
kfree(clp->cl_name.data);
22602266
err_no_name:
@@ -2268,6 +2274,7 @@ static void __free_client(struct kref *k)
22682274
struct nfs4_client *clp = container_of(c, struct nfs4_client, cl_nfsdfs);
22692275

22702276
free_svc_cred(&clp->cl_cred);
2277+
destroy_workqueue(clp->cl_callback_wq);
22712278
kfree(clp->cl_ownerstr_hashtbl);
22722279
kfree(clp->cl_name.data);
22732280
kfree(clp->cl_nii_domain.data);
@@ -8636,12 +8643,6 @@ nfs4_state_start(void)
86368643
if (ret)
86378644
return ret;
86388645

8639-
ret = nfsd4_create_callback_queue();
8640-
if (ret) {
8641-
rhltable_destroy(&nfs4_file_rhltable);
8642-
return ret;
8643-
}
8644-
86458646
set_max_delegations();
86468647
return 0;
86478648
}
@@ -8682,7 +8683,6 @@ nfs4_state_shutdown_net(struct net *net)
86828683
void
86838684
nfs4_state_shutdown(void)
86848685
{
8685-
nfsd4_destroy_callback_queue();
86868686
rhltable_destroy(&nfs4_file_rhltable);
86878687
}
86888688

fs/nfsd/state.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,8 @@ struct nfs4_client {
408408
1 << NFSD4_CLIENT_CB_KILL)
409409
#define NFSD4_CLIENT_CB_RECALL_ANY (6)
410410
unsigned long cl_flags;
411+
412+
struct workqueue_struct *cl_callback_wq;
411413
const struct cred *cl_cb_cred;
412414
struct rpc_clnt *cl_cb_client;
413415
u32 cl_cb_ident;
@@ -735,8 +737,6 @@ extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *
735737
extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
736738
const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op);
737739
extern bool nfsd4_run_cb(struct nfsd4_callback *cb);
738-
extern int nfsd4_create_callback_queue(void);
739-
extern void nfsd4_destroy_callback_queue(void);
740740
extern void nfsd4_shutdown_callback(struct nfs4_client *);
741741
extern void nfsd4_shutdown_copy(struct nfs4_client *clp);
742742
extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name,

0 commit comments

Comments
 (0)