diff options
Diffstat (limited to 'fs/afs/kafsasyncd.c')
-rw-r--r-- | fs/afs/kafsasyncd.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c new file mode 100644 index 00000000000..6fc88ae8ad9 --- /dev/null +++ b/fs/afs/kafsasyncd.c @@ -0,0 +1,257 @@ +/* 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(PF_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() */ |