aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2012-02-06 06:59:18 -0500
committerSteve French <sfrench@us.ibm.com>2012-03-21 12:35:03 -0400
commit2d86dbc97094ea4cfc2204fdefd7d07685496189 (patch)
tree9aee614e155fd837c78ded2cd083dead1a9d4a3f /fs/cifs
parentfc40f9cf828908e91d9af820e9300a9d42fbbd72 (diff)
CIFS: Introduce credit-based flow control
and send no more than credits value requests at once. For SMB/CIFS it's trivial: increment this value by receiving any message and decrement by sending one. Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsglob.h11
-rw-r--r--fs/cifs/cifsproto.h3
-rw-r--r--fs/cifs/cifssmb.c13
-rw-r--r--fs/cifs/connect.c14
-rw-r--r--fs/cifs/misc.c19
-rw-r--r--fs/cifs/transport.c44
6 files changed, 60 insertions, 44 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index fb78bc903887..d55de9684df9 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -250,8 +250,9 @@ struct TCP_Server_Info {
250 bool noblocksnd; /* use blocking sendmsg */ 250 bool noblocksnd; /* use blocking sendmsg */
251 bool noautotune; /* do not autotune send buf sizes */ 251 bool noautotune; /* do not autotune send buf sizes */
252 bool tcp_nodelay; 252 bool tcp_nodelay;
253 int credits; /* send no more requests at once */
253 unsigned int in_flight; /* number of requests on the wire to server */ 254 unsigned int in_flight; /* number of requests on the wire to server */
254 spinlock_t req_lock; /* protect the value above */ 255 spinlock_t req_lock; /* protect the two values above */
255 struct mutex srv_mutex; 256 struct mutex srv_mutex;
256 struct task_struct *tsk; 257 struct task_struct *tsk;
257 char server_GUID[16]; 258 char server_GUID[16];
@@ -314,12 +315,14 @@ in_flight(struct TCP_Server_Info *server)
314 return num; 315 return num;
315} 316}
316 317
317static inline void 318static inline bool
318dec_in_flight(struct TCP_Server_Info *server) 319has_credits(struct TCP_Server_Info *server)
319{ 320{
321 int num;
320 spin_lock(&server->req_lock); 322 spin_lock(&server->req_lock);
321 server->in_flight--; 323 num = server->credits;
322 spin_unlock(&server->req_lock); 324 spin_unlock(&server->req_lock);
325 return num > 0;
323} 326}
324 327
325/* 328/*
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6f4e243e0f62..47a769e535b1 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -88,6 +88,9 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
88 struct smb_hdr *in_buf , 88 struct smb_hdr *in_buf ,
89 struct smb_hdr *out_buf, 89 struct smb_hdr *out_buf,
90 int *bytes_returned); 90 int *bytes_returned);
91extern void cifs_add_credits(struct TCP_Server_Info *server,
92 const unsigned int add);
93extern void cifs_set_credits(struct TCP_Server_Info *server, const int val);
91extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); 94extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
92extern bool is_valid_oplock_break(struct smb_hdr *smb, 95extern bool is_valid_oplock_break(struct smb_hdr *smb,
93 struct TCP_Server_Info *); 96 struct TCP_Server_Info *);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index d7cbcfa21a0c..70aac35c398f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -461,7 +461,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
461 server->maxReq = min_t(unsigned int, 461 server->maxReq = min_t(unsigned int,
462 le16_to_cpu(rsp->MaxMpxCount), 462 le16_to_cpu(rsp->MaxMpxCount),
463 cifs_max_pending); 463 cifs_max_pending);
464 server->oplocks = server->maxReq > 1 ? enable_oplocks : false; 464 cifs_set_credits(server, server->maxReq);
465 server->maxBuf = le16_to_cpu(rsp->MaxBufSize); 465 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
466 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); 466 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
467 /* even though we do not use raw we might as well set this 467 /* even though we do not use raw we might as well set this
@@ -569,7 +569,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
569 little endian */ 569 little endian */
570 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), 570 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
571 cifs_max_pending); 571 cifs_max_pending);
572 server->oplocks = server->maxReq > 1 ? enable_oplocks : false; 572 cifs_set_credits(server, server->maxReq);
573 /* probably no need to store and check maxvcs */ 573 /* probably no need to store and check maxvcs */
574 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); 574 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
575 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); 575 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
@@ -721,8 +721,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
721 struct TCP_Server_Info *server = mid->callback_data; 721 struct TCP_Server_Info *server = mid->callback_data;
722 722
723 DeleteMidQEntry(mid); 723 DeleteMidQEntry(mid);
724 dec_in_flight(server); 724 cifs_add_credits(server, 1);
725 wake_up(&server->request_q);
726} 725}
727 726
728int 727int
@@ -1674,8 +1673,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
1674 1673
1675 queue_work(system_nrt_wq, &rdata->work); 1674 queue_work(system_nrt_wq, &rdata->work);
1676 DeleteMidQEntry(mid); 1675 DeleteMidQEntry(mid);
1677 dec_in_flight(server); 1676 cifs_add_credits(server, 1);
1678 wake_up(&server->request_q);
1679} 1677}
1680 1678
1681/* cifs_async_readv - send an async write, and set up mid to handle result */ 1679/* cifs_async_readv - send an async write, and set up mid to handle result */
@@ -2115,8 +2113,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
2115 2113
2116 queue_work(system_nrt_wq, &wdata->work); 2114 queue_work(system_nrt_wq, &wdata->work);
2117 DeleteMidQEntry(mid); 2115 DeleteMidQEntry(mid);
2118 dec_in_flight(tcon->ses->server); 2116 cifs_add_credits(tcon->ses->server, 1);
2119 wake_up(&tcon->ses->server->request_q);
2120} 2117}
2121 2118
2122/* cifs_async_writev - send an async write, and set up mid to handle result */ 2119/* cifs_async_writev - send an async write, and set up mid to handle result */
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index ed91abcce8a9..1d489010615b 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -642,14 +642,10 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
642 spin_unlock(&GlobalMid_Lock); 642 spin_unlock(&GlobalMid_Lock);
643 wake_up_all(&server->response_q); 643 wake_up_all(&server->response_q);
644 644
645 /* Check if we have blocked requests that need to free. */ 645 /* check if we have blocked requests that need to free */
646 spin_lock(&server->req_lock); 646 spin_lock(&server->req_lock);
647 if (server->in_flight >= server->maxReq) 647 if (server->credits <= 0)
648 server->in_flight = server->maxReq - 1; 648 server->credits = 1;
649 /*
650 * We do not want to set the max_pending too low or we could end up
651 * with the counter going negative.
652 */
653 spin_unlock(&server->req_lock); 649 spin_unlock(&server->req_lock);
654 /* 650 /*
655 * Although there should not be any requests blocked on this queue it 651 * Although there should not be any requests blocked on this queue it
@@ -1906,7 +1902,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1906 tcp_ses->noautotune = volume_info->noautotune; 1902 tcp_ses->noautotune = volume_info->noautotune;
1907 tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; 1903 tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
1908 tcp_ses->in_flight = 0; 1904 tcp_ses->in_flight = 0;
1909 tcp_ses->maxReq = 1; /* enough to send negotiate request */ 1905 tcp_ses->credits = 1;
1910 init_waitqueue_head(&tcp_ses->response_q); 1906 init_waitqueue_head(&tcp_ses->response_q);
1911 init_waitqueue_head(&tcp_ses->request_q); 1907 init_waitqueue_head(&tcp_ses->request_q);
1912 INIT_LIST_HEAD(&tcp_ses->pending_mid_q); 1908 INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
@@ -3757,9 +3753,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses)
3757 if (server->maxBuf != 0) 3753 if (server->maxBuf != 0)
3758 return 0; 3754 return 0;
3759 3755
3756 cifs_set_credits(server, 1);
3760 rc = CIFSSMBNegotiate(xid, ses); 3757 rc = CIFSSMBNegotiate(xid, ses);
3761 if (rc == -EAGAIN) { 3758 if (rc == -EAGAIN) {
3762 /* retry only once on 1st time connection */ 3759 /* retry only once on 1st time connection */
3760 cifs_set_credits(server, 1);
3763 rc = CIFSSMBNegotiate(xid, ses); 3761 rc = CIFSSMBNegotiate(xid, ses);
3764 if (rc == -EAGAIN) 3762 if (rc == -EAGAIN)
3765 rc = -EHOSTDOWN; 3763 rc = -EHOSTDOWN;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 703ef5c6fdb1..c273c12de98e 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -690,3 +690,22 @@ backup_cred(struct cifs_sb_info *cifs_sb)
690 690
691 return false; 691 return false;
692} 692}
693
694void
695cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add)
696{
697 spin_lock(&server->req_lock);
698 server->credits += add;
699 server->in_flight--;
700 spin_unlock(&server->req_lock);
701 wake_up(&server->request_q);
702}
703
704void
705cifs_set_credits(struct TCP_Server_Info *server, const int val)
706{
707 spin_lock(&server->req_lock);
708 server->credits = val;
709 server->oplocks = val > 1 ? enable_oplocks : false;
710 spin_unlock(&server->req_lock);
711}
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index e2673aa34381..e5202ddef2fb 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -262,16 +262,16 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
262 if (long_op == CIFS_ASYNC_OP) { 262 if (long_op == CIFS_ASYNC_OP) {
263 /* oplock breaks must not be held up */ 263 /* oplock breaks must not be held up */
264 server->in_flight++; 264 server->in_flight++;
265 server->credits--;
265 spin_unlock(&server->req_lock); 266 spin_unlock(&server->req_lock);
266 return 0; 267 return 0;
267 } 268 }
268 269
269 while (1) { 270 while (1) {
270 if (server->in_flight >= server->maxReq) { 271 if (server->credits <= 0) {
271 spin_unlock(&server->req_lock); 272 spin_unlock(&server->req_lock);
272 cifs_num_waiters_inc(server); 273 cifs_num_waiters_inc(server);
273 wait_event(server->request_q, 274 wait_event(server->request_q, has_credits(server));
274 in_flight(server) < server->maxReq);
275 cifs_num_waiters_dec(server); 275 cifs_num_waiters_dec(server);
276 spin_lock(&server->req_lock); 276 spin_lock(&server->req_lock);
277 } else { 277 } else {
@@ -280,12 +280,16 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op)
280 return -ENOENT; 280 return -ENOENT;
281 } 281 }
282 282
283 /* can not count locking commands against total 283 /*
284 as they are allowed to block on server */ 284 * Can not count locking commands against total
285 * as they are allowed to block on server.
286 */
285 287
286 /* update # of requests on the wire to server */ 288 /* update # of requests on the wire to server */
287 if (long_op != CIFS_BLOCKING_OP) 289 if (long_op != CIFS_BLOCKING_OP) {
290 server->credits--;
288 server->in_flight++; 291 server->in_flight++;
292 }
289 spin_unlock(&server->req_lock); 293 spin_unlock(&server->req_lock);
290 break; 294 break;
291 } 295 }
@@ -360,7 +364,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
360 mid = AllocMidQEntry(hdr, server); 364 mid = AllocMidQEntry(hdr, server);
361 if (mid == NULL) { 365 if (mid == NULL) {
362 mutex_unlock(&server->srv_mutex); 366 mutex_unlock(&server->srv_mutex);
363 dec_in_flight(server); 367 cifs_add_credits(server, 1);
364 wake_up(&server->request_q); 368 wake_up(&server->request_q);
365 return -ENOMEM; 369 return -ENOMEM;
366 } 370 }
@@ -393,7 +397,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
393 return rc; 397 return rc;
394out_err: 398out_err:
395 delete_mid(mid); 399 delete_mid(mid);
396 dec_in_flight(server); 400 cifs_add_credits(server, 1);
397 wake_up(&server->request_q); 401 wake_up(&server->request_q);
398 return rc; 402 return rc;
399} 403}
@@ -565,8 +569,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
565 mutex_unlock(&ses->server->srv_mutex); 569 mutex_unlock(&ses->server->srv_mutex);
566 cifs_small_buf_release(in_buf); 570 cifs_small_buf_release(in_buf);
567 /* Update # of requests on wire to server */ 571 /* Update # of requests on wire to server */
568 dec_in_flight(ses->server); 572 cifs_add_credits(ses->server, 1);
569 wake_up(&ses->server->request_q);
570 return rc; 573 return rc;
571 } 574 }
572 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); 575 rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
@@ -602,8 +605,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
602 midQ->callback = DeleteMidQEntry; 605 midQ->callback = DeleteMidQEntry;
603 spin_unlock(&GlobalMid_Lock); 606 spin_unlock(&GlobalMid_Lock);
604 cifs_small_buf_release(in_buf); 607 cifs_small_buf_release(in_buf);
605 dec_in_flight(ses->server); 608 cifs_add_credits(ses->server, 1);
606 wake_up(&ses->server->request_q);
607 return rc; 609 return rc;
608 } 610 }
609 spin_unlock(&GlobalMid_Lock); 611 spin_unlock(&GlobalMid_Lock);
@@ -613,8 +615,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
613 615
614 rc = cifs_sync_mid_result(midQ, ses->server); 616 rc = cifs_sync_mid_result(midQ, ses->server);
615 if (rc != 0) { 617 if (rc != 0) {
616 dec_in_flight(ses->server); 618 cifs_add_credits(ses->server, 1);
617 wake_up(&ses->server->request_q);
618 return rc; 619 return rc;
619 } 620 }
620 621
@@ -638,8 +639,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
638 midQ->resp_buf = NULL; 639 midQ->resp_buf = NULL;
639out: 640out:
640 delete_mid(midQ); 641 delete_mid(midQ);
641 dec_in_flight(ses->server); 642 cifs_add_credits(ses->server, 1);
642 wake_up(&ses->server->request_q);
643 643
644 return rc; 644 return rc;
645} 645}
@@ -689,8 +689,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
689 if (rc) { 689 if (rc) {
690 mutex_unlock(&ses->server->srv_mutex); 690 mutex_unlock(&ses->server->srv_mutex);
691 /* Update # of requests on wire to server */ 691 /* Update # of requests on wire to server */
692 dec_in_flight(ses->server); 692 cifs_add_credits(ses->server, 1);
693 wake_up(&ses->server->request_q);
694 return rc; 693 return rc;
695 } 694 }
696 695
@@ -722,8 +721,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
722 /* no longer considered to be "in-flight" */ 721 /* no longer considered to be "in-flight" */
723 midQ->callback = DeleteMidQEntry; 722 midQ->callback = DeleteMidQEntry;
724 spin_unlock(&GlobalMid_Lock); 723 spin_unlock(&GlobalMid_Lock);
725 dec_in_flight(ses->server); 724 cifs_add_credits(ses->server, 1);
726 wake_up(&ses->server->request_q);
727 return rc; 725 return rc;
728 } 726 }
729 spin_unlock(&GlobalMid_Lock); 727 spin_unlock(&GlobalMid_Lock);
@@ -731,8 +729,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
731 729
732 rc = cifs_sync_mid_result(midQ, ses->server); 730 rc = cifs_sync_mid_result(midQ, ses->server);
733 if (rc != 0) { 731 if (rc != 0) {
734 dec_in_flight(ses->server); 732 cifs_add_credits(ses->server, 1);
735 wake_up(&ses->server->request_q);
736 return rc; 733 return rc;
737 } 734 }
738 735
@@ -748,8 +745,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
748 rc = cifs_check_receive(midQ, ses->server, 0); 745 rc = cifs_check_receive(midQ, ses->server, 0);
749out: 746out:
750 delete_mid(midQ); 747 delete_mid(midQ);
751 dec_in_flight(ses->server); 748 cifs_add_credits(ses->server, 1);
752 wake_up(&ses->server->request_q);
753 749
754 return rc; 750 return rc;
755} 751}