~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to ubuntu/iscsitarget/nthread.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Network thread.
3
 
 * (C) 2004 - 2005 FUJITA Tomonori <tomof@acm.org>
4
 
 * (C) 2008 Arne Redlich <agr@powerkom-dd.de>
5
 
 *
6
 
 * This code is licenced under the GPL.
7
 
 */
8
 
 
9
 
#include <linux/sched.h>
10
 
#include <linux/file.h>
11
 
#include <linux/kthread.h>
12
 
#include <asm/ioctls.h>
13
 
 
14
 
#include "iscsi.h"
15
 
#include "iscsi_dbg.h"
16
 
#include "digest.h"
17
 
 
18
 
enum daemon_state_bit {
19
 
        D_ACTIVE,
20
 
        D_DATA_READY,
21
 
};
22
 
 
23
 
void __nthread_wakeup(struct network_thread_info *info)
24
 
{
25
 
        set_bit(D_DATA_READY, &info->flags);
26
 
        wake_up_process(info->task);
27
 
}
28
 
 
29
 
void nthread_wakeup(struct iscsi_target *target)
30
 
{
31
 
        struct network_thread_info *info = &target->nthread_info;
32
 
 
33
 
        spin_lock_bh(&info->nthread_lock);
34
 
        __nthread_wakeup(info);
35
 
        spin_unlock_bh(&info->nthread_lock);
36
 
}
37
 
 
38
 
static inline void iscsi_conn_init_read(struct iscsi_conn *conn, void *data, size_t len)
39
 
{
40
 
        len = (len + 3) & -4; // XXX ???
41
 
        conn->read_iov[0].iov_base = data;
42
 
        conn->read_iov[0].iov_len = len;
43
 
        conn->read_msg.msg_iov = conn->read_iov;
44
 
        conn->read_msg.msg_iovlen = 1;
45
 
        conn->read_size = (len + 3) & -4;
46
 
}
47
 
 
48
 
static void iscsi_conn_read_ahs(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
49
 
{
50
 
        cmnd->pdu.ahs = kmalloc(cmnd->pdu.ahssize, __GFP_NOFAIL|GFP_KERNEL);
51
 
        assert(cmnd->pdu.ahs);
52
 
        iscsi_conn_init_read(conn, cmnd->pdu.ahs, cmnd->pdu.ahssize);
53
 
}
54
 
 
55
 
static struct iscsi_cmnd * iscsi_get_send_cmnd(struct iscsi_conn *conn)
56
 
{
57
 
        struct iscsi_cmnd *cmnd = NULL;
58
 
 
59
 
        spin_lock(&conn->list_lock);
60
 
        if (!list_empty(&conn->write_list)) {
61
 
                cmnd = list_entry(conn->write_list.next, struct iscsi_cmnd, list);
62
 
                list_del_init(&cmnd->list);
63
 
        }
64
 
        spin_unlock(&conn->list_lock);
65
 
 
66
 
        return cmnd;
67
 
}
68
 
 
69
 
static int is_data_available(struct iscsi_conn *conn)
70
 
{
71
 
        int avail, res;
72
 
        mm_segment_t oldfs;
73
 
        struct socket *sock = conn->sock;
74
 
 
75
 
        oldfs = get_fs();
76
 
        set_fs(get_ds());
77
 
        res = sock->ops->ioctl(sock, SIOCINQ, (unsigned long) &avail);
78
 
        set_fs(oldfs);
79
 
        return (res >= 0) ? avail : res;
80
 
}
81
 
 
82
 
static void forward_iov(struct msghdr *msg, int len)
83
 
{
84
 
        while (msg->msg_iov->iov_len <= len) {
85
 
                len -= msg->msg_iov->iov_len;
86
 
                msg->msg_iov++;
87
 
                msg->msg_iovlen--;
88
 
        }
89
 
 
90
 
        msg->msg_iov->iov_base = (char *) msg->msg_iov->iov_base + len;
91
 
        msg->msg_iov->iov_len -= len;
92
 
}
93
 
 
94
 
static int do_recv(struct iscsi_conn *conn, int state)
95
 
{
96
 
        mm_segment_t oldfs;
97
 
        struct msghdr msg;
98
 
        struct iovec iov[ISCSI_CONN_IOV_MAX];
99
 
        int i, len, res;
100
 
 
101
 
        if (!test_bit(CONN_ACTIVE, &conn->state)) {
102
 
                res = -EIO;
103
 
                goto out;
104
 
        }
105
 
 
106
 
        if (is_data_available(conn) <= 0) {
107
 
                res = -EAGAIN;
108
 
                goto out;
109
 
        }
110
 
 
111
 
        msg.msg_iov = iov;
112
 
        msg.msg_iovlen = min_t(size_t, conn->read_msg.msg_iovlen, ISCSI_CONN_IOV_MAX);
113
 
        for (i = 0, len = 0; i < msg.msg_iovlen; i++) {
114
 
                iov[i] = conn->read_msg.msg_iov[i];
115
 
                len += iov[i].iov_len;
116
 
        }
117
 
 
118
 
        oldfs = get_fs();
119
 
        set_fs(get_ds());
120
 
        res = sock_recvmsg(conn->sock, &msg, len, MSG_DONTWAIT | MSG_NOSIGNAL);
121
 
        set_fs(oldfs);
122
 
 
123
 
        if (res <= 0) {
124
 
                switch (res) {
125
 
                case -EAGAIN:
126
 
                case -ERESTARTSYS:
127
 
                        break;
128
 
                default:
129
 
                        eprintk("%d\n", res);
130
 
                        conn_close(conn);
131
 
                        break;
132
 
                }
133
 
        } else {
134
 
                conn->read_size -= res;
135
 
                if (conn->read_size)
136
 
                        forward_iov(&conn->read_msg, res);
137
 
                else
138
 
                        conn->read_state = state;
139
 
        }
140
 
 
141
 
out:
142
 
        dprintk(D_IOD, "%d\n", res);
143
 
 
144
 
        return res;
145
 
}
146
 
 
147
 
enum rx_state {
148
 
        RX_INIT_BHS, /* Must be zero. */
149
 
        RX_BHS,
150
 
 
151
 
        RX_INIT_AHS,
152
 
        RX_AHS,
153
 
 
154
 
        RX_INIT_HDIGEST,
155
 
        RX_HDIGEST,
156
 
        RX_CHECK_HDIGEST,
157
 
 
158
 
        RX_INIT_DATA,
159
 
        RX_DATA,
160
 
 
161
 
        RX_INIT_DDIGEST,
162
 
        RX_DDIGEST,
163
 
        RX_CHECK_DDIGEST,
164
 
 
165
 
        RX_END,
166
 
};
167
 
 
168
 
static void rx_ddigest(struct iscsi_conn *conn, int state)
169
 
{
170
 
        struct iscsi_cmnd *cmnd = conn->read_cmnd;
171
 
        int res = digest_rx_data(cmnd);
172
 
 
173
 
        if (!res)
174
 
                conn->read_state = state;
175
 
        else
176
 
                conn_close(conn);
177
 
}
178
 
 
179
 
static void rx_hdigest(struct iscsi_conn *conn, int state)
180
 
{
181
 
        struct iscsi_cmnd *cmnd = conn->read_cmnd;
182
 
        int res = digest_rx_header(cmnd);
183
 
 
184
 
        if (!res)
185
 
                conn->read_state = state;
186
 
        else
187
 
                conn_close(conn);
188
 
}
189
 
 
190
 
static struct iscsi_cmnd *create_cmnd(struct iscsi_conn *conn)
191
 
{
192
 
        struct iscsi_cmnd *cmnd;
193
 
 
194
 
        cmnd = cmnd_alloc(conn, 1);
195
 
        iscsi_conn_init_read(cmnd->conn, &cmnd->pdu.bhs, sizeof(cmnd->pdu.bhs));
196
 
        conn->read_state = RX_BHS;
197
 
 
198
 
        return cmnd;
199
 
}
200
 
 
201
 
static int recv(struct iscsi_conn *conn)
202
 
{
203
 
        struct iscsi_cmnd *cmnd = conn->read_cmnd;
204
 
        int hdigest, ddigest, res = 1;
205
 
 
206
 
        if (!test_bit(CONN_ACTIVE, &conn->state))
207
 
                return -EIO;
208
 
 
209
 
        hdigest = conn->hdigest_type & DIGEST_NONE ? 0 : 1;
210
 
        ddigest = conn->ddigest_type & DIGEST_NONE ? 0 : 1;
211
 
 
212
 
next_state:
213
 
        switch (conn->read_state) {
214
 
        case RX_INIT_BHS:
215
 
                assert(!cmnd);
216
 
                cmnd = conn->read_cmnd = create_cmnd(conn);
217
 
        case RX_BHS:
218
 
                res = do_recv(conn, RX_INIT_AHS);
219
 
                if (res <= 0 || conn->read_state != RX_INIT_AHS)
220
 
                        break;
221
 
        case RX_INIT_AHS:
222
 
                iscsi_cmnd_get_length(&cmnd->pdu);
223
 
                if (cmnd->pdu.ahssize) {
224
 
                        iscsi_conn_read_ahs(conn, cmnd);
225
 
                        conn->read_state = RX_AHS;
226
 
                } else
227
 
                        conn->read_state = hdigest ? RX_INIT_HDIGEST : RX_INIT_DATA;
228
 
 
229
 
                if (conn->read_state != RX_AHS)
230
 
                        break;
231
 
        case RX_AHS:
232
 
                res = do_recv(conn, hdigest ? RX_INIT_HDIGEST : RX_INIT_DATA);
233
 
                if (res <= 0 || conn->read_state != RX_INIT_HDIGEST)
234
 
                        break;
235
 
        case RX_INIT_HDIGEST:
236
 
                iscsi_conn_init_read(conn, &cmnd->hdigest, sizeof(u32));
237
 
                conn->read_state = RX_HDIGEST;
238
 
        case RX_HDIGEST:
239
 
                res = do_recv(conn, RX_CHECK_HDIGEST);
240
 
                if (res <= 0 || conn->read_state != RX_CHECK_HDIGEST)
241
 
                        break;
242
 
        case RX_CHECK_HDIGEST:
243
 
                rx_hdigest(conn, RX_INIT_DATA);
244
 
                if (conn->read_state != RX_INIT_DATA)
245
 
                        break;
246
 
        case RX_INIT_DATA:
247
 
                cmnd_rx_start(cmnd);
248
 
                conn->read_state = cmnd->pdu.datasize ? RX_DATA : RX_END;
249
 
                if (conn->read_state != RX_DATA)
250
 
                        break;
251
 
        case RX_DATA:
252
 
                res = do_recv(conn, ddigest ? RX_INIT_DDIGEST : RX_END);
253
 
                if (res <= 0 || conn->read_state != RX_INIT_DDIGEST)
254
 
                        break;
255
 
        case RX_INIT_DDIGEST:
256
 
                iscsi_conn_init_read(conn, &cmnd->ddigest, sizeof(u32));
257
 
                conn->read_state = RX_DDIGEST;
258
 
        case RX_DDIGEST:
259
 
                res = do_recv(conn, RX_CHECK_DDIGEST);
260
 
                if (res <= 0 || conn->read_state != RX_CHECK_DDIGEST)
261
 
                        break;
262
 
        case RX_CHECK_DDIGEST:
263
 
                rx_ddigest(conn, RX_END);
264
 
                break;
265
 
        default:
266
 
                eprintk("%d %d %x\n", res, conn->read_state, cmnd_opcode(cmnd));
267
 
                assert(0);
268
 
        }
269
 
 
270
 
        if (res <= 0)
271
 
                return res;
272
 
 
273
 
        if (conn->read_state != RX_END)
274
 
                goto next_state;
275
 
 
276
 
        if (conn->read_size) {
277
 
                eprintk("%d %x %d\n", res, cmnd_opcode(cmnd), conn->read_size);
278
 
                assert(0);
279
 
        }
280
 
 
281
 
        cmnd_rx_end(cmnd);
282
 
        if (conn->read_size) {
283
 
                eprintk("%x %d\n", cmnd_opcode(cmnd), conn->read_size);
284
 
                conn->read_state = RX_DATA;
285
 
                return 1;
286
 
        }
287
 
 
288
 
        conn->read_cmnd = NULL;
289
 
        conn->read_state = RX_INIT_BHS;
290
 
 
291
 
        return 0;
292
 
}
293
 
 
294
 
/*
295
 
 * @locking: grabs the target's nthread_lock to protect it from races with
296
 
 * iet_write_space()
297
 
 */
298
 
static void set_conn_wspace_wait(struct iscsi_conn *conn)
299
 
{
300
 
        struct network_thread_info *info = &conn->session->target->nthread_info;
301
 
        struct sock *sk = conn->sock->sk;
302
 
 
303
 
        spin_lock_bh(&info->nthread_lock);
304
 
 
305
 
        if (sk_stream_wspace(sk) < sk_stream_min_wspace(sk))
306
 
                set_bit(CONN_WSPACE_WAIT, &conn->state);
307
 
 
308
 
        spin_unlock_bh(&info->nthread_lock);
309
 
}
310
 
 
311
 
/* This is taken from the Ardis code. */
312
 
static int write_data(struct iscsi_conn *conn)
313
 
{
314
 
        mm_segment_t oldfs;
315
 
        struct file *file;
316
 
        struct socket *sock;
317
 
        ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
318
 
        struct tio *tio;
319
 
        struct iovec *iop;
320
 
        int saved_size, size, sendsize;
321
 
        int offset, idx;
322
 
        int flags, res;
323
 
 
324
 
        file = conn->file;
325
 
        saved_size = size = conn->write_size;
326
 
        iop = conn->write_iop;
327
 
 
328
 
        if (iop) while (1) {
329
 
                loff_t off = 0;
330
 
                unsigned long count;
331
 
                struct iovec *vec;
332
 
                int rest;
333
 
 
334
 
                vec = iop;
335
 
                for (count = 0; vec->iov_len; count++, vec++)
336
 
                        ;
337
 
                oldfs = get_fs();
338
 
                set_fs(KERNEL_DS);
339
 
                res = vfs_writev(file, (struct iovec __user *) iop, count, &off);
340
 
                set_fs(oldfs);
341
 
                dprintk(D_DATA, "%#Lx:%u: %d(%ld)\n",
342
 
                        (unsigned long long) conn->session->sid, conn->cid,
343
 
                        res, (long) iop->iov_len);
344
 
                if (unlikely(res <= 0)) {
345
 
                        if (res == -EAGAIN || res == -EINTR) {
346
 
                                conn->write_iop = iop;
347
 
                                goto out_iov;
348
 
                        }
349
 
                        goto err;
350
 
                }
351
 
 
352
 
                rest = res;
353
 
                size -= res;
354
 
                while (iop->iov_len <= rest && rest) {
355
 
                        rest -= iop->iov_len;
356
 
                        iop++;
357
 
                }
358
 
                iop->iov_base += rest;
359
 
                iop->iov_len -= rest;
360
 
 
361
 
                if (!iop->iov_len) {
362
 
                        conn->write_iop = NULL;
363
 
                        if (size)
364
 
                                break;
365
 
                        goto out_iov;
366
 
                }
367
 
        }
368
 
 
369
 
        if (!(tio = conn->write_tcmnd)) {
370
 
                eprintk("%s\n", "warning data missing!");
371
 
                return 0;
372
 
        }
373
 
        offset = conn->write_offset;
374
 
        idx = offset >> PAGE_CACHE_SHIFT;
375
 
        offset &= ~PAGE_CACHE_MASK;
376
 
 
377
 
        sock = conn->sock;
378
 
        sendpage = sock->ops->sendpage ? : sock_no_sendpage;
379
 
        flags = MSG_DONTWAIT;
380
 
 
381
 
        while (1) {
382
 
                sendsize = PAGE_CACHE_SIZE - offset;
383
 
                if (size <= sendsize) {
384
 
                        res = sendpage(sock, tio->pvec[idx], offset, size, flags);
385
 
                        dprintk(D_DATA, "%s %#Lx:%u: %d(%lu,%u,%u)\n",
386
 
                                sock->ops->sendpage ? "sendpage" : "writepage",
387
 
                                (unsigned long long ) conn->session->sid, conn->cid,
388
 
                                res, tio->pvec[idx]->index, offset, size);
389
 
                        if (unlikely(res <= 0)) {
390
 
                                if (res == -EAGAIN || res == -EINTR) {
391
 
                                        goto out;
392
 
                                }
393
 
                                goto err;
394
 
                        }
395
 
                        if (res == size) {
396
 
                                conn->write_tcmnd = NULL;
397
 
                                conn->write_size = 0;
398
 
                                return saved_size;
399
 
                        }
400
 
                        offset += res;
401
 
                        size -= res;
402
 
                        continue;
403
 
                }
404
 
 
405
 
                res = sendpage(sock, tio->pvec[idx], offset,sendsize, flags | MSG_MORE);
406
 
                dprintk(D_DATA, "%s %#Lx:%u: %d(%lu,%u,%u)\n",
407
 
                        sock->ops->sendpage ? "sendpage" : "writepage",
408
 
                        (unsigned long long ) conn->session->sid, conn->cid,
409
 
                        res, tio->pvec[idx]->index, offset, sendsize);
410
 
                if (unlikely(res <= 0)) {
411
 
                        if (res == -EAGAIN || res == -EINTR) {
412
 
                                goto out;
413
 
                        }
414
 
                        goto err;
415
 
                }
416
 
                if (res == sendsize) {
417
 
                        idx++;
418
 
                        offset = 0;
419
 
                } else
420
 
                        offset += res;
421
 
                size -= res;
422
 
        }
423
 
 out:
424
 
        conn->write_offset = (idx << PAGE_CACHE_SHIFT) + offset;
425
 
 out_iov:
426
 
        conn->write_size = size;
427
 
        if (res == -EAGAIN) {
428
 
                set_conn_wspace_wait(conn);
429
 
                if (saved_size == size)
430
 
                        return res;
431
 
        }
432
 
 
433
 
        return saved_size - size;
434
 
 
435
 
 err:
436
 
        eprintk("error %d at %#Lx:%u\n", res,
437
 
                (unsigned long long) conn->session->sid, conn->cid);
438
 
        return res;
439
 
}
440
 
 
441
 
static void exit_tx(struct iscsi_conn *conn, int res)
442
 
{
443
 
        if (res > 0)
444
 
                return;
445
 
 
446
 
        switch (res) {
447
 
        case -EAGAIN:
448
 
        case -ERESTARTSYS:
449
 
                break;
450
 
        default:
451
 
                eprintk("%d %d %d\n", conn->write_size, conn->write_state, res);
452
 
                conn_close(conn);
453
 
                break;
454
 
        }
455
 
}
456
 
 
457
 
static int tx_ddigest(struct iscsi_cmnd *cmnd, int state)
458
 
{
459
 
        int res, rest = cmnd->conn->write_size;
460
 
        struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};
461
 
        struct kvec iov;
462
 
 
463
 
        iov.iov_base = (char *) (&cmnd->ddigest) + (sizeof(u32) - rest);
464
 
        iov.iov_len = rest;
465
 
 
466
 
        res = kernel_sendmsg(cmnd->conn->sock, &msg, &iov, 1, rest);
467
 
 
468
 
        if (res > 0) {
469
 
                cmnd->conn->write_size -= res;
470
 
                if (!cmnd->conn->write_size)
471
 
                        cmnd->conn->write_state = state;
472
 
        } else
473
 
                exit_tx(cmnd->conn, res);
474
 
 
475
 
        return res;
476
 
}
477
 
 
478
 
static void init_tx_hdigest(struct iscsi_cmnd *cmnd)
479
 
{
480
 
        struct iscsi_conn *conn = cmnd->conn;
481
 
        struct iovec *iop;
482
 
 
483
 
        if (conn->hdigest_type & DIGEST_NONE)
484
 
                return;
485
 
 
486
 
        digest_tx_header(cmnd);
487
 
 
488
 
        for (iop = conn->write_iop; iop->iov_len; iop++)
489
 
                ;
490
 
        iop->iov_base = &(cmnd->hdigest);
491
 
        iop->iov_len = sizeof(u32);
492
 
        conn->write_size += sizeof(u32);
493
 
        iop++;
494
 
        iop->iov_len = 0;
495
 
 
496
 
        return;
497
 
}
498
 
 
499
 
enum tx_state {
500
 
        TX_INIT, /* Must be zero. */
501
 
        TX_BHS_DATA,
502
 
        TX_INIT_DDIGEST,
503
 
        TX_DDIGEST,
504
 
        TX_END,
505
 
};
506
 
 
507
 
static int do_send(struct iscsi_conn *conn, int state)
508
 
{
509
 
        int res;
510
 
 
511
 
        res = write_data(conn);
512
 
 
513
 
        if (res > 0) {
514
 
                if (!conn->write_size)
515
 
                        conn->write_state = state;
516
 
        } else
517
 
                exit_tx(conn, res);
518
 
 
519
 
        return res;
520
 
}
521
 
 
522
 
static int send(struct iscsi_conn *conn)
523
 
{
524
 
        struct iscsi_cmnd *cmnd = conn->write_cmnd;
525
 
        int ddigest, res = 0;
526
 
 
527
 
        ddigest = conn->ddigest_type != DIGEST_NONE ? 1 : 0;
528
 
 
529
 
next_state:
530
 
        switch (conn->write_state) {
531
 
        case TX_INIT:
532
 
                assert(!cmnd);
533
 
                cmnd = conn->write_cmnd = iscsi_get_send_cmnd(conn);
534
 
                if (!cmnd)
535
 
                        return 0;
536
 
                cmnd_tx_start(cmnd);
537
 
                init_tx_hdigest(cmnd);
538
 
                conn->write_state = TX_BHS_DATA;
539
 
        case TX_BHS_DATA:
540
 
                res = do_send(conn, ddigest && cmnd->pdu.datasize ? TX_INIT_DDIGEST : TX_END);
541
 
                if (res <= 0 || conn->write_state != TX_INIT_DDIGEST)
542
 
                        break;
543
 
        case TX_INIT_DDIGEST:
544
 
                digest_tx_data(cmnd);
545
 
                assert(!cmnd->conn->write_size);
546
 
                cmnd->conn->write_size += sizeof(u32);
547
 
                conn->write_state = TX_DDIGEST;
548
 
        case TX_DDIGEST:
549
 
                res = tx_ddigest(cmnd, TX_END);
550
 
                break;
551
 
        default:
552
 
                eprintk("%d %d %x\n", res, conn->write_state, cmnd_opcode(cmnd));
553
 
                assert(0);
554
 
        }
555
 
 
556
 
        if (res <= 0)
557
 
                return res;
558
 
 
559
 
        if (conn->write_state != TX_END)
560
 
                goto next_state;
561
 
 
562
 
        if (conn->write_size) {
563
 
                eprintk("%d %x %u\n", res, cmnd_opcode(cmnd), conn->write_size);
564
 
                assert(!conn->write_size);
565
 
        }
566
 
        cmnd_tx_end(cmnd);
567
 
        cmnd_release(cmnd, 0);
568
 
        conn->write_cmnd = NULL;
569
 
        conn->write_state = TX_INIT;
570
 
 
571
 
        return 0;
572
 
}
573
 
 
574
 
static void conn_nop_timeout(unsigned long data)
575
 
{
576
 
        struct iscsi_conn *conn = (struct iscsi_conn *)data;
577
 
 
578
 
        if (test_bit(CONN_ACTIVE, &conn->state))
579
 
                set_bit(CONN_NEED_NOP_IN, &conn->state);
580
 
 
581
 
        dprintk(D_THREAD, "conn %llu:%hu, NOP timer %p\n", conn->session->sid,
582
 
                conn->cid, &conn->nop_timer);
583
 
 
584
 
        nthread_wakeup(conn->session->target);
585
 
}
586
 
 
587
 
static void conn_reset_nop_timer(struct iscsi_conn *conn)
588
 
{
589
 
        struct iscsi_target *target = conn->session->target;
590
 
 
591
 
        if (target->trgt_param.nop_interval)
592
 
                mod_timer(&conn->nop_timer,
593
 
                          jiffies + HZ * target->trgt_param.nop_interval);
594
 
}
595
 
 
596
 
static void conn_start_nop_timer(struct iscsi_conn *conn)
597
 
{
598
 
        struct iscsi_target *target = conn->session->target;
599
 
 
600
 
        if (!target->trgt_param.nop_interval || timer_pending(&conn->nop_timer))
601
 
                return;
602
 
 
603
 
        conn->nop_timer.data = (unsigned long)conn;
604
 
        conn->nop_timer.function = conn_nop_timeout;
605
 
 
606
 
        dprintk(D_THREAD, "conn %llu:%hu, NOP timer %p\n", conn->session->sid,
607
 
                conn->cid, &conn->nop_timer);
608
 
 
609
 
        mod_timer(&conn->nop_timer,
610
 
                  jiffies + HZ * target->trgt_param.nop_interval);
611
 
}
612
 
 
613
 
static void process_io(struct iscsi_conn *conn)
614
 
{
615
 
        struct iscsi_target *target = conn->session->target;
616
 
        int res, wakeup = 0;
617
 
 
618
 
        res = recv(conn);
619
 
 
620
 
        if (is_data_available(conn) > 0 || res > 0) {
621
 
                conn_reset_nop_timer(conn);
622
 
                wakeup = 1;
623
 
        }
624
 
 
625
 
        if (!test_bit(CONN_ACTIVE, &conn->state)) {
626
 
                wakeup = 1;
627
 
                goto out;
628
 
        }
629
 
 
630
 
        if (test_bit(CONN_WSPACE_WAIT, &conn->state))
631
 
                goto out;
632
 
 
633
 
        res = send(conn);
634
 
 
635
 
        if (!list_empty(&conn->write_list) || conn->write_cmnd) {
636
 
                conn_reset_nop_timer(conn);
637
 
                wakeup = 1;
638
 
        }
639
 
 
640
 
out:
641
 
        if (wakeup)
642
 
                nthread_wakeup(target);
643
 
        else if (test_and_clear_bit(CONN_NEED_NOP_IN, &conn->state)) {
644
 
                send_nop_in(conn);
645
 
                nthread_wakeup(target);
646
 
        } else
647
 
                conn_start_nop_timer(conn);
648
 
 
649
 
        return;
650
 
}
651
 
 
652
 
static void close_conn(struct iscsi_conn *conn)
653
 
{
654
 
        struct iscsi_session *session = conn->session;
655
 
        struct iscsi_target *target = conn->session->target;
656
 
        struct iscsi_cmnd *cmnd;
657
 
 
658
 
        if (target->trgt_param.nop_interval)
659
 
                del_timer_sync(&conn->nop_timer);
660
 
 
661
 
        conn->sock->ops->shutdown(conn->sock, 2);
662
 
 
663
 
        write_lock_bh(&conn->sock->sk->sk_callback_lock);
664
 
        conn->sock->sk->sk_state_change = target->nthread_info.old_state_change;
665
 
        conn->sock->sk->sk_data_ready = target->nthread_info.old_data_ready;
666
 
        conn->sock->sk->sk_write_space = target->nthread_info.old_write_space;
667
 
        write_unlock_bh(&conn->sock->sk->sk_callback_lock);
668
 
 
669
 
        fput(conn->file);
670
 
        conn->file = NULL;
671
 
        conn->sock = NULL;
672
 
 
673
 
        while (atomic_read(&conn->nr_busy_cmnds))
674
 
                yield();
675
 
 
676
 
        while (!list_empty(&conn->pdu_list)) {
677
 
                cmnd = list_entry(conn->pdu_list.next, struct iscsi_cmnd, conn_list);
678
 
 
679
 
                list_del_init(&cmnd->list);
680
 
                cmnd_release(cmnd, 1);
681
 
        }
682
 
 
683
 
        if (atomic_read(&conn->nr_cmnds)) {
684
 
                eprintk("%u\n", atomic_read(&conn->nr_cmnds));
685
 
                list_for_each_entry(cmnd, &conn->pdu_list, conn_list)
686
 
                        eprintk("%x %x\n", cmnd_opcode(cmnd), cmnd_itt(cmnd));
687
 
                assert(0);
688
 
        }
689
 
 
690
 
        event_send(target->tid, session->sid, conn->cid, E_CONN_CLOSE, 0);
691
 
        conn_free(conn);
692
 
 
693
 
        if (list_empty(&session->conn_list)) {
694
 
                if (session->done)
695
 
                        complete(session->done);
696
 
                else
697
 
                        session_del(target, session->sid);
698
 
        }
699
 
}
700
 
 
701
 
static int istd(void *arg)
702
 
{
703
 
        struct iscsi_target *target = arg;
704
 
        struct network_thread_info *info = &target->nthread_info;
705
 
        struct iscsi_conn *conn, *tmp;
706
 
 
707
 
        __set_current_state(TASK_RUNNING);
708
 
        do {
709
 
                spin_lock_bh(&info->nthread_lock);
710
 
                __set_current_state(TASK_INTERRUPTIBLE);
711
 
 
712
 
                if (!test_bit(D_DATA_READY, &info->flags)) {
713
 
                        spin_unlock_bh(&info->nthread_lock);
714
 
                        schedule();
715
 
                        spin_lock_bh(&info->nthread_lock);
716
 
                }
717
 
                __set_current_state(TASK_RUNNING);
718
 
                clear_bit(D_DATA_READY, &info->flags);
719
 
                spin_unlock_bh(&info->nthread_lock);
720
 
 
721
 
                target_lock(target, 0);
722
 
                list_for_each_entry_safe(conn, tmp, &info->active_conns, poll_list) {
723
 
                        if (test_bit(CONN_ACTIVE, &conn->state))
724
 
                                process_io(conn);
725
 
                        else
726
 
                                close_conn(conn);
727
 
                }
728
 
                target_unlock(target);
729
 
 
730
 
        } while (!kthread_should_stop());
731
 
 
732
 
        return 0;
733
 
}
734
 
 
735
 
int nthread_init(struct iscsi_target *target)
736
 
{
737
 
        struct network_thread_info *info = &target->nthread_info;
738
 
 
739
 
        info->flags = 0;
740
 
        info->task = NULL;
741
 
 
742
 
        info->old_state_change = NULL;
743
 
        info->old_data_ready = NULL;
744
 
        info->old_write_space = NULL;
745
 
 
746
 
        INIT_LIST_HEAD(&info->active_conns);
747
 
 
748
 
        spin_lock_init(&info->nthread_lock);
749
 
 
750
 
        return 0;
751
 
}
752
 
 
753
 
int nthread_start(struct iscsi_target *target)
754
 
{
755
 
        int err = 0;
756
 
        struct network_thread_info *info = &target->nthread_info;
757
 
        struct task_struct *task;
758
 
 
759
 
        if (info->task) {
760
 
                eprintk("Target (%u) already runs\n", target->tid);
761
 
                return -EALREADY;
762
 
        }
763
 
 
764
 
        task = kthread_run(istd, target, "istd%d", target->tid);
765
 
 
766
 
        if (IS_ERR(task))
767
 
                err = PTR_ERR(task);
768
 
        else
769
 
                info->task = task;
770
 
 
771
 
        return err;
772
 
}
773
 
 
774
 
int nthread_stop(struct iscsi_target *target)
775
 
{
776
 
        int err;
777
 
        struct network_thread_info *info = &target->nthread_info;
778
 
 
779
 
        if (!info->task)
780
 
                return -ESRCH;
781
 
 
782
 
        err = kthread_stop(info->task);
783
 
 
784
 
        if (err < 0 && err != -EINTR)
785
 
                return err;
786
 
 
787
 
        info->task = NULL;
788
 
 
789
 
        return 0;
790
 
}