From 10b9b98e41ba248a899f6175ce96ee91431b6194 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Tue, 20 Mar 2012 12:55:09 +0300 Subject: CIFS: Respect negotiated MaxMpxCount Some servers sets this value less than 50 that was hardcoded and we lost the connection if when we exceed this limit. Fix this by respecting this value - not sending more than the server allows. Cc: stable@kernel.org Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/cifs/transport.c') diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0cc9584f5889..99a27cfa6cd2 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -265,12 +265,12 @@ static int wait_for_free_request(struct TCP_Server_Info *server, spin_lock(&GlobalMid_Lock); while (1) { - if (atomic_read(&server->inFlight) >= cifs_max_pending) { + if (atomic_read(&server->inFlight) >= server->maxReq) { spin_unlock(&GlobalMid_Lock); cifs_num_waiters_inc(server); wait_event(server->request_q, atomic_read(&server->inFlight) - < cifs_max_pending); + < server->maxReq); cifs_num_waiters_dec(server); spin_lock(&GlobalMid_Lock); } else { -- cgit From fc40f9cf828908e91d9af820e9300a9d42fbbd72 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Fri, 17 Feb 2012 17:09:12 +0300 Subject: CIFS: Simplify inFlight logic by making it as unsigned integer and surround access with req_lock from server structure. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/transport.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'fs/cifs/transport.c') diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 99a27cfa6cd2..e2673aa34381 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -254,28 +254,29 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, return smb_sendv(server, &iov, 1); } -static int wait_for_free_request(struct TCP_Server_Info *server, - const int long_op) +static int +wait_for_free_request(struct TCP_Server_Info *server, const int long_op) { + spin_lock(&server->req_lock); + if (long_op == CIFS_ASYNC_OP) { /* oplock breaks must not be held up */ - atomic_inc(&server->inFlight); + server->in_flight++; + spin_unlock(&server->req_lock); return 0; } - spin_lock(&GlobalMid_Lock); while (1) { - if (atomic_read(&server->inFlight) >= server->maxReq) { - spin_unlock(&GlobalMid_Lock); + if (server->in_flight >= server->maxReq) { + spin_unlock(&server->req_lock); cifs_num_waiters_inc(server); wait_event(server->request_q, - atomic_read(&server->inFlight) - < server->maxReq); + in_flight(server) < server->maxReq); cifs_num_waiters_dec(server); - spin_lock(&GlobalMid_Lock); + spin_lock(&server->req_lock); } else { if (server->tcpStatus == CifsExiting) { - spin_unlock(&GlobalMid_Lock); + spin_unlock(&server->req_lock); return -ENOENT; } @@ -284,8 +285,8 @@ static int wait_for_free_request(struct TCP_Server_Info *server, /* update # of requests on the wire to server */ if (long_op != CIFS_BLOCKING_OP) - atomic_inc(&server->inFlight); - spin_unlock(&GlobalMid_Lock); + server->in_flight++; + spin_unlock(&server->req_lock); break; } } @@ -359,7 +360,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, mid = AllocMidQEntry(hdr, server); if (mid == NULL) { mutex_unlock(&server->srv_mutex); - atomic_dec(&server->inFlight); + dec_in_flight(server); wake_up(&server->request_q); return -ENOMEM; } @@ -392,7 +393,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, return rc; out_err: delete_mid(mid); - atomic_dec(&server->inFlight); + dec_in_flight(server); wake_up(&server->request_q); return rc; } @@ -564,7 +565,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(in_buf); /* Update # of requests on wire to server */ - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -601,7 +602,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); cifs_small_buf_release(in_buf); - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -612,7 +613,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -637,7 +638,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, midQ->resp_buf = NULL; out: delete_mid(midQ); - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; @@ -688,7 +689,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, if (rc) { mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -721,7 +722,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, /* no longer considered to be "in-flight" */ midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -730,7 +731,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; } @@ -747,7 +748,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, rc = cifs_check_receive(midQ, ses->server, 0); out: delete_mid(midQ); - atomic_dec(&ses->server->inFlight); + dec_in_flight(ses->server); wake_up(&ses->server->request_q); return rc; -- cgit From 2d86dbc97094ea4cfc2204fdefd7d07685496189 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Mon, 6 Feb 2012 15:59:18 +0400 Subject: 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 Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/transport.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) (limited to 'fs/cifs/transport.c') 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) if (long_op == CIFS_ASYNC_OP) { /* oplock breaks must not be held up */ server->in_flight++; + server->credits--; spin_unlock(&server->req_lock); return 0; } while (1) { - if (server->in_flight >= server->maxReq) { + if (server->credits <= 0) { spin_unlock(&server->req_lock); cifs_num_waiters_inc(server); - wait_event(server->request_q, - in_flight(server) < server->maxReq); + wait_event(server->request_q, has_credits(server)); cifs_num_waiters_dec(server); spin_lock(&server->req_lock); } else { @@ -280,12 +280,16 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op) return -ENOENT; } - /* can not count locking commands against total - as they are allowed to block on server */ + /* + * Can not count locking commands against total + * as they are allowed to block on server. + */ /* update # of requests on the wire to server */ - if (long_op != CIFS_BLOCKING_OP) + if (long_op != CIFS_BLOCKING_OP) { + server->credits--; server->in_flight++; + } spin_unlock(&server->req_lock); break; } @@ -360,7 +364,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, mid = AllocMidQEntry(hdr, server); if (mid == NULL) { mutex_unlock(&server->srv_mutex); - dec_in_flight(server); + cifs_add_credits(server, 1); wake_up(&server->request_q); return -ENOMEM; } @@ -393,7 +397,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, return rc; out_err: delete_mid(mid); - dec_in_flight(server); + cifs_add_credits(server, 1); wake_up(&server->request_q); return rc; } @@ -565,8 +569,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, mutex_unlock(&ses->server->srv_mutex); cifs_small_buf_release(in_buf); /* Update # of requests on wire to server */ - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } 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, midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); cifs_small_buf_release(in_buf); - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } spin_unlock(&GlobalMid_Lock); @@ -613,8 +615,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } @@ -638,8 +639,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, midQ->resp_buf = NULL; out: delete_mid(midQ); - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } @@ -689,8 +689,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, if (rc) { mutex_unlock(&ses->server->srv_mutex); /* Update # of requests on wire to server */ - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } @@ -722,8 +721,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, /* no longer considered to be "in-flight" */ midQ->callback = DeleteMidQEntry; spin_unlock(&GlobalMid_Lock); - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } spin_unlock(&GlobalMid_Lock); @@ -731,8 +729,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } @@ -748,8 +745,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, rc = cifs_check_receive(midQ, ses->server, 0); out: delete_mid(midQ); - dec_in_flight(ses->server); - wake_up(&ses->server->request_q); + cifs_add_credits(ses->server, 1); return rc; } -- cgit From 5bc594982f49220d33e927e3c9e028bf87b4745c Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Tue, 21 Feb 2012 19:56:08 +0300 Subject: CIFS: Make wait_for_free_request killable to let us kill the proccess if it hangs waiting for a credit when the session is down and echo is disabled. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/transport.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'fs/cifs/transport.c') diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index e5202ddef2fb..58b31da17fc5 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -257,6 +257,8 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, static int wait_for_free_request(struct TCP_Server_Info *server, const int long_op) { + int rc; + spin_lock(&server->req_lock); if (long_op == CIFS_ASYNC_OP) { @@ -271,8 +273,11 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op) if (server->credits <= 0) { spin_unlock(&server->req_lock); cifs_num_waiters_inc(server); - wait_event(server->request_q, has_credits(server)); + rc = wait_event_killable(server->request_q, + has_credits(server)); cifs_num_waiters_dec(server); + if (rc) + return rc; spin_lock(&server->req_lock); } else { if (server->tcpStatus == CifsExiting) { -- cgit From bc205ed19bdb56576b291830bc3f752aef5e3923 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 15 Mar 2012 13:22:27 +0300 Subject: CIFS: Prepare credits code for a slot reservation that is essential for CIFS/SMB/SMB2 oplock breaks and SMB2 echos. Reviewed-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French --- fs/cifs/transport.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'fs/cifs/transport.c') diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 58b31da17fc5..310918b6fcb4 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -255,26 +255,26 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, } static int -wait_for_free_request(struct TCP_Server_Info *server, const int long_op) +wait_for_free_credits(struct TCP_Server_Info *server, const int optype, + int *credits) { int rc; spin_lock(&server->req_lock); - - if (long_op == CIFS_ASYNC_OP) { + if (optype == CIFS_ASYNC_OP) { /* oplock breaks must not be held up */ server->in_flight++; - server->credits--; + *credits -= 1; spin_unlock(&server->req_lock); return 0; } while (1) { - if (server->credits <= 0) { + if (*credits <= 0) { spin_unlock(&server->req_lock); cifs_num_waiters_inc(server); rc = wait_event_killable(server->request_q, - has_credits(server)); + has_credits(server, credits)); cifs_num_waiters_dec(server); if (rc) return rc; @@ -291,8 +291,8 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op) */ /* update # of requests on the wire to server */ - if (long_op != CIFS_BLOCKING_OP) { - server->credits--; + if (optype != CIFS_BLOCKING_OP) { + *credits -= 1; server->in_flight++; } spin_unlock(&server->req_lock); @@ -302,6 +302,12 @@ wait_for_free_request(struct TCP_Server_Info *server, const int long_op) return 0; } +static int +wait_for_free_request(struct TCP_Server_Info *server, const int optype) +{ + return wait_for_free_credits(server, optype, get_credits_field(server)); +} + static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, struct mid_q_entry **ppmidQ) { -- cgit