diff options
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r-- | fs/cifs/smb2pdu.c | 54 |
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); |
226 | out: | ||
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 | ||
2858 | qinf_exit: | 2875 | qinf_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 | ||