OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [smbfs/] [smbiod.c] - Blame information for rev 65

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.