summaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2pdu.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r--fs/cifs/smb2pdu.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index e57f6aa1d638..2ff209ec4fab 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -162,24 +162,31 @@ static int __smb2_reconnect(const struct nls_table *nlsc,
162 int rc; 162 int rc;
163 struct dfs_cache_tgt_list tl; 163 struct dfs_cache_tgt_list tl;
164 struct dfs_cache_tgt_iterator *it = NULL; 164 struct dfs_cache_tgt_iterator *it = NULL;
165 char tree[MAX_TREE_SIZE + 1]; 165 char *tree;
166 const char *tcp_host; 166 const char *tcp_host;
167 size_t tcp_host_len; 167 size_t tcp_host_len;
168 const char *dfs_host; 168 const char *dfs_host;
169 size_t dfs_host_len; 169 size_t dfs_host_len;
170 170
171 tree = kzalloc(MAX_TREE_SIZE, GFP_KERNEL);
172 if (!tree)
173 return -ENOMEM;
174
171 if (tcon->ipc) { 175 if (tcon->ipc) {
172 snprintf(tree, sizeof(tree), "\\\\%s\\IPC$", 176 snprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$",
173 tcon->ses->server->hostname); 177 tcon->ses->server->hostname);
174 return SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); 178 rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
179 goto out;
175 } 180 }
176 181
177 if (!tcon->dfs_path) 182 if (!tcon->dfs_path) {
178 return SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nlsc); 183 rc = SMB2_tcon(0, tcon->ses, tcon->treeName, tcon, nlsc);
184 goto out;
185 }
179 186
180 rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl); 187 rc = dfs_cache_noreq_find(tcon->dfs_path + 1, NULL, &tl);
181 if (rc) 188 if (rc)
182 return rc; 189 goto out;
183 190
184 extract_unc_hostname(tcon->ses->server->hostname, &tcp_host, 191 extract_unc_hostname(tcon->ses->server->hostname, &tcp_host,
185 &tcp_host_len); 192 &tcp_host_len);
@@ -199,7 +206,7 @@ static int __smb2_reconnect(const struct nls_table *nlsc,
199 continue; 206 continue;
200 } 207 }
201 208
202 snprintf(tree, sizeof(tree), "\\%s", tgt); 209 snprintf(tree, MAX_TREE_SIZE, "\\%s", tgt);
203 210
204 rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); 211 rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc);
205 if (!rc) 212 if (!rc)
@@ -216,6 +223,8 @@ static int __smb2_reconnect(const struct nls_table *nlsc,
216 rc = -ENOENT; 223 rc = -ENOENT;
217 } 224 }
218 dfs_cache_free_tgts(&tl); 225 dfs_cache_free_tgts(&tl);
226out:
227 kfree(tree);
219 return rc; 228 return rc;
220} 229}
221#else 230#else
@@ -2807,6 +2816,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
2807 int resp_buftype = CIFS_NO_BUFFER; 2816 int resp_buftype = CIFS_NO_BUFFER;
2808 struct cifs_ses *ses = tcon->ses; 2817 struct cifs_ses *ses = tcon->ses;
2809 int flags = 0; 2818 int flags = 0;
2819 bool allocated = false;
2810 2820
2811 cifs_dbg(FYI, "Query Info\n"); 2821 cifs_dbg(FYI, "Query Info\n");
2812 2822
@@ -2846,14 +2856,21 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
2846 "Error %d allocating memory for acl\n", 2856 "Error %d allocating memory for acl\n",
2847 rc); 2857 rc);
2848 *dlen = 0; 2858 *dlen = 0;
2859 rc = -ENOMEM;
2849 goto qinf_exit; 2860 goto qinf_exit;
2850 } 2861 }
2862 allocated = true;
2851 } 2863 }
2852 } 2864 }
2853 2865
2854 rc = smb2_validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset), 2866 rc = smb2_validate_and_copy_iov(le16_to_cpu(rsp->OutputBufferOffset),
2855 le32_to_cpu(rsp->OutputBufferLength), 2867 le32_to_cpu(rsp->OutputBufferLength),
2856 &rsp_iov, min_len, *data); 2868 &rsp_iov, min_len, *data);
2869 if (rc && allocated) {
2870 kfree(*data);
2871 *data = NULL;
2872 *dlen = 0;
2873 }
2857 2874
2858qinf_exit: 2875qinf_exit:
2859 SMB2_query_info_free(&rqst); 2876 SMB2_query_info_free(&rqst);
@@ -2907,9 +2924,10 @@ smb2_echo_callback(struct mid_q_entry *mid)
2907{ 2924{
2908 struct TCP_Server_Info *server = mid->callback_data; 2925 struct TCP_Server_Info *server = mid->callback_data;
2909 struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf; 2926 struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf;
2910 unsigned int credits_received = 1; 2927 unsigned int credits_received = 0;
2911 2928
2912 if (mid->mid_state == MID_RESPONSE_RECEIVED) 2929 if (mid->mid_state == MID_RESPONSE_RECEIVED
2930 || mid->mid_state == MID_RESPONSE_MALFORMED)
2913 credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); 2931 credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest);
2914 2932
2915 DeleteMidQEntry(mid); 2933 DeleteMidQEntry(mid);
@@ -3166,7 +3184,7 @@ smb2_readv_callback(struct mid_q_entry *mid)
3166 struct TCP_Server_Info *server = tcon->ses->server; 3184 struct TCP_Server_Info *server = tcon->ses->server;
3167 struct smb2_sync_hdr *shdr = 3185 struct smb2_sync_hdr *shdr =
3168 (struct smb2_sync_hdr *)rdata->iov[0].iov_base; 3186 (struct smb2_sync_hdr *)rdata->iov[0].iov_base;
3169 unsigned int credits_received = 1; 3187 unsigned int credits_received = 0;
3170 struct smb_rqst rqst = { .rq_iov = rdata->iov, 3188 struct smb_rqst rqst = { .rq_iov = rdata->iov,
3171 .rq_nvec = 2, 3189 .rq_nvec = 2,
3172 .rq_pages = rdata->pages, 3190 .rq_pages = rdata->pages,
@@ -3205,6 +3223,9 @@ smb2_readv_callback(struct mid_q_entry *mid)
3205 task_io_account_read(rdata->got_bytes); 3223 task_io_account_read(rdata->got_bytes);
3206 cifs_stats_bytes_read(tcon, rdata->got_bytes); 3224 cifs_stats_bytes_read(tcon, rdata->got_bytes);
3207 break; 3225 break;
3226 case MID_RESPONSE_MALFORMED:
3227 credits_received = le16_to_cpu(shdr->CreditRequest);
3228 /* fall through */
3208 default: 3229 default:
3209 if (rdata->result != -ENODATA) 3230 if (rdata->result != -ENODATA)
3210 rdata->result = -EIO; 3231 rdata->result = -EIO;
@@ -3278,12 +3299,14 @@ smb2_async_readv(struct cifs_readdata *rdata)
3278 if (rdata->credits) { 3299 if (rdata->credits) {
3279 shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, 3300 shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
3280 SMB2_MAX_BUFFER_SIZE)); 3301 SMB2_MAX_BUFFER_SIZE));
3281 shdr->CreditRequest = shdr->CreditCharge; 3302 shdr->CreditRequest =
3303 cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1);
3282 spin_lock(&server->req_lock); 3304 spin_lock(&server->req_lock);
3283 server->credits += rdata->credits - 3305 server->credits += rdata->credits -
3284 le16_to_cpu(shdr->CreditCharge); 3306 le16_to_cpu(shdr->CreditCharge);
3285 spin_unlock(&server->req_lock); 3307 spin_unlock(&server->req_lock);
3286 wake_up(&server->request_q); 3308 wake_up(&server->request_q);
3309 rdata->credits = le16_to_cpu(shdr->CreditCharge);
3287 flags |= CIFS_HAS_CREDITS; 3310 flags |= CIFS_HAS_CREDITS;
3288 } 3311 }
3289 3312
@@ -3388,7 +3411,7 @@ smb2_writev_callback(struct mid_q_entry *mid)
3388 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); 3411 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
3389 unsigned int written; 3412 unsigned int written;
3390 struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf; 3413 struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf;
3391 unsigned int credits_received = 1; 3414 unsigned int credits_received = 0;
3392 3415
3393 switch (mid->mid_state) { 3416 switch (mid->mid_state) {
3394 case MID_RESPONSE_RECEIVED: 3417 case MID_RESPONSE_RECEIVED:
@@ -3416,6 +3439,9 @@ smb2_writev_callback(struct mid_q_entry *mid)
3416 case MID_RETRY_NEEDED: 3439 case MID_RETRY_NEEDED:
3417 wdata->result = -EAGAIN; 3440 wdata->result = -EAGAIN;
3418 break; 3441 break;
3442 case MID_RESPONSE_MALFORMED:
3443 credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest);
3444 /* fall through */
3419 default: 3445 default:
3420 wdata->result = -EIO; 3446 wdata->result = -EIO;
3421 break; 3447 break;
@@ -3555,12 +3581,14 @@ smb2_async_writev(struct cifs_writedata *wdata,
3555 if (wdata->credits) { 3581 if (wdata->credits) {
3556 shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, 3582 shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
3557 SMB2_MAX_BUFFER_SIZE)); 3583 SMB2_MAX_BUFFER_SIZE));
3558 shdr->CreditRequest = shdr->CreditCharge; 3584 shdr->CreditRequest =
3585 cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1);
3559 spin_lock(&server->req_lock); 3586 spin_lock(&server->req_lock);
3560 server->credits += wdata->credits - 3587 server->credits += wdata->credits -
3561 le16_to_cpu(shdr->CreditCharge); 3588 le16_to_cpu(shdr->CreditCharge);
3562 spin_unlock(&server->req_lock); 3589 spin_unlock(&server->req_lock);
3563 wake_up(&server->request_q); 3590 wake_up(&server->request_q);
3591 wdata->credits = le16_to_cpu(shdr->CreditCharge);
3564 flags |= CIFS_HAS_CREDITS; 3592 flags |= CIFS_HAS_CREDITS;
3565 } 3593 }
3566 3594