diff options
| author | Gordon Ross <Gordon.Ross@Sun.COM> | 2008-08-28 14:38:39 -0400 |
|---|---|---|
| committer | Gordon Ross <Gordon.Ross@Sun.COM> | 2008-08-28 14:38:39 -0400 |
| commit | 6723e17f4e092e7f275f0791f9fce3ea061339d7 (patch) | |
| tree | 719d7b623d4fea1f389221b71f45fec6b979a89e | |
| parent | 3b3f3420f42655c8a4fd7c5639c36b71ee8f23bd (diff) | |
| download | illumos-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.c | 114 | ||||
| -rw-r--r-- | usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c | 9 | ||||
| -rw-r--r-- | usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c | 149 |
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 */ |
