⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 transport.c

📁 Linux内核自带的cifs模块
💻 C
📖 第 1 页 / 共 2 页
字号:
	up(&ses->server->tcpSem);	cifs_small_buf_release(in_buf);	if (rc < 0)		goto out;	if (long_op == -1)		goto out;	else if (long_op == 2) /* writes past end of file can take loong time */		timeout = 180 * HZ;	else if (long_op == 1)		timeout = 45 * HZ; /* should be greater than			servers oplock break timeout (about 43 seconds) */	else		timeout = 15 * HZ;	/* wait for 15 seconds or until woken up due to response arriving or	   due to last connection to this server being unmounted */	if (signal_pending(current)) {		/* if signal pending do not hold up user for full smb timeout		but we still give response a chance to complete */		timeout = 2 * HZ;	}	/* No user interrupts in wait - wreaks havoc with performance */	wait_for_response(ses, midQ, timeout, 10 * HZ);	spin_lock(&GlobalMid_Lock);	if (midQ->resp_buf) {		spin_unlock(&GlobalMid_Lock);		receive_len = midQ->resp_buf->smb_buf_length;	} else {		cERROR(1, ("No response to cmd %d mid %d",			midQ->command, midQ->mid));		if (midQ->midState == MID_REQUEST_SUBMITTED) {			if (ses->server->tcpStatus == CifsExiting)				rc = -EHOSTDOWN;			else {				ses->server->tcpStatus = CifsNeedReconnect;				midQ->midState = MID_RETRY_NEEDED;			}		}		if (rc != -EHOSTDOWN) {			if (midQ->midState == MID_RETRY_NEEDED) {				rc = -EAGAIN;				cFYI(1, ("marking request for retry"));			} else {				rc = -EIO;			}		}		spin_unlock(&GlobalMid_Lock);		DeleteMidQEntry(midQ);		/* Update # of requests on wire to server */		atomic_dec(&ses->server->inFlight);		wake_up(&ses->server->request_q);		return rc;	}	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",			receive_len, xid));		rc = -EIO;	} else {		/* rcvd frame is ok */		if (midQ->resp_buf &&			(midQ->midState == MID_RESPONSE_RECEIVED)) {			iov[0].iov_base = (char *)midQ->resp_buf;			if (midQ->largeBuf)				*pRespBufType = CIFS_LARGE_BUFFER;			else				*pRespBufType = CIFS_SMALL_BUFFER;			iov[0].iov_len = receive_len + 4;			dump_smb(midQ->resp_buf, 80);			/* convert the length into a more usable form */			if ((receive_len > 24) &&			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |					SECMODE_SIGN_ENABLED))) {				rc = cifs_verify_signature(midQ->resp_buf,						&ses->server->mac_signing_key,						midQ->sequence_number+1);				if (rc) {					cERROR(1, ("Unexpected SMB signature"));					/* BB FIXME add code to kill session */				}			}			/* BB special case reconnect tid and uid here? */			/* BB special case Errbadpassword and pwdexpired here */			rc = map_smb_to_linux_error(midQ->resp_buf);			/* convert ByteCount if necessary */			if (receive_len >= sizeof(struct smb_hdr) - 4			    /* do not count RFC1001 header */  +			    (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )				BCC(midQ->resp_buf) =					le16_to_cpu(BCC_LE(midQ->resp_buf));			midQ->resp_buf = NULL;  /* mark it so will not be freed						by DeleteMidQEntry */		} else {			rc = -EIO;			cFYI(1, ("Bad MID state?"));		}	}out:	DeleteMidQEntry(midQ);	atomic_dec(&ses->server->inFlight);	wake_up(&ses->server->request_q);	return rc;}intSendReceive(const unsigned int xid, struct cifsSesInfo *ses,	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,	    int *pbytes_returned, const int long_op){	int rc = 0;	unsigned int receive_len;	unsigned long timeout;	struct mid_q_entry *midQ;	if (ses == NULL) {		cERROR(1, ("Null smb session"));		return -EIO;	}	if (ses->server == NULL) {		cERROR(1, ("Null tcp session"));		return -EIO;	}	if (ses->server->tcpStatus == CifsExiting)		return -ENOENT;	/* Ensure that we do not send more than 50 overlapping requests	   to the same server. We may make this configurable later or	   use ses->maxReq */	rc = wait_for_free_request(ses, long_op);	if (rc)		return rc;	/* make sure that we sign in the same order that we send on this socket	   and avoid races inside tcp sendmsg code that could cause corruption	   of smb data */	down(&ses->server->tcpSem);	rc = allocate_mid(ses, in_buf, &midQ);	if (rc) {		up(&ses->server->tcpSem);		/* Update # of requests on wire to server */		atomic_dec(&ses->server->inFlight);		wake_up(&ses->server->request_q);		return rc;	}	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {		cERROR(1, ("Illegal length, greater than maximum frame, %d",			in_buf->smb_buf_length));		DeleteMidQEntry(midQ);		up(&ses->server->tcpSem);		/* Update # of requests on wire to server */		atomic_dec(&ses->server->inFlight);		wake_up(&ses->server->request_q);		return -EIO;	}	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);	midQ->midState = MID_REQUEST_SUBMITTED;#ifdef CONFIG_CIFS_STATS2	atomic_inc(&ses->server->inSend);#endif	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,		      (struct sockaddr *) &(ses->server->addr.sockAddr));#ifdef CONFIG_CIFS_STATS2	atomic_dec(&ses->server->inSend);	midQ->when_sent = jiffies;#endif	up(&ses->server->tcpSem);	if (rc < 0)		goto out;	if (long_op == -1)		goto out;	else if (long_op == 2) /* writes past end of file can take loong time */		timeout = 180 * HZ;	else if (long_op == 1)		timeout = 45 * HZ; /* should be greater than			servers oplock break timeout (about 43 seconds) */	else		timeout = 15 * HZ;	/* wait for 15 seconds or until woken up due to response arriving or	   due to last connection to this server being unmounted */	if (signal_pending(current)) {		/* if signal pending do not hold up user for full smb timeout		but we still give response a chance to complete */		timeout = 2 * HZ;	}	/* No user interrupts in wait - wreaks havoc with performance */	wait_for_response(ses, midQ, timeout, 10 * HZ);	spin_lock(&GlobalMid_Lock);	if (midQ->resp_buf) {		spin_unlock(&GlobalMid_Lock);		receive_len = midQ->resp_buf->smb_buf_length;	} else {		cERROR(1, ("No response for cmd %d mid %d",			  midQ->command, midQ->mid));		if (midQ->midState == MID_REQUEST_SUBMITTED) {			if (ses->server->tcpStatus == CifsExiting)				rc = -EHOSTDOWN;			else {				ses->server->tcpStatus = CifsNeedReconnect;				midQ->midState = MID_RETRY_NEEDED;			}		}		if (rc != -EHOSTDOWN) {			if (midQ->midState == MID_RETRY_NEEDED) {				rc = -EAGAIN;				cFYI(1, ("marking request for retry"));			} else {				rc = -EIO;			}		}		spin_unlock(&GlobalMid_Lock);		DeleteMidQEntry(midQ);		/* Update # of requests on wire to server */		atomic_dec(&ses->server->inFlight);		wake_up(&ses->server->request_q);		return rc;	}	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",			receive_len, xid));		rc = -EIO;	} else {		/* rcvd frame is ok */		if (midQ->resp_buf && out_buf		    && (midQ->midState == MID_RESPONSE_RECEIVED)) {			out_buf->smb_buf_length = receive_len;			memcpy((char *)out_buf + 4,			       (char *)midQ->resp_buf + 4,			       receive_len);			dump_smb(out_buf, 92);			/* convert the length into a more usable form */			if ((receive_len > 24) &&			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |					SECMODE_SIGN_ENABLED))) {				rc = cifs_verify_signature(out_buf,						&ses->server->mac_signing_key,						midQ->sequence_number+1);				if (rc) {					cERROR(1, ("Unexpected SMB signature"));					/* BB FIXME add code to kill session */				}			}			*pbytes_returned = out_buf->smb_buf_length;			/* BB special case reconnect tid and uid here? */			rc = map_smb_to_linux_error(out_buf);			/* convert ByteCount if necessary */			if (receive_len >= sizeof(struct smb_hdr) - 4			    /* do not count RFC1001 header */  +			    (2 * out_buf->WordCount) + 2 /* bcc */ )				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));		} else {			rc = -EIO;			cERROR(1, ("Bad MID state?"));		}	}out:	DeleteMidQEntry(midQ);	atomic_dec(&ses->server->inFlight);	wake_up(&ses->server->request_q);	return rc;}/* Send an NT_CANCEL SMB to cause the POSIX blocking lock to return. */static intsend_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,		struct mid_q_entry *midQ){	int rc = 0;	struct cifsSesInfo *ses = tcon->ses;	__u16 mid = in_buf->Mid;	header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);	in_buf->Mid = mid;	down(&ses->server->tcpSem);	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);	if (rc) {		up(&ses->server->tcpSem);		return rc;	}	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,	      (struct sockaddr *) &(ses->server->addr.sockAddr));	up(&ses->server->tcpSem);	return rc;}/* We send a LOCKINGX_CANCEL_LOCK to cause the Windows   blocking lock to return. */static intsend_lock_cancel(const unsigned int xid, struct cifsTconInfo *tcon,			struct smb_hdr *in_buf,			struct smb_hdr *out_buf){	int bytes_returned;	struct cifsSesInfo *ses = tcon->ses;	LOCK_REQ *pSMB = (LOCK_REQ *)in_buf;	/* We just modify the current in_buf to change	   the type of lock from LOCKING_ANDX_SHARED_LOCK	   or LOCKING_ANDX_EXCLUSIVE_LOCK to	   LOCKING_ANDX_CANCEL_LOCK. */	pSMB->LockType = LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES;	pSMB->Timeout = 0;	pSMB->hdr.Mid = GetNextMid(ses->server);	return SendReceive(xid, ses, in_buf, out_buf,			&bytes_returned, 0);}intSendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,	    struct smb_hdr *in_buf, struct smb_hdr *out_buf,	    int *pbytes_returned){	int rc = 0;	int rstart = 0;	unsigned int receive_len;	struct mid_q_entry *midQ;	struct cifsSesInfo *ses;	if (tcon == NULL || tcon->ses == NULL) {		cERROR(1, ("Null smb session"));		return -EIO;	}	ses = tcon->ses;	if (ses->server == NULL) {		cERROR(1, ("Null tcp session"));		return -EIO;	}	if (ses->server->tcpStatus == CifsExiting)		return -ENOENT;	/* Ensure that we do not send more than 50 overlapping requests	   to the same server. We may make this configurable later or	   use ses->maxReq */	rc = wait_for_free_request(ses, 3);	if (rc)		return rc;	/* make sure that we sign in the same order that we send on this socket	   and avoid races inside tcp sendmsg code that could cause corruption	   of smb data */	down(&ses->server->tcpSem);	rc = allocate_mid(ses, in_buf, &midQ);	if (rc) {		up(&ses->server->tcpSem);		return rc;	}	if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {		up(&ses->server->tcpSem);		cERROR(1, ("Illegal length, greater than maximum frame, %d",			in_buf->smb_buf_length));		DeleteMidQEntry(midQ);		return -EIO;	}	rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);	midQ->midState = MID_REQUEST_SUBMITTED;#ifdef CONFIG_CIFS_STATS2	atomic_inc(&ses->server->inSend);#endif	rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,		      (struct sockaddr *) &(ses->server->addr.sockAddr));#ifdef CONFIG_CIFS_STATS2	atomic_dec(&ses->server->inSend);	midQ->when_sent = jiffies;#endif	up(&ses->server->tcpSem);	if (rc < 0) {		DeleteMidQEntry(midQ);		return rc;	}	/* Wait for a reply - allow signals to interrupt. */	rc = wait_event_interruptible(ses->server->response_q,		(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||		((ses->server->tcpStatus != CifsGood) &&		 (ses->server->tcpStatus != CifsNew)));	/* Were we interrupted by a signal ? */	if ((rc == -ERESTARTSYS) &&		(midQ->midState == MID_REQUEST_SUBMITTED) &&		((ses->server->tcpStatus == CifsGood) ||		 (ses->server->tcpStatus == CifsNew))) {		if (in_buf->Command == SMB_COM_TRANSACTION2) {			/* POSIX lock. We send a NT_CANCEL SMB to cause the			   blocking lock to return. */			rc = send_nt_cancel(tcon, in_buf, midQ);			if (rc) {				DeleteMidQEntry(midQ);				return rc;			}		} else {			/* Windows lock. We send a LOCKINGX_CANCEL_LOCK			   to cause the blocking lock to return. */			rc = send_lock_cancel(xid, tcon, in_buf, out_buf);			/* If we get -ENOLCK back the lock may have			   already been removed. Don't exit in this case. */			if (rc && rc != -ENOLCK) {				DeleteMidQEntry(midQ);				return rc;			}		}		/* Wait 5 seconds for the response. */		if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {			/* We got the response - restart system call. */			rstart = 1;		}	}	spin_lock(&GlobalMid_Lock);	if (midQ->resp_buf) {		spin_unlock(&GlobalMid_Lock);		receive_len = midQ->resp_buf->smb_buf_length;	} else {		cERROR(1, ("No response for cmd %d mid %d",			  midQ->command, midQ->mid));		if (midQ->midState == MID_REQUEST_SUBMITTED) {			if (ses->server->tcpStatus == CifsExiting)				rc = -EHOSTDOWN;			else {				ses->server->tcpStatus = CifsNeedReconnect;				midQ->midState = MID_RETRY_NEEDED;			}		}		if (rc != -EHOSTDOWN) {			if (midQ->midState == MID_RETRY_NEEDED) {				rc = -EAGAIN;				cFYI(1, ("marking request for retry"));			} else {				rc = -EIO;			}		}		spin_unlock(&GlobalMid_Lock);		DeleteMidQEntry(midQ);		return rc;	}	if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {		cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",			receive_len, xid));		rc = -EIO;	} else {		/* rcvd frame is ok */		if (midQ->resp_buf && out_buf		    && (midQ->midState == MID_RESPONSE_RECEIVED)) {			out_buf->smb_buf_length = receive_len;			memcpy((char *)out_buf + 4,			       (char *)midQ->resp_buf + 4,			       receive_len);			dump_smb(out_buf, 92);			/* convert the length into a more usable form */			if ((receive_len > 24) &&			   (ses->server->secMode & (SECMODE_SIGN_REQUIRED |					SECMODE_SIGN_ENABLED))) {				rc = cifs_verify_signature(out_buf,						&ses->server->mac_signing_key,						midQ->sequence_number+1);				if (rc) {					cERROR(1, ("Unexpected SMB signature"));					/* BB FIXME add code to kill session */				}			}			*pbytes_returned = out_buf->smb_buf_length;			/* BB special case reconnect tid and uid here? */			rc = map_smb_to_linux_error(out_buf);			/* convert ByteCount if necessary */			if (receive_len >= sizeof(struct smb_hdr) - 4			    /* do not count RFC1001 header */  +			    (2 * out_buf->WordCount) + 2 /* bcc */ )				BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));		} else {			rc = -EIO;			cERROR(1, ("Bad MID state?"));		}	}	DeleteMidQEntry(midQ);	if (rstart && rc == -EACCES)		return -ERESTARTSYS;	return rc;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -