/*
 *  smbiod.c
 *
 *  Copyright (C) 2000, Charles Loep / Corel Corp.
 *  Copyright (C) 2001, Urban Widmark
 */


#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/file.h>
#include <linux/dcache.h>
#include <linux/module.h>
#include <linux/net.h>
#include <linux/kthread.h>
#include <net/ip.h>

#include <linux/smb_fs.h>
#include <linux/smbno.h>
#include <linux/smb_mount.h>

#include <asm/system.h>
#include <asm/uaccess.h>

#include "smb_debug.h"
#include "request.h"
#include "proto.h"

enum smbiod_state {
	SMBIOD_DEAD,
	SMBIOD_STARTING,
	SMBIOD_RUNNING,
};

static enum smbiod_state smbiod_state = SMBIOD_DEAD;
static struct task_struct *smbiod_thread;
static DECLARE_WAIT_QUEUE_HEAD(smbiod_wait);
static LIST_HEAD(smb_servers);
static DEFINE_SPINLOCK(servers_lock);

#define SMBIOD_DATA_READY	(1<<0)
static long smbiod_flags;

static int smbiod(void *);
static int smbiod_start(void);

/*
 * called when there's work for us to do
 */
void smbiod_wake_up(void)
{
	if (smbiod_state == SMBIOD_DEAD)
		return;
	set_bit(SMBIOD_DATA_READY, &smbiod_flags);
	wake_up_interruptible(&smbiod_wait);
}

/*
 * start smbiod if none is running
 */
static int smbiod_start(void)
{
	struct task_struct *tsk;
	int err = 0;

	if (smbiod_state != SMBIOD_DEAD)
		return 0;
	smbiod_state = SMBIOD_STARTING;
	__module_get(THIS_MODULE);
	spin_unlock(&servers_lock);
	tsk = kthread_run(smbiod, NULL, "smbiod");
	if (IS_ERR(tsk)) {
		err = PTR_ERR(tsk);
		module_put(THIS_MODULE);
	}

	spin_lock(&servers_lock);
	if (err < 0) {
		smbiod_state = SMBIOD_DEAD;
		smbiod_thread = NULL;
	} else {
		smbiod_state = SMBIOD_RUNNING;
		smbiod_thread = tsk;
	}
	return err;
}

/*
 * register a server & start smbiod if necessary
 */
int smbiod_register_server(struct smb_sb_info *server)
{
	int ret;
	spin_lock(&servers_lock);
	list_add(&server->entry, &smb_servers);
	VERBOSE("%p\n", server);
	ret = smbiod_start();
	spin_unlock(&servers_lock);
	return ret;
}

/*
 * Unregister a server
 * Must be called with the server lock held.
 */
void smbiod_unregister_server(struct smb_sb_info *server)
{
	spin_lock(&servers_lock);
	list_del_init(&server->entry);
	VERBOSE("%p\n", server);
	spin_unlock(&servers_lock);

	smbiod_wake_up();
	smbiod_flush(server);
}

void smbiod_flush(struct smb_sb_info *server)
{
	struct list_head *tmp, *n;
	struct smb_request *req;

	list_for_each_safe(tmp, n, &server->xmitq) {
		req = list_entry(tmp, struct smb_request, rq_queue);
		req->rq_errno = -EIO;
		list_del_init(&req->rq_queue);
		smb_rput(req);
		wake_up_interruptible(&req->rq_wait);
	}
	list_for_each_safe(tmp, n, &server->recvq) {
		req = list_entry(tmp, struct smb_request, rq_queue);
		req->rq_errno = -EIO;
		list_del_init(&req->rq_queue);
		smb_rput(req);
		wake_up_interruptible(&req->rq_wait);
	}
}

/*
 * Wake up smbmount and make it reconnect to the server.
 * This must be called with the server locked.
 *
 * FIXME: add smbconnect version to this
 */
int smbiod_retry(struct smb_sb_info *server)
{
	struct list_head *head;
	struct smb_request *req;
	struct pid *pid = get_pid(server->conn_pid);
	int result = 0;

	VERBOSE("state: %d\n", server->state);
	if (server->state == CONN_VALID || server->state == CONN_RETRYING)
		goto out;

	smb_invalidate_inodes(server);

	/*
	 * Some requests are meaningless after a retry, so we abort them.
	 * One example are all requests using 'fileid' since the files are
	 * closed on retry.
	 */
	head = server->xmitq.next;
	while (head != &server->xmitq) {
		req = list_entry(head, struct smb_request, rq_queue);
		head = head->next;

		req->rq_bytes_sent = 0;
		if (req->rq_flags & SMB_REQ_NORETRY) {
			VERBOSE("aborting request %p on xmitq\n", req);
			req->rq_errno = -EIO;
			list_del_init(&req->rq_queue);
			smb_rput(req);
			wake_up_interruptible(&req->rq_wait);
		}
	}

	/*
	 * FIXME: test the code for retrying request we already sent
	 */
	head = server->recvq.next;
	while (head != &server->recvq) {
		req = list_entry(head, struct smb_request, rq_queue);
		head = head->next;
#if 0
		if (req->rq_flags & SMB_REQ_RETRY) {
			/* must move the request to the xmitq */
			VERBOSE("retrying request %p on recvq\n", req);
			list_move(&req->rq_queue, &server->xmitq);
			continue;
		}
#endif

		VERBOSE("aborting request %p on recvq\n", req);
		/* req->rq_rcls = ???; */ /* FIXME: set smb error code too? */
		req->rq_errno = -EIO;
		list_del_init(&req->rq_queue);
		smb_rput(req);
		wake_up_interruptible(&req->rq_wait);
	}

	smb_close_socket(server);

	if (pid == 0) {
		/* FIXME: this is fatal, umount? */
		printk(KERN_ERR "smb_retry: no connection process\n");
		server->state = CONN_RETRIED;
		goto out;
	}

	/*
	 * Change state so that only one retry per server will be started.
	 */
	server->state = CONN_RETRYING;

	/*
	 * Note: use the "priv" flag, as a user process may need to reconnect.
	 */
	result = kill_pid(pid, SIGUSR1, 1);
	if (result) {
		/* FIXME: this is most likely fatal, umount? */
		printk(KERN_ERR "smb_retry: signal failed [%d]\n", result);
		goto out;
	}
	VERBOSE("signalled pid %d\n", pid);

	/* FIXME: The retried requests should perhaps get a "time boost". */

out:
	put_pid(pid);
	return result;
}

/*
 * Currently handles lockingX packets.
 */
static void smbiod_handle_request(struct smb_sb_info *server)
{
	PARANOIA("smbiod got a request ... and we don't implement oplocks!\n");
	server->rstate = SMB_RECV_DROP;
}

/*
 * Do some IO for one server.
 */
static void smbiod_doio(struct smb_sb_info *server)
{
	int result;
	int maxwork = 7;

	if (server->state != CONN_VALID)
		goto out;

	do {
		result = smb_request_recv(server);
		if (result < 0) {
			server->state = CONN_INVALID;
			smbiod_retry(server);
			goto out;	/* reconnecting is slow */
		} else if (server->rstate == SMB_RECV_REQUEST)
			smbiod_handle_request(server);
	} while (result > 0 && maxwork-- > 0);

	/*
	 * If there is more to read then we want to be sure to wake up again.
	 */
	if (server->state != CONN_VALID)
		goto out;
	if (smb_recv_available(server) > 0)
		set_bit(SMBIOD_DATA_READY, &smbiod_flags);

	do {
		result = smb_request_send_server(server);
		if (result < 0) {
			server->state = CONN_INVALID;
			smbiod_retry(server);
			goto out;	/* reconnecting is slow */
		}
	} while (result > 0);

	/*
	 * If the last request was not sent out we want to wake up again.
	 */
	if (!list_empty(&server->xmitq))
		set_bit(SMBIOD_DATA_READY, &smbiod_flags);

out:
	return;
}

/*
 * smbiod kernel thread
 */
static int smbiod(void *unused)
{
	allow_signal(SIGKILL);

	VERBOSE("SMB Kernel thread starting (%d) ...\n", current->pid);

	for (;;) {
		struct smb_sb_info *server;
		struct list_head *pos, *n;

		/* FIXME: Use poll? */
		wait_event_interruptible(smbiod_wait,
			 test_bit(SMBIOD_DATA_READY, &smbiod_flags));
		if (signal_pending(current)) {
			spin_lock(&servers_lock);
			smbiod_state = SMBIOD_DEAD;
			spin_unlock(&servers_lock);
			break;
		}

		clear_bit(SMBIOD_DATA_READY, &smbiod_flags);

		spin_lock(&servers_lock);
		if (list_empty(&smb_servers)) {
			smbiod_state = SMBIOD_DEAD;
			spin_unlock(&servers_lock);
			break;
		}

		list_for_each_safe(pos, n, &smb_servers) {
			server = list_entry(pos, struct smb_sb_info, entry);
			VERBOSE("checking server %p\n", server);

			if (server->state == CONN_VALID) {
				spin_unlock(&servers_lock);

				smb_lock_server(server);
				smbiod_doio(server);
				smb_unlock_server(server);

				spin_lock(&servers_lock);
			}
		}
		spin_unlock(&servers_lock);
	}

	VERBOSE("SMB Kernel thread exiting (%d) ...\n", current->pid);
	module_put_and_exit(0);
}
