123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- /* kafsasyncd.c: AFS asynchronous operation daemon
- *
- * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- *
- * The AFS async daemon is used to the following:
- * - probe "dead" servers to see whether they've come back to life yet.
- * - probe "live" servers that we haven't talked to for a while to see if they are better
- * candidates for serving than what we're currently using
- * - poll volume location servers to keep up to date volume location lists
- */
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/sched.h>
- #include <linux/completion.h>
- #include "cell.h"
- #include "server.h"
- #include "volume.h"
- #include "kafsasyncd.h"
- #include "kafstimod.h"
- #include <rxrpc/call.h>
- #include <asm/errno.h>
- #include "internal.h"
- static DECLARE_COMPLETION(kafsasyncd_alive);
- static DECLARE_COMPLETION(kafsasyncd_dead);
- static DECLARE_WAIT_QUEUE_HEAD(kafsasyncd_sleepq);
- static struct task_struct *kafsasyncd_task;
- static int kafsasyncd_die;
- static int kafsasyncd(void *arg);
- static LIST_HEAD(kafsasyncd_async_attnq);
- static LIST_HEAD(kafsasyncd_async_busyq);
- static DEFINE_SPINLOCK(kafsasyncd_async_lock);
- static void kafsasyncd_null_call_attn_func(struct rxrpc_call *call)
- {
- }
- static void kafsasyncd_null_call_error_func(struct rxrpc_call *call)
- {
- }
- /*****************************************************************************/
- /*
- * start the async daemon
- */
- int afs_kafsasyncd_start(void)
- {
- int ret;
- ret = kernel_thread(kafsasyncd, NULL, 0);
- if (ret < 0)
- return ret;
- wait_for_completion(&kafsasyncd_alive);
- return ret;
- } /* end afs_kafsasyncd_start() */
- /*****************************************************************************/
- /*
- * stop the async daemon
- */
- void afs_kafsasyncd_stop(void)
- {
- /* get rid of my daemon */
- kafsasyncd_die = 1;
- wake_up(&kafsasyncd_sleepq);
- wait_for_completion(&kafsasyncd_dead);
- } /* end afs_kafsasyncd_stop() */
- /*****************************************************************************/
- /*
- * probing daemon
- */
- static int kafsasyncd(void *arg)
- {
- struct afs_async_op *op;
- int die;
- DECLARE_WAITQUEUE(myself, current);
- kafsasyncd_task = current;
- printk("kAFS: Started kafsasyncd %d\n", current->pid);
- daemonize("kafsasyncd");
- complete(&kafsasyncd_alive);
- /* loop around looking for things to attend to */
- do {
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&kafsasyncd_sleepq, &myself);
- for (;;) {
- if (!list_empty(&kafsasyncd_async_attnq) ||
- signal_pending(current) ||
- kafsasyncd_die)
- break;
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- }
- remove_wait_queue(&kafsasyncd_sleepq, &myself);
- set_current_state(TASK_RUNNING);
- try_to_freeze();
- /* discard pending signals */
- afs_discard_my_signals();
- die = kafsasyncd_die;
- /* deal with the next asynchronous operation requiring
- * attention */
- if (!list_empty(&kafsasyncd_async_attnq)) {
- struct afs_async_op *op;
- _debug("@@@ Begin Asynchronous Operation");
- op = NULL;
- spin_lock(&kafsasyncd_async_lock);
- if (!list_empty(&kafsasyncd_async_attnq)) {
- op = list_entry(kafsasyncd_async_attnq.next,
- struct afs_async_op, link);
- list_del(&op->link);
- list_add_tail(&op->link,
- &kafsasyncd_async_busyq);
- }
- spin_unlock(&kafsasyncd_async_lock);
- _debug("@@@ Operation %p {%p}\n",
- op, op ? op->ops : NULL);
- if (op)
- op->ops->attend(op);
- _debug("@@@ End Asynchronous Operation");
- }
- } while(!die);
- /* need to kill all outstanding asynchronous operations before
- * exiting */
- kafsasyncd_task = NULL;
- spin_lock(&kafsasyncd_async_lock);
- /* fold the busy and attention queues together */
- list_splice_init(&kafsasyncd_async_busyq,
- &kafsasyncd_async_attnq);
- /* dequeue kafsasyncd from all their wait queues */
- list_for_each_entry(op, &kafsasyncd_async_attnq, link) {
- op->call->app_attn_func = kafsasyncd_null_call_attn_func;
- op->call->app_error_func = kafsasyncd_null_call_error_func;
- remove_wait_queue(&op->call->waitq, &op->waiter);
- }
- spin_unlock(&kafsasyncd_async_lock);
- /* abort all the operations */
- while (!list_empty(&kafsasyncd_async_attnq)) {
- op = list_entry(kafsasyncd_async_attnq.next, struct afs_async_op, link);
- list_del_init(&op->link);
- rxrpc_call_abort(op->call, -EIO);
- rxrpc_put_call(op->call);
- op->call = NULL;
- op->ops->discard(op);
- }
- /* and that's all */
- _leave("");
- complete_and_exit(&kafsasyncd_dead, 0);
- } /* end kafsasyncd() */
- /*****************************************************************************/
- /*
- * begin an operation
- * - place operation on busy queue
- */
- void afs_kafsasyncd_begin_op(struct afs_async_op *op)
- {
- _enter("");
- spin_lock(&kafsasyncd_async_lock);
- init_waitqueue_entry(&op->waiter, kafsasyncd_task);
- add_wait_queue(&op->call->waitq, &op->waiter);
- list_del(&op->link);
- list_add_tail(&op->link, &kafsasyncd_async_busyq);
- spin_unlock(&kafsasyncd_async_lock);
- _leave("");
- } /* end afs_kafsasyncd_begin_op() */
- /*****************************************************************************/
- /*
- * request attention for an operation
- * - move to attention queue
- */
- void afs_kafsasyncd_attend_op(struct afs_async_op *op)
- {
- _enter("");
- spin_lock(&kafsasyncd_async_lock);
- list_del(&op->link);
- list_add_tail(&op->link, &kafsasyncd_async_attnq);
- spin_unlock(&kafsasyncd_async_lock);
- wake_up(&kafsasyncd_sleepq);
- _leave("");
- } /* end afs_kafsasyncd_attend_op() */
- /*****************************************************************************/
- /*
- * terminate an operation
- * - remove from either queue
- */
- void afs_kafsasyncd_terminate_op(struct afs_async_op *op)
- {
- _enter("");
- spin_lock(&kafsasyncd_async_lock);
- if (!list_empty(&op->link)) {
- list_del_init(&op->link);
- remove_wait_queue(&op->call->waitq, &op->waiter);
- }
- spin_unlock(&kafsasyncd_async_lock);
- wake_up(&kafsasyncd_sleepq);
- _leave("");
- } /* end afs_kafsasyncd_terminate_op() */
|