to make sure we don't exceed the number of credits we have in this case.
Signed-off-by: Pavel Shilovsky <[email protected]>
---
fs/cifs/cifsglob.h | 6 ++++-
fs/cifs/cifssmb.c | 6 ++--
fs/cifs/connect.c | 1 +
fs/cifs/transport.c | 57 +++++++++++++++++++++++++++++++++-----------------
4 files changed, 46 insertions(+), 24 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 35d3df4..fa1a9f9 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -257,6 +257,7 @@ struct TCP_Server_Info {
bool tcp_nodelay;
int credits; /* send no more requests at once */
unsigned int in_flight; /* number of requests on the wire to server */
+ unsigned int block_locks; /* number of oustanding blocking locks */
spinlock_t req_lock; /* protect the two values above */
struct mutex srv_mutex;
struct task_struct *tsk;
@@ -330,11 +331,14 @@ get_credits(struct TCP_Server_Info *server)
}
static inline void
-add_credits(struct TCP_Server_Info *server, const unsigned int add)
+add_credits(struct TCP_Server_Info *server, const unsigned int add, int optype)
{
spin_lock(&server->req_lock);
server->credits += add;
server->in_flight--;
+ /* blocking lock case */
+ if (optype == 1)
+ server->block_locks--;
spin_unlock(&server->req_lock);
}
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index c255c25..b1040c7 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -716,7 +716,7 @@ cifs_echo_callback(struct mid_q_entry *mid)
struct TCP_Server_Info *server = mid->callback_data;
DeleteMidQEntry(mid);
- add_credits(server, 1);
+ add_credits(server, 1, 0);
wake_up(&server->request_q);
}
@@ -1669,7 +1669,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
queue_work(system_nrt_wq, &rdata->work);
DeleteMidQEntry(mid);
- add_credits(server, 1);
+ add_credits(server, 1, 0);
wake_up(&server->request_q);
}
@@ -2110,7 +2110,7 @@ cifs_writev_callback(struct mid_q_entry *mid)
queue_work(system_nrt_wq, &wdata->work);
DeleteMidQEntry(mid);
- add_credits(tcon->ses->server, 1);
+ add_credits(tcon->ses->server, 1, 0);
wake_up(&tcon->ses->server->request_q);
}
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 673813f..708be6c 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1903,6 +1903,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay;
tcp_ses->in_flight = 0;
tcp_ses->credits = cifs_max_pending;
+ tcp_ses->block_locks = 0;
init_waitqueue_head(&tcp_ses->response_q);
init_waitqueue_head(&tcp_ses->request_q);
INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 44ac0aa..5fab0f1 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -267,6 +267,11 @@ wait_for_free_request(struct TCP_Server_Info *server,
const int long_op)
return 0;
}
+ /* we can't leave the client without available credits */
+ if (long_op == CIFS_BLOCKING_OP &&
+ (server->block_locks >= (server->in_flight + server->credits) / 2))
+ return -ENOLCK;
+
while (1) {
if (server->credits <= 0) {
spin_unlock(&server->req_lock);
@@ -279,15 +284,10 @@ wait_for_free_request(struct TCP_Server_Info *server,
const int long_op)
spin_unlock(&server->req_lock);
return -ENOENT;
}
-
- /* 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) {
- server->credits--;
- server->in_flight++;
- }
+ server->credits--;
+ server->in_flight++;
+ if (long_op == CIFS_BLOCKING_OP)
+ server->block_locks++;
spin_unlock(&server->req_lock);
break;
}
@@ -362,7 +362,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec
*iov,
mid = AllocMidQEntry(hdr, server);
if (mid == NULL) {
mutex_unlock(&server->srv_mutex);
- add_credits(server, 1);
+ add_credits(server, 1, 0);
wake_up(&server->request_q);
return -ENOMEM;
}
@@ -395,7 +395,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec
*iov,
return rc;
out_err:
delete_mid(mid);
- add_credits(server, 1);
+ add_credits(server, 1, 0);
wake_up(&server->request_q);
return rc;
}
@@ -567,7 +567,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 */
- add_credits(ses->server, 1);
+ add_credits(ses->server, 1, 0);
wake_up(&ses->server->request_q);
return rc;
}
@@ -604,7 +604,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
midQ->callback = DeleteMidQEntry;
spin_unlock(&GlobalMid_Lock);
cifs_small_buf_release(in_buf);
- add_credits(ses->server, 1);
+ add_credits(ses->server, 1, 0);
wake_up(&ses->server->request_q);
return rc;
}
@@ -615,7 +615,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
rc = cifs_sync_mid_result(midQ, ses->server);
if (rc != 0) {
- add_credits(ses->server, 1);
+ add_credits(ses->server, 1, 0);
wake_up(&ses->server->request_q);
return rc;
}
@@ -640,7 +640,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
midQ->resp_buf = NULL;
out:
delete_mid(midQ);
- add_credits(ses->server, 1);
+ add_credits(ses->server, 1, 0);
wake_up(&ses->server->request_q);
return rc;
@@ -691,7 +691,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 */
- add_credits(ses->server, 1);
+ add_credits(ses->server, 1, 0);
wake_up(&ses->server->request_q);
return rc;
}
@@ -724,7 +724,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
/* no longer considered to be "in-flight" */
midQ->callback = DeleteMidQEntry;
spin_unlock(&GlobalMid_Lock);
- add_credits(ses->server, 1);
+ add_credits(ses->server, 1, 0);
wake_up(&ses->server->request_q);
return rc;
}
@@ -733,7 +733,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
rc = cifs_sync_mid_result(midQ, ses->server);
if (rc != 0) {
- add_credits(ses->server, 1);
+ add_credits(ses->server, 1, 0);
wake_up(&ses->server->request_q);
return rc;
}
@@ -750,7 +750,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
rc = cifs_check_receive(midQ, ses->server, 0);
out:
delete_mid(midQ);
- add_credits(ses->server, 1);
+ add_credits(ses->server, 1, 0);
wake_up(&ses->server->request_q);
return rc;
@@ -829,6 +829,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct
cifs_tcon *tcon,
rc = allocate_mid(ses, in_buf, &midQ);
if (rc) {
mutex_unlock(&ses->server->srv_mutex);
+ add_credits(ses->server, 1, CIFS_BLOCKING_OP);
+ wake_up(&ses->server->request_q);
return rc;
}
@@ -836,6 +838,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct
cifs_tcon *tcon,
if (rc) {
delete_mid(midQ);
mutex_unlock(&ses->server->srv_mutex);
+ add_credits(ses->server, 1, CIFS_BLOCKING_OP);
+ wake_up(&ses->server->request_q);
return rc;
}
@@ -848,6 +852,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct
cifs_tcon *tcon,
if (rc < 0) {
delete_mid(midQ);
+ add_credits(ses->server, 1, CIFS_BLOCKING_OP);
+ wake_up(&ses->server->request_q);
return rc;
}
@@ -869,6 +875,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct
cifs_tcon *tcon,
rc = send_nt_cancel(ses->server, in_buf, midQ);
if (rc) {
delete_mid(midQ);
+ add_credits(ses->server, 1, CIFS_BLOCKING_OP);
+ wake_up(&ses->server->request_q);
return rc;
}
} else {
@@ -881,6 +889,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct
cifs_tcon *tcon,
already been removed. Don't exit in this case. */
if (rc && rc != -ENOLCK) {
delete_mid(midQ);
+ add_credits(ses->server, 1, CIFS_BLOCKING_OP);
+ wake_up(&ses->server->request_q);
return rc;
}
}
@@ -893,6 +903,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct
cifs_tcon *tcon,
/* no longer considered to be "in-flight" */
midQ->callback = DeleteMidQEntry;
spin_unlock(&GlobalMid_Lock);
+ add_credits(ses->server, 1, CIFS_BLOCKING_OP);
+ wake_up(&ses->server->request_q);
return rc;
}
spin_unlock(&GlobalMid_Lock);
@@ -903,8 +915,11 @@ SendReceiveBlockingLock(const unsigned int xid, struct
cifs_tcon *tcon,
}
rc = cifs_sync_mid_result(midQ, ses->server);
- if (rc != 0)
+ if (rc != 0) {
+ add_credits(ses->server, 1, CIFS_BLOCKING_OP);
+ wake_up(&ses->server->request_q);
return rc;
+ }
/* rcvd frame is ok */
if (out_buf == NULL || midQ->midState != MID_RESPONSE_RECEIVED) {
@@ -918,6 +933,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct
cifs_tcon *tcon,
rc = cifs_check_receive(midQ, ses->server, 0);
out:
delete_mid(midQ);
+ add_credits(ses->server, 1, CIFS_BLOCKING_OP);
+ wake_up(&ses->server->request_q);
if (rstart && rc == -EACCES)
return -ERESTARTSYS;
return rc;
--
1.7.1
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html