diff options
Diffstat (limited to 'fs/cifs/transport.c')
-rw-r--r-- | fs/cifs/transport.c | 173 |
1 files changed, 75 insertions, 98 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0961336513d5..83867ef348df 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -35,10 +35,8 @@ #include "cifsproto.h" #include "cifs_debug.h" -extern mempool_t *cifs_mid_poolp; - -static void -wake_up_task(struct mid_q_entry *mid) +void +cifs_wake_up_task(struct mid_q_entry *mid) { wake_up_process(mid->callback_data); } @@ -65,12 +63,13 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ /* when mid allocated can be before when sent */ temp->when_alloc = jiffies; + temp->server = server; /* * The default is for the mid to be synchronous, so the * default callback just wakes up the current task. */ - temp->callback = wake_up_task; + temp->callback = cifs_wake_up_task; temp->callback_data = current; } @@ -83,6 +82,7 @@ void DeleteMidQEntry(struct mid_q_entry *midEntry) { #ifdef CONFIG_CIFS_STATS2 + __le16 command = midEntry->server->vals->lock_cmd; unsigned long now; #endif midEntry->mid_state = MID_FREE; @@ -96,8 +96,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) /* commands taking longer than one second are indications that something is wrong, unless it is quite a slow link or server */ if ((now - midEntry->when_alloc) > HZ) { - if ((cifsFYI & CIFS_TIMER) && - (midEntry->command != cpu_to_le16(SMB_COM_LOCKING_ANDX))) { + if ((cifsFYI & CIFS_TIMER) && (midEntry->command != command)) { printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %llu", midEntry->command, midEntry->mid); printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n", @@ -126,7 +125,6 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) int rc = 0; int i = 0; struct msghdr smb_msg; - __be32 *buf_len = (__be32 *)(iov[0].iov_base); unsigned int len = iov[0].iov_len; unsigned int total_len; int first_vec = 0; @@ -235,9 +233,6 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) else rc = 0; - /* Don't want to modify the buffer as a side effect of this call. */ - *buf_len = cpu_to_be32(smb_buf_length); - return rc; } @@ -254,13 +249,13 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, } static int -wait_for_free_credits(struct TCP_Server_Info *server, const int optype, +wait_for_free_credits(struct TCP_Server_Info *server, const int timeout, int *credits) { int rc; spin_lock(&server->req_lock); - if (optype == CIFS_ASYNC_OP) { + if (timeout == CIFS_ASYNC_OP) { /* oplock breaks must not be held up */ server->in_flight++; *credits -= 1; @@ -290,7 +285,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int optype, */ /* update # of requests on the wire to server */ - if (optype != CIFS_BLOCKING_OP) { + if (timeout != CIFS_BLOCKING_OP) { *credits -= 1; server->in_flight++; } @@ -302,9 +297,11 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int optype, } static int -wait_for_free_request(struct TCP_Server_Info *server, const int optype) +wait_for_free_request(struct TCP_Server_Info *server, const int timeout, + const int optype) { - return wait_for_free_credits(server, optype, get_credits_field(server)); + return wait_for_free_credits(server, timeout, + server->ops->get_credits_field(server, optype)); } static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, @@ -348,7 +345,7 @@ wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *midQ) return 0; } -static int +int cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov, unsigned int nvec, struct mid_q_entry **ret_mid) { @@ -364,16 +361,14 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov, if (mid == NULL) return -ENOMEM; - /* put it on the pending_mid_q */ - spin_lock(&GlobalMid_Lock); - list_add_tail(&mid->qhead, &server->pending_mid_q); - spin_unlock(&GlobalMid_Lock); + rc = cifs_sign_smbv(iov, nvec, server, &mid->sequence_number); + if (rc) { + DeleteMidQEntry(mid); + return rc; + } - rc = cifs_sign_smb2(iov, nvec, server, &mid->sequence_number); - if (rc) - delete_mid(mid); *ret_mid = mid; - return rc; + return 0; } /* @@ -383,20 +378,23 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov, int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, unsigned int nvec, mid_receive_t *receive, - mid_callback_t *callback, void *cbdata, bool ignore_pend) + mid_callback_t *callback, void *cbdata, const int flags) { - int rc; + int rc, timeout, optype; struct mid_q_entry *mid; - rc = wait_for_free_request(server, ignore_pend ? CIFS_ASYNC_OP : 0); + timeout = flags & CIFS_TIMEOUT_MASK; + optype = flags & CIFS_OP_MASK; + + rc = wait_for_free_request(server, timeout, optype); if (rc) return rc; mutex_lock(&server->srv_mutex); - rc = cifs_setup_async_request(server, iov, nvec, &mid); + rc = server->ops->setup_async_request(server, iov, nvec, &mid); if (rc) { mutex_unlock(&server->srv_mutex); - cifs_add_credits(server, 1); + add_credits(server, 1, optype); wake_up(&server->request_q); return rc; } @@ -406,19 +404,23 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, mid->callback_data = cbdata; mid->mid_state = MID_REQUEST_SUBMITTED; + /* put it on the pending_mid_q */ + spin_lock(&GlobalMid_Lock); + list_add_tail(&mid->qhead, &server->pending_mid_q); + spin_unlock(&GlobalMid_Lock); + + cifs_in_send_inc(server); rc = smb_sendv(server, iov, nvec); cifs_in_send_dec(server); cifs_save_when_sent(mid); mutex_unlock(&server->srv_mutex); - if (rc) - goto out_err; + if (rc == 0) + return 0; - return rc; -out_err: delete_mid(mid); - cifs_add_credits(server, 1); + add_credits(server, 1, optype); wake_up(&server->request_q); return rc; } @@ -483,41 +485,11 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) return rc; } -/* - * An NT cancel request header looks just like the original request except: - * - * The Command is SMB_COM_NT_CANCEL - * The WordCount is zeroed out - * The ByteCount is zeroed out - * - * This function mangles an existing request buffer into a - * SMB_COM_NT_CANCEL request and then sends it. - */ -static int -send_nt_cancel(struct TCP_Server_Info *server, struct smb_hdr *in_buf, - struct mid_q_entry *mid) +static inline int +send_cancel(struct TCP_Server_Info *server, void *buf, struct mid_q_entry *mid) { - int rc = 0; - - /* -4 for RFC1001 length and +2 for BCC field */ - in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4 + 2); - in_buf->Command = SMB_COM_NT_CANCEL; - in_buf->WordCount = 0; - put_bcc(0, in_buf); - - mutex_lock(&server->srv_mutex); - rc = cifs_sign_smb(in_buf, server, &mid->sequence_number); - if (rc) { - mutex_unlock(&server->srv_mutex); - return rc; - } - rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length)); - mutex_unlock(&server->srv_mutex); - - cFYI(1, "issued NT_CANCEL for mid %u, rc = %d", - in_buf->Mid, rc); - - return rc; + return server->ops->send_cancel ? + server->ops->send_cancel(server, buf, mid) : 0; } int @@ -544,7 +516,7 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, return map_smb_to_linux_error(mid->resp_buf, log_error); } -static int +int cifs_setup_request(struct cifs_ses *ses, struct kvec *iov, unsigned int nvec, struct mid_q_entry **ret_mid) { @@ -555,7 +527,7 @@ cifs_setup_request(struct cifs_ses *ses, struct kvec *iov, rc = allocate_mid(ses, hdr, &mid); if (rc) return rc; - rc = cifs_sign_smb2(iov, nvec, ses->server, &mid->sequence_number); + rc = cifs_sign_smbv(iov, nvec, ses->server, &mid->sequence_number); if (rc) delete_mid(mid); *ret_mid = mid; @@ -564,17 +536,19 @@ cifs_setup_request(struct cifs_ses *ses, struct kvec *iov, int SendReceive2(const unsigned int xid, struct cifs_ses *ses, - struct kvec *iov, int n_vec, int *pRespBufType /* ret */, + struct kvec *iov, int n_vec, int *resp_buf_type /* ret */, const int flags) { int rc = 0; - int long_op; + int timeout, optype; struct mid_q_entry *midQ; char *buf = iov[0].iov_base; + unsigned int credits = 1; - long_op = flags & CIFS_TIMEOUT_MASK; + timeout = flags & CIFS_TIMEOUT_MASK; + optype = flags & CIFS_OP_MASK; - *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ + *resp_buf_type = CIFS_NO_BUFFER; /* no response buf yet */ if ((ses == NULL) || (ses->server == NULL)) { cifs_small_buf_release(buf); @@ -593,7 +567,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, * use ses->maxReq. */ - rc = wait_for_free_request(ses->server, long_op); + rc = wait_for_free_request(ses->server, timeout, optype); if (rc) { cifs_small_buf_release(buf); return rc; @@ -607,12 +581,12 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, mutex_lock(&ses->server->srv_mutex); - rc = cifs_setup_request(ses, iov, n_vec, &midQ); + rc = ses->server->ops->setup_request(ses, iov, n_vec, &midQ); if (rc) { mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(buf); /* Update # of requests on wire to server */ - cifs_add_credits(ses->server, 1); + add_credits(ses->server, 1, optype); return rc; } @@ -629,20 +603,20 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, goto out; } - if (long_op == CIFS_ASYNC_OP) { + if (timeout == CIFS_ASYNC_OP) { cifs_small_buf_release(buf); goto out; } rc = wait_for_response(ses->server, midQ); if (rc != 0) { - send_nt_cancel(ses->server, (struct smb_hdr *)buf, midQ); + send_cancel(ses->server, buf, midQ); spin_lock(&GlobalMid_Lock); if (midQ->mid_state == MID_REQUEST_SUBMITTED) { midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); cifs_small_buf_release(buf); - cifs_add_credits(ses->server, 1); + add_credits(ses->server, 1, optype); return rc; } spin_unlock(&GlobalMid_Lock); @@ -652,7 +626,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { - cifs_add_credits(ses->server, 1); + add_credits(ses->server, 1, optype); return rc; } @@ -666,18 +640,21 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, iov[0].iov_base = buf; iov[0].iov_len = get_rfc1002_length(buf) + 4; if (midQ->large_buf) - *pRespBufType = CIFS_LARGE_BUFFER; + *resp_buf_type = CIFS_LARGE_BUFFER; else - *pRespBufType = CIFS_SMALL_BUFFER; + *resp_buf_type = CIFS_SMALL_BUFFER; + + credits = ses->server->ops->get_credits(midQ); - rc = cifs_check_receive(midQ, ses->server, flags & CIFS_LOG_ERROR); + rc = ses->server->ops->check_receive(midQ, ses->server, + flags & CIFS_LOG_ERROR); /* mark it so buf will not be freed by delete_mid */ if ((flags & CIFS_NO_RESP) == 0) midQ->resp_buf = NULL; out: delete_mid(midQ); - cifs_add_credits(ses->server, 1); + add_credits(ses->server, credits, optype); return rc; } @@ -685,7 +662,7 @@ out: int SendReceive(const unsigned int xid, struct cifs_ses *ses, struct smb_hdr *in_buf, struct smb_hdr *out_buf, - int *pbytes_returned, const int long_op) + int *pbytes_returned, const int timeout) { int rc = 0; struct mid_q_entry *midQ; @@ -713,7 +690,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, return -EIO; } - rc = wait_for_free_request(ses->server, long_op); + rc = wait_for_free_request(ses->server, timeout, 0); if (rc) return rc; @@ -727,7 +704,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, if (rc) { mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ - cifs_add_credits(ses->server, 1); + add_credits(ses->server, 1, 0); return rc; } @@ -748,18 +725,18 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, if (rc < 0) goto out; - if (long_op == CIFS_ASYNC_OP) + if (timeout == CIFS_ASYNC_OP) goto out; rc = wait_for_response(ses->server, midQ); if (rc != 0) { - send_nt_cancel(ses->server, in_buf, midQ); + send_cancel(ses->server, in_buf, midQ); spin_lock(&GlobalMid_Lock); if (midQ->mid_state == MID_REQUEST_SUBMITTED) { /* no longer considered to be "in-flight" */ midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); - cifs_add_credits(ses->server, 1); + add_credits(ses->server, 1, 0); return rc; } spin_unlock(&GlobalMid_Lock); @@ -767,7 +744,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { - cifs_add_credits(ses->server, 1); + add_credits(ses->server, 1, 0); return rc; } @@ -783,7 +760,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, rc = cifs_check_receive(midQ, ses->server, 0); out: delete_mid(midQ); - cifs_add_credits(ses->server, 1); + add_credits(ses->server, 1, 0); return rc; } @@ -807,7 +784,7 @@ send_lock_cancel(const unsigned int xid, struct cifs_tcon *tcon, pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES; pSMB->Timeout = 0; - pSMB->hdr.Mid = GetNextMid(ses->server); + pSMB->hdr.Mid = get_next_mid(ses->server); return SendReceive(xid, ses, in_buf, out_buf, &bytes_returned, 0); @@ -848,7 +825,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, return -EIO; } - rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP); + rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP, 0); if (rc) return rc; @@ -898,7 +875,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, if (in_buf->Command == SMB_COM_TRANSACTION2) { /* POSIX lock. We send a NT_CANCEL SMB to cause the blocking lock to return. */ - rc = send_nt_cancel(ses->server, in_buf, midQ); + rc = send_cancel(ses->server, in_buf, midQ); if (rc) { delete_mid(midQ); return rc; @@ -919,7 +896,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, rc = wait_for_response(ses->server, midQ); if (rc) { - send_nt_cancel(ses->server, in_buf, midQ); + send_cancel(ses->server, in_buf, midQ); spin_lock(&GlobalMid_Lock); if (midQ->mid_state == MID_REQUEST_SUBMITTED) { /* no longer considered to be "in-flight" */ |