aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sunrpc/svc.h4
-rw-r--r--include/trace/events/sunrpc.h3
-rw-r--r--net/sunrpc/svc.c7
-rw-r--r--net/sunrpc/svc_xprt.c221
4 files changed, 132 insertions, 103 deletions
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 513957eba0a5..6f22cfeef5e3 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -45,7 +45,6 @@ struct svc_pool_stats {
45struct svc_pool { 45struct svc_pool {
46 unsigned int sp_id; /* pool id; also node id on NUMA */ 46 unsigned int sp_id; /* pool id; also node id on NUMA */
47 spinlock_t sp_lock; /* protects all fields */ 47 spinlock_t sp_lock; /* protects all fields */
48 struct list_head sp_threads; /* idle server threads */
49 struct list_head sp_sockets; /* pending sockets */ 48 struct list_head sp_sockets; /* pending sockets */
50 unsigned int sp_nrthreads; /* # of threads in pool */ 49 unsigned int sp_nrthreads; /* # of threads in pool */
51 struct list_head sp_all_threads; /* all server threads */ 50 struct list_head sp_all_threads; /* all server threads */
@@ -221,7 +220,6 @@ static inline void svc_putu32(struct kvec *iov, __be32 val)
221 * processed. 220 * processed.
222 */ 221 */
223struct svc_rqst { 222struct svc_rqst {
224 struct list_head rq_list; /* idle list */
225 struct list_head rq_all; /* all threads list */ 223 struct list_head rq_all; /* all threads list */
226 struct rcu_head rq_rcu_head; /* for RCU deferred kfree */ 224 struct rcu_head rq_rcu_head; /* for RCU deferred kfree */
227 struct svc_xprt * rq_xprt; /* transport ptr */ 225 struct svc_xprt * rq_xprt; /* transport ptr */
@@ -264,6 +262,7 @@ struct svc_rqst {
264 * to prevent encrypting page 262 * to prevent encrypting page
265 * cache pages */ 263 * cache pages */
266#define RQ_VICTIM (5) /* about to be shut down */ 264#define RQ_VICTIM (5) /* about to be shut down */
265#define RQ_BUSY (6) /* request is busy */
267 unsigned long rq_flags; /* flags field */ 266 unsigned long rq_flags; /* flags field */
268 267
269 void * rq_argp; /* decoded arguments */ 268 void * rq_argp; /* decoded arguments */
@@ -285,6 +284,7 @@ struct svc_rqst {
285 struct auth_domain * rq_gssclient; /* "gss/"-style peer info */ 284 struct auth_domain * rq_gssclient; /* "gss/"-style peer info */
286 struct svc_cacherep * rq_cacherep; /* cache info */ 285 struct svc_cacherep * rq_cacherep; /* cache info */
287 struct task_struct *rq_task; /* service thread */ 286 struct task_struct *rq_task; /* service thread */
287 spinlock_t rq_lock; /* per-request lock */
288}; 288};
289 289
290#define SVC_NET(svc_rqst) (svc_rqst->rq_xprt->xpt_net) 290#define SVC_NET(svc_rqst) (svc_rqst->rq_xprt->xpt_net)
diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h
index 08a5fed50f34..ee4438a63a48 100644
--- a/include/trace/events/sunrpc.h
+++ b/include/trace/events/sunrpc.h
@@ -419,7 +419,8 @@ TRACE_EVENT(xs_tcp_data_recv,
419 { (1UL << RQ_USEDEFERRAL), "RQ_USEDEFERRAL"}, \ 419 { (1UL << RQ_USEDEFERRAL), "RQ_USEDEFERRAL"}, \
420 { (1UL << RQ_DROPME), "RQ_DROPME"}, \ 420 { (1UL << RQ_DROPME), "RQ_DROPME"}, \
421 { (1UL << RQ_SPLICE_OK), "RQ_SPLICE_OK"}, \ 421 { (1UL << RQ_SPLICE_OK), "RQ_SPLICE_OK"}, \
422 { (1UL << RQ_VICTIM), "RQ_VICTIM"}) 422 { (1UL << RQ_VICTIM), "RQ_VICTIM"}, \
423 { (1UL << RQ_BUSY), "RQ_BUSY"})
423 424
424TRACE_EVENT(svc_recv, 425TRACE_EVENT(svc_recv,
425 TP_PROTO(struct svc_rqst *rqst, int status), 426 TP_PROTO(struct svc_rqst *rqst, int status),
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index b90d1bca4349..91eaef1844c8 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -476,7 +476,6 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
476 i, serv->sv_name); 476 i, serv->sv_name);
477 477
478 pool->sp_id = i; 478 pool->sp_id = i;
479 INIT_LIST_HEAD(&pool->sp_threads);
480 INIT_LIST_HEAD(&pool->sp_sockets); 479 INIT_LIST_HEAD(&pool->sp_sockets);
481 INIT_LIST_HEAD(&pool->sp_all_threads); 480 INIT_LIST_HEAD(&pool->sp_all_threads);
482 spin_lock_init(&pool->sp_lock); 481 spin_lock_init(&pool->sp_lock);
@@ -614,12 +613,14 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)
614 goto out_enomem; 613 goto out_enomem;
615 614
616 serv->sv_nrthreads++; 615 serv->sv_nrthreads++;
616 __set_bit(RQ_BUSY, &rqstp->rq_flags);
617 spin_lock_init(&rqstp->rq_lock);
618 rqstp->rq_server = serv;
619 rqstp->rq_pool = pool;
617 spin_lock_bh(&pool->sp_lock); 620 spin_lock_bh(&pool->sp_lock);
618 pool->sp_nrthreads++; 621 pool->sp_nrthreads++;
619 list_add_rcu(&rqstp->rq_all, &pool->sp_all_threads); 622 list_add_rcu(&rqstp->rq_all, &pool->sp_all_threads);
620 spin_unlock_bh(&pool->sp_lock); 623 spin_unlock_bh(&pool->sp_lock);
621 rqstp->rq_server = serv;
622 rqstp->rq_pool = pool;
623 624
624 rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node); 625 rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node);
625 if (!rqstp->rq_argp) 626 if (!rqstp->rq_argp)
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 579ff2249562..ed90d955f733 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -310,25 +310,6 @@ char *svc_print_addr(struct svc_rqst *rqstp, char *buf, size_t len)
310} 310}
311EXPORT_SYMBOL_GPL(svc_print_addr); 311EXPORT_SYMBOL_GPL(svc_print_addr);
312 312
313/*
314 * Queue up an idle server thread. Must have pool->sp_lock held.
315 * Note: this is really a stack rather than a queue, so that we only
316 * use as many different threads as we need, and the rest don't pollute
317 * the cache.
318 */
319static void svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp)
320{
321 list_add(&rqstp->rq_list, &pool->sp_threads);
322}
323
324/*
325 * Dequeue an nfsd thread. Must have pool->sp_lock held.
326 */
327static void svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
328{
329 list_del(&rqstp->rq_list);
330}
331
332static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt) 313static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt)
333{ 314{
334 if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE))) 315 if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE)))
@@ -343,6 +324,7 @@ static void svc_xprt_do_enqueue(struct svc_xprt *xprt)
343 struct svc_pool *pool; 324 struct svc_pool *pool;
344 struct svc_rqst *rqstp; 325 struct svc_rqst *rqstp;
345 int cpu; 326 int cpu;
327 bool queued = false;
346 328
347 if (!svc_xprt_has_something_to_do(xprt)) 329 if (!svc_xprt_has_something_to_do(xprt))
348 return; 330 return;
@@ -360,37 +342,60 @@ static void svc_xprt_do_enqueue(struct svc_xprt *xprt)
360 342
361 cpu = get_cpu(); 343 cpu = get_cpu();
362 pool = svc_pool_for_cpu(xprt->xpt_server, cpu); 344 pool = svc_pool_for_cpu(xprt->xpt_server, cpu);
363 spin_lock_bh(&pool->sp_lock);
364 345
365 atomic_long_inc(&pool->sp_stats.packets); 346 atomic_long_inc(&pool->sp_stats.packets);
366 347
367 if (!list_empty(&pool->sp_threads)) { 348redo_search:
368 rqstp = list_entry(pool->sp_threads.next, 349 /* find a thread for this xprt */
369 struct svc_rqst, 350 rcu_read_lock();
370 rq_list); 351 list_for_each_entry_rcu(rqstp, &pool->sp_all_threads, rq_all) {
371 dprintk("svc: transport %p served by daemon %p\n", 352 /* Do a lockless check first */
372 xprt, rqstp); 353 if (test_bit(RQ_BUSY, &rqstp->rq_flags))
373 svc_thread_dequeue(pool, rqstp); 354 continue;
374 if (rqstp->rq_xprt) 355
375 printk(KERN_ERR 356 /*
376 "svc_xprt_enqueue: server %p, rq_xprt=%p!\n", 357 * Once the xprt has been queued, it can only be dequeued by
377 rqstp, rqstp->rq_xprt); 358 * the task that intends to service it. All we can do at that
378 /* Note the order of the following 3 lines: 359 * point is to try to wake this thread back up so that it can
379 * We want to assign xprt to rqstp->rq_xprt only _after_ 360 * do so.
380 * we've woken up the process, so that we don't race with
381 * the lockless check in svc_get_next_xprt().
382 */ 361 */
383 svc_xprt_get(xprt); 362 if (!queued) {
384 wake_up_process(rqstp->rq_task); 363 spin_lock_bh(&rqstp->rq_lock);
385 rqstp->rq_xprt = xprt; 364 if (test_and_set_bit(RQ_BUSY, &rqstp->rq_flags)) {
365 /* already busy, move on... */
366 spin_unlock_bh(&rqstp->rq_lock);
367 continue;
368 }
369
370 /* this one will do */
371 rqstp->rq_xprt = xprt;
372 svc_xprt_get(xprt);
373 spin_unlock_bh(&rqstp->rq_lock);
374 }
375 rcu_read_unlock();
376
386 atomic_long_inc(&pool->sp_stats.threads_woken); 377 atomic_long_inc(&pool->sp_stats.threads_woken);
387 } else { 378 wake_up_process(rqstp->rq_task);
379 put_cpu();
380 return;