Merge branch 'work.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[platform/kernel/linux-rpi.git] / fs / cifs / smb2transport.c
index 7b351c6..d118157 100644 (file)
@@ -576,6 +576,7 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr,
                     struct TCP_Server_Info *server)
 {
        struct mid_q_entry *temp;
+       unsigned int credits = le16_to_cpu(shdr->CreditCharge);
 
        if (server == NULL) {
                cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n");
@@ -586,6 +587,7 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr,
        memset(temp, 0, sizeof(struct mid_q_entry));
        kref_init(&temp->refcount);
        temp->mid = le64_to_cpu(shdr->MessageId);
+       temp->credits = credits > 0 ? credits : 1;
        temp->pid = current->pid;
        temp->command = shdr->Command; /* Always LE */
        temp->when_alloc = jiffies;
@@ -600,6 +602,8 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr,
 
        atomic_inc(&midCount);
        temp->mid_state = MID_REQUEST_ALLOCATED;
+       trace_smb3_cmd_enter(shdr->TreeId, shdr->SessionId,
+               le16_to_cpu(shdr->Command), temp->mid);
        return temp;
 }
 
@@ -615,6 +619,10 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr,
                return -EAGAIN;
        }
 
+       if (ses->server->tcpStatus == CifsNeedNegotiate &&
+          shdr->Command != SMB2_NEGOTIATE)
+               return -EAGAIN;
+
        if (ses->status == CifsNew) {
                if ((shdr->Command != SMB2_SESSION_SETUP) &&
                    (shdr->Command != SMB2_NEGOTIATE))
@@ -634,6 +642,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr,
        spin_lock(&GlobalMid_Lock);
        list_add_tail(&(*mid)->qhead, &ses->server->pending_mid_q);
        spin_unlock(&GlobalMid_Lock);
+
        return 0;
 }
 
@@ -674,13 +683,18 @@ smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst)
        smb2_seq_num_into_buf(ses->server, shdr);
 
        rc = smb2_get_mid_entry(ses, shdr, &mid);
-       if (rc)
+       if (rc) {
+               revert_current_mid_from_hdr(ses->server, shdr);
                return ERR_PTR(rc);
+       }
+
        rc = smb2_sign_rqst(rqst, ses->server);
        if (rc) {
+               revert_current_mid_from_hdr(ses->server, shdr);
                cifs_delete_mid(mid);
                return ERR_PTR(rc);
        }
+
        return mid;
 }
 
@@ -692,14 +706,21 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
                        (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base;
        struct mid_q_entry *mid;
 
+       if (server->tcpStatus == CifsNeedNegotiate &&
+          shdr->Command != SMB2_NEGOTIATE)
+               return ERR_PTR(-EAGAIN);
+
        smb2_seq_num_into_buf(server, shdr);
 
        mid = smb2_mid_entry_alloc(shdr, server);
-       if (mid == NULL)
+       if (mid == NULL) {
+               revert_current_mid_from_hdr(server, shdr);
                return ERR_PTR(-ENOMEM);
+       }
 
        rc = smb2_sign_rqst(rqst, server);
        if (rc) {
+               revert_current_mid_from_hdr(server, shdr);
                DeleteMidQEntry(mid);
                return ERR_PTR(rc);
        }