diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 76b4517e74b07d5ff15865c2f4860ed9062c7780..fd877c110e4caee61dd26da3e0721a726902f067 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -543,9 +543,8 @@ struct mid_q_entry; * This is the prototype for the mid callback function. When creating one, * take special care to avoid deadlocks. Things to bear in mind: * - * - it will be called by cifsd - * - the GlobalMid_Lock will be held - * - the mid will be removed from the pending_mid_q list + * - it will be called by cifsd, with no locks held + * - the mid will be removed from any lists */ typedef void (mid_callback_t)(struct mid_q_entry *mid); @@ -656,6 +655,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, #define MID_RESPONSE_RECEIVED 4 #define MID_RETRY_NEEDED 8 /* session closed while this request out */ #define MID_RESPONSE_MALFORMED 0x10 +#define MID_SHUTDOWN 0x20 /* Types of response buffer returned from SendReceive2 */ #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 273cf42b29150a2b3fd10cf757037d2e3b1582cb..6070ba69647b9987f209aa12e94889782455eab6 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -137,6 +137,7 @@ cifs_reconnect(struct TCP_Server_Info *server) struct cifsSesInfo *ses; struct cifsTconInfo *tcon; struct mid_q_entry *mid_entry; + struct list_head retry_list; spin_lock(&GlobalMid_Lock); if (server->tcpStatus == CifsExiting) { @@ -188,16 +189,23 @@ cifs_reconnect(struct TCP_Server_Info *server) mutex_unlock(&server->srv_mutex); /* mark submitted MIDs for retry and issue callback */ - cFYI(1, "%s: issuing mid callbacks", __func__); + INIT_LIST_HEAD(&retry_list); + cFYI(1, "%s: moving mids to private list", __func__); spin_lock(&GlobalMid_Lock); list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, qhead); if (mid_entry->midState == MID_REQUEST_SUBMITTED) mid_entry->midState = MID_RETRY_NEEDED; + list_move(&mid_entry->qhead, &retry_list); + } + spin_unlock(&GlobalMid_Lock); + + cFYI(1, "%s: issuing mid callbacks", __func__); + list_for_each_safe(tmp, tmp2, &retry_list) { + mid_entry = list_entry(tmp, struct mid_q_entry, qhead); list_del_init(&mid_entry->qhead); mid_entry->callback(mid_entry); } - spin_unlock(&GlobalMid_Lock); while (server->tcpStatus == CifsNeedReconnect) { try_to_freeze(); @@ -671,12 +679,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) mid_entry->when_received = jiffies; #endif list_del_init(&mid_entry->qhead); - mid_entry->callback(mid_entry); break; } spin_unlock(&GlobalMid_Lock); if (mid_entry != NULL) { + mid_entry->callback(mid_entry); /* Was previous buf put in mpx struct for multi-rsp? */ if (!isMultiRsp) { /* smb buffer will be freed by user thread */ @@ -740,15 +748,25 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) cifs_small_buf_release(smallbuf); if (!list_empty(&server->pending_mid_q)) { + struct list_head dispose_list; + + INIT_LIST_HEAD(&dispose_list); spin_lock(&GlobalMid_Lock); list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { mid_entry = list_entry(tmp, struct mid_q_entry, qhead); - cFYI(1, "Clearing Mid 0x%x - issuing callback", - mid_entry->mid); + cFYI(1, "Clearing mid 0x%x", mid_entry->mid); + mid_entry->midState = MID_SHUTDOWN; + list_move(&mid_entry->qhead, &dispose_list); + } + spin_unlock(&GlobalMid_Lock); + + /* now walk dispose list and issue callbacks */ + list_for_each_safe(tmp, tmp2, &dispose_list) { + mid_entry = list_entry(tmp, struct mid_q_entry, qhead); + cFYI(1, "Callback mid 0x%x", mid_entry->mid); list_del_init(&mid_entry->qhead); mid_entry->callback(mid_entry); } - spin_unlock(&GlobalMid_Lock); /* 1/8th of sec is more than enough time for them to exit */ msleep(125); } diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 16bcc0725ceec28d63bf09a18c99d90265ab4d4f..d1998b6086ef0e190f0e1f5d42dea9c5944ebc2c 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -426,7 +426,7 @@ SendReceiveNoRsp(const unsigned int xid, struct cifsSesInfo *ses, } static int -sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) +cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) { int rc = 0; @@ -434,28 +434,21 @@ sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) mid->mid, mid->midState); spin_lock(&GlobalMid_Lock); - /* ensure that it's no longer on the pending_mid_q */ - list_del_init(&mid->qhead); - switch (mid->midState) { case MID_RESPONSE_RECEIVED: spin_unlock(&GlobalMid_Lock); return rc; - case MID_REQUEST_SUBMITTED: - /* socket is going down, reject all calls */ - if (server->tcpStatus == CifsExiting) { - cERROR(1, "%s: canceling mid=%d cmd=0x%x state=%d", - __func__, mid->mid, mid->command, mid->midState); - rc = -EHOSTDOWN; - break; - } case MID_RETRY_NEEDED: rc = -EAGAIN; break; case MID_RESPONSE_MALFORMED: rc = -EIO; break; + case MID_SHUTDOWN: + rc = -EHOSTDOWN; + break; default: + list_del_init(&mid->qhead); cERROR(1, "%s: invalid mid state mid=%d state=%d", __func__, mid->mid, mid->midState); rc = -EIO; @@ -618,7 +611,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, cifs_small_buf_release(in_buf); - rc = sync_mid_result(midQ, ses->server); + rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); @@ -739,7 +732,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, spin_unlock(&GlobalMid_Lock); } - rc = sync_mid_result(midQ, ses->server); + rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) { atomic_dec(&ses->server->inFlight); wake_up(&ses->server->request_q); @@ -914,7 +907,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, rstart = 1; } - rc = sync_mid_result(midQ, ses->server); + rc = cifs_sync_mid_result(midQ, ses->server); if (rc != 0) return rc;