diff options
Diffstat (limited to 'fs/cifs/smb2pdu.c')
| -rw-r--r-- | fs/cifs/smb2pdu.c | 108 |
1 files changed, 75 insertions, 33 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index e57f6aa1d638..77b3aaa39b35 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; |
| @@ -3220,8 +3241,17 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
| 3220 | rdata->mr = NULL; | 3241 | rdata->mr = NULL; |
| 3221 | } | 3242 | } |
| 3222 | #endif | 3243 | #endif |
| 3223 | if (rdata->result) | 3244 | if (rdata->result && rdata->result != -ENODATA) { |
| 3224 | cifs_stats_fail_inc(tcon, SMB2_READ_HE); | 3245 | cifs_stats_fail_inc(tcon, SMB2_READ_HE); |
| 3246 | trace_smb3_read_err(0 /* xid */, | ||
| 3247 | rdata->cfile->fid.persistent_fid, | ||
| 3248 | tcon->tid, tcon->ses->Suid, rdata->offset, | ||
| 3249 | rdata->bytes, rdata->result); | ||
| 3250 | } else | ||
| 3251 | trace_smb3_read_done(0 /* xid */, | ||
| 3252 | rdata->cfile->fid.persistent_fid, | ||
| 3253 | tcon->tid, tcon->ses->Suid, | ||
| 3254 | rdata->offset, rdata->got_bytes); | ||
| 3225 | 3255 | ||
| 3226 | queue_work(cifsiod_wq, &rdata->work); | 3256 | queue_work(cifsiod_wq, &rdata->work); |
| 3227 | DeleteMidQEntry(mid); | 3257 | DeleteMidQEntry(mid); |
| @@ -3278,12 +3308,14 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
| 3278 | if (rdata->credits) { | 3308 | if (rdata->credits) { |
| 3279 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, | 3309 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, |
| 3280 | SMB2_MAX_BUFFER_SIZE)); | 3310 | SMB2_MAX_BUFFER_SIZE)); |
| 3281 | shdr->CreditRequest = shdr->CreditCharge; | 3311 | shdr->CreditRequest = |
| 3312 | cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); | ||
| 3282 | spin_lock(&server->req_lock); | 3313 | spin_lock(&server->req_lock); |
| 3283 | server->credits += rdata->credits - | 3314 | server->credits += rdata->credits - |
| 3284 | le16_to_cpu(shdr->CreditCharge); | 3315 | le16_to_cpu(shdr->CreditCharge); |
| 3285 | spin_unlock(&server->req_lock); | 3316 | spin_unlock(&server->req_lock); |
| 3286 | wake_up(&server->request_q); | 3317 | wake_up(&server->request_q); |
| 3318 | rdata->credits = le16_to_cpu(shdr->CreditCharge); | ||
| 3287 | flags |= CIFS_HAS_CREDITS; | 3319 | flags |= CIFS_HAS_CREDITS; |
| 3288 | } | 3320 | } |
| 3289 | 3321 | ||
| @@ -3294,13 +3326,11 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
| 3294 | if (rc) { | 3326 | if (rc) { |
| 3295 | kref_put(&rdata->refcount, cifs_readdata_release); | 3327 | kref_put(&rdata->refcount, cifs_readdata_release); |
| 3296 | cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); | 3328 | cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); |
| 3297 | trace_smb3_read_err(rc, 0 /* xid */, io_parms.persistent_fid, | 3329 | trace_smb3_read_err(0 /* xid */, io_parms.persistent_fid, |
| 3298 | io_parms.tcon->tid, io_parms.tcon->ses->Suid, | 3330 | io_parms.tcon->tid, |
| 3299 | io_parms.offset, io_parms.length); | 3331 | io_parms.tcon->ses->Suid, |
| 3300 | } else | 3332 | io_parms.offset, io_parms.length, rc); |
| 3301 | trace_smb3_read_done(0 /* xid */, io_parms.persistent_fid, | 3333 | } |
| 3302 | io_parms.tcon->tid, io_parms.tcon->ses->Suid, | ||
| 3303 | io_parms.offset, io_parms.length); | ||
| 3304 | 3334 | ||
| 3305 | cifs_small_buf_release(buf); | 3335 | cifs_small_buf_release(buf); |
| 3306 | return rc; | 3336 | return rc; |
| @@ -3344,10 +3374,11 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
| 3344 | if (rc != -ENODATA) { | 3374 | if (rc != -ENODATA) { |
| 3345 | cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE); | 3375 | cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE); |
| 3346 | cifs_dbg(VFS, "Send error in read = %d\n", rc); | 3376 | cifs_dbg(VFS, "Send error in read = %d\n", rc); |
| 3377 | trace_smb3_read_err(xid, req->PersistentFileId, | ||
| 3378 | io_parms->tcon->tid, ses->Suid, | ||
| 3379 | io_parms->offset, io_parms->length, | ||
| 3380 | rc); | ||
| 3347 | } | 3381 | } |
| 3348 | trace_smb3_read_err(rc, xid, req->PersistentFileId, | ||
| 3349 | io_parms->tcon->tid, ses->Suid, | ||
| 3350 | io_parms->offset, io_parms->length); | ||
| 3351 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); | 3382 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
| 3352 | return rc == -ENODATA ? 0 : rc; | 3383 | return rc == -ENODATA ? 0 : rc; |
| 3353 | } else | 3384 | } else |
| @@ -3388,7 +3419,7 @@ smb2_writev_callback(struct mid_q_entry *mid) | |||
| 3388 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); | 3419 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); |
| 3389 | unsigned int written; | 3420 | unsigned int written; |
| 3390 | struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf; | 3421 | struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf; |
| 3391 | unsigned int credits_received = 1; | 3422 | unsigned int credits_received = 0; |
| 3392 | 3423 | ||
| 3393 | switch (mid->mid_state) { | 3424 | switch (mid->mid_state) { |
| 3394 | case MID_RESPONSE_RECEIVED: | 3425 | case MID_RESPONSE_RECEIVED: |
| @@ -3416,6 +3447,9 @@ smb2_writev_callback(struct mid_q_entry *mid) | |||
| 3416 | case MID_RETRY_NEEDED: | 3447 | case MID_RETRY_NEEDED: |
| 3417 | wdata->result = -EAGAIN; | 3448 | wdata->result = -EAGAIN; |
| 3418 | break; | 3449 | break; |
| 3450 | case MID_RESPONSE_MALFORMED: | ||
| 3451 | credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); | ||
| 3452 | /* fall through */ | ||
| 3419 | default: | 3453 | default: |
| 3420 | wdata->result = -EIO; | 3454 | wdata->result = -EIO; |
| 3421 | break; | 3455 | break; |
| @@ -3433,8 +3467,17 @@ smb2_writev_callback(struct mid_q_entry *mid) | |||
| 3433 | wdata->mr = NULL; | 3467 | wdata->mr = NULL; |
| 3434 | } | 3468 | } |
| 3435 | #endif | 3469 | #endif |
| 3436 | if (wdata->result) | 3470 | if (wdata->result) { |
| 3437 | cifs_stats_fail_inc(tcon, SMB2_WRITE_HE); | 3471 | cifs_stats_fail_inc(tcon, SMB2_WRITE_HE); |
| 3472 | trace_smb3_write_err(0 /* no xid */, | ||
| 3473 | wdata->cfile->fid.persistent_fid, | ||
| 3474 | tcon->tid, tcon->ses->Suid, wdata->offset, | ||
| 3475 | wdata->bytes, wdata->result); | ||
| 3476 | } else | ||
| 3477 | trace_smb3_write_done(0 /* no xid */, | ||
| 3478 | wdata->cfile->fid.persistent_fid, | ||
| 3479 | tcon->tid, tcon->ses->Suid, | ||
| 3480 | wdata->offset, wdata->bytes); | ||
| 3438 | 3481 | ||
| 3439 | queue_work(cifsiod_wq, &wdata->work); | 3482 | queue_work(cifsiod_wq, &wdata->work); |
| 3440 | DeleteMidQEntry(mid); | 3483 | DeleteMidQEntry(mid); |
| @@ -3555,12 +3598,14 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
| 3555 | if (wdata->credits) { | 3598 | if (wdata->credits) { |
| 3556 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, | 3599 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, |
| 3557 | SMB2_MAX_BUFFER_SIZE)); | 3600 | SMB2_MAX_BUFFER_SIZE)); |
| 3558 | shdr->CreditRequest = shdr->CreditCharge; | 3601 | shdr->CreditRequest = |
| 3602 | cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); | ||
| 3559 | spin_lock(&server->req_lock); | 3603 | spin_lock(&server->req_lock); |
| 3560 | server->credits += wdata->credits - | 3604 | server->credits += wdata->credits - |
| 3561 | le16_to_cpu(shdr->CreditCharge); | 3605 | le16_to_cpu(shdr->CreditCharge); |
| 3562 | spin_unlock(&server->req_lock); | 3606 | spin_unlock(&server->req_lock); |
| 3563 | wake_up(&server->request_q); | 3607 | wake_up(&server->request_q); |
| 3608 | wdata->credits = le16_to_cpu(shdr->CreditCharge); | ||
| 3564 | flags |= CIFS_HAS_CREDITS; | 3609 | flags |= CIFS_HAS_CREDITS; |
| 3565 | } | 3610 | } |
| 3566 | 3611 | ||
| @@ -3574,10 +3619,7 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
| 3574 | wdata->bytes, rc); | 3619 | wdata->bytes, rc); |
| 3575 | kref_put(&wdata->refcount, release); | 3620 | kref_put(&wdata->refcount, release); |
| 3576 | cifs_stats_fail_inc(tcon, SMB2_WRITE_HE); | 3621 | cifs_stats_fail_inc(tcon, SMB2_WRITE_HE); |
| 3577 | } else | 3622 | } |
| 3578 | trace_smb3_write_done(0 /* no xid */, req->PersistentFileId, | ||
| 3579 | tcon->tid, tcon->ses->Suid, wdata->offset, | ||
| 3580 | wdata->bytes); | ||
| 3581 | 3623 | ||
| 3582 | async_writev_out: | 3624 | async_writev_out: |
| 3583 | cifs_small_buf_release(req); | 3625 | cifs_small_buf_release(req); |
| @@ -3803,8 +3845,8 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 3803 | rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) { | 3845 | rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) { |
| 3804 | srch_inf->endOfSearch = true; | 3846 | srch_inf->endOfSearch = true; |
| 3805 | rc = 0; | 3847 | rc = 0; |
| 3806 | } | 3848 | } else |
| 3807 | cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); | 3849 | cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); |
| 3808 | goto qdir_exit; | 3850 | goto qdir_exit; |
| 3809 | } | 3851 | } |
| 3810 | 3852 | ||
| @@ -4399,8 +4441,8 @@ SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 4399 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov); | 4441 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buf_type, flags, &rsp_iov); |
| 4400 | cifs_small_buf_release(req); | 4442 | cifs_small_buf_release(req); |
| 4401 | 4443 | ||
| 4402 | please_key_low = (__u64 *)req->LeaseKey; | 4444 | please_key_low = (__u64 *)lease_key; |
| 4403 | please_key_high = (__u64 *)(req->LeaseKey+8); | 4445 | please_key_high = (__u64 *)(lease_key+8); |
| 4404 | if (rc) { | 4446 | if (rc) { |
| 4405 | cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE); | 4447 | cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE); |
| 4406 | trace_smb3_lease_err(le32_to_cpu(lease_state), tcon->tid, | 4448 | trace_smb3_lease_err(le32_to_cpu(lease_state), tcon->tid, |
