Release 4.11 net/sunrpc/sched.c
/*
* linux/net/sunrpc/sched.c
*
* Scheduling for synchronous and asynchronous RPC requests.
*
* Copyright (C) 1996 Olaf Kirch, <okir@monad.swb.de>
*
* TCP NFS related read + write fixes
* (C) 1999 Dave Airlie, University of Limerick, Ireland <airlied@linux.ie>
*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/mempool.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/freezer.h>
#include <linux/sunrpc/clnt.h>
#include "sunrpc.h"
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
#define RPCDBG_FACILITY RPCDBG_SCHED
#endif
#define CREATE_TRACE_POINTS
#include <trace/events/sunrpc.h>
/*
* RPC slabs and memory pools
*/
#define RPC_BUFFER_MAXSIZE (2048)
#define RPC_BUFFER_POOLSIZE (8)
#define RPC_TASK_POOLSIZE (8)
static struct kmem_cache *rpc_task_slabp __read_mostly;
static struct kmem_cache *rpc_buffer_slabp __read_mostly;
static mempool_t *rpc_task_mempool __read_mostly;
static mempool_t *rpc_buffer_mempool __read_mostly;
static void rpc_async_schedule(struct work_struct *);
static void rpc_release_task(struct rpc_task *task);
static void __rpc_queue_timer_fn(unsigned long ptr);
/*
* RPC tasks sit here while waiting for conditions to improve.
*/
static struct rpc_wait_queue delay_queue;
/*
* rpciod-related stuff
*/
struct workqueue_struct *rpciod_workqueue __read_mostly;
struct workqueue_struct *xprtiod_workqueue __read_mostly;
/*
* Disable the timer for a given RPC task. Should be called with
* queue->lock and bh_disabled in order to avoid races within
* rpc_run_timer().
*/
static void
__rpc_disable_timer(struct rpc_wait_queue *queue, struct rpc_task *task)
{
if (task->tk_timeout == 0)
return;
dprintk("RPC: %5u disabling timer\n", task->tk_pid);
task->tk_timeout = 0;
list_del(&task->u.tk_wait.timer_list);
if (list_empty(&queue->timer_list.list))
del_timer(&queue->timer_list.timer);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 49 | 66.22% | 2 | 50.00% |
Linus Torvalds (pre-git) | 24 | 32.43% | 1 | 25.00% |
Chuck Lever | 1 | 1.35% | 1 | 25.00% |
Total | 74 | 100.00% | 4 | 100.00% |
static void
rpc_set_queue_timer(struct rpc_wait_queue *queue, unsigned long expires)
{
queue->timer_list.expires = expires;
mod_timer(&queue->timer_list.timer, expires);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 34 | 97.14% | 1 | 50.00% |
Linus Torvalds (pre-git) | 1 | 2.86% | 1 | 50.00% |
Total | 35 | 100.00% | 2 | 100.00% |
/*
* Set up a timer for the current task.
*/
static void
__rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task)
{
if (!task->tk_timeout)
return;
dprintk("RPC: %5u setting alarm for %u ms\n",
task->tk_pid, jiffies_to_msecs(task->tk_timeout));
task->u.tk_wait.expires = jiffies + task->tk_timeout;
if (list_empty(&queue->timer_list.list) || time_before(task->u.tk_wait.expires, queue->timer_list.expires))
rpc_set_queue_timer(queue, task->u.tk_wait.expires);
list_add(&task->u.tk_wait.timer_list, &queue->timer_list.list);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 60 | 52.17% | 3 | 33.33% |
Linus Torvalds (pre-git) | 51 | 44.35% | 4 | 44.44% |
Nicholas Mc Guire | 4 | 3.48% | 2 | 22.22% |
Total | 115 | 100.00% | 9 | 100.00% |
static void rpc_rotate_queue_owner(struct rpc_wait_queue *queue)
{
struct list_head *q = &queue->tasks[queue->priority];
struct rpc_task *task;
if (!list_empty(q)) {
task = list_first_entry(q, struct rpc_task, u.tk_wait.list);
if (task->tk_owner == queue->owner)
list_move_tail(&task->u.tk_wait.list, q);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 81 | 100.00% | 1 | 100.00% |
Total | 81 | 100.00% | 1 | 100.00% |
static void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority)
{
if (queue->priority != priority) {
/* Fairness: rotate the list when changing priority */
rpc_rotate_queue_owner(queue);
queue->priority = priority;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 36 | 100.00% | 2 | 100.00% |
Total | 36 | 100.00% | 2 | 100.00% |
static void rpc_set_waitqueue_owner(struct rpc_wait_queue *queue, pid_t pid)
{
queue->owner = pid;
queue->nr = RPC_BATCH_COUNT;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 26 | 100.00% | 1 | 100.00% |
Total | 26 | 100.00% | 1 | 100.00% |
static void rpc_reset_waitqueue_priority(struct rpc_wait_queue *queue)
{
rpc_set_waitqueue_priority(queue, queue->maxpriority);
rpc_set_waitqueue_owner(queue, 0);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 27 | 100.00% | 1 | 100.00% |
Total | 27 | 100.00% | 1 | 100.00% |
/*
* Add new request to a priority queue.
*/
static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue,
struct rpc_task *task,
unsigned char queue_priority)
{
struct list_head *q;
struct rpc_task *t;
INIT_LIST_HEAD(&task->u.tk_wait.links);
if (unlikely(queue_priority > queue->maxpriority))
queue_priority = queue->maxpriority;
if (queue_priority > queue->priority)
rpc_set_waitqueue_priority(queue, queue_priority);
q = &queue->tasks[queue_priority];
list_for_each_entry(t, q, u.tk_wait.list) {
if (t->tk_owner == task->tk_owner) {
list_add_tail(&task->u.tk_wait.list, &t->u.tk_wait.links);
return;
}
}
list_add_tail(&task->u.tk_wait.list, q);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 142 | 100.00% | 5 | 100.00% |
Total | 142 | 100.00% | 5 | 100.00% |
/*
* Add new request to wait queue.
*
* Swapper tasks always get inserted at the head of the queue.
* This should avoid many nasty memory deadlocks and hopefully
* improve overall performance.
* Everyone else gets appended to the queue to ensure proper FIFO behavior.
*/
static void __rpc_add_wait_queue(struct rpc_wait_queue *queue,
struct rpc_task *task,
unsigned char queue_priority)
{
WARN_ON_ONCE(RPC_IS_QUEUED(task));
if (RPC_IS_QUEUED(task))
return;
if (RPC_IS_PRIORITY(queue))
__rpc_add_wait_queue_priority(queue, task, queue_priority);
else if (RPC_IS_SWAPPER(task))
list_add(&task->u.tk_wait.list, &queue->tasks[0]);
else
list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]);
task->tk_waitqueue = queue;
queue->qlen++;
/* barrier matches the read in rpc_wake_up_task_queue_locked() */
smp_wmb();
rpc_set_queued(task);
dprintk("RPC: %5u added to queue %p \"%s\"\n",
task->tk_pid, queue, rpc_qname(queue));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 58 | 42.34% | 2 | 18.18% |
Trond Myklebust | 52 | 37.96% | 5 | 45.45% |
Neil Brown | 12 | 8.76% | 1 | 9.09% |
Weston Andros Adamson | 9 | 6.57% | 1 | 9.09% |
Chuck Lever | 6 | 4.38% | 2 | 18.18% |
Total | 137 | 100.00% | 11 | 100.00% |
/*
* Remove request from a priority queue.
*/
static void __rpc_remove_wait_queue_priority(struct rpc_task *task)
{
struct rpc_task *t;
if (!list_empty(&task->u.tk_wait.links)) {
t = list_entry(task->u.tk_wait.links.next, struct rpc_task, u.tk_wait.list);
list_move(&t->u.tk_wait.list, &task->u.tk_wait.list);
list_splice_init(&task->u.tk_wait.links, &t->u.tk_wait.links);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 97 | 97.98% | 2 | 66.67% |
Linus Torvalds (pre-git) | 2 | 2.02% | 1 | 33.33% |
Total | 99 | 100.00% | 3 | 100.00% |
/*
* Remove request from queue.
* Note: must be called with spin lock held.
*/
static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
{
__rpc_disable_timer(queue, task);
if (RPC_IS_PRIORITY(queue))
__rpc_remove_wait_queue_priority(task);
list_del(&task->u.tk_wait.list);
queue->qlen--;
dprintk("RPC: %5u removed from queue %p \"%s\"\n",
task->tk_pid, queue, rpc_qname(queue));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 31 | 45.59% | 5 | 50.00% |
Linus Torvalds (pre-git) | 29 | 42.65% | 2 | 20.00% |
Chuck Lever | 6 | 8.82% | 2 | 20.00% |
Neil Brown | 2 | 2.94% | 1 | 10.00% |
Total | 68 | 100.00% | 10 | 100.00% |
static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname, unsigned char nr_queues)
{
int i;
spin_lock_init(&queue->lock);
for (i = 0; i < ARRAY_SIZE(queue->tasks); i++)
INIT_LIST_HEAD(&queue->tasks[i]);
queue->maxpriority = nr_queues - 1;
rpc_reset_waitqueue_priority(queue);
queue->qlen = 0;
setup_timer(&queue->timer_list.timer, __rpc_queue_timer_fn, (unsigned long)queue);
INIT_LIST_HEAD(&queue->timer_list.list);
rpc_assign_waitqueue_name(queue, qname);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 114 | 100.00% | 5 | 100.00% |
Total | 114 | 100.00% | 5 | 100.00% |
void rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const char *qname)
{
__rpc_init_priority_wait_queue(queue, qname, RPC_NR_PRIORITY);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 24 | 100.00% | 2 | 100.00% |
Total | 24 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_init_priority_wait_queue);
void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname)
{
__rpc_init_priority_wait_queue(queue, qname, 1);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 24 | 100.00% | 2 | 100.00% |
Total | 24 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_init_wait_queue);
void rpc_destroy_wait_queue(struct rpc_wait_queue *queue)
{
del_timer_sync(&queue->timer_list.timer);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 20 | 100.00% | 2 | 100.00% |
Total | 20 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue);
static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode)
{
freezable_schedule_unsafe();
if (signal_pending_state(mode, current))
return -ERESTARTSYS;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 20 | 60.61% | 1 | 25.00% |
Peter Zijlstra | 9 | 27.27% | 1 | 25.00% |
Neil Brown | 3 | 9.09% | 1 | 25.00% |
Matthew Wilcox | 1 | 3.03% | 1 | 25.00% |
Total | 33 | 100.00% | 4 | 100.00% |
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS)
static void rpc_task_set_debuginfo(struct rpc_task *task)
{
static atomic_t rpc_pid;
task->tk_pid = atomic_inc_return(&rpc_pid);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 25 | 100.00% | 1 | 100.00% |
Total | 25 | 100.00% | 1 | 100.00% |
#else
static inline void rpc_task_set_debuginfo(struct rpc_task *task)
{
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 11 | 100.00% | 1 | 100.00% |
Total | 11 | 100.00% | 1 | 100.00% |
#endif
static void rpc_set_active(struct rpc_task *task)
{
trace_rpc_task_begin(task->tk_client, task, NULL);
rpc_task_set_debuginfo(task);
set_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 37 | 100.00% | 5 | 100.00% |
Total | 37 | 100.00% | 5 | 100.00% |
/*
* Mark an RPC call as having completed by clearing the 'active' bit
* and then waking up all tasks that were sleeping.
*/
static int rpc_complete_task(struct rpc_task *task)
{
void *m = &task->tk_runstate;
wait_queue_head_t *wq = bit_waitqueue(m, RPC_TASK_ACTIVE);
struct wait_bit_key k = __WAIT_BIT_KEY_INITIALIZER(m, RPC_TASK_ACTIVE);
unsigned long flags;
int ret;
trace_rpc_task_complete(task->tk_client, task, NULL);
spin_lock_irqsave(&wq->lock, flags);
clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
ret = atomic_dec_and_test(&task->tk_count);
if (waitqueue_active(wq))
__wake_up_locked_key(wq, TASK_NORMAL, &k);
spin_unlock_irqrestore(&wq->lock, flags);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 120 | 100.00% | 4 | 100.00% |
Total | 120 | 100.00% | 4 | 100.00% |
/*
* Allow callers to wait for completion of an RPC call
*
* Note the use of out_of_line_wait_on_bit() rather than wait_on_bit()
* to enforce taking of the wq->lock and hence avoid races with
* rpc_complete_task().
*/
int __rpc_wait_for_completion_task(struct rpc_task *task, wait_bit_action_f *action)
{
if (action == NULL)
action = rpc_wait_bit_killable;
return out_of_line_wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE,
action, TASK_KILLABLE);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 36 | 92.31% | 2 | 50.00% |
Matthew Wilcox | 2 | 5.13% | 1 | 25.00% |
Neil Brown | 1 | 2.56% | 1 | 25.00% |
Total | 39 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task);
/*
* Make an RPC task runnable.
*
* Note: If the task is ASYNC, and is being made runnable after sitting on an
* rpc_wait_queue, this must be called with the queue spinlock held to protect
* the wait queue operation.
* Note the ordering of rpc_test_and_set_running() and rpc_clear_queued(),
* which is needed to ensure that __rpc_execute() doesn't loop (due to the
* lockless RPC_IS_QUEUED() test) before we've had a chance to test
* the RPC_TASK_RUNNING flag.
*/
static void rpc_make_runnable(struct workqueue_struct *wq,
struct rpc_task *task)
{
bool need_wakeup = !rpc_test_and_set_running(task);
rpc_clear_queued(task);
if (!need_wakeup)
return;
if (RPC_IS_ASYNC(task)) {
INIT_WORK(&task->u.tk_work, rpc_async_schedule);
queue_work(wq, &task->u.tk_work);
} else
wake_up_bit(&task->tk_runstate, RPC_TASK_QUEUED);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 40 | 50.00% | 4 | 44.44% |
Linus Torvalds (pre-git) | 35 | 43.75% | 4 | 44.44% |
Christophe Saout | 5 | 6.25% | 1 | 11.11% |
Total | 80 | 100.00% | 9 | 100.00% |
/*
* Prepare for sleeping on a wait queue.
* By always appending tasks to the list we ensure FIFO behavior.
* NB: An RPC task will only receive interrupt-driven events as long
* as it's on a wait queue.
*/
static void __rpc_sleep_on_priority(struct rpc_wait_queue *q,
struct rpc_task *task,
rpc_action action,
unsigned char queue_priority)
{
dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n",
task->tk_pid, rpc_qname(q), jiffies);
trace_rpc_task_sleep(task->tk_client, task, q);
__rpc_add_wait_queue(q, task, queue_priority);
WARN_ON_ONCE(task->tk_callback != NULL);
task->tk_callback = action;
__rpc_add_timer(q, task);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 57 | 70.37% | 6 | 50.00% |
Trond Myklebust | 22 | 27.16% | 4 | 33.33% |
Weston Andros Adamson | 1 | 1.23% | 1 | 8.33% |
Chuck Lever | 1 | 1.23% | 1 | 8.33% |
Total | 81 | 100.00% | 12 | 100.00% |
void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
rpc_action action)
{
/* We shouldn't ever put an inactive task to sleep */
WARN_ON_ONCE(!RPC_IS_ACTIVATED(task));
if (!RPC_IS_ACTIVATED(task)) {
task->tk_status = -EIO;
rpc_put_task_async(task);
return;
}
/*
* Protect the queue operations.
*/
spin_lock_bh(&q->lock);
__rpc_sleep_on_priority(q, task, action, task->tk_priority);
spin_unlock_bh(&q->lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 36 | 44.44% | 3 | 37.50% |
Weston Andros Adamson | 24 | 29.63% | 1 | 12.50% |
Trond Myklebust | 21 | 25.93% | 4 | 50.00% |
Total | 81 | 100.00% | 8 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_sleep_on);
void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task,
rpc_action action, int priority)
{
/* We shouldn't ever put an inactive task to sleep */
WARN_ON_ONCE(!RPC_IS_ACTIVATED(task));
if (!RPC_IS_ACTIVATED(task)) {
task->tk_status = -EIO;
rpc_put_task_async(task);
return;
}
/*
* Protect the queue operations.
*/
spin_lock_bh(&q->lock);
__rpc_sleep_on_priority(q, task, action, priority - RPC_PRIORITY_LOW);
spin_unlock_bh(&q->lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 60 | 71.43% | 1 | 50.00% |
Weston Andros Adamson | 24 | 28.57% | 1 | 50.00% |
Total | 84 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_sleep_on_priority);
/**
* __rpc_do_wake_up_task_on_wq - wake up a single rpc_task
* @wq: workqueue on which to run task
* @queue: wait queue
* @task: task to be woken up
*
* Caller must hold queue->lock, and have cleared the task queued flag.
*/
static void __rpc_do_wake_up_task_on_wq(struct workqueue_struct *wq,
struct rpc_wait_queue *queue,
struct rpc_task *task)
{
dprintk("RPC: %5u __rpc_wake_up_task (now %lu)\n",
task->tk_pid, jiffies);
/* Has the task been executed yet? If not, we cannot wake it up! */
if (!RPC_IS_ACTIVATED(task)) {
printk(KERN_ERR "RPC: Inactive task (%p) being woken up!\n", task);
return;
}
trace_rpc_task_wakeup(task->tk_client, task, queue);
__rpc_remove_wait_queue(queue, task);
rpc_make_runnable(wq, task);
dprintk("RPC: __rpc_wake_up_task done\n");
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 43 | 52.44% | 2 | 28.57% |
Trond Myklebust | 37 | 45.12% | 4 | 57.14% |
Chuck Lever | 2 | 2.44% | 1 | 14.29% |
Total | 82 | 100.00% | 7 | 100.00% |
/*
* Wake up a queued task while the queue lock is being held
*/
static void rpc_wake_up_task_on_wq_queue_locked(struct workqueue_struct *wq,
struct rpc_wait_queue *queue, struct rpc_task *task)
{
if (RPC_IS_QUEUED(task)) {
smp_rmb();
if (task->tk_waitqueue == queue)
__rpc_do_wake_up_task_on_wq(wq, queue, task);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 42 | 84.00% | 5 | 71.43% |
Linus Torvalds (pre-git) | 8 | 16.00% | 2 | 28.57% |
Total | 50 | 100.00% | 7 | 100.00% |
/*
* Wake up a queued task while the queue lock is being held
*/
static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct rpc_task *task)
{
rpc_wake_up_task_on_wq_queue_locked(rpciod_workqueue, queue, task);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 25 | 100.00% | 1 | 100.00% |
Total | 25 | 100.00% | 1 | 100.00% |
/*
* Wake up a task on a specific queue
*/
void rpc_wake_up_queued_task(struct rpc_wait_queue *queue, struct rpc_task *task)
{
spin_lock_bh(&queue->lock);
rpc_wake_up_task_queue_locked(queue, task);
spin_unlock_bh(&queue->lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 38 | 100.00% | 5 | 100.00% |
Total | 38 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_wake_up_queued_task);
/*
* Wake up the next task on a priority queue.
*/
static struct rpc_task *__rpc_find_next_queued_priority(struct rpc_wait_queue *queue)
{
struct list_head *q;
struct rpc_task *task;
/*
* Service a batch of tasks from a single owner.
*/
q = &queue->tasks[queue->priority];
if (!list_empty(q)) {
task = list_entry(q->next, struct rpc_task, u.tk_wait.list);
if (queue->owner == task->tk_owner) {
if (--queue->nr)
goto out;
list_move_tail(&task->u.tk_wait.list, q);
}
/*
* Check if we need to switch queues.
*/
goto new_owner;
}
/*
* Service the next queue.
*/
do {
if (q == &queue->tasks[0])
q = &queue->tasks[queue->maxpriority];
else
q = q - 1;
if (!list_empty(q)) {
task = list_entry(q->next, struct rpc_task, u.tk_wait.list);
goto new_queue;
}
} while (q != &queue->tasks[queue->priority]);
rpc_reset_waitqueue_priority(queue);
return NULL;
new_queue:
rpc_set_waitqueue_priority(queue, (unsigned int)(q - &queue->tasks[0]));
new_owner:
rpc_set_waitqueue_owner(queue, task->tk_owner);
out:
return task;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 209 | 90.09% | 4 | 57.14% |
Linus Torvalds (pre-git) | 23 | 9.91% | 3 | 42.86% |
Total | 232 | 100.00% | 7 | 100.00% |
static struct rpc_task *__rpc_find_next_queued(struct rpc_wait_queue *queue)
{
if (RPC_IS_PRIORITY(queue))
return __rpc_find_next_queued_priority(queue);
if (!list_empty(&queue->tasks[0]))
return list_first_entry(&queue->tasks[0], struct rpc_task, u.tk_wait.list);
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 61 | 95.31% | 3 | 75.00% |
Linus Torvalds (pre-git) | 3 | 4.69% | 1 | 25.00% |
Total | 64 | 100.00% | 4 | 100.00% |
/*
* Wake up the first task on the wait queue.
*/
struct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq,
struct rpc_wait_queue *queue,
bool (*func)(struct rpc_task *, void *), void *data)
{
struct rpc_task *task = NULL;
dprintk("RPC: wake_up_first(%p \"%s\")\n",
queue, rpc_qname(queue));
spin_lock_bh(&queue->lock);
task = __rpc_find_next_queued(queue);
if (task != NULL) {
if (func(task, data))
rpc_wake_up_task_on_wq_queue_locked(wq, queue, task);
else
task = NULL;
}
spin_unlock_bh(&queue->lock);
return task;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 64 | 57.66% | 6 | 66.67% |
Linus Torvalds (pre-git) | 42 | 37.84% | 2 | 22.22% |
Neil Brown | 5 | 4.50% | 1 | 11.11% |
Total | 111 | 100.00% | 9 | 100.00% |
/*
* Wake up the first task on the wait queue.
*/
struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *queue,
bool (*func)(struct rpc_task *, void *), void *data)
{
return rpc_wake_up_first_on_wq(rpciod_workqueue, queue, func, data);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 42 | 100.00% | 1 | 100.00% |
Total | 42 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_wake_up_first);
static bool rpc_wake_up_next_func(struct rpc_task *task, void *data)
{
return true;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 18 | 100.00% | 1 | 100.00% |
Total | 18 | 100.00% | 1 | 100.00% |
/*
* Wake up the next task on the wait queue.
*/
struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *queue)
{
return rpc_wake_up_first(queue, rpc_wake_up_next_func, NULL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 22 | 100.00% | 1 | 100.00% |
Total | 22 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_wake_up_next);
/**
* rpc_wake_up - wake up all rpc_tasks
* @queue: rpc_wait_queue on which the tasks are sleeping
*
* Grabs queue->lock
*/
void rpc_wake_up(struct rpc_wait_queue *queue)
{
struct list_head *head;
spin_lock_bh(&queue->lock);
head = &queue->tasks[queue->maxpriority];
for (;;) {
while (!list_empty(head)) {
struct rpc_task *task;
task = list_first_entry(head,
struct rpc_task,
u.tk_wait.list);
rpc_wake_up_task_queue_locked(queue, task);
}
if (head == &queue->tasks[0])
break;
head--;
}
spin_unlock_bh(&queue->lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 80 | 76.92% | 6 | 66.67% |
Linus Torvalds (pre-git) | 21 | 20.19% | 2 | 22.22% |
Neil Brown | 3 | 2.88% | 1 | 11.11% |
Total | 104 | 100.00% | 9 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_wake_up);
/**
* rpc_wake_up_status - wake up all rpc_tasks and set their status value.
* @queue: rpc_wait_queue on which the tasks are sleeping
* @status: status value to set
*
* Grabs queue->lock
*/
void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
{
struct list_head *head;
spin_lock_bh(&queue->lock);
head = &queue->tasks[queue->maxpriority];
for (;;) {
while (!list_empty(head)) {
struct rpc_task *task;
task = list_first_entry(head,
struct rpc_task,
u.tk_wait.list);
task->tk_status = status;
rpc_wake_up_task_queue_locked(queue, task);
}
if (head == &queue->tasks[0])
break;
head--;
}
spin_unlock_bh(&queue->lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 75 | 66.37% | 6 | 66.67% |
Linus Torvalds (pre-git) | 34 | 30.09% | 2 | 22.22% |
Neil Brown | 4 | 3.54% | 1 | 11.11% |
Total | 113 | 100.00% | 9 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_wake_up_status);
static void __rpc_queue_timer_fn(unsigned long ptr)
{
struct rpc_wait_queue *queue = (struct rpc_wait_queue *)ptr;
struct rpc_task *task, *n;
unsigned long expires, now, timeo;
spin_lock(&queue->lock);
expires = now = jiffies;
list_for_each_entry_safe(task, n, &queue->timer_list.list, u.tk_wait.timer_list) {
timeo = task->u.tk_wait.expires;
if (time_after_eq(now, timeo)) {
dprintk("RPC: %5u timeout\n", task->tk_pid);
task->tk_status = -ETIMEDOUT;
rpc_wake_up_task_queue_locked(queue, task);
continue;
}
if (expires == now || time_after(expires, timeo))
expires = timeo;
}
if (!list_empty(&queue->timer_list.list))
rpc_set_queue_timer(queue, expires);
spin_unlock(&queue->lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 154 | 100.00% | 1 | 100.00% |
Total | 154 | 100.00% | 1 | 100.00% |
static void __rpc_atrun(struct rpc_task *task)
{
if (task->tk_status == -ETIMEDOUT)
task->tk_status = 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 26 | 100.00% | 3 | 100.00% |
Total | 26 | 100.00% | 3 | 100.00% |
/*
* Run a task at a later time
*/
void rpc_delay(struct rpc_task *task, unsigned long delay)
{
task->tk_timeout = delay;
rpc_sleep_on(&delay_queue, task, __rpc_atrun);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 29 | 96.67% | 1 | 50.00% |
Trond Myklebust | 1 | 3.33% | 1 | 50.00% |
Total | 30 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_delay);
/*
* Helper to call task->tk_ops->rpc_call_prepare
*/
void rpc_prepare_task(struct rpc_task *task)
{
task->tk_ops->rpc_call_prepare(task, task->tk_calldata);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 23 | 100.00% | 1 | 100.00% |
Total | 23 | 100.00% | 1 | 100.00% |
static void
rpc_init_task_statistics(struct rpc_task *task)
{
/* Initialize retry counters */
task->tk_garb_retry = 2;
task->tk_cred_retry = 2;
task->tk_rebind_retry = 2;
/* starting timestamp */
task->tk_start = ktime_get();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 38 | 100.00% | 1 | 100.00% |
Total | 38 | 100.00% | 1 | 100.00% |
static void
rpc_reset_task_statistics(struct rpc_task *task)
{
task->tk_timeouts = 0;
task->tk_flags &= ~(RPC_CALL_MAJORSEEN|RPC_TASK_KILLED|RPC_TASK_SENT);
rpc_init_task_statistics(task);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 35 | 100.00% | 1 | 100.00% |
Total | 35 | 100.00% | 1 | 100.00% |
/*
* Helper that calls task->tk_ops->rpc_call_done if it exists
*/
void rpc_exit_task(struct rpc_task *task)
{
task->tk_action = NULL;
if (task->tk_ops->rpc_call_done != NULL) {
task->tk_ops->rpc_call_done(task, task->tk_calldata);
if (task->tk_action != NULL) {
WARN_ON(RPC_ASSASSINATED(task));
/* Always release the RPC slot and buffer memory */
xprt_release(task);
rpc_reset_task_statistics(task);
}
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 70 | 100.00% | 4 | 100.00% |
Total | 70 | 100.00% | 4 | 100.00% |
void rpc_exit(struct rpc_task *task, int status)
{
task->tk_status = status;
task->tk_action = rpc_exit_task;
if (RPC_IS_QUEUED(task))
rpc_wake_up_queued_task(task->tk_waitqueue, task);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 41 | 100.00% | 1 | 100.00% |
Total | 41 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_exit);
void rpc_release_calldata(const struct rpc_call_ops *ops, void *calldata)
{
if (ops->rpc_release != NULL)
ops->rpc_release(calldata);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 30 | 100.00% | 1 | 100.00% |
Total | 30 | 100.00% | 1 | 100.00% |
/*
* This is the RPC `scheduler' (or rather, the finite state machine).
*/
static void __rpc_execute(struct rpc_task *task)
{
struct rpc_wait_queue *queue;
int task_is_async = RPC_IS_ASYNC(task);
int status = 0;
dprintk("RPC: %5u __rpc_execute flags=0x%x\n",
task->tk_pid, task->tk_flags);
WARN_ON_ONCE(RPC_IS_QUEUED(task));
if (RPC_IS_QUEUED(task))
return;
for (;;) {
void (*do_action)(struct rpc_task *);
/*
* Execute any pending callback first.
*/
do_action = task->tk_callback;
task->tk_callback = NULL;
if (do_action == NULL) {
/*
* Perform the next FSM step.
* tk_action may be NULL if the task has been killed.
* In particular, note that rpc_killall_tasks may
* do this at any time, so beware when dereferencing.
*/
do_action = task->tk_action;
if (do_action == NULL)
break;
}
trace_rpc_task_run_action(task->tk_client, task, task->tk_action);
do_action(task);
/*
* Lockless check for whether task is sleeping or not.
*/
if (!RPC_IS_QUEUED(task))
continue;
/*
* The queue->lock protects against races with
* rpc_make_runnable().
*
* Note that once we clear RPC_TASK_RUNNING on an asynchronous
* rpc_task, rpc_make_runnable() can assign it to a
* different workqueue. We therefore cannot assume that the
* rpc_task pointer may still be dereferenced.
*/
queue = task->tk_waitqueue;
spin_lock_bh(&queue->lock);
if (!RPC_IS_QUEUED(task)) {
spin_unlock_bh(&queue->lock);
continue;
}
rpc_clear_running(task);
spin_unlock_bh(&queue->lock);
if (task_is_async)
return;
/* sync task: sleep here */
dprintk("RPC: %5u sync task going to sleep\n", task->tk_pid);
status = out_of_line_wait_on_bit(&task->tk_runstate,
RPC_TASK_QUEUED, rpc_wait_bit_killable,
TASK_KILLABLE);
if (status == -ERESTARTSYS) {
/*
* When a sync task receives a signal, it exits with
* -ERESTARTSYS. In order to catch any callbacks that
* clean up after sleeping on some queue, we don't
* break the loop here, but go around once more.
*/
dprintk("RPC: %5u got signal\n", task->tk_pid);
task->tk_flags |= RPC_TASK_KILLED;
rpc_exit(task, -ERESTARTSYS);
}
dprintk("RPC: %5u sync task resuming\n", task->tk_pid);
}
dprintk("RPC: %5u return %d, status %d\n", task->tk_pid, status,
task->tk_status);
/* Release all resources associated with the task */
rpc_release_task(task);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 140 | 50.00% | 5 | 27.78% |
Trond Myklebust | 124 | 44.29% | 10 | 55.56% |
Weston Andros Adamson | 9 | 3.21% | 1 | 5.56% |
Chuck Lever | 5 | 1.79% | 1 | 5.56% |
Matthew Wilcox | 2 | 0.71% | 1 | 5.56% |
Total | 280 | 100.00% | 18 | 100.00% |
/*
* User-visible entry point to the scheduler.
*
* This may be called recursively if e.g. an async NFS task updates
* the attributes and finds that dirty pages must be flushed.
* NOTE: Upon exit of this function the task is guaranteed to be
* released. In particular note that tk_release() will have
* been called, so your task memory may have been freed.
*/
void rpc_execute(struct rpc_task *task)
{
bool is_async = RPC_IS_ASYNC(task);
rpc_set_active(task);
rpc_make_runnable(rpciod_workqueue, task);
if (!is_async)
__rpc_execute(task);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 20 | 50.00% | 5 | 45.45% |
Trond Myklebust | 20 | 50.00% | 6 | 54.55% |
Total | 40 | 100.00% | 11 | 100.00% |
static void rpc_async_schedule(struct work_struct *work)
{
__rpc_execute(container_of(work, struct rpc_task, u.tk_work));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David Howells | 12 | 46.15% | 1 | 25.00% |
Trond Myklebust | 10 | 38.46% | 1 | 25.00% |
Linus Torvalds (pre-git) | 4 | 15.38% | 2 | 50.00% |
Total | 26 | 100.00% | 4 | 100.00% |
/**
* rpc_malloc - allocate RPC buffer resources
* @task: RPC task
*
* A single memory region is allocated, which is split between the
* RPC call and RPC reply that this task is being used for. When
* this RPC is retired, the memory is released by calling rpc_free.
*
* To prevent rpciod from hanging, this allocator never sleeps,
* returning -ENOMEM and suppressing warning if the request cannot
* be serviced immediately. The caller can arrange to sleep in a
* way that is safe for rpciod.
*
* Most requests are 'small' (under 2KiB) and can be serviced from a
* mempool, ensuring that NFS reads and writes can always proceed,
* and that there is good locality of reference for these buffers.
*
* In order to avoid memory starvation triggering more writebacks of
* NFS requests, we avoid using GFP_KERNEL.
*/
int rpc_malloc(struct rpc_task *task)
{
struct rpc_rqst *rqst = task->tk_rqstp;
size_t size = rqst->rq_callsize + rqst->rq_rcvsize;
struct rpc_buffer *buf;
gfp_t gfp = GFP_NOIO | __GFP_NOWARN;
if (RPC_IS_SWAPPER(task))
gfp = __GFP_MEMALLOC | GFP_NOWAIT | __GFP_NOWARN;
size += sizeof(struct rpc_buffer);
if (size <= RPC_BUFFER_MAXSIZE)
buf = mempool_alloc(rpc_buffer_mempool, gfp);
else
buf = kmalloc(size, gfp);
if (!buf)
return -ENOMEM;
buf->len = size;
dprintk("RPC: %5u allocated buffer of size %zu at %p\n",
task->tk_pid, size, buf);
rqst->rq_buffer = buf->data;
rqst->rq_rbuffer = (char *)rqst->rq_buffer + rqst->rq_callsize;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chuck Lever | 87 | 60.00% | 5 | 33.33% |
Trond Myklebust | 24 | 16.55% | 3 | 20.00% |
Linus Torvalds (pre-git) | 16 | 11.03% | 2 | 13.33% |
Peter Zijlstra | 7 | 4.83% | 1 | 6.67% |
Mel Gorman | 7 | 4.83% | 1 | 6.67% |
David Rientjes | 2 | 1.38% | 1 | 6.67% |
Geert Uytterhoeven | 1 | 0.69% | 1 | 6.67% |
Al Viro | 1 | 0.69% | 1 | 6.67% |
Total | 145 | 100.00% | 15 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_malloc);
/**
* rpc_free - free RPC buffer resources allocated via rpc_malloc
* @task: RPC task
*
*/
void rpc_free(struct rpc_task *task)
{
void *buffer = task->tk_rqstp->rq_buffer;
size_t size;
struct rpc_buffer *buf;
buf = container_of(buffer, struct rpc_buffer, data);
size = buf->len;
dprintk("RPC: freeing buffer of size %zu at %p\n",
size, buf);
if (size <= RPC_BUFFER_MAXSIZE)
mempool_free(buf, rpc_buffer_mempool);
else
kfree(buf);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Chuck Lever | 52 | 70.27% | 4 | 57.14% |
Trond Myklebust | 12 | 16.22% | 1 | 14.29% |
Linus Torvalds (pre-git) | 9 | 12.16% | 1 | 14.29% |
Geert Uytterhoeven | 1 | 1.35% | 1 | 14.29% |
Total | 74 | 100.00% | 7 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_free);
/*
* Creation and deletion of RPC task structures
*/
static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *task_setup_data)
{
memset(task, 0, sizeof(*task));
atomic_set(&task->tk_count, 1);
task->tk_flags = task_setup_data->flags;
task->tk_ops = task_setup_data->callback_ops;
task->tk_calldata = task_setup_data->callback_data;
INIT_LIST_HEAD(&task->tk_task);
task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW;
task->tk_owner = current->tgid;
/* Initialize workqueue for async tasks */
task->tk_workqueue = task_setup_data->workqueue;
task->tk_xprt = xprt_get(task_setup_data->rpc_xprt);
if (task->tk_ops->rpc_call_prepare != NULL)
task->tk_action = rpc_prepare_task;
rpc_init_task_statistics(task);
dprintk("RPC: new task initialized, procpid %u\n",
task_pid_nr(current));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 96 | 68.09% | 13 | 72.22% |
Linus Torvalds (pre-git) | 39 | 27.66% | 2 | 11.11% |
Chuck Lever | 3 | 2.13% | 2 | 11.11% |
Pavel Emelyanov | 3 | 2.13% | 1 | 5.56% |
Total | 141 | 100.00% | 18 | 100.00% |
static struct rpc_task *
rpc_alloc_task(void)
{
return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOIO);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 21 | 91.30% | 1 | 33.33% |
Mel Gorman | 1 | 4.35% | 1 | 33.33% |
Linus Torvalds (pre-git) | 1 | 4.35% | 1 | 33.33% |
Total | 23 | 100.00% | 3 | 100.00% |
/*
* Create a new task for the specified client.
*/
struct rpc_task *rpc_new_task(const struct rpc_task_setup *setup_data)
{
struct rpc_task *task = setup_data->task;
unsigned short flags = 0;
if (task == NULL) {
task = rpc_alloc_task();
if (task == NULL) {
rpc_release_calldata(setup_data->callback_ops,
setup_data->callback_data);
return ERR_PTR(-ENOMEM);
}
flags = RPC_TASK_DYNAMIC;
}
rpc_init_task(task, setup_data);
task->tk_flags |= flags;
dprintk("RPC: allocated task %p\n", task);
return task;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 58 | 61.70% | 5 | 62.50% |
Linus Torvalds (pre-git) | 35 | 37.23% | 2 | 25.00% |
Chuck Lever | 1 | 1.06% | 1 | 12.50% |
Total | 94 | 100.00% | 8 | 100.00% |
/*
* rpc_free_task - release rpc task and perform cleanups
*
* Note that we free up the rpc_task _after_ rpc_release_calldata()
* in order to work around a workqueue dependency issue.
*
* Tejun Heo states:
* "Workqueue currently considers two work items to be the same if they're
* on the same address and won't execute them concurrently - ie. it
* makes a work item which is queued again while being executed wait
* for the previous execution to complete.
*
* If a work function frees the work item, and then waits for an event
* which should be performed by another work item and *that* work item
* recycles the freed work item, it can create a false dependency loop.
* There really is no reliable way to detect this short of verifying
* every memory free."
*
*/
static void rpc_free_task(struct rpc_task *task)
{
unsigned short tk_flags = task->tk_flags;
rpc_release_calldata(task->tk_ops, task->tk_calldata);
if (tk_flags & RPC_TASK_DYNAMIC) {
dprintk("RPC: %5u freeing task\n", task->tk_pid);
mempool_free(task, rpc_task_mempool);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 47 | 87.04% | 6 | 85.71% |
Linus Torvalds (pre-git) | 7 | 12.96% | 1 | 14.29% |
Total | 54 | 100.00% | 7 | 100.00% |
static void rpc_async_release(struct work_struct *work)
{
rpc_free_task(container_of(work, struct rpc_task, u.tk_work));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 26 | 100.00% | 1 | 100.00% |
Total | 26 | 100.00% | 1 | 100.00% |
static void rpc_release_resources_task(struct rpc_task *task)
{
xprt_release(task);
if (task->tk_msg.rpc_cred) {
put_rpccred(task->tk_msg.rpc_cred);
task->tk_msg.rpc_cred = NULL;
}
rpc_task_release_client(task);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds (pre-git) | 21 | 43.75% | 2 | 28.57% |
Trond Myklebust | 17 | 35.42% | 4 | 57.14% |
Hirofumi Ogawa | 10 | 20.83% | 1 | 14.29% |
Total | 48 | 100.00% | 7 | 100.00% |
static void rpc_final_put_task(struct rpc_task *task,
struct workqueue_struct *q)
{
if (q != NULL) {
INIT_WORK(&task->u.tk_work, rpc_async_release);
queue_work(q, &task->u.tk_work);
} else
rpc_free_task(task);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 46 | 85.19% | 5 | 83.33% |
Linus Torvalds (pre-git) | 8 | 14.81% | 1 | 16.67% |
Total | 54 | 100.00% | 6 | 100.00% |
static void rpc_do_put_task(struct rpc_task *task, struct workqueue_struct *q)
{
if (atomic_dec_and_test(&task->tk_count)) {
rpc_release_resources_task(task);
rpc_final_put_task(task, q);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 40 | 100.00% | 1 | 100.00% |
Total | 40 | 100.00% | 1 | 100.00% |
void rpc_put_task(struct rpc_task *task)
{
rpc_do_put_task(task, NULL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 17 | 100.00% | 1 | 100.00% |
Total | 17 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_put_task);
void rpc_put_task_async(struct rpc_task *task)
{
rpc_do_put_task(task, task->tk_workqueue);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 19 | 100.00% | 1 | 100.00% |
Total | 19 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(rpc_put_task_async);
static void rpc_release_task(struct rpc_task *task)
{
dprintk("RPC: %5u release task\n", task->tk_pid);
WARN_ON_ONCE(RPC_IS_QUEUED(task));
rpc_release_resources_task(task);
/*
* Note: at this point we have been removed from rpc_clnt->cl_tasks,
* so it should be safe to use task->tk_count as a test for whether
* or not any other processes still hold references to our rpc_task.
*/
if (atomic_read(&task->tk_count) != 1 + !RPC_IS_ASYNC(task)) {
/* Wake up anyone who may be waiting for task completion */
if (!rpc_complete_task(task))
return;
} else {
if (!atomic_dec_and_test(&task->tk_count))
return;
}
rpc_final_put_task(task, task->tk_workqueue);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 86 | 97.73% | 3 | 60.00% |
Weston Andros Adamson | 1 | 1.14% | 1 | 20.00% |
Chuck Lever | 1 | 1.14% | 1 | 20.00% |
Total | 88 | 100.00% | 5 | 100.00% |
int rpciod_up(void)
{
return try_module_get(THIS_MODULE) ? 0 : -EINVAL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 11 | 61.11% | 2 | 50.00% |
Linus Torvalds (pre-git) | 7 | 38.89% | 2 | 50.00% |
Total | 18 | 100.00% | 4 | 100.00% |
void rpciod_down(void)
{
module_put(THIS_MODULE);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 9 | 75.00% | 1 | 50.00% |
Linus Torvalds (pre-git) | 3 | 25.00% | 1 | 50.00% |
Total | 12 | 100.00% | 2 | 100.00% |
/*
* Start up the rpciod workqueue.
*/
static int rpciod_start(void)
{
struct workqueue_struct *wq;
/*
* Create the rpciod thread and wait for it to start.
*/
dprintk("RPC: creating workqueue rpciod\n");
wq = alloc_workqueue("rpciod", WQ_MEM_RECLAIM, 0);
if (!wq)
goto out_failed;
rpciod_workqueue = wq;
/* Note: highpri because network receive is latency sensitive */
wq = alloc_workqueue("xprtiod", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
if (!wq)
goto free_rpciod;
xprtiod_workqueue = wq;
return 1;
free_rpciod:
wq = rpciod_workqueue;
rpciod_workqueue = NULL;
destroy_workqueue(wq);
out_failed:
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 80 | 87.91% | 6 | 66.67% |
Linus Torvalds (pre-git) | 10 | 10.99% | 2 | 22.22% |
Tejun Heo | 1 | 1.10% | 1 | 11.11% |
Total | 91 | 100.00% | 9 | 100.00% |
static void rpciod_stop(void)
{
struct workqueue_struct *wq = NULL;
if (rpciod_workqueue == NULL)
return;
dprintk("RPC: destroying workqueue rpciod\n");
wq = rpciod_workqueue;
rpciod_workqueue = NULL;
destroy_workqueue(wq);
wq = xprtiod_workqueue;
xprtiod_workqueue = NULL;
destroy_workqueue(wq);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 39 | 73.58% | 4 | 66.67% |
Linus Torvalds (pre-git) | 14 | 26.42% | 2 | 33.33% |
Total | 53 | 100.00% | 6 | 100.00% |
void
rpc_destroy_mempool(void)
{
rpciod_stop();
mempool_destroy(rpc_buffer_mempool);
mempool_destroy(rpc_task_mempool);
kmem_cache_destroy(rpc_task_slabp);
kmem_cache_destroy(rpc_buffer_slabp);
rpc_destroy_wait_queue(&delay_queue);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 36 | 100.00% | 3 | 100.00% |
Total | 36 | 100.00% | 3 | 100.00% |
int
rpc_init_mempool(void)
{
/*
* The following is not strictly a mempool initialisation,
* but there is no harm in doing it here
*/
rpc_init_wait_queue(&delay_queue, "delayq");
if (!rpciod_start())
goto err_nomem;
rpc_task_slabp = kmem_cache_create("rpc_tasks",
sizeof(struct rpc_task),
0, SLAB_HWCACHE_ALIGN,
NULL);
if (!rpc_task_slabp)
goto err_nomem;
rpc_buffer_slabp = kmem_cache_create("rpc_buffers",
RPC_BUFFER_MAXSIZE,
0, SLAB_HWCACHE_ALIGN,
NULL);
if (!rpc_buffer_slabp)
goto err_nomem;
rpc_task_mempool = mempool_create_slab_pool(RPC_TASK_POOLSIZE,
rpc_task_slabp);
if (!rpc_task_mempool)
goto err_nomem;
rpc_buffer_mempool = mempool_create_slab_pool(RPC_BUFFER_POOLSIZE,
rpc_buffer_slabp);
if (!rpc_buffer_mempool)
goto err_nomem;
return 0;
err_nomem:
rpc_destroy_mempool();
return -ENOMEM;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 119 | 98.35% | 2 | 66.67% |
Matthew Dobson | 2 | 1.65% | 1 | 33.33% |
Total | 121 | 100.00% | 3 | 100.00% |
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Trond Myklebust | 3477 | 73.51% | 73 | 57.03% |
Linus Torvalds (pre-git) | 870 | 18.39% | 14 | 10.94% |
Chuck Lever | 167 | 3.53% | 9 | 7.03% |
Weston Andros Adamson | 68 | 1.44% | 4 | 3.12% |
Neil Brown | 31 | 0.66% | 2 | 1.56% |
Peter Zijlstra | 16 | 0.34% | 2 | 1.56% |
David Howells | 14 | 0.30% | 1 | 0.78% |
Jeff Layton | 13 | 0.27% | 3 | 2.34% |
Talpey, Thomas | 10 | 0.21% | 1 | 0.78% |
Hirofumi Ogawa | 10 | 0.21% | 1 | 0.78% |
Mel Gorman | 8 | 0.17% | 1 | 0.78% |
Matthew Wilcox | 5 | 0.11% | 1 | 0.78% |
Christophe Saout | 5 | 0.11% | 1 | 0.78% |
Alexandros Batsakis | 5 | 0.11% | 1 | 0.78% |
Nicholas Mc Guire | 4 | 0.08% | 2 | 1.56% |
Eric Dumazet | 4 | 0.08% | 1 | 0.78% |
Christoph Lameter | 4 | 0.08% | 1 | 0.78% |
Arjan van de Ven | 3 | 0.06% | 1 | 0.78% |
Pavel Emelyanov | 3 | 0.06% | 1 | 0.78% |
Benny Halevy | 3 | 0.06% | 1 | 0.78% |
Geert Uytterhoeven | 2 | 0.04% | 1 | 0.78% |
David Rientjes | 2 | 0.04% | 1 | 0.78% |
Matthew Dobson | 2 | 0.04% | 1 | 0.78% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 0.02% | 1 | 0.78% |
Linus Torvalds | 1 | 0.02% | 1 | 0.78% |
Al Viro | 1 | 0.02% | 1 | 0.78% |
Tejun Heo | 1 | 0.02% | 1 | 0.78% |
Total | 4730 | 100.00% | 128 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.