diff options
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r-- | fs/cifs/smb2pdu.c | 89 |
1 files changed, 67 insertions, 22 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index f6ba2c03f7cc..d1a90371b649 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -293,10 +293,46 @@ fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon, void *buf, | |||
293 | *total_len = parmsize + sizeof(struct smb2_sync_hdr); | 293 | *total_len = parmsize + sizeof(struct smb2_sync_hdr); |
294 | } | 294 | } |
295 | 295 | ||
296 | /* init request without RFC1001 length at the beginning */ | ||
297 | static int | ||
298 | smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon, | ||
299 | void **request_buf, unsigned int *total_len) | ||
300 | { | ||
301 | int rc; | ||
302 | struct smb2_sync_hdr *shdr; | ||
303 | |||
304 | rc = smb2_reconnect(smb2_command, tcon); | ||
305 | if (rc) | ||
306 | return rc; | ||
307 | |||
308 | /* BB eventually switch this to SMB2 specific small buf size */ | ||
309 | *request_buf = cifs_small_buf_get(); | ||
310 | if (*request_buf == NULL) { | ||
311 | /* BB should we add a retry in here if not a writepage? */ | ||
312 | return -ENOMEM; | ||
313 | } | ||
314 | |||
315 | shdr = (struct smb2_sync_hdr *)(*request_buf); | ||
316 | |||
317 | fill_small_buf(smb2_command, tcon, shdr, total_len); | ||
318 | |||
319 | if (tcon != NULL) { | ||
320 | #ifdef CONFIG_CIFS_STATS2 | ||
321 | uint16_t com_code = le16_to_cpu(smb2_command); | ||
322 | |||
323 | cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[com_code]); | ||
324 | #endif | ||
325 | cifs_stats_inc(&tcon->num_smbs_sent); | ||
326 | } | ||
327 | |||
328 | return rc; | ||
329 | } | ||
330 | |||
296 | /* | 331 | /* |
297 | * Allocate and return pointer to an SMB request hdr, and set basic | 332 | * Allocate and return pointer to an SMB request hdr, and set basic |
298 | * SMB information in the SMB header. If the return code is zero, this | 333 | * SMB information in the SMB header. If the return code is zero, this |
299 | * function must have filled in request_buf pointer. | 334 | * function must have filled in request_buf pointer. The returned buffer |
335 | * has RFC1001 length at the beginning. | ||
300 | */ | 336 | */ |
301 | static int | 337 | static int |
302 | small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon, | 338 | small_smb2_init(__le16 smb2_command, struct cifs_tcon *tcon, |
@@ -2140,16 +2176,17 @@ smb2_new_read_req(void **buf, unsigned int *total_len, | |||
2140 | int request_type) | 2176 | int request_type) |
2141 | { | 2177 | { |
2142 | int rc = -EACCES; | 2178 | int rc = -EACCES; |
2143 | struct smb2_read_req *req = NULL; | 2179 | struct smb2_read_plain_req *req = NULL; |
2144 | struct smb2_sync_hdr *shdr; | 2180 | struct smb2_sync_hdr *shdr; |
2145 | 2181 | ||
2146 | rc = small_smb2_init(SMB2_READ, io_parms->tcon, (void **) &req); | 2182 | rc = smb2_plain_req_init(SMB2_READ, io_parms->tcon, (void **) &req, |
2183 | total_len); | ||
2147 | if (rc) | 2184 | if (rc) |
2148 | return rc; | 2185 | return rc; |
2149 | if (io_parms->tcon->ses->server == NULL) | 2186 | if (io_parms->tcon->ses->server == NULL) |
2150 | return -ECONNABORTED; | 2187 | return -ECONNABORTED; |
2151 | 2188 | ||
2152 | shdr = get_sync_hdr(req); | 2189 | shdr = &req->sync_hdr; |
2153 | shdr->ProcessId = cpu_to_le32(io_parms->pid); | 2190 | shdr->ProcessId = cpu_to_le32(io_parms->pid); |
2154 | 2191 | ||
2155 | req->PersistentFileId = io_parms->persistent_fid; | 2192 | req->PersistentFileId = io_parms->persistent_fid; |
@@ -2163,9 +2200,9 @@ smb2_new_read_req(void **buf, unsigned int *total_len, | |||
2163 | 2200 | ||
2164 | if (request_type & CHAINED_REQUEST) { | 2201 | if (request_type & CHAINED_REQUEST) { |
2165 | if (!(request_type & END_OF_CHAIN)) { | 2202 | if (!(request_type & END_OF_CHAIN)) { |
2166 | /* 4 for rfc1002 length field */ | 2203 | /* next 8-byte aligned request */ |
2167 | shdr->NextCommand = | 2204 | *total_len = DIV_ROUND_UP(*total_len, 8) * 8; |
2168 | cpu_to_le32(get_rfc1002_length(req) + 4); | 2205 | shdr->NextCommand = cpu_to_le32(*total_len); |
2169 | } else /* END_OF_CHAIN */ | 2206 | } else /* END_OF_CHAIN */ |
2170 | shdr->NextCommand = 0; | 2207 | shdr->NextCommand = 0; |
2171 | if (request_type & RELATED_REQUEST) { | 2208 | if (request_type & RELATED_REQUEST) { |
@@ -2186,8 +2223,6 @@ smb2_new_read_req(void **buf, unsigned int *total_len, | |||
2186 | req->RemainingBytes = 0; | 2223 | req->RemainingBytes = 0; |
2187 | 2224 | ||
2188 | *buf = req; | 2225 | *buf = req; |
2189 | /* 4 for rfc1002 length field */ | ||
2190 | *total_len = get_rfc1002_length(req) + 4; | ||
2191 | return rc; | 2226 | return rc; |
2192 | } | 2227 | } |
2193 | 2228 | ||
@@ -2264,6 +2299,7 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
2264 | .rq_nvec = 2 }; | 2299 | .rq_nvec = 2 }; |
2265 | struct TCP_Server_Info *server; | 2300 | struct TCP_Server_Info *server; |
2266 | unsigned int total_len; | 2301 | unsigned int total_len; |
2302 | __be32 req_len; | ||
2267 | 2303 | ||
2268 | cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", | 2304 | cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n", |
2269 | __func__, rdata->offset, rdata->bytes); | 2305 | __func__, rdata->offset, rdata->bytes); |
@@ -2290,12 +2326,14 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
2290 | return rc; | 2326 | return rc; |
2291 | } | 2327 | } |
2292 | 2328 | ||
2293 | shdr = get_sync_hdr(buf); | 2329 | req_len = cpu_to_be32(total_len); |
2294 | /* 4 for rfc1002 length field */ | 2330 | |
2295 | rdata->iov[0].iov_len = 4; | 2331 | rdata->iov[0].iov_base = &req_len; |
2296 | rdata->iov[0].iov_base = buf; | 2332 | rdata->iov[0].iov_len = sizeof(__be32); |
2297 | rdata->iov[1].iov_len = total_len - 4; | 2333 | rdata->iov[1].iov_base = buf; |
2298 | rdata->iov[1].iov_base = buf + 4; | 2334 | rdata->iov[1].iov_len = total_len; |
2335 | |||
2336 | shdr = (struct smb2_sync_hdr *)buf; | ||
2299 | 2337 | ||
2300 | if (rdata->credits) { | 2338 | if (rdata->credits) { |
2301 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, | 2339 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, |
@@ -2327,24 +2365,31 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
2327 | unsigned int *nbytes, char **buf, int *buf_type) | 2365 | unsigned int *nbytes, char **buf, int *buf_type) |
2328 | { | 2366 | { |
2329 | int resp_buftype, rc = -EACCES; | 2367 | int resp_buftype, rc = -EACCES; |
2368 | struct smb2_read_plain_req *req = NULL; | ||
2330 | struct smb2_read_rsp *rsp = NULL; | 2369 | struct smb2_read_rsp *rsp = NULL; |
2331 | struct smb2_sync_hdr *shdr; | 2370 | struct smb2_sync_hdr *shdr; |
2332 | struct kvec iov[1]; | 2371 | struct kvec iov[2]; |
2333 | struct kvec rsp_iov; | 2372 | struct kvec rsp_iov; |
2334 | unsigned int total_len; | 2373 | unsigned int total_len; |
2335 | char *req; | 2374 | __be32 req_len; |
2375 | struct smb_rqst rqst = { .rq_iov = iov, | ||
2376 | .rq_nvec = 2 }; | ||
2336 | 2377 | ||
2337 | *nbytes = 0; | 2378 | *nbytes = 0; |
2338 | rc = smb2_new_read_req((void **)&req, &total_len, io_parms, 0, 0); | 2379 | rc = smb2_new_read_req((void **)&req, &total_len, io_parms, 0, 0); |
2339 | if (rc) | 2380 | if (rc) |
2340 | return rc; | 2381 | return rc; |
2341 | 2382 | ||
2342 | iov[0].iov_base = buf; | 2383 | req_len = cpu_to_be32(total_len); |
2343 | iov[0].iov_len = total_len; | ||
2344 | 2384 | ||
2345 | rc = SendReceive2(xid, io_parms->tcon->ses, iov, 1, | 2385 | iov[0].iov_base = &req_len; |
2346 | &resp_buftype, CIFS_LOG_ERROR, &rsp_iov); | 2386 | iov[0].iov_len = sizeof(__be32); |
2347 | cifs_small_buf_release(iov[0].iov_base); | 2387 | iov[1].iov_base = req; |
2388 | iov[1].iov_len = total_len; | ||
2389 | |||
2390 | rc = cifs_send_recv(xid, io_parms->tcon->ses, &rqst, &resp_buftype, | ||
2391 | CIFS_LOG_ERROR, &rsp_iov); | ||
2392 | cifs_small_buf_release(req); | ||
2348 | 2393 | ||
2349 | rsp = (struct smb2_read_rsp *)rsp_iov.iov_base; | 2394 | rsp = (struct smb2_read_rsp *)rsp_iov.iov_base; |
2350 | shdr = get_sync_hdr(rsp); | 2395 | shdr = get_sync_hdr(rsp); |