aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsglob.h15
-rw-r--r--fs/cifs/cifsproto.h3
-rw-r--r--fs/cifs/file.c36
-rw-r--r--fs/cifs/smb1ops.c1
-rw-r--r--fs/cifs/smb2ops.c55
-rw-r--r--fs/cifs/smb2pdu.c30
-rw-r--r--fs/cifs/smb2transport.c5
-rw-r--r--fs/cifs/transport.c25
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
411struct smb_version_values { 414struct smb_version_values {
@@ -642,6 +645,16 @@ add_credits(struct TCP_Server_Info *server, const unsigned int add,
642} 645}
643 646
644static inline void 647static inline void
648add_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
657static inline void
645set_credits(struct TCP_Server_Info *server, const int val) 658set_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 *);
91extern int cifs_check_receive(struct mid_q_entry *mid, 91extern 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);
93extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server,
94 unsigned int size, unsigned int *num,
95 unsigned int *credits);
93extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, 96extern 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;
2056retry: 2058retry:
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
115static int
116smb2_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
115static __u64 162static __u64
116smb2_get_next_mid(struct TCP_Server_Info *server) 163smb2_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
1892smb2_async_writev(struct cifs_writedata *wdata, 1891smb2_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)
466static inline void 466static inline void
467smb2_seq_num_into_buf(struct TCP_Server_Info *server, struct smb2_hdr *hdr) 467smb2_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
472static struct mid_q_entry * 477static 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
451int
452cifs_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
451static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, 460static 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