aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2pdu.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r--fs/cifs/smb2pdu.c108
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);
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;
@@ -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
3582async_writev_out: 3624async_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,