diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-18 13:17:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-18 13:17:56 -0400 |
commit | 442c9ac989d71599ebc39f4ea4d5b0e64996904b (patch) | |
tree | 0770f4746d0c041c1f8288561ce3236e49f0b80b | |
parent | ba5a2655c270f59dea2d9b4d764aec2f6e7f5f41 (diff) | |
parent | 71335664c38f03de10d7cf1d82705fe55a130b33 (diff) |
Merge branch 'sendmsg.cifs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull cifs iovec cleanups from Al Viro.
* 'sendmsg.cifs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
cifs: don't bother with kmap on read_pages side
cifs_readv_receive: use cifs_read_from_socket()
cifs: no need to wank with copying and advancing iovec on recvmsg side either
cifs: quit playing games with draining iovecs
cifs: merge the hash calculation helpers
-rw-r--r-- | fs/cifs/cifsencrypt.c | 97 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 12 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 11 | ||||
-rw-r--r-- | fs/cifs/connect.c | 127 | ||||
-rw-r--r-- | fs/cifs/file.c | 53 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 107 | ||||
-rw-r--r-- | fs/cifs/transport.c | 141 |
8 files changed, 167 insertions, 383 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 4897dacf8944..6aeb8d4616a4 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -66,45 +66,15 @@ cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server) | |||
66 | return 0; | 66 | return 0; |
67 | } | 67 | } |
68 | 68 | ||
69 | /* | 69 | int __cifs_calc_signature(struct smb_rqst *rqst, |
70 | * Calculate and return the CIFS signature based on the mac key and SMB PDU. | 70 | struct TCP_Server_Info *server, char *signature, |
71 | * The 16 byte signature must be allocated by the caller. Note we only use the | 71 | struct shash_desc *shash) |
72 | * 1st eight bytes and that the smb header signature field on input contains | ||
73 | * the sequence number before this function is called. Also, this function | ||
74 | * should be called with the server->srv_mutex held. | ||
75 | */ | ||
76 | static int cifs_calc_signature(struct smb_rqst *rqst, | ||
77 | struct TCP_Server_Info *server, char *signature) | ||
78 | { | 72 | { |
79 | int i; | 73 | int i; |
80 | int rc; | 74 | int rc; |
81 | struct kvec *iov = rqst->rq_iov; | 75 | struct kvec *iov = rqst->rq_iov; |
82 | int n_vec = rqst->rq_nvec; | 76 | int n_vec = rqst->rq_nvec; |
83 | 77 | ||
84 | if (iov == NULL || signature == NULL || server == NULL) | ||
85 | return -EINVAL; | ||
86 | |||
87 | if (!server->secmech.sdescmd5) { | ||
88 | rc = cifs_crypto_shash_md5_allocate(server); | ||
89 | if (rc) { | ||
90 | cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__); | ||
91 | return -1; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
96 | if (rc) { | ||
97 | cifs_dbg(VFS, "%s: Could not init md5\n", __func__); | ||
98 | return rc; | ||
99 | } | ||
100 | |||
101 | rc = crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
102 | server->session_key.response, server->session_key.len); | ||
103 | if (rc) { | ||
104 | cifs_dbg(VFS, "%s: Could not update with response\n", __func__); | ||
105 | return rc; | ||
106 | } | ||
107 | |||
108 | for (i = 0; i < n_vec; i++) { | 78 | for (i = 0; i < n_vec; i++) { |
109 | if (iov[i].iov_len == 0) | 79 | if (iov[i].iov_len == 0) |
110 | continue; | 80 | continue; |
@@ -117,12 +87,10 @@ static int cifs_calc_signature(struct smb_rqst *rqst, | |||
117 | if (i == 0) { | 87 | if (i == 0) { |
118 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | 88 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ |
119 | break; /* nothing to sign or corrupt header */ | 89 | break; /* nothing to sign or corrupt header */ |
120 | rc = | 90 | rc = crypto_shash_update(shash, |
121 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
122 | iov[i].iov_base + 4, iov[i].iov_len - 4); | 91 | iov[i].iov_base + 4, iov[i].iov_len - 4); |
123 | } else { | 92 | } else { |
124 | rc = | 93 | rc = crypto_shash_update(shash, |
125 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
126 | iov[i].iov_base, iov[i].iov_len); | 94 | iov[i].iov_base, iov[i].iov_len); |
127 | } | 95 | } |
128 | if (rc) { | 96 | if (rc) { |
@@ -134,21 +102,64 @@ static int cifs_calc_signature(struct smb_rqst *rqst, | |||
134 | 102 | ||
135 | /* now hash over the rq_pages array */ | 103 | /* now hash over the rq_pages array */ |
136 | for (i = 0; i < rqst->rq_npages; i++) { | 104 | for (i = 0; i < rqst->rq_npages; i++) { |
137 | struct kvec p_iov; | 105 | void *kaddr = kmap(rqst->rq_pages[i]); |
106 | size_t len = rqst->rq_pagesz; | ||
107 | |||
108 | if (i == rqst->rq_npages - 1) | ||
109 | len = rqst->rq_tailsz; | ||
110 | |||
111 | crypto_shash_update(shash, kaddr, len); | ||
138 | 112 | ||
139 | cifs_rqst_page_to_kvec(rqst, i, &p_iov); | ||
140 | crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
141 | p_iov.iov_base, p_iov.iov_len); | ||
142 | kunmap(rqst->rq_pages[i]); | 113 | kunmap(rqst->rq_pages[i]); |
143 | } | 114 | } |
144 | 115 | ||
145 | rc = crypto_shash_final(&server->secmech.sdescmd5->shash, signature); | 116 | rc = crypto_shash_final(shash, signature); |
146 | if (rc) | 117 | if (rc) |
147 | cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); | 118 | cifs_dbg(VFS, "%s: Could not generate hash\n", __func__); |
148 | 119 | ||
149 | return rc; | 120 | return rc; |
150 | } | 121 | } |
151 | 122 | ||
123 | /* | ||
124 | * Calculate and return the CIFS signature based on the mac key and SMB PDU. | ||
125 | * The 16 byte signature must be allocated by the caller. Note we only use the | ||
126 | * 1st eight bytes and that the smb header signature field on input contains | ||
127 | * the sequence number before this function is called. Also, this function | ||
128 | * should be called with the server->srv_mutex held. | ||
129 | */ | ||
130 | static int cifs_calc_signature(struct smb_rqst *rqst, | ||
131 | struct TCP_Server_Info *server, char *signature) | ||
132 | { | ||
133 | int rc; | ||
134 | |||
135 | if (!rqst->rq_iov || !signature || !server) | ||
136 | return -EINVAL; | ||
137 | |||
138 | if (!server->secmech.sdescmd5) { | ||
139 | rc = cifs_crypto_shash_md5_allocate(server); | ||
140 | if (rc) { | ||
141 | cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__); | ||
142 | return -1; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | rc = crypto_shash_init(&server->secmech.sdescmd5->shash); | ||
147 | if (rc) { | ||
148 | cifs_dbg(VFS, "%s: Could not init md5\n", __func__); | ||
149 | return rc; | ||
150 | } | ||
151 | |||
152 | rc = crypto_shash_update(&server->secmech.sdescmd5->shash, | ||
153 | server->session_key.response, server->session_key.len); | ||
154 | if (rc) { | ||
155 | cifs_dbg(VFS, "%s: Could not update with response\n", __func__); | ||
156 | return rc; | ||
157 | } | ||
158 | |||
159 | return __cifs_calc_signature(rqst, server, signature, | ||
160 | &server->secmech.sdescmd5->shash); | ||
161 | } | ||
162 | |||
152 | /* must be called with server->srv_mutex held */ | 163 | /* must be called with server->srv_mutex held */ |
153 | int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server, | 164 | int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server, |
154 | __u32 *pexpected_response_sequence_number) | 165 | __u32 *pexpected_response_sequence_number) |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index f2cc0b3d1af7..bba106cdc43c 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -615,8 +615,6 @@ struct TCP_Server_Info { | |||
615 | bool sec_mskerberos; /* supports legacy MS Kerberos */ | 615 | bool sec_mskerberos; /* supports legacy MS Kerberos */ |
616 | bool large_buf; /* is current buffer large? */ | 616 | bool large_buf; /* is current buffer large? */ |
617 | struct delayed_work echo; /* echo ping workqueue job */ | 617 | struct delayed_work echo; /* echo ping workqueue job */ |
618 | struct kvec *iov; /* reusable kvec array for receives */ | ||
619 | unsigned int nr_iov; /* number of kvecs in array */ | ||
620 | char *smallbuf; /* pointer to current "small" buffer */ | 618 | char *smallbuf; /* pointer to current "small" buffer */ |
621 | char *bigbuf; /* pointer to current "big" buffer */ | 619 | char *bigbuf; /* pointer to current "big" buffer */ |
622 | unsigned int total_read; /* total amount of data read in this pass */ | 620 | unsigned int total_read; /* total amount of data read in this pass */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index eed7ff50faf0..0f9a6bc4ba43 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -37,8 +37,6 @@ extern void cifs_buf_release(void *); | |||
37 | extern struct smb_hdr *cifs_small_buf_get(void); | 37 | extern struct smb_hdr *cifs_small_buf_get(void); |
38 | extern void cifs_small_buf_release(void *); | 38 | extern void cifs_small_buf_release(void *); |
39 | extern void free_rsp_buf(int, void *); | 39 | extern void free_rsp_buf(int, void *); |
40 | extern void cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx, | ||
41 | struct kvec *iov); | ||
42 | extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *, | 40 | extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *, |
43 | unsigned int /* length */); | 41 | unsigned int /* length */); |
44 | extern unsigned int _get_xid(void); | 42 | extern unsigned int _get_xid(void); |
@@ -181,10 +179,9 @@ extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, | |||
181 | 179 | ||
182 | extern void dequeue_mid(struct mid_q_entry *mid, bool malformed); | 180 | extern void dequeue_mid(struct mid_q_entry *mid, bool malformed); |
183 | extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, | 181 | extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, |
184 | unsigned int to_read); | 182 | unsigned int to_read); |
185 | extern int cifs_readv_from_socket(struct TCP_Server_Info *server, | 183 | extern int cifs_read_page_from_socket(struct TCP_Server_Info *server, |
186 | struct kvec *iov_orig, unsigned int nr_segs, | 184 | struct page *page, unsigned int to_read); |
187 | unsigned int to_read); | ||
188 | extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, | 185 | extern void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, |
189 | struct cifs_sb_info *cifs_sb); | 186 | struct cifs_sb_info *cifs_sb); |
190 | extern int cifs_match_super(struct super_block *, void *); | 187 | extern int cifs_match_super(struct super_block *, void *); |
@@ -512,4 +509,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, | |||
512 | struct cifs_sb_info *cifs_sb, | 509 | struct cifs_sb_info *cifs_sb, |
513 | const unsigned char *path, char *pbuf, | 510 | const unsigned char *path, char *pbuf, |
514 | unsigned int *pbytes_written); | 511 | unsigned int *pbytes_written); |
512 | int __cifs_calc_signature(struct smb_rqst *rqst, | ||
513 | struct TCP_Server_Info *server, char *signature, | ||
514 | struct shash_desc *shash); | ||
515 | #endif /* _CIFSPROTO_H */ | 515 | #endif /* _CIFSPROTO_H */ |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 145c03e75ee4..d47197ea4ab6 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -1447,10 +1447,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1447 | len = min_t(unsigned int, buflen, server->vals->read_rsp_size) - | 1447 | len = min_t(unsigned int, buflen, server->vals->read_rsp_size) - |
1448 | HEADER_SIZE(server) + 1; | 1448 | HEADER_SIZE(server) + 1; |
1449 | 1449 | ||
1450 | rdata->iov.iov_base = buf + HEADER_SIZE(server) - 1; | 1450 | length = cifs_read_from_socket(server, |
1451 | rdata->iov.iov_len = len; | 1451 | buf + HEADER_SIZE(server) - 1, len); |
1452 | |||
1453 | length = cifs_readv_from_socket(server, &rdata->iov, 1, len); | ||
1454 | if (length < 0) | 1452 | if (length < 0) |
1455 | return length; | 1453 | return length; |
1456 | server->total_read += length; | 1454 | server->total_read += length; |
@@ -1502,9 +1500,8 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1502 | len = data_offset - server->total_read; | 1500 | len = data_offset - server->total_read; |
1503 | if (len > 0) { | 1501 | if (len > 0) { |
1504 | /* read any junk before data into the rest of smallbuf */ | 1502 | /* read any junk before data into the rest of smallbuf */ |
1505 | rdata->iov.iov_base = buf + server->total_read; | 1503 | length = cifs_read_from_socket(server, |
1506 | rdata->iov.iov_len = len; | 1504 | buf + server->total_read, len); |
1507 | length = cifs_readv_from_socket(server, &rdata->iov, 1, len); | ||
1508 | if (length < 0) | 1505 | if (length < 0) |
1509 | return length; | 1506 | return length; |
1510 | server->total_read += length; | 1507 | server->total_read += length; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 1bb258af1648..66736f57b5ab 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -501,99 +501,34 @@ server_unresponsive(struct TCP_Server_Info *server) | |||
501 | return false; | 501 | return false; |
502 | } | 502 | } |
503 | 503 | ||
504 | /* | 504 | static int |
505 | * kvec_array_init - clone a kvec array, and advance into it | 505 | cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_msg) |
506 | * @new: pointer to memory for cloned array | ||
507 | * @iov: pointer to original array | ||
508 | * @nr_segs: number of members in original array | ||
509 | * @bytes: number of bytes to advance into the cloned array | ||
510 | * | ||
511 | * This function will copy the array provided in iov to a section of memory | ||
512 | * and advance the specified number of bytes into the new array. It returns | ||
513 | * the number of segments in the new array. "new" must be at least as big as | ||
514 | * the original iov array. | ||
515 | */ | ||
516 | static unsigned int | ||
517 | kvec_array_init(struct kvec *new, struct kvec *iov, unsigned int nr_segs, | ||
518 | size_t bytes) | ||
519 | { | ||
520 | size_t base = 0; | ||
521 | |||
522 | while (bytes || !iov->iov_len) { | ||
523 | int copy = min(bytes, iov->iov_len); | ||
524 | |||
525 | bytes -= copy; | ||
526 | base += copy; | ||
527 | if (iov->iov_len == base) { | ||
528 | iov++; | ||
529 | nr_segs--; | ||
530 | base = 0; | ||
531 | } | ||
532 | } | ||
533 | memcpy(new, iov, sizeof(*iov) * nr_segs); | ||
534 | new->iov_base += base; | ||
535 | new->iov_len -= base; | ||
536 | return nr_segs; | ||
537 | } | ||
538 | |||
539 | static struct kvec * | ||
540 | get_server_iovec(struct TCP_Server_Info *server, unsigned int nr_segs) | ||
541 | { | ||
542 | struct kvec *new_iov; | ||
543 | |||
544 | if (server->iov && nr_segs <= server->nr_iov) | ||
545 | return server->iov; | ||
546 | |||
547 | /* not big enough -- allocate a new one and release the old */ | ||
548 | new_iov = kmalloc(sizeof(*new_iov) * nr_segs, GFP_NOFS); | ||
549 | if (new_iov) { | ||
550 | kfree(server->iov); | ||
551 | server->iov = new_iov; | ||
552 | server->nr_iov = nr_segs; | ||
553 | } | ||
554 | return new_iov; | ||
555 | } | ||
556 | |||
557 | int | ||
558 | cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, | ||
559 | unsigned int nr_segs, unsigned int to_read) | ||
560 | { | 506 | { |
561 | int length = 0; | 507 | int length = 0; |
562 | int total_read; | 508 | int total_read; |
563 | unsigned int segs; | ||
564 | struct msghdr smb_msg; | ||
565 | struct kvec *iov; | ||
566 | |||
567 | iov = get_server_iovec(server, nr_segs); | ||
568 | if (!iov) | ||
569 | return -ENOMEM; | ||
570 | 509 | ||
571 | smb_msg.msg_control = NULL; | 510 | smb_msg->msg_control = NULL; |
572 | smb_msg.msg_controllen = 0; | 511 | smb_msg->msg_controllen = 0; |
573 | 512 | ||
574 | for (total_read = 0; to_read; total_read += length, to_read -= length) { | 513 | for (total_read = 0; msg_data_left(smb_msg); total_read += length) { |
575 | try_to_freeze(); | 514 | try_to_freeze(); |
576 | 515 | ||
577 | if (server_unresponsive(server)) { | 516 | if (server_unresponsive(server)) |
578 | total_read = -ECONNABORTED; | 517 | return -ECONNABORTED; |
579 | break; | ||
580 | } | ||
581 | 518 | ||
582 | segs = kvec_array_init(iov, iov_orig, nr_segs, total_read); | 519 | length = sock_recvmsg(server->ssocket, smb_msg, 0); |
583 | 520 | ||
584 | length = kernel_recvmsg(server->ssocket, &smb_msg, | 521 | if (server->tcpStatus == CifsExiting) |
585 | iov, segs, to_read, 0); | 522 | return -ESHUTDOWN; |
586 | 523 | ||
587 | if (server->tcpStatus == CifsExiting) { | 524 | if (server->tcpStatus == CifsNeedReconnect) { |
588 | total_read = -ESHUTDOWN; | ||
589 | break; | ||
590 | } else if (server->tcpStatus == CifsNeedReconnect) { | ||
591 | cifs_reconnect(server); | 525 | cifs_reconnect(server); |
592 | total_read = -ECONNABORTED; | 526 | return -ECONNABORTED; |
593 | break; | 527 | } |
594 | } else if (length == -ERESTARTSYS || | 528 | |
595 | length == -EAGAIN || | 529 | if (length == -ERESTARTSYS || |
596 | length == -EINTR) { | 530 | length == -EAGAIN || |
531 | length == -EINTR) { | ||
597 | /* | 532 | /* |
598 | * Minimum sleep to prevent looping, allowing socket | 533 | * Minimum sleep to prevent looping, allowing socket |
599 | * to clear and app threads to set tcpStatus | 534 | * to clear and app threads to set tcpStatus |
@@ -602,12 +537,12 @@ cifs_readv_from_socket(struct TCP_Server_Info *server, struct kvec *iov_orig, | |||
602 | usleep_range(1000, 2000); | 537 | usleep_range(1000, 2000); |
603 | length = 0; | 538 | length = 0; |
604 | continue; | 539 | continue; |
605 | } else if (length <= 0) { | 540 | } |
606 | cifs_dbg(FYI, "Received no data or error: expecting %d\n" | 541 | |
607 | "got %d", to_read, length); | 542 | if (length <= 0) { |
543 | cifs_dbg(FYI, "Received no data or error: %d\n", length); | ||
608 | cifs_reconnect(server); | 544 | cifs_reconnect(server); |
609 | total_read = -ECONNABORTED; | 545 | return -ECONNABORTED; |
610 | break; | ||
611 | } | 546 | } |
612 | } | 547 | } |
613 | return total_read; | 548 | return total_read; |
@@ -617,12 +552,21 @@ int | |||
617 | cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, | 552 | cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, |
618 | unsigned int to_read) | 553 | unsigned int to_read) |
619 | { | 554 | { |
620 | struct kvec iov; | 555 | struct msghdr smb_msg; |
556 | struct kvec iov = {.iov_base = buf, .iov_len = to_read}; | ||
557 | iov_iter_kvec(&smb_msg.msg_iter, READ | ITER_KVEC, &iov, 1, to_read); | ||
621 | 558 | ||
622 | iov.iov_base = buf; | 559 | return cifs_readv_from_socket(server, &smb_msg); |
623 | iov.iov_len = to_read; | 560 | } |
624 | 561 | ||
625 | return cifs_readv_from_socket(server, &iov, 1, to_read); | 562 | int |
563 | cifs_read_page_from_socket(struct TCP_Server_Info *server, struct page *page, | ||
564 | unsigned int to_read) | ||
565 | { | ||
566 | struct msghdr smb_msg; | ||
567 | struct bio_vec bv = {.bv_page = page, .bv_len = to_read}; | ||
568 | iov_iter_bvec(&smb_msg.msg_iter, READ | ITER_BVEC, &bv, 1, to_read); | ||
569 | return cifs_readv_from_socket(server, &smb_msg); | ||
626 | } | 570 | } |
627 | 571 | ||
628 | static bool | 572 | static bool |
@@ -783,7 +727,6 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) | |||
783 | } | 727 | } |
784 | 728 | ||
785 | kfree(server->hostname); | 729 | kfree(server->hostname); |
786 | kfree(server->iov); | ||
787 | kfree(server); | 730 | kfree(server); |
788 | 731 | ||
789 | length = atomic_dec_return(&tcpSesAllocCount); | 732 | length = atomic_dec_return(&tcpSesAllocCount); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index f3a90298dfe2..9793ae0bcaa2 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -2852,39 +2852,31 @@ cifs_uncached_read_into_pages(struct TCP_Server_Info *server, | |||
2852 | int result = 0; | 2852 | int result = 0; |
2853 | unsigned int i; | 2853 | unsigned int i; |
2854 | unsigned int nr_pages = rdata->nr_pages; | 2854 | unsigned int nr_pages = rdata->nr_pages; |
2855 | struct kvec iov; | ||
2856 | 2855 | ||
2857 | rdata->got_bytes = 0; | 2856 | rdata->got_bytes = 0; |
2858 | rdata->tailsz = PAGE_SIZE; | 2857 | rdata->tailsz = PAGE_SIZE; |
2859 | for (i = 0; i < nr_pages; i++) { | 2858 | for (i = 0; i < nr_pages; i++) { |
2860 | struct page *page = rdata->pages[i]; | 2859 | struct page *page = rdata->pages[i]; |
2860 | size_t n; | ||
2861 | 2861 | ||
2862 | if (len >= PAGE_SIZE) { | 2862 | if (len <= 0) { |
2863 | /* enough data to fill the page */ | ||
2864 | iov.iov_base = kmap(page); | ||
2865 | iov.iov_len = PAGE_SIZE; | ||
2866 | cifs_dbg(FYI, "%u: iov_base=%p iov_len=%zu\n", | ||
2867 | i, iov.iov_base, iov.iov_len); | ||
2868 | len -= PAGE_SIZE; | ||
2869 | } else if (len > 0) { | ||
2870 | /* enough for partial page, fill and zero the rest */ | ||
2871 | iov.iov_base = kmap(page); | ||
2872 | iov.iov_len = len; | ||
2873 | cifs_dbg(FYI, "%u: iov_base=%p iov_len=%zu\n", | ||
2874 | i, iov.iov_base, iov.iov_len); | ||
2875 | memset(iov.iov_base + len, '\0', PAGE_SIZE - len); | ||
2876 | rdata->tailsz = len; | ||
2877 | len = 0; | ||
2878 | } else { | ||
2879 | /* no need to hold page hostage */ | 2863 | /* no need to hold page hostage */ |
2880 | rdata->pages[i] = NULL; | 2864 | rdata->pages[i] = NULL; |
2881 | rdata->nr_pages--; | 2865 | rdata->nr_pages--; |
2882 | put_page(page); | 2866 | put_page(page); |
2883 | continue; | 2867 | continue; |
2884 | } | 2868 | } |
2885 | 2869 | n = len; | |
2886 | result = cifs_readv_from_socket(server, &iov, 1, iov.iov_len); | 2870 | if (len >= PAGE_SIZE) { |
2887 | kunmap(page); | 2871 | /* enough data to fill the page */ |
2872 | n = PAGE_SIZE; | ||
2873 | len -= n; | ||
2874 | } else { | ||
2875 | zero_user(page, len, PAGE_SIZE - len); | ||
2876 | rdata->tailsz = len; | ||
2877 | len = 0; | ||
2878 | } | ||
2879 | result = cifs_read_page_from_socket(server, page, n); | ||
2888 | if (result < 0) | 2880 | if (result < 0) |
2889 | break; | 2881 | break; |
2890 | 2882 | ||
@@ -3300,7 +3292,6 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server, | |||
3300 | u64 eof; | 3292 | u64 eof; |
3301 | pgoff_t eof_index; | 3293 | pgoff_t eof_index; |
3302 | unsigned int nr_pages = rdata->nr_pages; | 3294 | unsigned int nr_pages = rdata->nr_pages; |
3303 | struct kvec iov; | ||
3304 | 3295 | ||
3305 | /* determine the eof that the server (probably) has */ | 3296 | /* determine the eof that the server (probably) has */ |
3306 | eof = CIFS_I(rdata->mapping->host)->server_eof; | 3297 | eof = CIFS_I(rdata->mapping->host)->server_eof; |
@@ -3311,23 +3302,14 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server, | |||
3311 | rdata->tailsz = PAGE_SIZE; | 3302 | rdata->tailsz = PAGE_SIZE; |
3312 | for (i = 0; i < nr_pages; i++) { | 3303 | for (i = 0; i < nr_pages; i++) { |
3313 | struct page *page = rdata->pages[i]; | 3304 | struct page *page = rdata->pages[i]; |
3305 | size_t n = PAGE_SIZE; | ||
3314 | 3306 | ||
3315 | if (len >= PAGE_SIZE) { | 3307 | if (len >= PAGE_SIZE) { |
3316 | /* enough data to fill the page */ | ||
3317 | iov.iov_base = kmap(page); | ||
3318 | iov.iov_len = PAGE_SIZE; | ||
3319 | cifs_dbg(FYI, "%u: idx=%lu iov_base=%p iov_len=%zu\n", | ||
3320 | i, page->index, iov.iov_base, iov.iov_len); | ||
3321 | len -= PAGE_SIZE; | 3308 | len -= PAGE_SIZE; |
3322 | } else if (len > 0) { | 3309 | } else if (len > 0) { |
3323 | /* enough for partial page, fill and zero the rest */ | 3310 | /* enough for partial page, fill and zero the rest */ |
3324 | iov.iov_base = kmap(page); | 3311 | zero_user(page, len, PAGE_SIZE - len); |
3325 | iov.iov_len = len; | 3312 | n = rdata->tailsz = len; |
3326 | cifs_dbg(FYI, "%u: idx=%lu iov_base=%p iov_len=%zu\n", | ||
3327 | i, page->index, iov.iov_base, iov.iov_len); | ||
3328 | memset(iov.iov_base + len, | ||
3329 | '\0', PAGE_SIZE - len); | ||
3330 | rdata->tailsz = len; | ||
3331 | len = 0; | 3313 | len = 0; |
3332 | } else if (page->index > eof_index) { | 3314 | } else if (page->index > eof_index) { |
3333 | /* | 3315 | /* |
@@ -3357,8 +3339,7 @@ cifs_readpages_read_into_pages(struct TCP_Server_Info *server, | |||
3357 | continue; | 3339 | continue; |
3358 | } | 3340 | } |
3359 | 3341 | ||
3360 | result = cifs_readv_from_socket(server, &iov, 1, iov.iov_len); | 3342 | result = cifs_read_page_from_socket(server, page, n); |
3361 | kunmap(page); | ||
3362 | if (result < 0) | 3343 | if (result < 0) |
3363 | break; | 3344 | break; |
3364 | 3345 | ||
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 8732a43b1008..bc9a7b634643 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c | |||
@@ -135,11 +135,10 @@ smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server) | |||
135 | int | 135 | int |
136 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | 136 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
137 | { | 137 | { |
138 | int i, rc; | 138 | int rc; |
139 | unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; | 139 | unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; |
140 | unsigned char *sigptr = smb2_signature; | 140 | unsigned char *sigptr = smb2_signature; |
141 | struct kvec *iov = rqst->rq_iov; | 141 | struct kvec *iov = rqst->rq_iov; |
142 | int n_vec = rqst->rq_nvec; | ||
143 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; | 142 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; |
144 | struct cifs_ses *ses; | 143 | struct cifs_ses *ses; |
145 | 144 | ||
@@ -171,53 +170,11 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
171 | return rc; | 170 | return rc; |
172 | } | 171 | } |
173 | 172 | ||
174 | for (i = 0; i < n_vec; i++) { | 173 | rc = __cifs_calc_signature(rqst, server, sigptr, |
175 | if (iov[i].iov_len == 0) | 174 | &server->secmech.sdeschmacsha256->shash); |
176 | continue; | ||
177 | if (iov[i].iov_base == NULL) { | ||
178 | cifs_dbg(VFS, "null iovec entry\n"); | ||
179 | return -EIO; | ||
180 | } | ||
181 | /* | ||
182 | * The first entry includes a length field (which does not get | ||
183 | * signed that occupies the first 4 bytes before the header). | ||
184 | */ | ||
185 | if (i == 0) { | ||
186 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | ||
187 | break; /* nothing to sign or corrupt header */ | ||
188 | rc = | ||
189 | crypto_shash_update( | ||
190 | &server->secmech.sdeschmacsha256->shash, | ||
191 | iov[i].iov_base + 4, iov[i].iov_len - 4); | ||
192 | } else { | ||
193 | rc = | ||
194 | crypto_shash_update( | ||
195 | &server->secmech.sdeschmacsha256->shash, | ||
196 | iov[i].iov_base, iov[i].iov_len); | ||
197 | } | ||
198 | if (rc) { | ||
199 | cifs_dbg(VFS, "%s: Could not update with payload\n", | ||
200 | __func__); | ||
201 | return rc; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | /* now hash over the rq_pages array */ | ||
206 | for (i = 0; i < rqst->rq_npages; i++) { | ||
207 | struct kvec p_iov; | ||
208 | |||
209 | cifs_rqst_page_to_kvec(rqst, i, &p_iov); | ||
210 | crypto_shash_update(&server->secmech.sdeschmacsha256->shash, | ||
211 | p_iov.iov_base, p_iov.iov_len); | ||
212 | kunmap(rqst->rq_pages[i]); | ||
213 | } | ||
214 | |||
215 | rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash, | ||
216 | sigptr); | ||
217 | if (rc) | ||
218 | cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__); | ||
219 | 175 | ||
220 | memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); | 176 | if (!rc) |
177 | memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); | ||
221 | 178 | ||
222 | return rc; | 179 | return rc; |
223 | } | 180 | } |
@@ -395,12 +352,10 @@ generate_smb311signingkey(struct cifs_ses *ses) | |||
395 | int | 352 | int |
396 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | 353 | smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
397 | { | 354 | { |
398 | int i; | ||
399 | int rc = 0; | 355 | int rc = 0; |
400 | unsigned char smb3_signature[SMB2_CMACAES_SIZE]; | 356 | unsigned char smb3_signature[SMB2_CMACAES_SIZE]; |
401 | unsigned char *sigptr = smb3_signature; | 357 | unsigned char *sigptr = smb3_signature; |
402 | struct kvec *iov = rqst->rq_iov; | 358 | struct kvec *iov = rqst->rq_iov; |
403 | int n_vec = rqst->rq_nvec; | ||
404 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; | 359 | struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base; |
405 | struct cifs_ses *ses; | 360 | struct cifs_ses *ses; |
406 | 361 | ||
@@ -431,54 +386,12 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
431 | cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__); | 386 | cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__); |
432 | return rc; | 387 | return rc; |
433 | } | 388 | } |
389 | |||
390 | rc = __cifs_calc_signature(rqst, server, sigptr, | ||
391 | &server->secmech.sdesccmacaes->shash); | ||
434 | 392 | ||
435 | for (i = 0; i < n_vec; i++) { | 393 | if (!rc) |
436 | if (iov[i].iov_len == 0) | 394 | memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); |
437 | continue; | ||
438 | if (iov[i].iov_base == NULL) { | ||
439 | cifs_dbg(VFS, "null iovec entry"); | ||
440 | return -EIO; | ||
441 | } | ||
442 | /* | ||
443 | * The first entry includes a length field (which does not get | ||
444 | * signed that occupies the first 4 bytes before the header). | ||
445 | */ | ||
446 | if (i == 0) { | ||
447 | if (iov[0].iov_len <= 8) /* cmd field at offset 9 */ | ||
448 | break; /* nothing to sign or corrupt header */ | ||
449 | rc = | ||
450 | crypto_shash_update( | ||
451 | &server->secmech.sdesccmacaes->shash, | ||
452 | iov[i].iov_base + 4, iov[i].iov_len - 4); | ||
453 | } else { | ||
454 | rc = | ||
455 | crypto_shash_update( | ||
456 | &server->secmech.sdesccmacaes->shash, | ||
457 | iov[i].iov_base, iov[i].iov_len); | ||
458 | } | ||
459 | if (rc) { | ||
460 | cifs_dbg(VFS, "%s: Couldn't update cmac aes with payload\n", | ||
461 | __func__); | ||
462 | return rc; | ||
463 | } | ||
464 | } | ||
465 | |||
466 | /* now hash over the rq_pages array */ | ||
467 | for (i = 0; i < rqst->rq_npages; i++) { | ||
468 | struct kvec p_iov; | ||
469 | |||
470 | cifs_rqst_page_to_kvec(rqst, i, &p_iov); | ||
471 | crypto_shash_update(&server->secmech.sdesccmacaes->shash, | ||
472 | p_iov.iov_base, p_iov.iov_len); | ||
473 | kunmap(rqst->rq_pages[i]); | ||
474 | } | ||
475 | |||
476 | rc = crypto_shash_final(&server->secmech.sdesccmacaes->shash, | ||
477 | sigptr); | ||
478 | if (rc) | ||
479 | cifs_dbg(VFS, "%s: Could not generate cmac aes\n", __func__); | ||
480 | |||
481 | memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE); | ||
482 | 395 | ||
483 | return rc; | 396 | return rc; |
484 | } | 397 | } |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 87abe8ed074c..206a597b2293 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -124,41 +124,32 @@ cifs_delete_mid(struct mid_q_entry *mid) | |||
124 | /* | 124 | /* |
125 | * smb_send_kvec - send an array of kvecs to the server | 125 | * smb_send_kvec - send an array of kvecs to the server |
126 | * @server: Server to send the data to | 126 | * @server: Server to send the data to |
127 | * @iov: Pointer to array of kvecs | 127 | * @smb_msg: Message to send |
128 | * @n_vec: length of kvec array | ||
129 | * @sent: amount of data sent on socket is stored here | 128 | * @sent: amount of data sent on socket is stored here |
130 | * | 129 | * |
131 | * Our basic "send data to server" function. Should be called with srv_mutex | 130 | * Our basic "send data to server" function. Should be called with srv_mutex |
132 | * held. The caller is responsible for handling the results. | 131 | * held. The caller is responsible for handling the results. |
133 | */ | 132 | */ |
134 | static int | 133 | static int |
135 | smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec, | 134 | smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, |
136 | size_t *sent) | 135 | size_t *sent) |
137 | { | 136 | { |
138 | int rc = 0; | 137 | int rc = 0; |
139 | int i = 0; | 138 | int retries = 0; |
140 | struct msghdr smb_msg; | ||
141 | unsigned int remaining; | ||
142 | size_t first_vec = 0; | ||
143 | struct socket *ssocket = server->ssocket; | 139 | struct socket *ssocket = server->ssocket; |
144 | 140 | ||
145 | *sent = 0; | 141 | *sent = 0; |
146 | 142 | ||
147 | smb_msg.msg_name = (struct sockaddr *) &server->dstaddr; | 143 | smb_msg->msg_name = (struct sockaddr *) &server->dstaddr; |
148 | smb_msg.msg_namelen = sizeof(struct sockaddr); | 144 | smb_msg->msg_namelen = sizeof(struct sockaddr); |
149 | smb_msg.msg_control = NULL; | 145 | smb_msg->msg_control = NULL; |
150 | smb_msg.msg_controllen = 0; | 146 | smb_msg->msg_controllen = 0; |
151 | if (server->noblocksnd) | 147 | if (server->noblocksnd) |
152 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; | 148 | smb_msg->msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; |
153 | else | 149 | else |
154 | smb_msg.msg_flags = MSG_NOSIGNAL; | 150 | smb_msg->msg_flags = MSG_NOSIGNAL; |
155 | |||
156 | remaining = 0; | ||
157 | for (i = 0; i < n_vec; i++) | ||
158 | remaining += iov[i].iov_len; | ||
159 | 151 | ||
160 | i = 0; | 152 | while (msg_data_left(smb_msg)) { |
161 | while (remaining) { | ||
162 | /* | 153 | /* |
163 | * If blocking send, we try 3 times, since each can block | 154 | * If blocking send, we try 3 times, since each can block |
164 | * for 5 seconds. For nonblocking we have to try more | 155 | * for 5 seconds. For nonblocking we have to try more |
@@ -177,35 +168,21 @@ smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec, | |||
177 | * after the retries we will kill the socket and | 168 | * after the retries we will kill the socket and |
178 | * reconnect which may clear the network problem. | 169 | * reconnect which may clear the network problem. |
179 | */ | 170 | */ |
180 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], | 171 | rc = sock_sendmsg(ssocket, smb_msg); |
181 | n_vec - first_vec, remaining); | ||
182 | if (rc == -EAGAIN) { | 172 | if (rc == -EAGAIN) { |
183 | i++; | 173 | retries++; |
184 | if (i >= 14 || (!server->noblocksnd && (i > 2))) { | 174 | if (retries >= 14 || |
175 | (!server->noblocksnd && (retries > 2))) { | ||
185 | cifs_dbg(VFS, "sends on sock %p stuck for 15 seconds\n", | 176 | cifs_dbg(VFS, "sends on sock %p stuck for 15 seconds\n", |
186 | ssocket); | 177 | ssocket); |
187 | rc = -EAGAIN; | 178 | return -EAGAIN; |
188 | break; | ||
189 | } | 179 | } |
190 | msleep(1 << i); | 180 | msleep(1 << retries); |
191 | continue; | 181 | continue; |
192 | } | 182 | } |
193 | 183 | ||
194 | if (rc < 0) | 184 | if (rc < 0) |
195 | break; | 185 | return rc; |
196 | |||
197 | /* send was at least partially successful */ | ||
198 | *sent += rc; | ||
199 | |||
200 | if (rc == remaining) { | ||
201 | remaining = 0; | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | if (rc > remaining) { | ||
206 | cifs_dbg(VFS, "sent %d requested %d\n", rc, remaining); | ||
207 | break; | ||
208 | } | ||
209 | 186 | ||
210 | if (rc == 0) { | 187 | if (rc == 0) { |
211 | /* should never happen, letting socket clear before | 188 | /* should never happen, letting socket clear before |
@@ -215,59 +192,11 @@ smb_send_kvec(struct TCP_Server_Info *server, struct kvec *iov, size_t n_vec, | |||
215 | continue; | 192 | continue; |
216 | } | 193 | } |
217 | 194 | ||
218 | remaining -= rc; | 195 | /* send was at least partially successful */ |
219 | 196 | *sent += rc; | |
220 | /* the line below resets i */ | 197 | retries = 0; /* in case we get ENOSPC on the next send */ |
221 | for (i = first_vec; i < n_vec; i++) { | ||
222 | if (iov[i].iov_len) { | ||
223 | if (rc > iov[i].iov_len) { | ||
224 | rc -= iov[i].iov_len; | ||
225 | iov[i].iov_len = 0; | ||
226 | } else { | ||
227 | iov[i].iov_base += rc; | ||
228 | iov[i].iov_len -= rc; | ||
229 | first_vec = i; | ||
230 | break; | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | |||
235 | i = 0; /* in case we get ENOSPC on the next send */ | ||
236 | rc = 0; | ||
237 | } | 198 | } |
238 | return rc; | 199 | return 0; |
239 | } | ||
240 | |||
241 | /** | ||
242 | * rqst_page_to_kvec - Turn a slot in the smb_rqst page array into a kvec | ||
243 | * @rqst: pointer to smb_rqst | ||
244 | * @idx: index into the array of the page | ||
245 | * @iov: pointer to struct kvec that will hold the result | ||
246 | * | ||
247 | * Helper function to convert a slot in the rqst->rq_pages array into a kvec. | ||
248 | * The page will be kmapped and the address placed into iov_base. The length | ||
249 | * will then be adjusted according to the ptailoff. | ||
250 | */ | ||
251 | void | ||
252 | cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx, | ||
253 | struct kvec *iov) | ||
254 | { | ||
255 | /* | ||
256 | * FIXME: We could avoid this kmap altogether if we used | ||
257 | * kernel_sendpage instead of kernel_sendmsg. That will only | ||
258 | * work if signing is disabled though as sendpage inlines the | ||
259 | * page directly into the fraglist. If userspace modifies the | ||
260 | * page after we calculate the signature, then the server will | ||
261 | * reject it and may break the connection. kernel_sendmsg does | ||
262 | * an extra copy of the data and avoids that issue. | ||
263 | */ | ||
264 | iov->iov_base = kmap(rqst->rq_pages[idx]); | ||
265 | |||
266 | /* if last page, don't send beyond this offset into page */ | ||
267 | if (idx == (rqst->rq_npages - 1)) | ||
268 | iov->iov_len = rqst->rq_tailsz; | ||
269 | else | ||
270 | iov->iov_len = rqst->rq_pagesz; | ||
271 | } | 200 | } |
272 | 201 | ||
273 | static unsigned long | 202 | static unsigned long |
@@ -299,8 +228,9 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
299 | unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); | 228 | unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base); |
300 | unsigned long send_length; | 229 | unsigned long send_length; |
301 | unsigned int i; | 230 | unsigned int i; |
302 | size_t total_len = 0, sent; | 231 | size_t total_len = 0, sent, size; |
303 | struct socket *ssocket = server->ssocket; | 232 | struct socket *ssocket = server->ssocket; |
233 | struct msghdr smb_msg; | ||
304 | int val = 1; | 234 | int val = 1; |
305 | 235 | ||
306 | if (ssocket == NULL) | 236 | if (ssocket == NULL) |
@@ -321,7 +251,13 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
321 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, | 251 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, |
322 | (char *)&val, sizeof(val)); | 252 | (char *)&val, sizeof(val)); |
323 | 253 | ||
324 | rc = smb_send_kvec(server, iov, n_vec, &sent); | 254 | size = 0; |
255 | for (i = 0; i < n_vec; i++) | ||
256 | size += iov[i].iov_len; | ||
257 | |||
258 | iov_iter_kvec(&smb_msg.msg_iter, WRITE | ITER_KVEC, iov, n_vec, size); | ||
259 | |||
260 | rc = smb_send_kvec(server, &smb_msg, &sent); | ||
325 | if (rc < 0) | 261 | if (rc < 0) |
326 | goto uncork; | 262 | goto uncork; |
327 | 263 | ||
@@ -329,11 +265,16 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
329 | 265 | ||
330 | /* now walk the page array and send each page in it */ | 266 | /* now walk the page array and send each page in it */ |
331 | for (i = 0; i < rqst->rq_npages; i++) { | 267 | for (i = 0; i < rqst->rq_npages; i++) { |
332 | struct kvec p_iov; | 268 | size_t len = i == rqst->rq_npages - 1 |
333 | 269 | ? rqst->rq_tailsz | |
334 | cifs_rqst_page_to_kvec(rqst, i, &p_iov); | 270 | : rqst->rq_pagesz; |
335 | rc = smb_send_kvec(server, &p_iov, 1, &sent); | 271 | struct bio_vec bvec = { |
336 | kunmap(rqst->rq_pages[i]); | 272 | .bv_page = rqst->rq_pages[i], |
273 | .bv_len = len | ||
274 | }; | ||
275 | iov_iter_bvec(&smb_msg.msg_iter, WRITE | ITER_BVEC, | ||
276 | &bvec, 1, len); | ||
277 | rc = smb_send_kvec(server, &smb_msg, &sent); | ||
337 | if (rc < 0) | 278 | if (rc < 0) |
338 | break; | 279 | break; |
339 | 280 | ||