diff options
| -rw-r--r-- | fs/cifs/cifsglob.h | 6 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 30 | ||||
| -rw-r--r-- | fs/cifs/transport.c | 23 | 
3 files changed, 35 insertions, 24 deletions
| diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 76b4517e74b0..fd877c110e4c 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 273cf42b2915..6070ba69647b 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 @@ multi_t2_fnd:  			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 @@ multi_t2_fnd:  		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 16bcc0725cee..d1998b6086ef 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; | 
