diff options
-rw-r--r-- | fs/cifs/cifsglob.h | 15 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 3 | ||||
-rw-r--r-- | fs/cifs/file.c | 36 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 1 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 55 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 30 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 5 | ||||
-rw-r--r-- | fs/cifs/transport.c | 25 |
8 files changed, 150 insertions, 20 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 8c53f2093152..54ca2b985a0d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -406,6 +406,9 @@ struct smb_version_operations { | |||
406 | int); | 406 | int); |
407 | /* writepages retry size */ | 407 | /* writepages retry size */ |
408 | unsigned int (*wp_retry_size)(struct inode *); | 408 | unsigned int (*wp_retry_size)(struct inode *); |
409 | /* get mtu credits */ | ||
410 | int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int, | ||
411 | unsigned int *, unsigned int *); | ||
409 | }; | 412 | }; |
410 | 413 | ||
411 | struct smb_version_values { | 414 | struct smb_version_values { |
@@ -642,6 +645,16 @@ add_credits(struct TCP_Server_Info *server, const unsigned int add, | |||
642 | } | 645 | } |
643 | 646 | ||
644 | static inline void | 647 | static inline void |
648 | add_credits_and_wake_if(struct TCP_Server_Info *server, const unsigned int add, | ||
649 | const int optype) | ||
650 | { | ||
651 | if (add) { | ||
652 | server->ops->add_credits(server, add, optype); | ||
653 | wake_up(&server->request_q); | ||
654 | } | ||
655 | } | ||
656 | |||
657 | static inline void | ||
645 | set_credits(struct TCP_Server_Info *server, const int val) | 658 | set_credits(struct TCP_Server_Info *server, const int val) |
646 | { | 659 | { |
647 | server->ops->set_credits(server, val); | 660 | server->ops->set_credits(server, val); |
@@ -1075,6 +1088,7 @@ struct cifs_writedata { | |||
1075 | int result; | 1088 | int result; |
1076 | unsigned int pagesz; | 1089 | unsigned int pagesz; |
1077 | unsigned int tailsz; | 1090 | unsigned int tailsz; |
1091 | unsigned int credits; | ||
1078 | unsigned int nr_pages; | 1092 | unsigned int nr_pages; |
1079 | struct page *pages[]; | 1093 | struct page *pages[]; |
1080 | }; | 1094 | }; |
@@ -1400,6 +1414,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, | |||
1400 | #define CIFS_OBREAK_OP 0x0100 /* oplock break request */ | 1414 | #define CIFS_OBREAK_OP 0x0100 /* oplock break request */ |
1401 | #define CIFS_NEG_OP 0x0200 /* negotiate request */ | 1415 | #define CIFS_NEG_OP 0x0200 /* negotiate request */ |
1402 | #define CIFS_OP_MASK 0x0380 /* mask request type */ | 1416 | #define CIFS_OP_MASK 0x0380 /* mask request type */ |
1417 | #define CIFS_HAS_CREDITS 0x0400 /* already has credits */ | ||
1403 | 1418 | ||
1404 | /* Security Flags: indicate type of session setup needed */ | 1419 | /* Security Flags: indicate type of session setup needed */ |
1405 | #define CIFSSEC_MAY_SIGN 0x00001 | 1420 | #define CIFSSEC_MAY_SIGN 0x00001 |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index de49d7a37b00..c31ce98c1704 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -90,6 +90,9 @@ extern struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *, | |||
90 | struct smb_rqst *); | 90 | struct smb_rqst *); |
91 | extern int cifs_check_receive(struct mid_q_entry *mid, | 91 | extern int cifs_check_receive(struct mid_q_entry *mid, |
92 | struct TCP_Server_Info *server, bool log_error); | 92 | struct TCP_Server_Info *server, bool log_error); |
93 | extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server, | ||
94 | unsigned int size, unsigned int *num, | ||
95 | unsigned int *credits); | ||
93 | extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, | 96 | extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, |
94 | struct kvec *, int /* nvec to send */, | 97 | struct kvec *, int /* nvec to send */, |
95 | int * /* type of buf returned */ , const int flags); | 98 | int * /* type of buf returned */ , const int flags); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c9c4f5ac3c78..c79bdf3e6f51 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1670,8 +1670,8 @@ cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, | |||
1670 | break; | 1670 | break; |
1671 | } | 1671 | } |
1672 | 1672 | ||
1673 | len = min((size_t)cifs_sb->wsize, | 1673 | len = min(server->ops->wp_retry_size(dentry->d_inode), |
1674 | write_size - total_written); | 1674 | (unsigned int)write_size - total_written); |
1675 | /* iov[0] is reserved for smb header */ | 1675 | /* iov[0] is reserved for smb header */ |
1676 | iov[1].iov_base = (char *)write_data + total_written; | 1676 | iov[1].iov_base = (char *)write_data + total_written; |
1677 | iov[1].iov_len = len; | 1677 | iov[1].iov_len = len; |
@@ -2031,6 +2031,7 @@ static int cifs_writepages(struct address_space *mapping, | |||
2031 | struct writeback_control *wbc) | 2031 | struct writeback_control *wbc) |
2032 | { | 2032 | { |
2033 | struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb); | 2033 | struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb); |
2034 | struct TCP_Server_Info *server; | ||
2034 | bool done = false, scanned = false, range_whole = false; | 2035 | bool done = false, scanned = false, range_whole = false; |
2035 | pgoff_t end, index; | 2036 | pgoff_t end, index; |
2036 | struct cifs_writedata *wdata; | 2037 | struct cifs_writedata *wdata; |
@@ -2053,23 +2054,30 @@ static int cifs_writepages(struct address_space *mapping, | |||
2053 | range_whole = true; | 2054 | range_whole = true; |
2054 | scanned = true; | 2055 | scanned = true; |
2055 | } | 2056 | } |
2057 | server = cifs_sb_master_tcon(cifs_sb)->ses->server; | ||
2056 | retry: | 2058 | retry: |
2057 | while (!done && index <= end) { | 2059 | while (!done && index <= end) { |
2058 | unsigned int i, nr_pages, found_pages; | 2060 | unsigned int i, nr_pages, found_pages, wsize, credits; |
2059 | pgoff_t next = 0, tofind, saved_index = index; | 2061 | pgoff_t next = 0, tofind, saved_index = index; |
2060 | 2062 | ||
2061 | tofind = min((cifs_sb->wsize / PAGE_CACHE_SIZE) - 1, | 2063 | rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, |
2062 | end - index) + 1; | 2064 | &wsize, &credits); |
2065 | if (rc) | ||
2066 | break; | ||
2067 | |||
2068 | tofind = min((wsize / PAGE_CACHE_SIZE) - 1, end - index) + 1; | ||
2063 | 2069 | ||
2064 | wdata = wdata_alloc_and_fillpages(tofind, mapping, end, &index, | 2070 | wdata = wdata_alloc_and_fillpages(tofind, mapping, end, &index, |
2065 | &found_pages); | 2071 | &found_pages); |
2066 | if (!wdata) { | 2072 | if (!wdata) { |
2067 | rc = -ENOMEM; | 2073 | rc = -ENOMEM; |
2074 | add_credits_and_wake_if(server, credits, 0); | ||
2068 | break; | 2075 | break; |
2069 | } | 2076 | } |
2070 | 2077 | ||
2071 | if (found_pages == 0) { | 2078 | if (found_pages == 0) { |
2072 | kref_put(&wdata->refcount, cifs_writedata_release); | 2079 | kref_put(&wdata->refcount, cifs_writedata_release); |
2080 | add_credits_and_wake_if(server, credits, 0); | ||
2073 | break; | 2081 | break; |
2074 | } | 2082 | } |
2075 | 2083 | ||
@@ -2079,13 +2087,17 @@ retry: | |||
2079 | /* nothing to write? */ | 2087 | /* nothing to write? */ |
2080 | if (nr_pages == 0) { | 2088 | if (nr_pages == 0) { |
2081 | kref_put(&wdata->refcount, cifs_writedata_release); | 2089 | kref_put(&wdata->refcount, cifs_writedata_release); |
2090 | add_credits_and_wake_if(server, credits, 0); | ||
2082 | continue; | 2091 | continue; |
2083 | } | 2092 | } |
2084 | 2093 | ||
2094 | wdata->credits = credits; | ||
2095 | |||
2085 | rc = wdata_send_pages(wdata, nr_pages, mapping, wbc); | 2096 | rc = wdata_send_pages(wdata, nr_pages, mapping, wbc); |
2086 | 2097 | ||
2087 | /* send failure -- clean up the mess */ | 2098 | /* send failure -- clean up the mess */ |
2088 | if (rc != 0) { | 2099 | if (rc != 0) { |
2100 | add_credits_and_wake_if(server, wdata->credits, 0); | ||
2089 | for (i = 0; i < nr_pages; ++i) { | 2101 | for (i = 0; i < nr_pages; ++i) { |
2090 | if (rc == -EAGAIN) | 2102 | if (rc == -EAGAIN) |
2091 | redirty_page_for_writepage(wbc, | 2103 | redirty_page_for_writepage(wbc, |
@@ -2466,17 +2478,26 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, | |||
2466 | memcpy(&saved_from, from, sizeof(struct iov_iter)); | 2478 | memcpy(&saved_from, from, sizeof(struct iov_iter)); |
2467 | 2479 | ||
2468 | do { | 2480 | do { |
2469 | nr_pages = get_numpages(cifs_sb->wsize, len, &cur_len); | 2481 | unsigned int wsize, credits; |
2482 | |||
2483 | rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, | ||
2484 | &wsize, &credits); | ||
2485 | if (rc) | ||
2486 | break; | ||
2487 | |||
2488 | nr_pages = get_numpages(wsize, len, &cur_len); | ||
2470 | wdata = cifs_writedata_alloc(nr_pages, | 2489 | wdata = cifs_writedata_alloc(nr_pages, |
2471 | cifs_uncached_writev_complete); | 2490 | cifs_uncached_writev_complete); |
2472 | if (!wdata) { | 2491 | if (!wdata) { |
2473 | rc = -ENOMEM; | 2492 | rc = -ENOMEM; |
2493 | add_credits_and_wake_if(server, credits, 0); | ||
2474 | break; | 2494 | break; |
2475 | } | 2495 | } |
2476 | 2496 | ||
2477 | rc = cifs_write_allocate_pages(wdata->pages, nr_pages); | 2497 | rc = cifs_write_allocate_pages(wdata->pages, nr_pages); |
2478 | if (rc) { | 2498 | if (rc) { |
2479 | kfree(wdata); | 2499 | kfree(wdata); |
2500 | add_credits_and_wake_if(server, credits, 0); | ||
2480 | break; | 2501 | break; |
2481 | } | 2502 | } |
2482 | 2503 | ||
@@ -2486,6 +2507,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, | |||
2486 | for (i = 0; i < nr_pages; i++) | 2507 | for (i = 0; i < nr_pages; i++) |
2487 | put_page(wdata->pages[i]); | 2508 | put_page(wdata->pages[i]); |
2488 | kfree(wdata); | 2509 | kfree(wdata); |
2510 | add_credits_and_wake_if(server, credits, 0); | ||
2489 | break; | 2511 | break; |
2490 | } | 2512 | } |
2491 | 2513 | ||
@@ -2504,12 +2526,14 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, | |||
2504 | wdata->bytes = cur_len; | 2526 | wdata->bytes = cur_len; |
2505 | wdata->pagesz = PAGE_SIZE; | 2527 | wdata->pagesz = PAGE_SIZE; |
2506 | wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE); | 2528 | wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE); |
2529 | wdata->credits = credits; | ||
2507 | 2530 | ||
2508 | if (!wdata->cfile->invalidHandle || | 2531 | if (!wdata->cfile->invalidHandle || |
2509 | !cifs_reopen_file(wdata->cfile, false)) | 2532 | !cifs_reopen_file(wdata->cfile, false)) |
2510 | rc = server->ops->async_writev(wdata, | 2533 | rc = server->ops->async_writev(wdata, |
2511 | cifs_uncached_writedata_release); | 2534 | cifs_uncached_writedata_release); |
2512 | if (rc) { | 2535 | if (rc) { |
2536 | add_credits_and_wake_if(server, wdata->credits, 0); | ||
2513 | kref_put(&wdata->refcount, | 2537 | kref_put(&wdata->refcount, |
2514 | cifs_uncached_writedata_release); | 2538 | cifs_uncached_writedata_release); |
2515 | if (rc == -EAGAIN) { | 2539 | if (rc == -EAGAIN) { |
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 8a963426d810..5e8c22d6c7b9 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -1025,6 +1025,7 @@ struct smb_version_operations smb1_operations = { | |||
1025 | .set_credits = cifs_set_credits, | 1025 | .set_credits = cifs_set_credits, |
1026 | .get_credits_field = cifs_get_credits_field, | 1026 | .get_credits_field = cifs_get_credits_field, |
1027 | .get_credits = cifs_get_credits, | 1027 | .get_credits = cifs_get_credits, |
1028 | .wait_mtu_credits = cifs_wait_mtu_credits, | ||
1028 | .get_next_mid = cifs_get_next_mid, | 1029 | .get_next_mid = cifs_get_next_mid, |
1029 | .read_data_offset = cifs_read_data_offset, | 1030 | .read_data_offset = cifs_read_data_offset, |
1030 | .read_data_length = cifs_read_data_length, | 1031 | .read_data_length = cifs_read_data_length, |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index e35ce5b3d88f..3427c1fa3806 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -112,6 +112,53 @@ smb2_get_credits(struct mid_q_entry *mid) | |||
112 | return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest); | 112 | return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest); |
113 | } | 113 | } |
114 | 114 | ||
115 | static int | ||
116 | smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, | ||
117 | unsigned int *num, unsigned int *credits) | ||
118 | { | ||
119 | int rc = 0; | ||
120 | unsigned int scredits; | ||
121 | |||
122 | spin_lock(&server->req_lock); | ||
123 | while (1) { | ||
124 | if (server->credits <= 0) { | ||
125 | spin_unlock(&server->req_lock); | ||
126 | cifs_num_waiters_inc(server); | ||
127 | rc = wait_event_killable(server->request_q, | ||
128 | has_credits(server, &server->credits)); | ||
129 | cifs_num_waiters_dec(server); | ||
130 | if (rc) | ||
131 | return rc; | ||
132 | spin_lock(&server->req_lock); | ||
133 | } else { | ||
134 | if (server->tcpStatus == CifsExiting) { | ||
135 | spin_unlock(&server->req_lock); | ||
136 | return -ENOENT; | ||
137 | } | ||
138 | |||
139 | scredits = server->credits; | ||
140 | /* can deadlock with reopen */ | ||
141 | if (scredits == 1) { | ||
142 | *num = SMB2_MAX_BUFFER_SIZE; | ||
143 | *credits = 0; | ||
144 | break; | ||
145 | } | ||
146 | |||
147 | /* leave one credit for a possible reopen */ | ||
148 | scredits--; | ||
149 | *num = min_t(unsigned int, size, | ||
150 | scredits * SMB2_MAX_BUFFER_SIZE); | ||
151 | |||
152 | *credits = DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE); | ||
153 | server->credits -= *credits; | ||
154 | server->in_flight++; | ||
155 | break; | ||
156 | } | ||
157 | } | ||
158 | spin_unlock(&server->req_lock); | ||
159 | return rc; | ||
160 | } | ||
161 | |||
115 | static __u64 | 162 | static __u64 |
116 | smb2_get_next_mid(struct TCP_Server_Info *server) | 163 | smb2_get_next_mid(struct TCP_Server_Info *server) |
117 | { | 164 | { |
@@ -182,8 +229,9 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) | |||
182 | /* start with specified wsize, or default */ | 229 | /* start with specified wsize, or default */ |
183 | wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; | 230 | wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; |
184 | wsize = min_t(unsigned int, wsize, server->max_write); | 231 | wsize = min_t(unsigned int, wsize, server->max_write); |
185 | /* set it to the maximum buffer size value we can send with 1 credit */ | 232 | |
186 | wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); | 233 | if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) |
234 | wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); | ||
187 | 235 | ||
188 | return wsize; | 236 | return wsize; |
189 | } | 237 | } |
@@ -1120,6 +1168,7 @@ struct smb_version_operations smb20_operations = { | |||
1120 | .set_credits = smb2_set_credits, | 1168 | .set_credits = smb2_set_credits, |
1121 | .get_credits_field = smb2_get_credits_field, | 1169 | .get_credits_field = smb2_get_credits_field, |
1122 | .get_credits = smb2_get_credits, | 1170 | .get_credits = smb2_get_credits, |
1171 | .wait_mtu_credits = cifs_wait_mtu_credits, | ||
1123 | .get_next_mid = smb2_get_next_mid, | 1172 | .get_next_mid = smb2_get_next_mid, |
1124 | .read_data_offset = smb2_read_data_offset, | 1173 | .read_data_offset = smb2_read_data_offset, |
1125 | .read_data_length = smb2_read_data_length, | 1174 | .read_data_length = smb2_read_data_length, |
@@ -1196,6 +1245,7 @@ struct smb_version_operations smb21_operations = { | |||
1196 | .set_credits = smb2_set_credits, | 1245 | .set_credits = smb2_set_credits, |
1197 | .get_credits_field = smb2_get_credits_field, | 1246 | .get_credits_field = smb2_get_credits_field, |
1198 | .get_credits = smb2_get_credits, | 1247 | .get_credits = smb2_get_credits, |
1248 | .wait_mtu_credits = smb2_wait_mtu_credits, | ||
1199 | .get_next_mid = smb2_get_next_mid, | 1249 | .get_next_mid = smb2_get_next_mid, |
1200 | .read_data_offset = smb2_read_data_offset, | 1250 | .read_data_offset = smb2_read_data_offset, |
1201 | .read_data_length = smb2_read_data_length, | 1251 | .read_data_length = smb2_read_data_length, |
@@ -1272,6 +1322,7 @@ struct smb_version_operations smb30_operations = { | |||
1272 | .set_credits = smb2_set_credits, | 1322 | .set_credits = smb2_set_credits, |
1273 | .get_credits_field = smb2_get_credits_field, | 1323 | .get_credits_field = smb2_get_credits_field, |
1274 | .get_credits = smb2_get_credits, | 1324 | .get_credits = smb2_get_credits, |
1325 | .wait_mtu_credits = smb2_wait_mtu_credits, | ||
1275 | .get_next_mid = smb2_get_next_mid, | 1326 | .get_next_mid = smb2_get_next_mid, |
1276 | .read_data_offset = smb2_read_data_offset, | 1327 | .read_data_offset = smb2_read_data_offset, |
1277 | .read_data_length = smb2_read_data_length, | 1328 | .read_data_length = smb2_read_data_length, |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index da7aa62bf061..be7b2eb55134 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -108,7 +108,6 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , | |||
108 | if (!tcon) | 108 | if (!tcon) |
109 | goto out; | 109 | goto out; |
110 | 110 | ||
111 | /* BB FIXME when we do write > 64K add +1 for every 64K in req or rsp */ | ||
112 | /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */ | 111 | /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */ |
113 | /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */ | 112 | /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */ |
114 | if ((tcon->ses) && | 113 | if ((tcon->ses) && |
@@ -1892,15 +1891,25 @@ int | |||
1892 | smb2_async_writev(struct cifs_writedata *wdata, | 1891 | smb2_async_writev(struct cifs_writedata *wdata, |
1893 | void (*release)(struct kref *kref)) | 1892 | void (*release)(struct kref *kref)) |
1894 | { | 1893 | { |
1895 | int rc = -EACCES; | 1894 | int rc = -EACCES, flags = 0; |
1896 | struct smb2_write_req *req = NULL; | 1895 | struct smb2_write_req *req = NULL; |
1897 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); | 1896 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); |
1897 | struct TCP_Server_Info *server = tcon->ses->server; | ||
1898 | struct kvec iov; | 1898 | struct kvec iov; |
1899 | struct smb_rqst rqst; | 1899 | struct smb_rqst rqst; |
1900 | 1900 | ||
1901 | rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req); | 1901 | rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req); |
1902 | if (rc) | 1902 | if (rc) { |
1903 | if (rc == -EAGAIN && wdata->credits) { | ||
1904 | /* credits was reset by reconnect */ | ||
1905 | wdata->credits = 0; | ||
1906 | /* reduce in_flight value since we won't send the req */ | ||
1907 | spin_lock(&server->req_lock); | ||
1908 | server->in_flight--; | ||
1909 | spin_unlock(&server->req_lock); | ||
1910 | } | ||
1903 | goto async_writev_out; | 1911 | goto async_writev_out; |
1912 | } | ||
1904 | 1913 | ||
1905 | req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid); | 1914 | req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid); |
1906 | 1915 | ||
@@ -1933,9 +1942,20 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
1933 | 1942 | ||
1934 | inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */); | 1943 | inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */); |
1935 | 1944 | ||
1945 | if (wdata->credits) { | ||
1946 | req->hdr.CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, | ||
1947 | SMB2_MAX_BUFFER_SIZE)); | ||
1948 | spin_lock(&server->req_lock); | ||
1949 | server->credits += wdata->credits - | ||
1950 | le16_to_cpu(req->hdr.CreditCharge); | ||
1951 | spin_unlock(&server->req_lock); | ||
1952 | wake_up(&server->request_q); | ||
1953 | flags = CIFS_HAS_CREDITS; | ||
1954 | } | ||
1955 | |||
1936 | kref_get(&wdata->refcount); | 1956 | kref_get(&wdata->refcount); |
1937 | rc = cifs_call_async(tcon->ses->server, &rqst, NULL, | 1957 | rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, wdata, |
1938 | smb2_writev_callback, wdata, 0); | 1958 | flags); |
1939 | 1959 | ||
1940 | if (rc) { | 1960 | if (rc) { |
1941 | kref_put(&wdata->refcount, release); | 1961 | kref_put(&wdata->refcount, release); |
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 59c748ce872f..5111e7272db6 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c | |||
@@ -466,7 +466,12 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | |||
466 | static inline void | 466 | static inline void |
467 | smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr) | 467 | smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr) |
468 | { | 468 | { |
469 | unsigned int i, num = le16_to_cpu(hdr->CreditCharge); | ||
470 | |||
469 | hdr->MessageId = get_next_mid64(server); | 471 | hdr->MessageId = get_next_mid64(server); |
472 | /* skip message numbers according to CreditCharge field */ | ||
473 | for (i = 1; i < num; i++) | ||
474 | get_next_mid(server); | ||
470 | } | 475 | } |
471 | 476 | ||
472 | static struct mid_q_entry * | 477 | static struct mid_q_entry * |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 18cd5650a5fc..9d087f4e7d4e 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -448,6 +448,15 @@ wait_for_free_request(struct TCP_Server_Info *server, const int timeout, | |||
448 | return wait_for_free_credits(server, timeout, val); | 448 | return wait_for_free_credits(server, timeout, val); |
449 | } | 449 | } |
450 | 450 | ||
451 | int | ||
452 | cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, | ||
453 | unsigned int *num, unsigned int *credits) | ||
454 | { | ||
455 | *num = size; | ||
456 | *credits = 0; | ||
457 | return 0; | ||
458 | } | ||
459 | |||
451 | static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, | 460 | static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, |
452 | struct mid_q_entry **ppmidQ) | 461 | struct mid_q_entry **ppmidQ) |
453 | { | 462 | { |
@@ -531,20 +540,23 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, | |||
531 | { | 540 | { |
532 | int rc, timeout, optype; | 541 | int rc, timeout, optype; |
533 | struct mid_q_entry *mid; | 542 | struct mid_q_entry *mid; |
543 | unsigned int credits = 0; | ||
534 | 544 | ||
535 | timeout = flags & CIFS_TIMEOUT_MASK; | 545 | timeout = flags & CIFS_TIMEOUT_MASK; |
536 | optype = flags & CIFS_OP_MASK; | 546 | optype = flags & CIFS_OP_MASK; |
537 | 547 | ||
538 | rc = wait_for_free_request(server, timeout, optype); | 548 | if ((flags & CIFS_HAS_CREDITS) == 0) { |
539 | if (rc) | 549 | rc = wait_for_free_request(server, timeout, optype); |
540 | return rc; | 550 | if (rc) |
551 | return rc; | ||
552 | credits = 1; | ||
553 | } | ||
541 | 554 | ||
542 | mutex_lock(&server->srv_mutex); | 555 | mutex_lock(&server->srv_mutex); |
543 | mid = server->ops->setup_async_request(server, rqst); | 556 | mid = server->ops->setup_async_request(server, rqst); |
544 | if (IS_ERR(mid)) { | 557 | if (IS_ERR(mid)) { |
545 | mutex_unlock(&server->srv_mutex); | 558 | mutex_unlock(&server->srv_mutex); |
546 | add_credits(server, 1, optype); | 559 | add_credits_and_wake_if(server, credits, optype); |
547 | wake_up(&server->request_q); | ||
548 | return PTR_ERR(mid); | 560 | return PTR_ERR(mid); |
549 | } | 561 | } |
550 | 562 | ||
@@ -572,8 +584,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, | |||
572 | return 0; | 584 | return 0; |
573 | 585 | ||
574 | cifs_delete_mid(mid); | 586 | cifs_delete_mid(mid); |
575 | add_credits(server, 1, optype); | 587 | add_credits_and_wake_if(server, credits, optype); |
576 | wake_up(&server->request_q); | ||
577 | return rc; | 588 | return rc; |
578 | } | 589 | } |
579 | 590 | ||