⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smbiod.c

📁 linux 内核源代码
💻 C
字号:
/* *  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 unsigned 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_nr(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){	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);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -