aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/lockd/host.c12
-rw-r--r--include/linux/sunrpc/clnt.h2
-rw-r--r--net/sunrpc/clnt.c57
-rw-r--r--net/sunrpc/rpc_pipe.c2
-rw-r--r--net/sunrpc/sched.c6
5 files changed, 35 insertions, 44 deletions
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 96070bff93fc..c252a1c95857 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -161,15 +161,9 @@ nlm_destroy_host(struct nlm_host *host)
161 */ 161 */
162 nsm_unmonitor(host); 162 nsm_unmonitor(host);
163 163
164 if ((clnt = host->h_rpcclnt) != NULL) { 164 clnt = host->h_rpcclnt;
165 if (atomic_read(&clnt->cl_users)) { 165 if (clnt != NULL)
166 printk(KERN_WARNING 166 rpc_shutdown_client(clnt);
167 "lockd: active RPC handle\n");
168 clnt->cl_dead = 1;
169 } else {
170 rpc_destroy_client(host->h_rpcclnt);
171 }
172 }
173 kfree(host); 167 kfree(host);
174} 168}
175 169
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 2f4b520a7419..003d8ea70c19 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -24,8 +24,8 @@ struct rpc_inode;
24 * The high-level client handle 24 * The high-level client handle
25 */ 25 */
26struct rpc_clnt { 26struct rpc_clnt {
27 struct kref cl_kref; /* Number of references */
27 atomic_t cl_count; /* Number of clones */ 28 atomic_t cl_count; /* Number of clones */
28 atomic_t cl_users; /* number of references */
29 struct list_head cl_clients; /* Global list of clients */ 29 struct list_head cl_clients; /* Global list of clients */
30 struct list_head cl_tasks; /* List of tasks */ 30 struct list_head cl_tasks; /* List of tasks */
31 spinlock_t cl_lock; /* spinlock */ 31 spinlock_t cl_lock; /* spinlock */
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 424dfdc6862c..254a6e1a5770 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -121,7 +121,6 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
121 clnt = kzalloc(sizeof(*clnt), GFP_KERNEL); 121 clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
122 if (!clnt) 122 if (!clnt)
123 goto out_err; 123 goto out_err;
124 atomic_set(&clnt->cl_users, 0);
125 atomic_set(&clnt->cl_count, 1); 124 atomic_set(&clnt->cl_count, 1);
126 clnt->cl_parent = clnt; 125 clnt->cl_parent = clnt;
127 126
@@ -157,6 +156,8 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
157 clnt->cl_rtt = &clnt->cl_rtt_default; 156 clnt->cl_rtt = &clnt->cl_rtt_default;
158 rpc_init_rtt(&clnt->cl_rtt_default, xprt->timeout.to_initval); 157 rpc_init_rtt(&clnt->cl_rtt_default, xprt->timeout.to_initval);
159 158
159 kref_init(&clnt->cl_kref);
160
160 err = rpc_setup_pipedir(clnt, program->pipe_dir_name); 161 err = rpc_setup_pipedir(clnt, program->pipe_dir_name);
161 if (err < 0) 162 if (err < 0)
162 goto out_no_path; 163 goto out_no_path;
@@ -272,10 +273,10 @@ rpc_clone_client(struct rpc_clnt *clnt)
272 if (!new) 273 if (!new)
273 goto out_no_clnt; 274 goto out_no_clnt;
274 atomic_set(&new->cl_count, 1); 275 atomic_set(&new->cl_count, 1);
275 atomic_set(&new->cl_users, 0);
276 new->cl_metrics = rpc_alloc_iostats(clnt); 276 new->cl_metrics = rpc_alloc_iostats(clnt);
277 if (new->cl_metrics == NULL) 277 if (new->cl_metrics == NULL)
278 goto out_no_stats; 278 goto out_no_stats;
279 kref_init(&new->cl_kref);
279 err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); 280 err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
280 if (err != 0) 281 if (err != 0)
281 goto out_no_path; 282 goto out_no_path;
@@ -311,40 +312,28 @@ out_no_clnt:
311int 312int
312rpc_shutdown_client(struct rpc_clnt *clnt) 313rpc_shutdown_client(struct rpc_clnt *clnt)
313{ 314{
314 dprintk("RPC: shutting down %s client for %s, tasks=%d\n", 315 dprintk("RPC: shutting down %s client for %s\n",
315 clnt->cl_protname, clnt->cl_server, 316 clnt->cl_protname, clnt->cl_server);
316 atomic_read(&clnt->cl_users));
317 317
318 while (atomic_read(&clnt->cl_users) > 0) { 318 while (!list_empty(&clnt->cl_tasks)) {
319 /* Don't let rpc_release_client destroy us */ 319 /* Don't let rpc_release_client destroy us */
320 clnt->cl_oneshot = 0; 320 clnt->cl_oneshot = 0;
321 clnt->cl_dead = 0; 321 clnt->cl_dead = 0;
322 rpc_killall_tasks(clnt); 322 rpc_killall_tasks(clnt);
323 wait_event_timeout(destroy_wait, 323 wait_event_timeout(destroy_wait,
324 !atomic_read(&clnt->cl_users), 1*HZ); 324 list_empty(&clnt->cl_tasks), 1*HZ);
325 }
326
327 if (atomic_read(&clnt->cl_users) < 0) {
328 printk(KERN_ERR "RPC: rpc_shutdown_client clnt %p tasks=%d\n",
329 clnt, atomic_read(&clnt->cl_users));
330#ifdef RPC_DEBUG
331 rpc_show_tasks();
332#endif
333 BUG();
334 } 325 }
335 326
336 return rpc_destroy_client(clnt); 327 return rpc_destroy_client(clnt);
337} 328}
338 329
339/* 330/*
340 * Delete an RPC client 331 * Free an RPC client
341 */ 332 */
342int 333static void
343rpc_destroy_client(struct rpc_clnt *clnt) 334rpc_free_client(struct kref *kref)
344{ 335{
345 if (!atomic_dec_and_test(&clnt->cl_count)) 336 struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref);
346 return 1;
347 BUG_ON(atomic_read(&clnt->cl_users) != 0);
348 337
349 dprintk("RPC: destroying %s client for %s\n", 338 dprintk("RPC: destroying %s client for %s\n",
350 clnt->cl_protname, clnt->cl_server); 339 clnt->cl_protname, clnt->cl_server);
@@ -368,23 +357,33 @@ out_free:
368 clnt->cl_metrics = NULL; 357 clnt->cl_metrics = NULL;
369 xprt_put(clnt->cl_xprt); 358 xprt_put(clnt->cl_xprt);
370 kfree(clnt); 359 kfree(clnt);
371 return 0;
372} 360}
373 361
374/* 362/*
375 * Release an RPC client 363 * Release reference to the RPC client
376 */ 364 */
377void 365void
378rpc_release_client(struct rpc_clnt *clnt) 366rpc_release_client(struct rpc_clnt *clnt)
379{ 367{
380 dprintk("RPC: rpc_release_client(%p, %d)\n", 368 dprintk("RPC: rpc_release_client(%p)\n", clnt);
381 clnt, atomic_read(&clnt->cl_users));
382 369
383 if (!atomic_dec_and_test(&clnt->cl_users)) 370 if (list_empty(&clnt->cl_tasks))
384 return; 371 wake_up(&destroy_wait);
385 wake_up(&destroy_wait);
386 if (clnt->cl_oneshot || clnt->cl_dead) 372 if (clnt->cl_oneshot || clnt->cl_dead)
387 rpc_destroy_client(clnt); 373 rpc_destroy_client(clnt);
374 kref_put(&clnt->cl_kref, rpc_free_client);
375}
376
377/*
378 * Delete an RPC client
379 */
380int
381rpc_destroy_client(struct rpc_clnt *clnt)
382{
383 if (!atomic_dec_and_test(&clnt->cl_count))
384 return 1;
385 kref_put(&clnt->cl_kref, rpc_free_client);
386 return 0;
388} 387}
389 388
390/** 389/**
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 5887457dc936..826190dacfce 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -344,7 +344,7 @@ rpc_info_open(struct inode *inode, struct file *file)
344 mutex_lock(&inode->i_mutex); 344 mutex_lock(&inode->i_mutex);
345 clnt = RPC_I(inode)->private; 345 clnt = RPC_I(inode)->private;
346 if (clnt) { 346 if (clnt) {
347 atomic_inc(&clnt->cl_users); 347 kref_get(&clnt->cl_kref);
348 m->private = clnt; 348 m->private = clnt;
349 } else { 349 } else {
350 single_release(inode, file); 350 single_release(inode, file);
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 0e9fbbd4f987..bb12983580a0 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -846,7 +846,7 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons
846 task->tk_workqueue = rpciod_workqueue; 846 task->tk_workqueue = rpciod_workqueue;
847 847
848 if (clnt) { 848 if (clnt) {
849 atomic_inc(&clnt->cl_users); 849 kref_get(&clnt->cl_kref);
850 if (clnt->cl_softrtry) 850 if (clnt->cl_softrtry)
851 task->tk_flags |= RPC_TASK_SOFT; 851 task->tk_flags |= RPC_TASK_SOFT;
852 if (!clnt->cl_intr) 852 if (!clnt->cl_intr)
@@ -898,9 +898,7 @@ out:
898cleanup: 898cleanup:
899 /* Check whether to release the client */ 899 /* Check whether to release the client */
900 if (clnt) { 900 if (clnt) {
901 printk("rpc_new_task: failed, users=%d, oneshot=%d\n", 901 kref_get(&clnt->cl_kref); /* pretend we were used ... */
902 atomic_read(&clnt->cl_users), clnt->cl_oneshot);
903 atomic_inc(&clnt->cl_users); /* pretend we were used ... */
904 rpc_release_client(clnt); 902 rpc_release_client(clnt);
905 } 903 }
906 goto out; 904 goto out;