diff options
Diffstat (limited to 'fs/cifs/smb2pdu.c')
| -rw-r--r-- | fs/cifs/smb2pdu.c | 179 |
1 files changed, 116 insertions, 63 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 77b3aaa39b35..60fbe306f604 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
| @@ -107,13 +107,13 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd, | |||
| 107 | struct TCP_Server_Info *server = tcon->ses->server; | 107 | struct TCP_Server_Info *server = tcon->ses->server; |
| 108 | 108 | ||
| 109 | spin_lock(&server->req_lock); | 109 | spin_lock(&server->req_lock); |
| 110 | /* Request up to 2 credits but don't go over the limit. */ | 110 | /* Request up to 10 credits but don't go over the limit. */ |
| 111 | if (server->credits >= server->max_credits) | 111 | if (server->credits >= server->max_credits) |
| 112 | shdr->CreditRequest = cpu_to_le16(0); | 112 | shdr->CreditRequest = cpu_to_le16(0); |
| 113 | else | 113 | else |
| 114 | shdr->CreditRequest = cpu_to_le16( | 114 | shdr->CreditRequest = cpu_to_le16( |
| 115 | min_t(int, server->max_credits - | 115 | min_t(int, server->max_credits - |
| 116 | server->credits, 2)); | 116 | server->credits, 10)); |
| 117 | spin_unlock(&server->req_lock); | 117 | spin_unlock(&server->req_lock); |
| 118 | } else { | 118 | } else { |
| 119 | shdr->CreditRequest = cpu_to_le16(2); | 119 | shdr->CreditRequest = cpu_to_le16(2); |
| @@ -173,8 +173,8 @@ static int __smb2_reconnect(const struct nls_table *nlsc, | |||
| 173 | return -ENOMEM; | 173 | return -ENOMEM; |
| 174 | 174 | ||
| 175 | if (tcon->ipc) { | 175 | if (tcon->ipc) { |
| 176 | snprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", | 176 | scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", |
| 177 | tcon->ses->server->hostname); | 177 | tcon->ses->server->hostname); |
| 178 | rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); | 178 | rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); |
| 179 | goto out; | 179 | goto out; |
| 180 | } | 180 | } |
| @@ -206,7 +206,7 @@ static int __smb2_reconnect(const struct nls_table *nlsc, | |||
| 206 | continue; | 206 | continue; |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | snprintf(tree, MAX_TREE_SIZE, "\\%s", tgt); | 209 | scnprintf(tree, MAX_TREE_SIZE, "\\%s", tgt); |
| 210 | 210 | ||
| 211 | rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); | 211 | rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); |
| 212 | if (!rc) | 212 | if (!rc) |
| @@ -490,6 +490,23 @@ build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt) | |||
| 490 | { | 490 | { |
| 491 | pneg_ctxt->ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE; | 491 | pneg_ctxt->ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE; |
| 492 | pneg_ctxt->DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN); | 492 | pneg_ctxt->DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN); |
| 493 | /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */ | ||
| 494 | pneg_ctxt->Name[0] = 0x93; | ||
| 495 | pneg_ctxt->Name[1] = 0xAD; | ||
| 496 | pneg_ctxt->Name[2] = 0x25; | ||
| 497 | pneg_ctxt->Name[3] = 0x50; | ||
| 498 | pneg_ctxt->Name[4] = 0x9C; | ||
| 499 | pneg_ctxt->Name[5] = 0xB4; | ||
| 500 | pneg_ctxt->Name[6] = 0x11; | ||
| 501 | pneg_ctxt->Name[7] = 0xE7; | ||
| 502 | pneg_ctxt->Name[8] = 0xB4; | ||
| 503 | pneg_ctxt->Name[9] = 0x23; | ||
| 504 | pneg_ctxt->Name[10] = 0x83; | ||
| 505 | pneg_ctxt->Name[11] = 0xDE; | ||
| 506 | pneg_ctxt->Name[12] = 0x96; | ||
| 507 | pneg_ctxt->Name[13] = 0x8B; | ||
| 508 | pneg_ctxt->Name[14] = 0xCD; | ||
| 509 | pneg_ctxt->Name[15] = 0x7C; | ||
| 493 | } | 510 | } |
| 494 | 511 | ||
| 495 | static void | 512 | static void |
| @@ -986,8 +1003,14 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) | |||
| 986 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, | 1003 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, |
| 987 | FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, | 1004 | FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, |
| 988 | (char *)pneg_inbuf, inbuflen, (char **)&pneg_rsp, &rsplen); | 1005 | (char *)pneg_inbuf, inbuflen, (char **)&pneg_rsp, &rsplen); |
| 989 | 1006 | if (rc == -EOPNOTSUPP) { | |
| 990 | if (rc != 0) { | 1007 | /* |
| 1008 | * Old Windows versions or Netapp SMB server can return | ||
| 1009 | * not supported error. Client should accept it. | ||
| 1010 | */ | ||
| 1011 | cifs_dbg(VFS, "Server does not support validate negotiate\n"); | ||
| 1012 | return 0; | ||
| 1013 | } else if (rc != 0) { | ||
| 991 | cifs_dbg(VFS, "validate protocol negotiate failed: %d\n", rc); | 1014 | cifs_dbg(VFS, "validate protocol negotiate failed: %d\n", rc); |
| 992 | rc = -EIO; | 1015 | rc = -EIO; |
| 993 | goto out_free_inbuf; | 1016 | goto out_free_inbuf; |
| @@ -1614,6 +1637,9 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, | |||
| 1614 | rqst.rq_iov = iov; | 1637 | rqst.rq_iov = iov; |
| 1615 | rqst.rq_nvec = 2; | 1638 | rqst.rq_nvec = 2; |
| 1616 | 1639 | ||
| 1640 | /* Need 64 for max size write so ask for more in case not there yet */ | ||
| 1641 | req->sync_hdr.CreditRequest = cpu_to_le16(64); | ||
| 1642 | |||
| 1617 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); | 1643 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
| 1618 | cifs_small_buf_release(req); | 1644 | cifs_small_buf_release(req); |
| 1619 | rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base; | 1645 | rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base; |
| @@ -2170,6 +2196,8 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, | |||
| 2170 | rqst.rq_iov = iov; | 2196 | rqst.rq_iov = iov; |
| 2171 | rqst.rq_nvec = n_iov; | 2197 | rqst.rq_nvec = n_iov; |
| 2172 | 2198 | ||
| 2199 | trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, CREATE_NOT_FILE, | ||
| 2200 | FILE_WRITE_ATTRIBUTES); | ||
| 2173 | /* resource #4: response buffer */ | 2201 | /* resource #4: response buffer */ |
| 2174 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); | 2202 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
| 2175 | if (rc) { | 2203 | if (rc) { |
| @@ -2388,6 +2416,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, | |||
| 2388 | if (rc) | 2416 | if (rc) |
| 2389 | goto creat_exit; | 2417 | goto creat_exit; |
| 2390 | 2418 | ||
| 2419 | trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, | ||
| 2420 | oparms->create_options, oparms->desired_access); | ||
| 2421 | |||
| 2391 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, | 2422 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, |
| 2392 | &rsp_iov); | 2423 | &rsp_iov); |
| 2393 | rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; | 2424 | rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; |
| @@ -2837,6 +2868,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 2837 | if (rc) | 2868 | if (rc) |
| 2838 | goto qinf_exit; | 2869 | goto qinf_exit; |
| 2839 | 2870 | ||
| 2871 | trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid, | ||
| 2872 | ses->Suid, info_class, (__u32)info_type); | ||
| 2873 | |||
| 2840 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); | 2874 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
| 2841 | rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; | 2875 | rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; |
| 2842 | 2876 | ||
| @@ -2847,6 +2881,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 2847 | goto qinf_exit; | 2881 | goto qinf_exit; |
| 2848 | } | 2882 | } |
| 2849 | 2883 | ||
| 2884 | trace_smb3_query_info_done(xid, persistent_fid, tcon->tid, | ||
| 2885 | ses->Suid, info_class, (__u32)info_type); | ||
| 2886 | |||
| 2850 | if (dlen) { | 2887 | if (dlen) { |
| 2851 | *dlen = le32_to_cpu(rsp->OutputBufferLength); | 2888 | *dlen = le32_to_cpu(rsp->OutputBufferLength); |
| 2852 | if (!*data) { | 2889 | if (!*data) { |
| @@ -2924,14 +2961,16 @@ smb2_echo_callback(struct mid_q_entry *mid) | |||
| 2924 | { | 2961 | { |
| 2925 | struct TCP_Server_Info *server = mid->callback_data; | 2962 | struct TCP_Server_Info *server = mid->callback_data; |
| 2926 | struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf; | 2963 | struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf; |
| 2927 | unsigned int credits_received = 0; | 2964 | struct cifs_credits credits = { .value = 0, .instance = 0 }; |
| 2928 | 2965 | ||
| 2929 | if (mid->mid_state == MID_RESPONSE_RECEIVED | 2966 | if (mid->mid_state == MID_RESPONSE_RECEIVED |
| 2930 | || mid->mid_state == MID_RESPONSE_MALFORMED) | 2967 | || mid->mid_state == MID_RESPONSE_MALFORMED) { |
| 2931 | credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); | 2968 | credits.value = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
| 2969 | credits.instance = server->reconnect_instance; | ||
| 2970 | } | ||
| 2932 | 2971 | ||
| 2933 | DeleteMidQEntry(mid); | 2972 | DeleteMidQEntry(mid); |
| 2934 | add_credits(server, credits_received, CIFS_ECHO_OP); | 2973 | add_credits(server, &credits, CIFS_ECHO_OP); |
| 2935 | } | 2974 | } |
| 2936 | 2975 | ||
| 2937 | void smb2_reconnect_server(struct work_struct *work) | 2976 | void smb2_reconnect_server(struct work_struct *work) |
| @@ -3023,7 +3062,7 @@ SMB2_echo(struct TCP_Server_Info *server) | |||
| 3023 | iov[0].iov_base = (char *)req; | 3062 | iov[0].iov_base = (char *)req; |
| 3024 | 3063 | ||
| 3025 | rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL, | 3064 | rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL, |
| 3026 | server, CIFS_ECHO_OP); | 3065 | server, CIFS_ECHO_OP, NULL); |
| 3027 | if (rc) | 3066 | if (rc) |
| 3028 | cifs_dbg(FYI, "Echo request failed: %d\n", rc); | 3067 | cifs_dbg(FYI, "Echo request failed: %d\n", rc); |
| 3029 | 3068 | ||
| @@ -3114,6 +3153,11 @@ smb2_new_read_req(void **buf, unsigned int *total_len, | |||
| 3114 | req->MinimumCount = 0; | 3153 | req->MinimumCount = 0; |
| 3115 | req->Length = cpu_to_le32(io_parms->length); | 3154 | req->Length = cpu_to_le32(io_parms->length); |
| 3116 | req->Offset = cpu_to_le64(io_parms->offset); | 3155 | req->Offset = cpu_to_le64(io_parms->offset); |
| 3156 | |||
| 3157 | trace_smb3_read_enter(0 /* xid */, | ||
| 3158 | io_parms->persistent_fid, | ||
| 3159 | io_parms->tcon->tid, io_parms->tcon->ses->Suid, | ||
| 3160 | io_parms->offset, io_parms->length); | ||
| 3117 | #ifdef CONFIG_CIFS_SMB_DIRECT | 3161 | #ifdef CONFIG_CIFS_SMB_DIRECT |
| 3118 | /* | 3162 | /* |
| 3119 | * If we want to do a RDMA write, fill in and append | 3163 | * If we want to do a RDMA write, fill in and append |
| @@ -3184,7 +3228,7 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
| 3184 | struct TCP_Server_Info *server = tcon->ses->server; | 3228 | struct TCP_Server_Info *server = tcon->ses->server; |
| 3185 | struct smb2_sync_hdr *shdr = | 3229 | struct smb2_sync_hdr *shdr = |
| 3186 | (struct smb2_sync_hdr *)rdata->iov[0].iov_base; | 3230 | (struct smb2_sync_hdr *)rdata->iov[0].iov_base; |
| 3187 | unsigned int credits_received = 0; | 3231 | struct cifs_credits credits = { .value = 0, .instance = 0 }; |
| 3188 | struct smb_rqst rqst = { .rq_iov = rdata->iov, | 3232 | struct smb_rqst rqst = { .rq_iov = rdata->iov, |
| 3189 | .rq_nvec = 2, | 3233 | .rq_nvec = 2, |
| 3190 | .rq_pages = rdata->pages, | 3234 | .rq_pages = rdata->pages, |
| @@ -3199,7 +3243,8 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
| 3199 | 3243 | ||
| 3200 | switch (mid->mid_state) { | 3244 | switch (mid->mid_state) { |
| 3201 | case MID_RESPONSE_RECEIVED: | 3245 | case MID_RESPONSE_RECEIVED: |
| 3202 | credits_received = le16_to_cpu(shdr->CreditRequest); | 3246 | credits.value = le16_to_cpu(shdr->CreditRequest); |
| 3247 | credits.instance = server->reconnect_instance; | ||
| 3203 | /* result already set, check signature */ | 3248 | /* result already set, check signature */ |
| 3204 | if (server->sign && !mid->decrypted) { | 3249 | if (server->sign && !mid->decrypted) { |
| 3205 | int rc; | 3250 | int rc; |
| @@ -3224,11 +3269,11 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
| 3224 | cifs_stats_bytes_read(tcon, rdata->got_bytes); | 3269 | cifs_stats_bytes_read(tcon, rdata->got_bytes); |
| 3225 | break; | 3270 | break; |
| 3226 | case MID_RESPONSE_MALFORMED: | 3271 | case MID_RESPONSE_MALFORMED: |
| 3227 | credits_received = le16_to_cpu(shdr->CreditRequest); | 3272 | credits.value = le16_to_cpu(shdr->CreditRequest); |
| 3273 | credits.instance = server->reconnect_instance; | ||
| 3228 | /* fall through */ | 3274 | /* fall through */ |
| 3229 | default: | 3275 | default: |
| 3230 | if (rdata->result != -ENODATA) | 3276 | rdata->result = -EIO; |
| 3231 | rdata->result = -EIO; | ||
| 3232 | } | 3277 | } |
| 3233 | #ifdef CONFIG_CIFS_SMB_DIRECT | 3278 | #ifdef CONFIG_CIFS_SMB_DIRECT |
| 3234 | /* | 3279 | /* |
| @@ -3255,7 +3300,7 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
| 3255 | 3300 | ||
| 3256 | queue_work(cifsiod_wq, &rdata->work); | 3301 | queue_work(cifsiod_wq, &rdata->work); |
| 3257 | DeleteMidQEntry(mid); | 3302 | DeleteMidQEntry(mid); |
| 3258 | add_credits(server, credits_received, 0); | 3303 | add_credits(server, &credits, 0); |
| 3259 | } | 3304 | } |
| 3260 | 3305 | ||
| 3261 | /* smb2_async_readv - send an async read, and set up mid to handle result */ | 3306 | /* smb2_async_readv - send an async read, and set up mid to handle result */ |
| @@ -3285,17 +3330,8 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
| 3285 | 3330 | ||
| 3286 | rc = smb2_new_read_req( | 3331 | rc = smb2_new_read_req( |
| 3287 | (void **) &buf, &total_len, &io_parms, rdata, 0, 0); | 3332 | (void **) &buf, &total_len, &io_parms, rdata, 0, 0); |
| 3288 | if (rc) { | 3333 | if (rc) |
| 3289 | if (rc == -EAGAIN && rdata->credits) { | ||
| 3290 | /* credits was reset by reconnect */ | ||
| 3291 | rdata->credits = 0; | ||
| 3292 | /* reduce in_flight value since we won't send the req */ | ||
| 3293 | spin_lock(&server->req_lock); | ||
| 3294 | server->in_flight--; | ||
| 3295 | spin_unlock(&server->req_lock); | ||
| 3296 | } | ||
| 3297 | return rc; | 3334 | return rc; |
| 3298 | } | ||
| 3299 | 3335 | ||
| 3300 | if (smb3_encryption_required(io_parms.tcon)) | 3336 | if (smb3_encryption_required(io_parms.tcon)) |
| 3301 | flags |= CIFS_TRANSFORM_REQ; | 3337 | flags |= CIFS_TRANSFORM_REQ; |
| @@ -3305,24 +3341,24 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
| 3305 | 3341 | ||
| 3306 | shdr = (struct smb2_sync_hdr *)buf; | 3342 | shdr = (struct smb2_sync_hdr *)buf; |
| 3307 | 3343 | ||
| 3308 | if (rdata->credits) { | 3344 | if (rdata->credits.value > 0) { |
| 3309 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, | 3345 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, |
| 3310 | SMB2_MAX_BUFFER_SIZE)); | 3346 | SMB2_MAX_BUFFER_SIZE)); |
| 3311 | shdr->CreditRequest = | 3347 | shdr->CreditRequest = |
| 3312 | cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); | 3348 | cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); |
| 3313 | spin_lock(&server->req_lock); | 3349 | |
| 3314 | server->credits += rdata->credits - | 3350 | rc = adjust_credits(server, &rdata->credits, rdata->bytes); |
| 3315 | le16_to_cpu(shdr->CreditCharge); | 3351 | if (rc) |
| 3316 | spin_unlock(&server->req_lock); | 3352 | goto async_readv_out; |
| 3317 | wake_up(&server->request_q); | 3353 | |
| 3318 | rdata->credits = le16_to_cpu(shdr->CreditCharge); | ||
| 3319 | flags |= CIFS_HAS_CREDITS; | 3354 | flags |= CIFS_HAS_CREDITS; |
| 3320 | } | 3355 | } |
| 3321 | 3356 | ||
| 3322 | kref_get(&rdata->refcount); | 3357 | kref_get(&rdata->refcount); |
| 3323 | rc = cifs_call_async(io_parms.tcon->ses->server, &rqst, | 3358 | rc = cifs_call_async(io_parms.tcon->ses->server, &rqst, |
| 3324 | cifs_readv_receive, smb2_readv_callback, | 3359 | cifs_readv_receive, smb2_readv_callback, |
| 3325 | smb3_handle_read_data, rdata, flags); | 3360 | smb3_handle_read_data, rdata, flags, |
| 3361 | &rdata->credits); | ||
| 3326 | if (rc) { | 3362 | if (rc) { |
| 3327 | kref_put(&rdata->refcount, cifs_readdata_release); | 3363 | kref_put(&rdata->refcount, cifs_readdata_release); |
| 3328 | cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); | 3364 | cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); |
| @@ -3332,6 +3368,7 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
| 3332 | io_parms.offset, io_parms.length, rc); | 3368 | io_parms.offset, io_parms.length, rc); |
| 3333 | } | 3369 | } |
| 3334 | 3370 | ||
| 3371 | async_readv_out: | ||
| 3335 | cifs_small_buf_release(buf); | 3372 | cifs_small_buf_release(buf); |
| 3336 | return rc; | 3373 | return rc; |
| 3337 | } | 3374 | } |
| @@ -3378,7 +3415,10 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
| 3378 | io_parms->tcon->tid, ses->Suid, | 3415 | io_parms->tcon->tid, ses->Suid, |
| 3379 | io_parms->offset, io_parms->length, | 3416 | io_parms->offset, io_parms->length, |
| 3380 | rc); | 3417 | rc); |
| 3381 | } | 3418 | } else |
| 3419 | trace_smb3_read_done(xid, req->PersistentFileId, | ||
| 3420 | io_parms->tcon->tid, ses->Suid, | ||
| 3421 | io_parms->offset, 0); | ||
| 3382 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); | 3422 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
| 3383 | return rc == -ENODATA ? 0 : rc; | 3423 | return rc == -ENODATA ? 0 : rc; |
| 3384 | } else | 3424 | } else |
| @@ -3417,14 +3457,16 @@ smb2_writev_callback(struct mid_q_entry *mid) | |||
| 3417 | { | 3457 | { |
| 3418 | struct cifs_writedata *wdata = mid->callback_data; | 3458 | struct cifs_writedata *wdata = mid->callback_data; |
| 3419 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); | 3459 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); |
| 3460 | struct TCP_Server_Info *server = tcon->ses->server; | ||
| 3420 | unsigned int written; | 3461 | unsigned int written; |
| 3421 | struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf; | 3462 | struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf; |
| 3422 | unsigned int credits_received = 0; | 3463 | struct cifs_credits credits = { .value = 0, .instance = 0 }; |
| 3423 | 3464 | ||
| 3424 | switch (mid->mid_state) { | 3465 | switch (mid->mid_state) { |
| 3425 | case MID_RESPONSE_RECEIVED: | 3466 | case MID_RESPONSE_RECEIVED: |
| 3426 | credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); | 3467 | credits.value = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
| 3427 | wdata->result = smb2_check_receive(mid, tcon->ses->server, 0); | 3468 | credits.instance = server->reconnect_instance; |
| 3469 | wdata->result = smb2_check_receive(mid, server, 0); | ||
| 3428 | if (wdata->result != 0) | 3470 | if (wdata->result != 0) |
| 3429 | break; | 3471 | break; |
| 3430 | 3472 | ||
| @@ -3448,7 +3490,8 @@ smb2_writev_callback(struct mid_q_entry *mid) | |||
| 3448 | wdata->result = -EAGAIN; | 3490 | wdata->result = -EAGAIN; |
| 3449 | break; | 3491 | break; |
| 3450 | case MID_RESPONSE_MALFORMED: | 3492 | case MID_RESPONSE_MALFORMED: |
| 3451 | credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); | 3493 | credits.value = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
| 3494 | credits.instance = server->reconnect_instance; | ||
| 3452 | /* fall through */ | 3495 | /* fall through */ |
| 3453 | default: | 3496 | default: |
| 3454 | wdata->result = -EIO; | 3497 | wdata->result = -EIO; |
| @@ -3481,7 +3524,7 @@ smb2_writev_callback(struct mid_q_entry *mid) | |||
| 3481 | 3524 | ||
| 3482 | queue_work(cifsiod_wq, &wdata->work); | 3525 | queue_work(cifsiod_wq, &wdata->work); |
| 3483 | DeleteMidQEntry(mid); | 3526 | DeleteMidQEntry(mid); |
| 3484 | add_credits(tcon->ses->server, credits_received, 0); | 3527 | add_credits(server, &credits, 0); |
| 3485 | } | 3528 | } |
| 3486 | 3529 | ||
| 3487 | /* smb2_async_writev - send an async write, and set up mid to handle result */ | 3530 | /* smb2_async_writev - send an async write, and set up mid to handle result */ |
| @@ -3499,17 +3542,8 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
| 3499 | unsigned int total_len; | 3542 | unsigned int total_len; |
| 3500 | 3543 | ||
| 3501 | rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len); | 3544 | rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len); |
| 3502 | if (rc) { | 3545 | if (rc) |
| 3503 | if (rc == -EAGAIN && wdata->credits) { | 3546 | return rc; |
| 3504 | /* credits was reset by reconnect */ | ||
| 3505 | wdata->credits = 0; | ||
| 3506 | /* reduce in_flight value since we won't send the req */ | ||
| 3507 | spin_lock(&server->req_lock); | ||
| 3508 | server->in_flight--; | ||
| 3509 | spin_unlock(&server->req_lock); | ||
| 3510 | } | ||
| 3511 | goto async_writev_out; | ||
| 3512 | } | ||
| 3513 | 3547 | ||
| 3514 | if (smb3_encryption_required(tcon)) | 3548 | if (smb3_encryption_required(tcon)) |
| 3515 | flags |= CIFS_TRANSFORM_REQ; | 3549 | flags |= CIFS_TRANSFORM_REQ; |
| @@ -3526,6 +3560,9 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
| 3526 | req->DataOffset = cpu_to_le16( | 3560 | req->DataOffset = cpu_to_le16( |
| 3527 | offsetof(struct smb2_write_req, Buffer)); | 3561 | offsetof(struct smb2_write_req, Buffer)); |
| 3528 | req->RemainingBytes = 0; | 3562 | req->RemainingBytes = 0; |
| 3563 | |||
| 3564 | trace_smb3_write_enter(0 /* xid */, wdata->cfile->fid.persistent_fid, | ||
| 3565 | tcon->tid, tcon->ses->Suid, wdata->offset, wdata->bytes); | ||
| 3529 | #ifdef CONFIG_CIFS_SMB_DIRECT | 3566 | #ifdef CONFIG_CIFS_SMB_DIRECT |
| 3530 | /* | 3567 | /* |
| 3531 | * If we want to do a server RDMA read, fill in and append | 3568 | * If we want to do a server RDMA read, fill in and append |
| @@ -3595,23 +3632,22 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
| 3595 | req->Length = cpu_to_le32(wdata->bytes); | 3632 | req->Length = cpu_to_le32(wdata->bytes); |
| 3596 | #endif | 3633 | #endif |
| 3597 | 3634 | ||
| 3598 | if (wdata->credits) { | 3635 | if (wdata->credits.value > 0) { |
| 3599 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, | 3636 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, |
| 3600 | SMB2_MAX_BUFFER_SIZE)); | 3637 | SMB2_MAX_BUFFER_SIZE)); |
| 3601 | shdr->CreditRequest = | 3638 | shdr->CreditRequest = |
| 3602 | cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); | 3639 | cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); |
| 3603 | spin_lock(&server->req_lock); | 3640 | |
| 3604 | server->credits += wdata->credits - | 3641 | rc = adjust_credits(server, &wdata->credits, wdata->bytes); |
| 3605 | le16_to_cpu(shdr->CreditCharge); | 3642 | if (rc) |
| 3606 | spin_unlock(&server->req_lock); | 3643 | goto async_writev_out; |
| 3607 | wake_up(&server->request_q); | 3644 | |
| 3608 | wdata->credits = le16_to_cpu(shdr->CreditCharge); | ||
| 3609 | flags |= CIFS_HAS_CREDITS; | 3645 | flags |= CIFS_HAS_CREDITS; |
| 3610 | } | 3646 | } |
| 3611 | 3647 | ||
| 3612 | kref_get(&wdata->refcount); | 3648 | kref_get(&wdata->refcount); |
| 3613 | rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, NULL, | 3649 | rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, NULL, |
| 3614 | wdata, flags); | 3650 | wdata, flags, &wdata->credits); |
| 3615 | 3651 | ||
| 3616 | if (rc) { | 3652 | if (rc) { |
| 3617 | trace_smb3_write_err(0 /* no xid */, req->PersistentFileId, | 3653 | trace_smb3_write_err(0 /* no xid */, req->PersistentFileId, |
| @@ -3674,6 +3710,10 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
| 3674 | offsetof(struct smb2_write_req, Buffer)); | 3710 | offsetof(struct smb2_write_req, Buffer)); |
| 3675 | req->RemainingBytes = 0; | 3711 | req->RemainingBytes = 0; |
| 3676 | 3712 | ||
| 3713 | trace_smb3_write_enter(xid, io_parms->persistent_fid, | ||
| 3714 | io_parms->tcon->tid, io_parms->tcon->ses->Suid, | ||
| 3715 | io_parms->offset, io_parms->length); | ||
| 3716 | |||
| 3677 | iov[0].iov_base = (char *)req; | 3717 | iov[0].iov_base = (char *)req; |
| 3678 | /* 1 for Buffer */ | 3718 | /* 1 for Buffer */ |
| 3679 | iov[0].iov_len = total_len - 1; | 3719 | iov[0].iov_len = total_len - 1; |
| @@ -3836,6 +3876,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 3836 | rqst.rq_iov = iov; | 3876 | rqst.rq_iov = iov; |
| 3837 | rqst.rq_nvec = 2; | 3877 | rqst.rq_nvec = 2; |
| 3838 | 3878 | ||
| 3879 | trace_smb3_query_dir_enter(xid, persistent_fid, tcon->tid, | ||
| 3880 | tcon->ses->Suid, index, output_size); | ||
| 3881 | |||
| 3839 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); | 3882 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
| 3840 | cifs_small_buf_release(req); | 3883 | cifs_small_buf_release(req); |
| 3841 | rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base; | 3884 | rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base; |
| @@ -3843,18 +3886,26 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 3843 | if (rc) { | 3886 | if (rc) { |
| 3844 | if (rc == -ENODATA && | 3887 | if (rc == -ENODATA && |
| 3845 | rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) { | 3888 | rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) { |
| 3889 | trace_smb3_query_dir_done(xid, persistent_fid, | ||
| 3890 | tcon->tid, tcon->ses->Suid, index, 0); | ||
| 3846 | srch_inf->endOfSearch = true; | 3891 | srch_inf->endOfSearch = true; |
| 3847 | rc = 0; | 3892 | rc = 0; |
| 3848 | } else | 3893 | } else { |
| 3894 | trace_smb3_query_dir_err(xid, persistent_fid, tcon->tid, | ||
| 3895 | tcon->ses->Suid, index, 0, rc); | ||
| 3849 | cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); | 3896 | cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); |
| 3897 | } | ||
| 3850 | goto qdir_exit; | 3898 | goto qdir_exit; |
| 3851 | } | 3899 | } |
| 3852 | 3900 | ||
| 3853 | rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), | 3901 | rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), |
| 3854 | le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, | 3902 | le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, |
| 3855 | info_buf_size); | 3903 | info_buf_size); |
| 3856 | if (rc) | 3904 | if (rc) { |
| 3905 | trace_smb3_query_dir_err(xid, persistent_fid, tcon->tid, | ||
| 3906 | tcon->ses->Suid, index, 0, rc); | ||
| 3857 | goto qdir_exit; | 3907 | goto qdir_exit; |
| 3908 | } | ||
| 3858 | 3909 | ||
| 3859 | srch_inf->unicode = true; | 3910 | srch_inf->unicode = true; |
| 3860 | 3911 | ||
| @@ -3882,6 +3933,8 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, | |||
| 3882 | else | 3933 | else |
| 3883 | cifs_dbg(VFS, "illegal search buffer type\n"); | 3934 | cifs_dbg(VFS, "illegal search buffer type\n"); |
| 3884 | 3935 | ||
| 3936 | trace_smb3_query_dir_done(xid, persistent_fid, tcon->tid, | ||
| 3937 | tcon->ses->Suid, index, srch_inf->entries_in_buffer); | ||
| 3885 | return rc; | 3938 | return rc; |
| 3886 | 3939 | ||
| 3887 | qdir_exit: | 3940 | qdir_exit: |
