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