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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [fs/] [cifs/] [transport.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 *   fs/cifs/transport.c
3
 *
4
 *   Copyright (C) International Business Machines  Corp., 2002,2007
5
 *   Author(s): Steve French (sfrench@us.ibm.com)
6
 *   Jeremy Allison (jra@samba.org) 2006.
7
 *
8
 *   This library is free software; you can redistribute it and/or modify
9
 *   it under the terms of the GNU Lesser General Public License as published
10
 *   by the Free Software Foundation; either version 2.1 of the License, or
11
 *   (at your option) any later version.
12
 *
13
 *   This library is distributed in the hope that it will be useful,
14
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
16
 *   the GNU Lesser General Public License for more details.
17
 *
18
 *   You should have received a copy of the GNU Lesser General Public License
19
 *   along with this library; if not, write to the Free Software
20
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
 */
22
 
23
#include <linux/fs.h>
24
#include <linux/list.h>
25
#include <linux/wait.h>
26
#include <linux/net.h>
27
#include <linux/delay.h>
28
#include <asm/uaccess.h>
29
#include <asm/processor.h>
30
#include <linux/mempool.h>
31
#include "cifspdu.h"
32
#include "cifsglob.h"
33
#include "cifsproto.h"
34
#include "cifs_debug.h"
35
 
36
extern mempool_t *cifs_mid_poolp;
37
extern struct kmem_cache *cifs_oplock_cachep;
38
 
39
static struct mid_q_entry *
40
AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
41
{
42
        struct mid_q_entry *temp;
43
 
44
        if (ses == NULL) {
45
                cERROR(1, ("Null session passed in to AllocMidQEntry"));
46
                return NULL;
47
        }
48
        if (ses->server == NULL) {
49
                cERROR(1, ("Null TCP session in AllocMidQEntry"));
50
                return NULL;
51
        }
52
 
53
        temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
54
                                                    GFP_KERNEL | GFP_NOFS);
55
        if (temp == NULL)
56
                return temp;
57
        else {
58
                memset(temp, 0, sizeof(struct mid_q_entry));
59
                temp->mid = smb_buffer->Mid;    /* always LE */
60
                temp->pid = current->pid;
61
                temp->command = smb_buffer->Command;
62
                cFYI(1, ("For smb_command %d", temp->command));
63
        /*      do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
64
                /* when mid allocated can be before when sent */
65
                temp->when_alloc = jiffies;
66
                temp->ses = ses;
67
                temp->tsk = current;
68
        }
69
 
70
        spin_lock(&GlobalMid_Lock);
71
        list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
72
        atomic_inc(&midCount);
73
        temp->midState = MID_REQUEST_ALLOCATED;
74
        spin_unlock(&GlobalMid_Lock);
75
        return temp;
76
}
77
 
78
static void
79
DeleteMidQEntry(struct mid_q_entry *midEntry)
80
{
81
#ifdef CONFIG_CIFS_STATS2
82
        unsigned long now;
83
#endif
84
        spin_lock(&GlobalMid_Lock);
85
        midEntry->midState = MID_FREE;
86
        list_del(&midEntry->qhead);
87
        atomic_dec(&midCount);
88
        spin_unlock(&GlobalMid_Lock);
89
        if (midEntry->largeBuf)
90
                cifs_buf_release(midEntry->resp_buf);
91
        else
92
                cifs_small_buf_release(midEntry->resp_buf);
93
#ifdef CONFIG_CIFS_STATS2
94
        now = jiffies;
95
        /* commands taking longer than one second are indications that
96
           something is wrong, unless it is quite a slow link or server */
97
        if ((now - midEntry->when_alloc) > HZ) {
98
                if ((cifsFYI & CIFS_TIMER) &&
99
                   (midEntry->command != SMB_COM_LOCKING_ANDX)) {
100
                        printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
101
                               midEntry->command, midEntry->mid);
102
                        printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
103
                               now - midEntry->when_alloc,
104
                               now - midEntry->when_sent,
105
                               now - midEntry->when_received);
106
                }
107
        }
108
#endif
109
        mempool_free(midEntry, cifs_mid_poolp);
110
}
111
 
112
struct oplock_q_entry *
113
AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
114
{
115
        struct oplock_q_entry *temp;
116
        if ((pinode == NULL) || (tcon == NULL)) {
117
                cERROR(1, ("Null parms passed to AllocOplockQEntry"));
118
                return NULL;
119
        }
120
        temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
121
                                                       GFP_KERNEL);
122
        if (temp == NULL)
123
                return temp;
124
        else {
125
                temp->pinode = pinode;
126
                temp->tcon = tcon;
127
                temp->netfid = fid;
128
                spin_lock(&GlobalMid_Lock);
129
                list_add_tail(&temp->qhead, &GlobalOplock_Q);
130
                spin_unlock(&GlobalMid_Lock);
131
        }
132
        return temp;
133
 
134
}
135
 
136
void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
137
{
138
        spin_lock(&GlobalMid_Lock);
139
    /* should we check if list empty first? */
140
        list_del(&oplockEntry->qhead);
141
        spin_unlock(&GlobalMid_Lock);
142
        kmem_cache_free(cifs_oplock_cachep, oplockEntry);
143
}
144
 
145
int
146
smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
147
         unsigned int smb_buf_length, struct sockaddr *sin)
148
{
149
        int rc = 0;
150
        int i = 0;
151
        struct msghdr smb_msg;
152
        struct kvec iov;
153
        unsigned len = smb_buf_length + 4;
154
 
155
        if (ssocket == NULL)
156
                return -ENOTSOCK; /* BB eventually add reconnect code here */
157
        iov.iov_base = smb_buffer;
158
        iov.iov_len = len;
159
 
160
        smb_msg.msg_name = sin;
161
        smb_msg.msg_namelen = sizeof(struct sockaddr);
162
        smb_msg.msg_control = NULL;
163
        smb_msg.msg_controllen = 0;
164
        smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
165
 
166
        /* smb header is converted in header_assemble. bcc and rest of SMB word
167
           area, and byte area if necessary, is converted to littleendian in
168
           cifssmb.c and RFC1001 len is converted to bigendian in smb_send
169
           Flags2 is converted in SendReceive */
170
 
171
        smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
172
        cFYI(1, ("Sending smb of length %d", smb_buf_length));
173
        dump_smb(smb_buffer, len);
174
 
175
        while (len > 0) {
176
                rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
177
                if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
178
                        i++;
179
                /* smaller timeout here than send2 since smaller size */
180
                /* Although it may not be required, this also is smaller
181
                   oplock break time */
182
                        if (i > 12) {
183
                                cERROR(1,
184
                                   ("sends on sock %p stuck for 7 seconds",
185
                                    ssocket));
186
                                rc = -EAGAIN;
187
                                break;
188
                        }
189
                        msleep(1 << i);
190
                        continue;
191
                }
192
                if (rc < 0)
193
                        break;
194
                else
195
                        i = 0; /* reset i after each successful send */
196
                iov.iov_base += rc;
197
                iov.iov_len -= rc;
198
                len -= rc;
199
        }
200
 
201
        if (rc < 0) {
202
                cERROR(1, ("Error %d sending data on socket to server", rc));
203
        } else {
204
                rc = 0;
205
        }
206
 
207
        /* Don't want to modify the buffer as a
208
           side effect of this call. */
209
        smb_buffer->smb_buf_length = smb_buf_length;
210
 
211
        return rc;
212
}
213
 
214
static int
215
smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
216
          struct sockaddr *sin)
217
{
218
        int rc = 0;
219
        int i = 0;
220
        struct msghdr smb_msg;
221
        struct smb_hdr *smb_buffer = iov[0].iov_base;
222
        unsigned int len = iov[0].iov_len;
223
        unsigned int total_len;
224
        int first_vec = 0;
225
        unsigned int smb_buf_length = smb_buffer->smb_buf_length;
226
 
227
        if (ssocket == NULL)
228
                return -ENOTSOCK; /* BB eventually add reconnect code here */
229
 
230
        smb_msg.msg_name = sin;
231
        smb_msg.msg_namelen = sizeof(struct sockaddr);
232
        smb_msg.msg_control = NULL;
233
        smb_msg.msg_controllen = 0;
234
        smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
235
 
236
        /* smb header is converted in header_assemble. bcc and rest of SMB word
237
           area, and byte area if necessary, is converted to littleendian in
238
           cifssmb.c and RFC1001 len is converted to bigendian in smb_send
239
           Flags2 is converted in SendReceive */
240
 
241
 
242
        total_len = 0;
243
        for (i = 0; i < n_vec; i++)
244
                total_len += iov[i].iov_len;
245
 
246
        smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
247
        cFYI(1, ("Sending smb:  total_len %d", total_len));
248
        dump_smb(smb_buffer, len);
249
 
250
        while (total_len) {
251
                rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
252
                                    n_vec - first_vec, total_len);
253
                if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
254
                        i++;
255
                        if (i >= 14) {
256
                                cERROR(1,
257
                                   ("sends on sock %p stuck for 15 seconds",
258
                                    ssocket));
259
                                rc = -EAGAIN;
260
                                break;
261
                        }
262
                        msleep(1 << i);
263
                        continue;
264
                }
265
                if (rc < 0)
266
                        break;
267
 
268
                if (rc >= total_len) {
269
                        WARN_ON(rc > total_len);
270
                        break;
271
                }
272
                if (rc == 0) {
273
                        /* should never happen, letting socket clear before
274
                           retrying is our only obvious option here */
275
                        cERROR(1, ("tcp sent no data"));
276
                        msleep(500);
277
                        continue;
278
                }
279
                total_len -= rc;
280
                /* the line below resets i */
281
                for (i = first_vec; i < n_vec; i++) {
282
                        if (iov[i].iov_len) {
283
                                if (rc > iov[i].iov_len) {
284
                                        rc -= iov[i].iov_len;
285
                                        iov[i].iov_len = 0;
286
                                } else {
287
                                        iov[i].iov_base += rc;
288
                                        iov[i].iov_len -= rc;
289
                                        first_vec = i;
290
                                        break;
291
                                }
292
                        }
293
                }
294
                i = 0; /* in case we get ENOSPC on the next send */
295
        }
296
 
297
        if (rc < 0) {
298
                cERROR(1, ("Error %d sending data on socket to server", rc));
299
        } else
300
                rc = 0;
301
 
302
        /* Don't want to modify the buffer as a
303
           side effect of this call. */
304
        smb_buffer->smb_buf_length = smb_buf_length;
305
 
306
        return rc;
307
}
308
 
309
static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
310
{
311
        if (long_op == CIFS_ASYNC_OP) {
312
                /* oplock breaks must not be held up */
313
                atomic_inc(&ses->server->inFlight);
314
        } else {
315
                spin_lock(&GlobalMid_Lock);
316
                while (1) {
317
                        if (atomic_read(&ses->server->inFlight) >=
318
                                        cifs_max_pending){
319
                                spin_unlock(&GlobalMid_Lock);
320
#ifdef CONFIG_CIFS_STATS2
321
                                atomic_inc(&ses->server->num_waiters);
322
#endif
323
                                wait_event(ses->server->request_q,
324
                                        atomic_read(&ses->server->inFlight)
325
                                         < cifs_max_pending);
326
#ifdef CONFIG_CIFS_STATS2
327
                                atomic_dec(&ses->server->num_waiters);
328
#endif
329
                                spin_lock(&GlobalMid_Lock);
330
                        } else {
331
                                if (ses->server->tcpStatus == CifsExiting) {
332
                                        spin_unlock(&GlobalMid_Lock);
333
                                        return -ENOENT;
334
                                }
335
 
336
                                /* can not count locking commands against total
337
                                   as they are allowed to block on server */
338
 
339
                                /* update # of requests on the wire to server */
340
                                if (long_op != CIFS_BLOCKING_OP)
341
                                        atomic_inc(&ses->server->inFlight);
342
                                spin_unlock(&GlobalMid_Lock);
343
                                break;
344
                        }
345
                }
346
        }
347
        return 0;
348
}
349
 
350
static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
351
                        struct mid_q_entry **ppmidQ)
352
{
353
        if (ses->server->tcpStatus == CifsExiting) {
354
                return -ENOENT;
355
        } else if (ses->server->tcpStatus == CifsNeedReconnect) {
356
                cFYI(1, ("tcp session dead - return to caller to retry"));
357
                return -EAGAIN;
358
        } else if (ses->status != CifsGood) {
359
                /* check if SMB session is bad because we are setting it up */
360
                if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
361
                        (in_buf->Command != SMB_COM_NEGOTIATE)) {
362
                        return -EAGAIN;
363
                } /* else ok - we are setting up session */
364
        }
365
        *ppmidQ = AllocMidQEntry(in_buf, ses);
366
        if (*ppmidQ == NULL)
367
                return -ENOMEM;
368
        return 0;
369
}
370
 
371
static int wait_for_response(struct cifsSesInfo *ses,
372
                        struct mid_q_entry *midQ,
373
                        unsigned long timeout,
374
                        unsigned long time_to_wait)
375
{
376
        unsigned long curr_timeout;
377
 
378
        for (;;) {
379
                curr_timeout = timeout + jiffies;
380
                wait_event(ses->server->response_q,
381
                        (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
382
                        time_after(jiffies, curr_timeout) ||
383
                        ((ses->server->tcpStatus != CifsGood) &&
384
                         (ses->server->tcpStatus != CifsNew)));
385
 
386
                if (time_after(jiffies, curr_timeout) &&
387
                        (midQ->midState == MID_REQUEST_SUBMITTED) &&
388
                        ((ses->server->tcpStatus == CifsGood) ||
389
                         (ses->server->tcpStatus == CifsNew))) {
390
 
391
                        unsigned long lrt;
392
 
393
                        /* We timed out. Is the server still
394
                           sending replies ? */
395
                        spin_lock(&GlobalMid_Lock);
396
                        lrt = ses->server->lstrp;
397
                        spin_unlock(&GlobalMid_Lock);
398
 
399
                        /* Calculate time_to_wait past last receive time.
400
                         Although we prefer not to time out if the
401
                         server is still responding - we will time
402
                         out if the server takes more than 15 (or 45
403
                         or 180) seconds to respond to this request
404
                         and has not responded to any request from
405
                         other threads on the client within 10 seconds */
406
                        lrt += time_to_wait;
407
                        if (time_after(jiffies, lrt)) {
408
                                /* No replies for time_to_wait. */
409
                                cERROR(1, ("server not responding"));
410
                                return -1;
411
                        }
412
                } else {
413
                        return 0;
414
                }
415
        }
416
}
417
 
418
 
419
/*
420
 *
421
 * Send an SMB Request.  No response info (other than return code)
422
 * needs to be parsed.
423
 *
424
 * flags indicate the type of request buffer and how long to wait
425
 * and whether to log NT STATUS code (error) before mapping it to POSIX error
426
 *
427
 */
428
int
429
SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses,
430
                struct smb_hdr *in_buf, int flags)
431
{
432
        int rc;
433
        struct kvec iov[1];
434
        int resp_buf_type;
435
 
436
        iov[0].iov_base = (char *)in_buf;
437
        iov[0].iov_len = in_buf->smb_buf_length + 4;
438
        flags |= CIFS_NO_RESP;
439
        rc = SendReceive2(xid, ses, iov, 1, &resp_buf_type, flags);
440
#ifdef CONFIG_CIFS_DEBUG2
441
        cFYI(1, ("SendRcvNoR flags %d rc %d", flags, rc));
442
#endif
443
        return rc;
444
}
445
 
446
int
447
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
448
             struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
449
             const int flags)
450
{
451
        int rc = 0;
452
        int long_op;
453
        unsigned int receive_len;
454
        unsigned long timeout;
455
        struct mid_q_entry *midQ;
456
        struct smb_hdr *in_buf = iov[0].iov_base;
457
 
458
        long_op = flags & CIFS_TIMEOUT_MASK;
459
 
460
        *pRespBufType = CIFS_NO_BUFFER;  /* no response buf yet */
461
 
462
        if ((ses == NULL) || (ses->server == NULL)) {
463
                cifs_small_buf_release(in_buf);
464
                cERROR(1, ("Null session"));
465
                return -EIO;
466
        }
467
 
468
        if (ses->server->tcpStatus == CifsExiting) {
469
                cifs_small_buf_release(in_buf);
470
                return -ENOENT;
471
        }
472
 
473
        /* Ensure that we do not send more than 50 overlapping requests
474
           to the same server. We may make this configurable later or
475
           use ses->maxReq */
476
 
477
        rc = wait_for_free_request(ses, long_op);
478
        if (rc) {
479
                cifs_small_buf_release(in_buf);
480
                return rc;
481
        }
482
 
483
        /* make sure that we sign in the same order that we send on this socket
484
           and avoid races inside tcp sendmsg code that could cause corruption
485
           of smb data */
486
 
487
        down(&ses->server->tcpSem);
488
 
489
        rc = allocate_mid(ses, in_buf, &midQ);
490
        if (rc) {
491
                up(&ses->server->tcpSem);
492
                cifs_small_buf_release(in_buf);
493
                /* Update # of requests on wire to server */
494
                atomic_dec(&ses->server->inFlight);
495
                wake_up(&ses->server->request_q);
496
                return rc;
497
        }
498
        rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
499
 
500
        midQ->midState = MID_REQUEST_SUBMITTED;
501
#ifdef CONFIG_CIFS_STATS2
502
        atomic_inc(&ses->server->inSend);
503
#endif
504
        rc = smb_send2(ses->server->ssocket, iov, n_vec,
505
                      (struct sockaddr *) &(ses->server->addr.sockAddr));
506
#ifdef CONFIG_CIFS_STATS2
507
        atomic_dec(&ses->server->inSend);
508
        midQ->when_sent = jiffies;
509
#endif
510
 
511
        up(&ses->server->tcpSem);
512
        cifs_small_buf_release(in_buf);
513
 
514
        if (rc < 0)
515
                goto out;
516
 
517
        if (long_op == CIFS_STD_OP)
518
                timeout = 15 * HZ;
519
        else if (long_op == CIFS_VLONG_OP) /* e.g. slow writes past EOF */
520
                timeout = 180 * HZ;
521
        else if (long_op == CIFS_LONG_OP)
522
                timeout = 45 * HZ; /* should be greater than
523
                        servers oplock break timeout (about 43 seconds) */
524
        else if (long_op == CIFS_ASYNC_OP)
525
                goto out;
526
        else if (long_op == CIFS_BLOCKING_OP)
527
                timeout = 0x7FFFFFFF; /*  large, but not so large as to wrap */
528
        else {
529
                cERROR(1, ("unknown timeout flag %d", long_op));
530
                rc = -EIO;
531
                goto out;
532
        }
533
 
534
        /* wait for 15 seconds or until woken up due to response arriving or
535
           due to last connection to this server being unmounted */
536
        if (signal_pending(current)) {
537
                /* if signal pending do not hold up user for full smb timeout
538
                but we still give response a chance to complete */
539
                timeout = 2 * HZ;
540
        }
541
 
542
        /* No user interrupts in wait - wreaks havoc with performance */
543
        wait_for_response(ses, midQ, timeout, 10 * HZ);
544
 
545
        spin_lock(&GlobalMid_Lock);
546
        if (midQ->resp_buf) {
547
                spin_unlock(&GlobalMid_Lock);
548
                receive_len = midQ->resp_buf->smb_buf_length;
549
        } else {
550
                cERROR(1, ("No response to cmd %d mid %d",
551
                        midQ->command, midQ->mid));
552
                if (midQ->midState == MID_REQUEST_SUBMITTED) {
553
                        if (ses->server->tcpStatus == CifsExiting)
554
                                rc = -EHOSTDOWN;
555
                        else {
556
                                ses->server->tcpStatus = CifsNeedReconnect;
557
                                midQ->midState = MID_RETRY_NEEDED;
558
                        }
559
                }
560
 
561
                if (rc != -EHOSTDOWN) {
562
                        if (midQ->midState == MID_RETRY_NEEDED) {
563
                                rc = -EAGAIN;
564
                                cFYI(1, ("marking request for retry"));
565
                        } else {
566
                                rc = -EIO;
567
                        }
568
                }
569
                spin_unlock(&GlobalMid_Lock);
570
                DeleteMidQEntry(midQ);
571
                /* Update # of requests on wire to server */
572
                atomic_dec(&ses->server->inFlight);
573
                wake_up(&ses->server->request_q);
574
                return rc;
575
        }
576
 
577
        if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
578
                cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
579
                        receive_len, xid));
580
                rc = -EIO;
581
        } else {                /* rcvd frame is ok */
582
                if (midQ->resp_buf &&
583
                        (midQ->midState == MID_RESPONSE_RECEIVED)) {
584
 
585
                        iov[0].iov_base = (char *)midQ->resp_buf;
586
                        if (midQ->largeBuf)
587
                                *pRespBufType = CIFS_LARGE_BUFFER;
588
                        else
589
                                *pRespBufType = CIFS_SMALL_BUFFER;
590
                        iov[0].iov_len = receive_len + 4;
591
 
592
                        dump_smb(midQ->resp_buf, 80);
593
                        /* convert the length into a more usable form */
594
                        if ((receive_len > 24) &&
595
                           (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
596
                                        SECMODE_SIGN_ENABLED))) {
597
                                rc = cifs_verify_signature(midQ->resp_buf,
598
                                                &ses->server->mac_signing_key,
599
                                                midQ->sequence_number+1);
600
                                if (rc) {
601
                                        cERROR(1, ("Unexpected SMB signature"));
602
                                        /* BB FIXME add code to kill session */
603
                                }
604
                        }
605
 
606
                        /* BB special case reconnect tid and uid here? */
607
                        rc = map_smb_to_linux_error(midQ->resp_buf,
608
                                                flags & CIFS_LOG_ERROR);
609
 
610
                        /* convert ByteCount if necessary */
611
                        if (receive_len >= sizeof(struct smb_hdr) - 4
612
                            /* do not count RFC1001 header */  +
613
                            (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
614
                                BCC(midQ->resp_buf) =
615
                                        le16_to_cpu(BCC_LE(midQ->resp_buf));
616
                        if ((flags & CIFS_NO_RESP) == 0)
617
                                midQ->resp_buf = NULL;  /* mark it so buf will
618
                                                           not be freed by
619
                                                           DeleteMidQEntry */
620
                } else {
621
                        rc = -EIO;
622
                        cFYI(1, ("Bad MID state?"));
623
                }
624
        }
625
 
626
out:
627
        DeleteMidQEntry(midQ);
628
        atomic_dec(&ses->server->inFlight);
629
        wake_up(&ses->server->request_q);
630
 
631
        return rc;
632
}
633
 
634
int
635
SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
636
            struct smb_hdr *in_buf, struct smb_hdr *out_buf,
637
            int *pbytes_returned, const int long_op)
638
{
639
        int rc = 0;
640
        unsigned int receive_len;
641
        unsigned long timeout;
642
        struct mid_q_entry *midQ;
643
 
644
        if (ses == NULL) {
645
                cERROR(1, ("Null smb session"));
646
                return -EIO;
647
        }
648
        if (ses->server == NULL) {
649
                cERROR(1, ("Null tcp session"));
650
                return -EIO;
651
        }
652
 
653
        if (ses->server->tcpStatus == CifsExiting)
654
                return -ENOENT;
655
 
656
        /* Ensure that we do not send more than 50 overlapping requests
657
           to the same server. We may make this configurable later or
658
           use ses->maxReq */
659
 
660
        rc = wait_for_free_request(ses, long_op);
661
        if (rc)
662
                return rc;
663
 
664
        /* make sure that we sign in the same order that we send on this socket
665
           and avoid races inside tcp sendmsg code that could cause corruption
666
           of smb data */
667
 
668
        down(&ses->server->tcpSem);
669
 
670
        rc = allocate_mid(ses, in_buf, &midQ);
671
        if (rc) {
672
                up(&ses->server->tcpSem);
673
                /* Update # of requests on wire to server */
674
                atomic_dec(&ses->server->inFlight);
675
                wake_up(&ses->server->request_q);
676
                return rc;
677
        }
678
 
679
        if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
680
                cERROR(1, ("Illegal length, greater than maximum frame, %d",
681
                        in_buf->smb_buf_length));
682
                DeleteMidQEntry(midQ);
683
                up(&ses->server->tcpSem);
684
                /* Update # of requests on wire to server */
685
                atomic_dec(&ses->server->inFlight);
686
                wake_up(&ses->server->request_q);
687
                return -EIO;
688
        }
689
 
690
        rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
691
 
692
        midQ->midState = MID_REQUEST_SUBMITTED;
693
#ifdef CONFIG_CIFS_STATS2
694
        atomic_inc(&ses->server->inSend);
695
#endif
696
        rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
697
                      (struct sockaddr *) &(ses->server->addr.sockAddr));
698
#ifdef CONFIG_CIFS_STATS2
699
        atomic_dec(&ses->server->inSend);
700
        midQ->when_sent = jiffies;
701
#endif
702
        up(&ses->server->tcpSem);
703
 
704
        if (rc < 0)
705
                goto out;
706
 
707
        if (long_op == CIFS_STD_OP)
708
                timeout = 15 * HZ;
709
        /* wait for 15 seconds or until woken up due to response arriving or
710
           due to last connection to this server being unmounted */
711
        else if (long_op == CIFS_ASYNC_OP)
712
                goto out;
713
        else if (long_op == CIFS_VLONG_OP) /* writes past EOF can be slow */
714
                timeout = 180 * HZ;
715
        else if (long_op == CIFS_LONG_OP)
716
                timeout = 45 * HZ; /* should be greater than
717
                        servers oplock break timeout (about 43 seconds) */
718
        else if (long_op == CIFS_BLOCKING_OP)
719
                timeout = 0x7FFFFFFF; /* large but no so large as to wrap */
720
        else {
721
                cERROR(1, ("unknown timeout flag %d", long_op));
722
                rc = -EIO;
723
                goto out;
724
        }
725
 
726
        if (signal_pending(current)) {
727
                /* if signal pending do not hold up user for full smb timeout
728
                but we still give response a chance to complete */
729
                timeout = 2 * HZ;
730
        }
731
 
732
        /* No user interrupts in wait - wreaks havoc with performance */
733
        wait_for_response(ses, midQ, timeout, 10 * HZ);
734
 
735
        spin_lock(&GlobalMid_Lock);
736
        if (midQ->resp_buf) {
737
                spin_unlock(&GlobalMid_Lock);
738
                receive_len = midQ->resp_buf->smb_buf_length;
739
        } else {
740
                cERROR(1, ("No response for cmd %d mid %d",
741
                          midQ->command, midQ->mid));
742
                if (midQ->midState == MID_REQUEST_SUBMITTED) {
743
                        if (ses->server->tcpStatus == CifsExiting)
744
                                rc = -EHOSTDOWN;
745
                        else {
746
                                ses->server->tcpStatus = CifsNeedReconnect;
747
                                midQ->midState = MID_RETRY_NEEDED;
748
                        }
749
                }
750
 
751
                if (rc != -EHOSTDOWN) {
752
                        if (midQ->midState == MID_RETRY_NEEDED) {
753
                                rc = -EAGAIN;
754
                                cFYI(1, ("marking request for retry"));
755
                        } else {
756
                                rc = -EIO;
757
                        }
758
                }
759
                spin_unlock(&GlobalMid_Lock);
760
                DeleteMidQEntry(midQ);
761
                /* Update # of requests on wire to server */
762
                atomic_dec(&ses->server->inFlight);
763
                wake_up(&ses->server->request_q);
764
                return rc;
765
        }
766
 
767
        if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
768
                cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
769
                        receive_len, xid));
770
                rc = -EIO;
771
        } else {                /* rcvd frame is ok */
772
 
773
                if (midQ->resp_buf && out_buf
774
                    && (midQ->midState == MID_RESPONSE_RECEIVED)) {
775
                        out_buf->smb_buf_length = receive_len;
776
                        memcpy((char *)out_buf + 4,
777
                               (char *)midQ->resp_buf + 4,
778
                               receive_len);
779
 
780
                        dump_smb(out_buf, 92);
781
                        /* convert the length into a more usable form */
782
                        if ((receive_len > 24) &&
783
                           (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
784
                                        SECMODE_SIGN_ENABLED))) {
785
                                rc = cifs_verify_signature(out_buf,
786
                                                &ses->server->mac_signing_key,
787
                                                midQ->sequence_number+1);
788
                                if (rc) {
789
                                        cERROR(1, ("Unexpected SMB signature"));
790
                                        /* BB FIXME add code to kill session */
791
                                }
792
                        }
793
 
794
                        *pbytes_returned = out_buf->smb_buf_length;
795
 
796
                        /* BB special case reconnect tid and uid here? */
797
                        rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
798
 
799
                        /* convert ByteCount if necessary */
800
                        if (receive_len >= sizeof(struct smb_hdr) - 4
801
                            /* do not count RFC1001 header */  +
802
                            (2 * out_buf->WordCount) + 2 /* bcc */ )
803
                                BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
804
                } else {
805
                        rc = -EIO;
806
                        cERROR(1, ("Bad MID state?"));
807
                }
808
        }
809
 
810
out:
811
        DeleteMidQEntry(midQ);
812
        atomic_dec(&ses->server->inFlight);
813
        wake_up(&ses->server->request_q);
814
 
815
        return rc;
816
}
817
 
818
/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */
819
 
820
static int
821
send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
822
                struct mid_q_entry *midQ)
823
{
824
        int rc = 0;
825
        struct cifsSesInfo *ses = tcon->ses;
826
        __u16 mid = in_buf->Mid;
827
 
828
        header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
829
        in_buf->Mid = mid;
830
        down(&ses->server->tcpSem);
831
        rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
832
        if (rc) {
833
                up(&ses->server->tcpSem);
834
                return rc;
835
        }
836
        rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
837
              (struct sockaddr *) &(ses->server->addr.sockAddr));
838
        up(&ses->server->tcpSem);
839
        return rc;
840
}
841
 
842
/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows
843
   blocking lock to return. */
844
 
845
static int
846
send_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,
847
                        struct smb_hdr *in_buf,
848
                        struct smb_hdr *out_buf)
849
{
850
        int bytes_returned;
851
        struct cifsSesInfo *ses = tcon->ses;
852
        LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;
853
 
854
        /* We just modify the current in_buf to change
855
           the type of lock from LOCKING_ANDX_SHARED_LOCK
856
           or LOCKING_ANDX_EXCLUSIVE_LOCK to
857
           LOCKING_ANDX_CANCEL_LOCK. */
858
 
859
        pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;
860
        pSMB->Timeout = 0;
861
        pSMB->hdr.Mid = GetNextMid(ses->server);
862
 
863
        return SendReceive(xid, ses, in_buf, out_buf,
864
                        &bytes_returned, CIFS_STD_OP);
865
}
866
 
867
int
868
SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
869
            struct smb_hdr *in_buf, struct smb_hdr *out_buf,
870
            int *pbytes_returned)
871
{
872
        int rc = 0;
873
        int rstart = 0;
874
        unsigned int receive_len;
875
        struct mid_q_entry *midQ;
876
        struct cifsSesInfo *ses;
877
 
878
        if (tcon == NULL || tcon->ses == NULL) {
879
                cERROR(1, ("Null smb session"));
880
                return -EIO;
881
        }
882
        ses = tcon->ses;
883
 
884
        if (ses->server == NULL) {
885
                cERROR(1, ("Null tcp session"));
886
                return -EIO;
887
        }
888
 
889
        if (ses->server->tcpStatus == CifsExiting)
890
                return -ENOENT;
891
 
892
        /* Ensure that we do not send more than 50 overlapping requests
893
           to the same server. We may make this configurable later or
894
           use ses->maxReq */
895
 
896
        rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
897
        if (rc)
898
                return rc;
899
 
900
        /* make sure that we sign in the same order that we send on this socket
901
           and avoid races inside tcp sendmsg code that could cause corruption
902
           of smb data */
903
 
904
        down(&ses->server->tcpSem);
905
 
906
        rc = allocate_mid(ses, in_buf, &midQ);
907
        if (rc) {
908
                up(&ses->server->tcpSem);
909
                return rc;
910
        }
911
 
912
        if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
913
                up(&ses->server->tcpSem);
914
                cERROR(1, ("Illegal length, greater than maximum frame, %d",
915
                        in_buf->smb_buf_length));
916
                DeleteMidQEntry(midQ);
917
                return -EIO;
918
        }
919
 
920
        rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
921
 
922
        midQ->midState = MID_REQUEST_SUBMITTED;
923
#ifdef CONFIG_CIFS_STATS2
924
        atomic_inc(&ses->server->inSend);
925
#endif
926
        rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
927
                      (struct sockaddr *) &(ses->server->addr.sockAddr));
928
#ifdef CONFIG_CIFS_STATS2
929
        atomic_dec(&ses->server->inSend);
930
        midQ->when_sent = jiffies;
931
#endif
932
        up(&ses->server->tcpSem);
933
 
934
        if (rc < 0) {
935
                DeleteMidQEntry(midQ);
936
                return rc;
937
        }
938
 
939
        /* Wait for a reply - allow signals to interrupt. */
940
        rc = wait_event_interruptible(ses->server->response_q,
941
                (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
942
                ((ses->server->tcpStatus != CifsGood) &&
943
                 (ses->server->tcpStatus != CifsNew)));
944
 
945
        /* Were we interrupted by a signal ? */
946
        if ((rc == -ERESTARTSYS) &&
947
                (midQ->midState == MID_REQUEST_SUBMITTED) &&
948
                ((ses->server->tcpStatus == CifsGood) ||
949
                 (ses->server->tcpStatus == CifsNew))) {
950
 
951
                if (in_buf->Command == SMB_COM_TRANSACTION2) {
952
                        /* POSIX lock. We send a NT_CANCEL SMB to cause the
953
                           blocking lock to return. */
954
 
955
                        rc = send_nt_cancel(tcon, in_buf, midQ);
956
                        if (rc) {
957
                                DeleteMidQEntry(midQ);
958
                                return rc;
959
                        }
960
                } else {
961
                        /* Windows lock. We send a LOCKINGX_CANCEL_LOCK
962
                           to cause the blocking lock to return. */
963
 
964
                        rc = send_lock_cancel(xid, tcon, in_buf, out_buf);
965
 
966
                        /* If we get -ENOLCK back the lock may have
967
                           already been removed. Don't exit in this case. */
968
                        if (rc && rc != -ENOLCK) {
969
                                DeleteMidQEntry(midQ);
970
                                return rc;
971
                        }
972
                }
973
 
974
                /* Wait 5 seconds for the response. */
975
                if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
976
                        /* We got the response - restart system call. */
977
                        rstart = 1;
978
                }
979
        }
980
 
981
        spin_lock(&GlobalMid_Lock);
982
        if (midQ->resp_buf) {
983
                spin_unlock(&GlobalMid_Lock);
984
                receive_len = midQ->resp_buf->smb_buf_length;
985
        } else {
986
                cERROR(1, ("No response for cmd %d mid %d",
987
                          midQ->command, midQ->mid));
988
                if (midQ->midState == MID_REQUEST_SUBMITTED) {
989
                        if (ses->server->tcpStatus == CifsExiting)
990
                                rc = -EHOSTDOWN;
991
                        else {
992
                                ses->server->tcpStatus = CifsNeedReconnect;
993
                                midQ->midState = MID_RETRY_NEEDED;
994
                        }
995
                }
996
 
997
                if (rc != -EHOSTDOWN) {
998
                        if (midQ->midState == MID_RETRY_NEEDED) {
999
                                rc = -EAGAIN;
1000
                                cFYI(1, ("marking request for retry"));
1001
                        } else {
1002
                                rc = -EIO;
1003
                        }
1004
                }
1005
                spin_unlock(&GlobalMid_Lock);
1006
                DeleteMidQEntry(midQ);
1007
                return rc;
1008
        }
1009
 
1010
        if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
1011
                cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
1012
                        receive_len, xid));
1013
                rc = -EIO;
1014
        } else {                /* rcvd frame is ok */
1015
 
1016
                if (midQ->resp_buf && out_buf
1017
                    && (midQ->midState == MID_RESPONSE_RECEIVED)) {
1018
                        out_buf->smb_buf_length = receive_len;
1019
                        memcpy((char *)out_buf + 4,
1020
                               (char *)midQ->resp_buf + 4,
1021
                               receive_len);
1022
 
1023
                        dump_smb(out_buf, 92);
1024
                        /* convert the length into a more usable form */
1025
                        if ((receive_len > 24) &&
1026
                           (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
1027
                                        SECMODE_SIGN_ENABLED))) {
1028
                                rc = cifs_verify_signature(out_buf,
1029
                                                &ses->server->mac_signing_key,
1030
                                                midQ->sequence_number+1);
1031
                                if (rc) {
1032
                                        cERROR(1, ("Unexpected SMB signature"));
1033
                                        /* BB FIXME add code to kill session */
1034
                                }
1035
                        }
1036
 
1037
                        *pbytes_returned = out_buf->smb_buf_length;
1038
 
1039
                        /* BB special case reconnect tid and uid here? */
1040
                        rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
1041
 
1042
                        /* convert ByteCount if necessary */
1043
                        if (receive_len >= sizeof(struct smb_hdr) - 4
1044
                            /* do not count RFC1001 header */  +
1045
                            (2 * out_buf->WordCount) + 2 /* bcc */ )
1046
                                BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
1047
                } else {
1048
                        rc = -EIO;
1049
                        cERROR(1, ("Bad MID state?"));
1050
                }
1051
        }
1052
        DeleteMidQEntry(midQ);
1053
        if (rstart && rc == -EACCES)
1054
                return -ERESTARTSYS;
1055
        return rc;
1056
}

powered by: WebSVN 2.1.0

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