The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/smbfs/smbiod.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  smbiod.c
    3  *
    4  *  Copyright (C) 2000, Charles Loep / Corel Corp.
    5  *  Copyright (C) 2001, Urban Widmark
    6  */
    7 
    8 
    9 #include <linux/sched.h>
   10 #include <linux/kernel.h>
   11 #include <linux/mm.h>
   12 #include <linux/string.h>
   13 #include <linux/stat.h>
   14 #include <linux/errno.h>
   15 #include <linux/init.h>
   16 #include <linux/file.h>
   17 #include <linux/dcache.h>
   18 #include <linux/module.h>
   19 #include <linux/net.h>
   20 #include <linux/kthread.h>
   21 #include <net/ip.h>
   22 
   23 #include <linux/smb_fs.h>
   24 #include <linux/smbno.h>
   25 #include <linux/smb_mount.h>
   26 
   27 #include <asm/system.h>
   28 #include <asm/uaccess.h>
   29 
   30 #include "smb_debug.h"
   31 #include "request.h"
   32 #include "proto.h"
   33 
   34 enum smbiod_state {
   35         SMBIOD_DEAD,
   36         SMBIOD_STARTING,
   37         SMBIOD_RUNNING,
   38 };
   39 
   40 static enum smbiod_state smbiod_state = SMBIOD_DEAD;
   41 static struct task_struct *smbiod_thread;
   42 static DECLARE_WAIT_QUEUE_HEAD(smbiod_wait);
   43 static LIST_HEAD(smb_servers);
   44 static DEFINE_SPINLOCK(servers_lock);
   45 
   46 #define SMBIOD_DATA_READY       (1<<0)
   47 static unsigned long smbiod_flags;
   48 
   49 static int smbiod(void *);
   50 static int smbiod_start(void);
   51 
   52 /*
   53  * called when there's work for us to do
   54  */
   55 void smbiod_wake_up(void)
   56 {
   57         if (smbiod_state == SMBIOD_DEAD)
   58                 return;
   59         set_bit(SMBIOD_DATA_READY, &smbiod_flags);
   60         wake_up_interruptible(&smbiod_wait);
   61 }
   62 
   63 /*
   64  * start smbiod if none is running
   65  */
   66 static int smbiod_start(void)
   67 {
   68         struct task_struct *tsk;
   69         int err = 0;
   70 
   71         if (smbiod_state != SMBIOD_DEAD)
   72                 return 0;
   73         smbiod_state = SMBIOD_STARTING;
   74         __module_get(THIS_MODULE);
   75         spin_unlock(&servers_lock);
   76         tsk = kthread_run(smbiod, NULL, "smbiod");
   77         if (IS_ERR(tsk)) {
   78                 err = PTR_ERR(tsk);
   79                 module_put(THIS_MODULE);
   80         }
   81 
   82         spin_lock(&servers_lock);
   83         if (err < 0) {
   84                 smbiod_state = SMBIOD_DEAD;
   85                 smbiod_thread = NULL;
   86         } else {
   87                 smbiod_state = SMBIOD_RUNNING;
   88                 smbiod_thread = tsk;
   89         }
   90         return err;
   91 }
   92 
   93 /*
   94  * register a server & start smbiod if necessary
   95  */
   96 int smbiod_register_server(struct smb_sb_info *server)
   97 {
   98         int ret;
   99         spin_lock(&servers_lock);
  100         list_add(&server->entry, &smb_servers);
  101         VERBOSE("%p\n", server);
  102         ret = smbiod_start();
  103         spin_unlock(&servers_lock);
  104         return ret;
  105 }
  106 
  107 /*
  108  * Unregister a server
  109  * Must be called with the server lock held.
  110  */
  111 void smbiod_unregister_server(struct smb_sb_info *server)
  112 {
  113         spin_lock(&servers_lock);
  114         list_del_init(&server->entry);
  115         VERBOSE("%p\n", server);
  116         spin_unlock(&servers_lock);
  117 
  118         smbiod_wake_up();
  119         smbiod_flush(server);
  120 }
  121 
  122 void smbiod_flush(struct smb_sb_info *server)
  123 {
  124         struct list_head *tmp, *n;
  125         struct smb_request *req;
  126 
  127         list_for_each_safe(tmp, n, &server->xmitq) {
  128                 req = list_entry(tmp, struct smb_request, rq_queue);
  129                 req->rq_errno = -EIO;
  130                 list_del_init(&req->rq_queue);
  131                 smb_rput(req);
  132                 wake_up_interruptible(&req->rq_wait);
  133         }
  134         list_for_each_safe(tmp, n, &server->recvq) {
  135                 req = list_entry(tmp, struct smb_request, rq_queue);
  136                 req->rq_errno = -EIO;
  137                 list_del_init(&req->rq_queue);
  138                 smb_rput(req);
  139                 wake_up_interruptible(&req->rq_wait);
  140         }
  141 }
  142 
  143 /*
  144  * Wake up smbmount and make it reconnect to the server.
  145  * This must be called with the server locked.
  146  *
  147  * FIXME: add smbconnect version to this
  148  */
  149 int smbiod_retry(struct smb_sb_info *server)
  150 {
  151         struct list_head *head;
  152         struct smb_request *req;
  153         struct pid *pid = get_pid(server->conn_pid);
  154         int result = 0;
  155 
  156         VERBOSE("state: %d\n", server->state);
  157         if (server->state == CONN_VALID || server->state == CONN_RETRYING)
  158                 goto out;
  159 
  160         smb_invalidate_inodes(server);
  161 
  162         /*
  163          * Some requests are meaningless after a retry, so we abort them.
  164          * One example are all requests using 'fileid' since the files are
  165          * closed on retry.
  166          */
  167         head = server->xmitq.next;
  168         while (head != &server->xmitq) {
  169                 req = list_entry(head, struct smb_request, rq_queue);
  170                 head = head->next;
  171 
  172                 req->rq_bytes_sent = 0;
  173                 if (req->rq_flags & SMB_REQ_NORETRY) {
  174                         VERBOSE("aborting request %p on xmitq\n", req);
  175                         req->rq_errno = -EIO;
  176                         list_del_init(&req->rq_queue);
  177                         smb_rput(req);
  178                         wake_up_interruptible(&req->rq_wait);
  179                 }
  180         }
  181 
  182         /*
  183          * FIXME: test the code for retrying request we already sent
  184          */
  185         head = server->recvq.next;
  186         while (head != &server->recvq) {
  187                 req = list_entry(head, struct smb_request, rq_queue);
  188                 head = head->next;
  189 #if 0
  190                 if (req->rq_flags & SMB_REQ_RETRY) {
  191                         /* must move the request to the xmitq */
  192                         VERBOSE("retrying request %p on recvq\n", req);
  193                         list_move(&req->rq_queue, &server->xmitq);
  194                         continue;
  195                 }
  196 #endif
  197 
  198                 VERBOSE("aborting request %p on recvq\n", req);
  199                 /* req->rq_rcls = ???; */ /* FIXME: set smb error code too? */
  200                 req->rq_errno = -EIO;
  201                 list_del_init(&req->rq_queue);
  202                 smb_rput(req);
  203                 wake_up_interruptible(&req->rq_wait);
  204         }
  205 
  206         smb_close_socket(server);
  207 
  208         if (!pid) {
  209                 /* FIXME: this is fatal, umount? */
  210                 printk(KERN_ERR "smb_retry: no connection process\n");
  211                 server->state = CONN_RETRIED;
  212                 goto out;
  213         }
  214 
  215         /*
  216          * Change state so that only one retry per server will be started.
  217          */
  218         server->state = CONN_RETRYING;
  219 
  220         /*
  221          * Note: use the "priv" flag, as a user process may need to reconnect.
  222          */
  223         result = kill_pid(pid, SIGUSR1, 1);
  224         if (result) {
  225                 /* FIXME: this is most likely fatal, umount? */
  226                 printk(KERN_ERR "smb_retry: signal failed [%d]\n", result);
  227                 goto out;
  228         }
  229         VERBOSE("signalled pid %d\n", pid_nr(pid));
  230 
  231         /* FIXME: The retried requests should perhaps get a "time boost". */
  232 
  233 out:
  234         put_pid(pid);
  235         return result;
  236 }
  237 
  238 /*
  239  * Currently handles lockingX packets.
  240  */
  241 static void smbiod_handle_request(struct smb_sb_info *server)
  242 {
  243         PARANOIA("smbiod got a request ... and we don't implement oplocks!\n");
  244         server->rstate = SMB_RECV_DROP;
  245 }
  246 
  247 /*
  248  * Do some IO for one server.
  249  */
  250 static void smbiod_doio(struct smb_sb_info *server)
  251 {
  252         int result;
  253         int maxwork = 7;
  254 
  255         if (server->state != CONN_VALID)
  256                 goto out;
  257 
  258         do {
  259                 result = smb_request_recv(server);
  260                 if (result < 0) {
  261                         server->state = CONN_INVALID;
  262                         smbiod_retry(server);
  263                         goto out;       /* reconnecting is slow */
  264                 } else if (server->rstate == SMB_RECV_REQUEST)
  265                         smbiod_handle_request(server);
  266         } while (result > 0 && maxwork-- > 0);
  267 
  268         /*
  269          * If there is more to read then we want to be sure to wake up again.
  270          */
  271         if (server->state != CONN_VALID)
  272                 goto out;
  273         if (smb_recv_available(server) > 0)
  274                 set_bit(SMBIOD_DATA_READY, &smbiod_flags);
  275 
  276         do {
  277                 result = smb_request_send_server(server);
  278                 if (result < 0) {
  279                         server->state = CONN_INVALID;
  280                         smbiod_retry(server);
  281                         goto out;       /* reconnecting is slow */
  282                 }
  283         } while (result > 0);
  284 
  285         /*
  286          * If the last request was not sent out we want to wake up again.
  287          */
  288         if (!list_empty(&server->xmitq))
  289                 set_bit(SMBIOD_DATA_READY, &smbiod_flags);
  290 
  291 out:
  292         return;
  293 }
  294 
  295 /*
  296  * smbiod kernel thread
  297  */
  298 static int smbiod(void *unused)
  299 {
  300         VERBOSE("SMB Kernel thread starting (%d) ...\n", current->pid);
  301 
  302         for (;;) {
  303                 struct smb_sb_info *server;
  304                 struct list_head *pos, *n;
  305 
  306                 /* FIXME: Use poll? */
  307                 wait_event_interruptible(smbiod_wait,
  308                          test_bit(SMBIOD_DATA_READY, &smbiod_flags));
  309                 if (signal_pending(current)) {
  310                         spin_lock(&servers_lock);
  311                         smbiod_state = SMBIOD_DEAD;
  312                         spin_unlock(&servers_lock);
  313                         break;
  314                 }
  315 
  316                 clear_bit(SMBIOD_DATA_READY, &smbiod_flags);
  317 
  318                 spin_lock(&servers_lock);
  319                 if (list_empty(&smb_servers)) {
  320                         smbiod_state = SMBIOD_DEAD;
  321                         spin_unlock(&servers_lock);
  322                         break;
  323                 }
  324 
  325                 list_for_each_safe(pos, n, &smb_servers) {
  326                         server = list_entry(pos, struct smb_sb_info, entry);
  327                         VERBOSE("checking server %p\n", server);
  328 
  329                         if (server->state == CONN_VALID) {
  330                                 spin_unlock(&servers_lock);
  331 
  332                                 smb_lock_server(server);
  333                                 smbiod_doio(server);
  334                                 smb_unlock_server(server);
  335 
  336                                 spin_lock(&servers_lock);
  337                         }
  338                 }
  339                 spin_unlock(&servers_lock);
  340         }
  341 
  342         VERBOSE("SMB Kernel thread exiting (%d) ...\n", current->pid);
  343         module_put_and_exit(0);
  344 }

Cache object: eabd34c2f3b75d54e1b74790ec79ce83


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.