summaryrefslogtreecommitdiffstats
path: root/fs/afs/kafsasyncd.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs/kafsasyncd.c')
-rw-r--r--fs/afs/kafsasyncd.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c
new file mode 100644
index 000000000000..6fc88ae8ad94
--- /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() */