Exemple #1
0
/*
 * Initialize sockets and congestion for a new NFS connection.
 * We do not free the sockaddr if error.
 */
int
nfs_connect(struct nfsmount *nmp)
{
	int rcvreserve, sndreserve;
	int pktscale;
	struct sockaddr *saddr;
	struct ucred *origcred;
	struct thread *td = curthread;
	CLIENT *client;
	struct netconfig *nconf;
	rpcvers_t vers;
	int one = 1, retries;

	/*
	 * We need to establish the socket using the credentials of
	 * the mountpoint.  Some parts of this process (such as
	 * sobind() and soconnect()) will use the curent thread's
	 * credential instead of the socket credential.  To work
	 * around this, temporarily change the current thread's
	 * credential to that of the mountpoint.
	 *
	 * XXX: It would be better to explicitly pass the correct
	 * credential to sobind() and soconnect().
	 */
	origcred = td->td_ucred;
	td->td_ucred = nmp->nm_mountp->mnt_cred;
	saddr = nmp->nm_nam;

	vers = NFS_VER2;
	if (nmp->nm_flag & NFSMNT_NFSV3)
		vers = NFS_VER3;
	else if (nmp->nm_flag & NFSMNT_NFSV4)
		vers = NFS_VER4;
	if (saddr->sa_family == AF_INET)
		if (nmp->nm_sotype == SOCK_DGRAM)
			nconf = getnetconfigent("udp");
		else
			nconf = getnetconfigent("tcp");
	else
		if (nmp->nm_sotype == SOCK_DGRAM)
			nconf = getnetconfigent("udp6");
		else
			nconf = getnetconfigent("tcp6");

	/*
	 * Get buffer reservation size from sysctl, but impose reasonable
	 * limits.
	 */
	pktscale = nfs_bufpackets;
	if (pktscale < 2)
		pktscale = 2;
	if (pktscale > 64)
		pktscale = 64;
	mtx_lock(&nmp->nm_mtx);
	if (nmp->nm_sotype == SOCK_DGRAM) {
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale;
		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
		    NFS_MAXPKTHDR) * pktscale;
	} else if (nmp->nm_sotype == SOCK_SEQPACKET) {
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale;
		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
		    NFS_MAXPKTHDR) * pktscale;
	} else {
		if (nmp->nm_sotype != SOCK_STREAM)
			panic("nfscon sotype");
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR +
		    sizeof (u_int32_t)) * pktscale;
		rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR +
		    sizeof (u_int32_t)) * pktscale;
	}
	mtx_unlock(&nmp->nm_mtx);

	client = clnt_reconnect_create(nconf, saddr, NFS_PROG, vers,
	    sndreserve, rcvreserve);
	CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq");
	if (nmp->nm_flag & NFSMNT_INT)
		CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
	if (nmp->nm_flag & NFSMNT_RESVPORT)
		CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
	if (nmp->nm_flag & NFSMNT_SOFT)
		retries = nmp->nm_retry;
	else
		retries = INT_MAX;
	CLNT_CONTROL(client, CLSET_RETRIES, &retries);

	mtx_lock(&nmp->nm_mtx);
	if (nmp->nm_client) {
		/*
		 * Someone else already connected.
		 */
		CLNT_RELEASE(client);
	} else
		nmp->nm_client = client;

	/*
	 * Protocols that do not require connections may be optionally left
	 * unconnected for servers that reply from a port other than NFS_PORT.
	 */
	if (!(nmp->nm_flag & NFSMNT_NOCONN)) {
		mtx_unlock(&nmp->nm_mtx);
		CLNT_CONTROL(client, CLSET_CONNECT, &one);
	} else
		mtx_unlock(&nmp->nm_mtx);

	/* Restore current thread's credentials. */
	td->td_ucred = origcred;

	mtx_lock(&nmp->nm_mtx);
	/* Initialize other non-zero congestion variables. */
	nfs_init_rtt(nmp);
	mtx_unlock(&nmp->nm_mtx);
	return (0);
}
/*
 * Initialize sockets and congestion for a new NFS connection.
 * We do not free the sockaddr if error.
 */
int
nfs_connect(struct nfsmount *nmp)
{
	int rcvreserve, sndreserve;
	int pktscale;
	struct sockaddr *saddr;
	struct ucred *origcred;
	struct thread *td = curthread;
	CLIENT *client;
	struct netconfig *nconf;
	rpcvers_t vers;
	int one = 1, retries;
	struct timeval timo;

	/*
	 * We need to establish the socket using the credentials of
	 * the mountpoint.  Some parts of this process (such as
	 * sobind() and soconnect()) will use the curent thread's
	 * credential instead of the socket credential.  To work
	 * around this, temporarily change the current thread's
	 * credential to that of the mountpoint.
	 *
	 * XXX: It would be better to explicitly pass the correct
	 * credential to sobind() and soconnect().
	 */
	origcred = td->td_ucred;
	td->td_ucred = nmp->nm_mountp->mnt_cred;
	saddr = nmp->nm_nam;

	vers = NFS_VER2;
	if (nmp->nm_flag & NFSMNT_NFSV3)
		vers = NFS_VER3;
	else if (nmp->nm_flag & NFSMNT_NFSV4)
		vers = NFS_VER4;
	if (saddr->sa_family == AF_INET)
		if (nmp->nm_sotype == SOCK_DGRAM)
			nconf = getnetconfigent("udp");
		else
			nconf = getnetconfigent("tcp");
	else
		if (nmp->nm_sotype == SOCK_DGRAM)
			nconf = getnetconfigent("udp6");
		else
			nconf = getnetconfigent("tcp6");

	/*
	 * Get buffer reservation size from sysctl, but impose reasonable
	 * limits.
	 */
	pktscale = nfs_bufpackets;
	if (pktscale < 2)
		pktscale = 2;
	if (pktscale > 64)
		pktscale = 64;
	mtx_lock(&nmp->nm_mtx);
	if (nmp->nm_sotype == SOCK_DGRAM) {
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale;
		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
		    NFS_MAXPKTHDR) * pktscale;
	} else if (nmp->nm_sotype == SOCK_SEQPACKET) {
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR) * pktscale;
		rcvreserve = (max(nmp->nm_rsize, nmp->nm_readdirsize) +
		    NFS_MAXPKTHDR) * pktscale;
	} else {
		if (nmp->nm_sotype != SOCK_STREAM)
			panic("nfscon sotype");
		sndreserve = (nmp->nm_wsize + NFS_MAXPKTHDR +
		    sizeof (u_int32_t)) * pktscale;
		rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR +
		    sizeof (u_int32_t)) * pktscale;
	}
	mtx_unlock(&nmp->nm_mtx);

	client = clnt_reconnect_create(nconf, saddr, NFS_PROG, vers,
	    sndreserve, rcvreserve);
	CLNT_CONTROL(client, CLSET_WAITCHAN, "nfsreq");
	if (nmp->nm_flag & NFSMNT_INT)
		CLNT_CONTROL(client, CLSET_INTERRUPTIBLE, &one);
	if (nmp->nm_flag & NFSMNT_RESVPORT)
		CLNT_CONTROL(client, CLSET_PRIVPORT, &one);
	if ((nmp->nm_flag & NFSMNT_SOFT) != 0) {
		if (nmp->nm_sotype == SOCK_DGRAM)
			/*
			 * For UDP, the large timeout for a reconnect will
			 * be set to "nm_retry * nm_timeo / 2", so we only
			 * want to do 2 reconnect timeout retries.
			 */
			retries = 2;
		else
			retries = nmp->nm_retry;
	} else
		retries = INT_MAX;
	CLNT_CONTROL(client, CLSET_RETRIES, &retries);

	/*
	 * For UDP, there are 2 timeouts:
	 * - CLSET_RETRY_TIMEOUT sets the initial timeout for the timer
	 *   that does a retransmit of an RPC request using the same socket
	 *   and xid. This is what you normally want to do, since NFS
	 *   servers depend on "same xid" for their Duplicate Request Cache.
	 * - timeout specified in CLNT_CALL_MBUF(), which specifies when
	 *   retransmits on the same socket should fail and a fresh socket
	 *   created. Each of these timeouts counts as one CLSET_RETRIES,
	 *   as set above.
	 * Set the initial retransmit timeout for UDP. This timeout doesn't
	 * exist for TCP and the following call just fails, which is ok.
	 */
	timo.tv_sec = nmp->nm_timeo / NFS_HZ;
	timo.tv_usec = (nmp->nm_timeo % NFS_HZ) * 1000000 / NFS_HZ;
	CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, &timo);

	mtx_lock(&nmp->nm_mtx);
	if (nmp->nm_client) {
		/*
		 * Someone else already connected.
		 */
		CLNT_RELEASE(client);
	} else
		nmp->nm_client = client;

	/*
	 * Protocols that do not require connections may be optionally left
	 * unconnected for servers that reply from a port other than NFS_PORT.
	 */
	if (!(nmp->nm_flag & NFSMNT_NOCONN)) {
		mtx_unlock(&nmp->nm_mtx);
		CLNT_CONTROL(client, CLSET_CONNECT, &one);
	} else
		mtx_unlock(&nmp->nm_mtx);

	/* Restore current thread's credentials. */
	td->td_ucred = origcred;

	mtx_lock(&nmp->nm_mtx);
	/* Initialize other non-zero congestion variables. */
	nfs_init_rtt(nmp);
	mtx_unlock(&nmp->nm_mtx);
	return (0);
}