summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Ross <Gordon.Ross@Sun.COM>2008-08-28 14:38:39 -0400
committerGordon Ross <Gordon.Ross@Sun.COM>2008-08-28 14:38:39 -0400
commit6723e17f4e092e7f275f0791f9fce3ea061339d7 (patch)
tree719d7b623d4fea1f389221b71f45fec6b979a89e
parent3b3f3420f42655c8a4fd7c5639c36b71ee8f23bd (diff)
downloadillumos-joyent-6723e17f4e092e7f275f0791f9fce3ea061339d7.tar.gz
6676465 smbfs time expired, then smbmount hang
6738417 manual reconnect not possible
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c114
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c9
-rw-r--r--usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c149
3 files changed, 142 insertions, 130 deletions
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
index 7c902eeff0..af3a4a39b2 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c
@@ -31,8 +31,10 @@
*
* $Id: smb_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $
*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
/*
* Connection engine.
@@ -261,6 +263,62 @@ top:
created = 0;
SMB_CO_UNLOCK(&smb_vclist);
+ if (created == 0) {
+ /*
+ * Found an existing VC. Reuse it, but first,
+ * wait for any other thread doing setup, etc.
+ * Note: We hold a reference on the VC.
+ */
+ error = 0;
+ SMB_VC_LOCK(vcp);
+ while (vcp->vc_state < SMBIOD_ST_VCACTIVE) {
+ if (vcp->vc_flags & SMBV_GONE)
+ break;
+ tmo = lbolt + SEC_TO_TICK(2);
+ tmo = cv_timedwait_sig(&vcp->vc_statechg,
+ &vcp->vc_lock, tmo);
+ if (tmo == 0) {
+ error = EINTR;
+ break;
+ }
+ }
+ SMB_VC_UNLOCK(vcp);
+
+ /* Interrupted? */
+ if (error)
+ goto out;
+
+ /*
+ * Was there a vc_kill while we waited?
+ * If so, this VC is gone. Start over.
+ */
+ if (vcp->vc_flags & SMBV_GONE) {
+ smb_vc_rele(vcp);
+ goto top;
+ }
+
+ /*
+ * The possible states here are:
+ * SMBIOD_ST_VCACTIVE, SMBIOD_ST_DEAD
+ *
+ * SMBIOD_ST_VCACTIVE is the normal case,
+ * where found a connection ready to use.
+ *
+ * We may find vc_state == SMBIOD_ST_DEAD
+ * if a previous session has disconnected.
+ * In this case, we'd like to reconnect,
+ * so take over setting up this VC as if
+ * this thread had created it.
+ */
+ SMB_VC_LOCK(vcp);
+ if (vcp->vc_state == SMBIOD_ST_DEAD) {
+ vcp->vc_state = SMBIOD_ST_NOTCONN;
+ created = 1;
+ /* Will signal vc_statechg below */
+ }
+ SMB_VC_UNLOCK(vcp);
+ }
+
if (created) {
/*
* We have a NEW VC, held, but not locked.
@@ -307,47 +365,19 @@ top:
break;
}
- SMB_VC_LOCK(vcp);
- cv_broadcast(&vcp->vc_statechg);
- SMB_VC_UNLOCK(vcp);
-
- } else {
- /*
- * Found an existing VC. Reuse it, but first,
- * wait for authentication to finish, etc.
- * Note: We hold a reference on the VC.
- */
- error = 0;
- SMB_VC_LOCK(vcp);
- while (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
- tmo = lbolt + SEC_TO_TICK(5);
- tmo = cv_timedwait_sig(&vcp->vc_statechg,
- &vcp->vc_lock, tmo);
- if (tmo == 0) {
- error = EINTR;
- break;
- }
- if (vcp->vc_flags & SMBV_GONE)
- break;
- }
- SMB_VC_UNLOCK(vcp);
-
- /* Interrupted? */
- if (error)
- goto out;
-
- /*
- * The other guy failed authentication,
- * or otherwise gave up on this VC.
- * Drop reference, start over.
- */
- if (vcp->vc_flags & SMBV_GONE) {
- smb_vc_rele(vcp);
- goto top;
+ if (error) {
+ /*
+ * Leave the VC in a state that allows the
+ * next open to attempt a new connection.
+ * This call does the cv_broadcast too,
+ * so that's in the else part.
+ */
+ smb_iod_disconnect(vcp);
+ } else {
+ SMB_VC_LOCK(vcp);
+ cv_broadcast(&vcp->vc_statechg);
+ SMB_VC_UNLOCK(vcp);
}
-
- ASSERT(vcp->vc_state == SMBIOD_ST_VCACTIVE);
- /* Success! */
}
out:
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
index a2fc78bd4c..6362d43d83 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c
@@ -37,8 +37,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/param.h>
#include <sys/errno.h>
@@ -905,12 +903,11 @@ nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
/*
* If this dev minor was doing session setup
* and failed to authenticate (or whatever)
- * then we need to "kill" the VC here so any
- * other threads waiting for the VC setup to
- * finish will drop their references.
+ * then we need to put the VC in a state that
+ * allows later commands to try again.
*/
if (sdp->sd_flags & NSMBFL_NEWVC)
- smb_vc_kill(vcp);
+ smb_iod_disconnect(vcp);
smb_vc_rele(vcp);
}
smb_credrele(&scred);
diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
index a285bf6d27..57080029ed 100644
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c
@@ -36,8 +36,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/autoconf.h>
@@ -92,46 +90,6 @@ static int nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
uint8_t *rpcodep, struct proc *p);
static int nb_disconnect(struct nbpcb *nbp);
-static int
-nb_wait_ack(TIUSER *tiptr, t_scalar_t ack_prim, int fmode)
-{
- int msgsz;
- union T_primitives *pptr;
- mblk_t *bp;
- ptrdiff_t diff;
- int error;
-
- /*
- * wait for ack
- */
- bp = NULL;
- if ((error = tli_recv(tiptr, &bp, fmode)) != 0)
- return (error);
-
- diff = MBLKL(bp);
- ASSERT(diff == (ptrdiff_t)((int)diff));
- msgsz = (int)diff;
-
- if (msgsz < sizeof (int)) {
- freemsg(bp);
- return (EPROTO);
- }
-
- /*LINTED*/
- pptr = (union T_primitives *)bp->b_rptr;
- if (pptr->type == ack_prim)
- error = 0; /* Success */
- else if (pptr->type == T_ERROR_ACK) {
- if (pptr->error_ack.TLI_error == TSYSERR)
- error = pptr->error_ack.UNIX_error;
- else
- error = t_tlitosyserr(pptr->error_ack.TLI_error);
- } else
- error = EPROTO;
-
- freemsg(bp);
- return (error);
-}
/*
* Internal set sockopt for int-sized options.
@@ -145,6 +103,7 @@ nb_setsockopt_int(TIUSER *tiptr, int level, int name, int val)
mblk_t *mp;
struct opthdr *opt;
struct T_optmgmt_req *tor;
+ struct T_optmgmt_ack *toa;
int *valp;
int error, mlen;
@@ -178,11 +137,62 @@ nb_setsockopt_int(TIUSER *tiptr, int level, int name, int val)
if ((error = tli_send(tiptr, mp, fmode)) != 0)
return (error);
+ /*
+ * Wait for T_OPTMGMT_ACK
+ */
+ mp = NULL;
fmode = 0; /* need to block */
- error = nb_wait_ack(tiptr, T_OPTMGMT_ACK, fmode);
+ if ((error = tli_recv(tiptr, &mp, fmode)) != 0)
+ return (error);
+ /*LINTED*/
+ toa = (struct T_optmgmt_ack *)mp->b_rptr;
+ if (toa->PRIM_type != T_OPTMGMT_ACK)
+ error = EPROTO;
+ freemsg(mp);
+
return (error);
}
+static void
+nb_setopts(struct nbpcb *nbp)
+{
+ int error;
+ TIUSER *tiptr = NULL;
+
+ tiptr = nbp->nbp_tiptr;
+ if (tiptr == NULL) {
+ NBDEBUG("no tiptr!\n");
+ return;
+ }
+
+ /*
+ * Set various socket/TCP options.
+ * Failures here are not fatal -
+ * just log a complaint.
+ *
+ * We don't need these two:
+ * SO_RCVTIMEO, SO_SNDTIMEO
+ */
+
+ error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_SNDBUF,
+ nbp->nbp_sndbuf);
+ if (error)
+ NBDEBUG("can't set SO_SNDBUF");
+
+ error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_RCVBUF,
+ nbp->nbp_rcvbuf);
+ if (error)
+ NBDEBUG("can't set SO_RCVBUF");
+
+ error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_KEEPALIVE, 1);
+ if (error)
+ NBDEBUG("can't set SO_KEEPALIVE");
+
+ error = nb_setsockopt_int(tiptr, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (error)
+ NBDEBUG("can't set TCP_NODELAY");
+}
+
/*
* Get mblks into *mpp until the data length is at least mlen.
* Note that *mpp may already contain a fragment.
@@ -344,10 +354,9 @@ nb_snddis(TIUSER *tiptr)
if ((error = tli_send(tiptr, mp, fmode)) != 0)
return (error);
-#if 0 /* Now letting the IOD recv this. */
fmode = 0; /* need to block */
- error = nb_wait_ack(tiptr, T_OK_ACK, fmode);
-#endif
+ error = get_ok_ack(tiptr, T_OK_ACK, fmode);
+
return (error);
}
@@ -478,33 +487,6 @@ nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct proc *p)
if (nbp->nbp_flags & NBF_CONNECTED)
return (EISCONN);
- /*
- * Set various socket/TCP options.
- * Failures here are not fatal -
- * just log a complaint.
- *
- * We don't need these two:
- * SO_RCVTIMEO, SO_SNDTIMEO
- */
-
- error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_SNDBUF,
- nbp->nbp_sndbuf);
- if (error)
- NBDEBUG("nb_connect_in: set SO_SNDBUF");
-
- error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_RCVBUF,
- nbp->nbp_rcvbuf);
- if (error)
- NBDEBUG("nb_connect_in: set SO_RCVBUF");
-
- error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_KEEPALIVE, 1);
- if (error)
- NBDEBUG("nb_connect_in: set SO_KEEPALIVE");
-
- error = nb_setsockopt_int(tiptr, IPPROTO_TCP, TCP_NODELAY, 1);
- if (error)
- NBDEBUG("nb_connect_in: set TCP_NODELAY");
-
/* Do local bind (any address) */
if ((error = t_kbind(tiptr, NULL, NULL)) != 0) {
NBDEBUG("nb_connect_in: bind local");
@@ -525,12 +507,6 @@ nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct proc *p)
error = t_kconnect(tiptr, &call, NULL);
if (error) {
NBDEBUG("nb_connect_in: connect %d error", error);
- /*
- * XXX: t_kconnect returning EPROTO here instead of ETIMEDOUT
- * here. Temporarily return ETIMEDOUT error if we get EPROTO.
- */
- if (error == EPROTO)
- error = ETIMEDOUT;
} else {
mutex_enter(&nbp->nbp_lock);
nbp->nbp_flags |= NBF_CONNECTED;
@@ -853,6 +829,9 @@ smb_nbst_create(struct smb_vc *vcp, struct proc *p)
nbp->nbp_rcvbuf = smb_tcprcvbuf;
mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
vcp->vc_tdata = nbp;
+
+ nb_setopts(nbp);
+
return (0);
}
@@ -895,8 +874,10 @@ smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
NBDEBUG("\n");
error = EINVAL;
- if (nbp->nbp_flags & NBF_LOCADDR)
- goto out;
+ /*
+ * Allow repeated bind calls on one endpoint.
+ * This happens with reconnect.
+ */
/*
* Null name is an "anonymous" (NULL) bind request.
@@ -913,6 +894,8 @@ smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
goto out;
}
mutex_enter(&nbp->nbp_lock);
+ if (nbp->nbp_laddr)
+ smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
nbp->nbp_laddr = snb;
nbp->nbp_flags |= NBF_LOCADDR;
mutex_exit(&nbp->nbp_lock);
@@ -1028,8 +1011,10 @@ nb_disconnect(struct nbpcb *nbp)
}
mutex_exit(&nbp->nbp_lock);
- if (save_flags & NBF_CONNECTED)
+ if (save_flags & NBF_CONNECTED) {
nb_snddis(tiptr);
+ (void) t_kunbind(tiptr);
+ }
if (nbp->nbp_state != NBST_RETARGET) {
nbp->nbp_state = NBST_CLOSED; /* really IDLE */