smb_iod.c revision 97209
175374Sbp/* 275374Sbp * Copyright (c) 2000-2001 Boris Popov 375374Sbp * All rights reserved. 475374Sbp * 575374Sbp * Redistribution and use in source and binary forms, with or without 675374Sbp * modification, are permitted provided that the following conditions 775374Sbp * are met: 875374Sbp * 1. Redistributions of source code must retain the above copyright 975374Sbp * notice, this list of conditions and the following disclaimer. 1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright 1175374Sbp * notice, this list of conditions and the following disclaimer in the 1275374Sbp * documentation and/or other materials provided with the distribution. 1375374Sbp * 3. All advertising materials mentioning features or use of this software 1475374Sbp * must display the following acknowledgement: 1575374Sbp * This product includes software developed by Boris Popov. 1675374Sbp * 4. Neither the name of the author nor the names of any co-contributors 1775374Sbp * may be used to endorse or promote products derived from this software 1875374Sbp * without specific prior written permission. 1975374Sbp * 2075374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2175374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2275374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2375374Sbp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2475374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2575374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2675374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2775374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2875374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2975374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3075374Sbp * SUCH DAMAGE. 3175374Sbp * 3275374Sbp * $FreeBSD: head/sys/netsmb/smb_iod.c 97209 2002-05-24 05:40:51Z peter $ 3375374Sbp */ 3475374Sbp 3575374Sbp#include <sys/param.h> 3675374Sbp#include <sys/systm.h> 3795533Smike#include <sys/endian.h> 3875374Sbp#include <sys/proc.h> 3975374Sbp#include <sys/kernel.h> 4075374Sbp#include <sys/kthread.h> 4175374Sbp#include <sys/malloc.h> 4275374Sbp#include <sys/mbuf.h> 4375374Sbp#include <sys/unistd.h> 4475374Sbp 4575374Sbp#include <netsmb/smb.h> 4675374Sbp#include <netsmb/smb_conn.h> 4775374Sbp#include <netsmb/smb_rq.h> 4875374Sbp#include <netsmb/smb_tran.h> 4975374Sbp#include <netsmb/smb_trantcp.h> 5075374Sbp 5175374Sbp 5275374Sbp#define SMBIOD_SLEEP_TIMO 2 5375374Sbp#define SMBIOD_PING_TIMO 60 /* seconds */ 5475374Sbp 5575374Sbp#define SMB_IOD_EVLOCKPTR(iod) (&((iod)->iod_evlock)) 5675374Sbp#define SMB_IOD_EVLOCK(iod) smb_sl_lock(&((iod)->iod_evlock)) 5775374Sbp#define SMB_IOD_EVUNLOCK(iod) smb_sl_unlock(&((iod)->iod_evlock)) 5875374Sbp 5975374Sbp#define SMB_IOD_RQLOCKPTR(iod) (&((iod)->iod_rqlock)) 6075374Sbp#define SMB_IOD_RQLOCK(iod) smb_sl_lock(&((iod)->iod_rqlock)) 6175374Sbp#define SMB_IOD_RQUNLOCK(iod) smb_sl_unlock(&((iod)->iod_rqlock)) 6275374Sbp 6375374Sbp#define smb_iod_wakeup(iod) wakeup(&(iod)->iod_flags) 6475374Sbp 6575374Sbp 6675374Sbpstatic MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon"); 6775374Sbp 6875374Sbpstatic int smb_iod_next; 6975374Sbp 7075374Sbpstatic int smb_iod_sendall(struct smbiod *iod); 7175374Sbpstatic int smb_iod_disconnect(struct smbiod *iod); 7275374Sbpstatic void smb_iod_thread(void *); 7375374Sbp 7475374Sbpstatic __inline void 7575374Sbpsmb_iod_rqprocessed(struct smb_rq *rqp, int error) 7675374Sbp{ 7775374Sbp SMBRQ_SLOCK(rqp); 7875374Sbp rqp->sr_lerror = error; 7975374Sbp rqp->sr_rpgen++; 8075374Sbp rqp->sr_state = SMBRQ_NOTIFIED; 8175374Sbp wakeup(&rqp->sr_state); 8275374Sbp SMBRQ_SUNLOCK(rqp); 8375374Sbp} 8475374Sbp 8575374Sbpstatic void 8675374Sbpsmb_iod_invrq(struct smbiod *iod) 8775374Sbp{ 8875374Sbp struct smb_rq *rqp; 8975374Sbp 9075374Sbp /* 9182045Sbp * Invalidate all outstanding requests for this connection 9275374Sbp */ 9375374Sbp SMB_IOD_RQLOCK(iod); 9475374Sbp TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 9575374Sbp if (rqp->sr_flags & SMBR_INTERNAL) 9675374Sbp SMBRQ_SUNLOCK(rqp); 9775374Sbp rqp->sr_flags |= SMBR_RESTART; 9875374Sbp smb_iod_rqprocessed(rqp, ENOTCONN); 9975374Sbp } 10075374Sbp SMB_IOD_RQUNLOCK(iod); 10175374Sbp} 10275374Sbp 10375374Sbpstatic void 10475374Sbpsmb_iod_closetran(struct smbiod *iod) 10575374Sbp{ 10675374Sbp struct smb_vc *vcp = iod->iod_vc; 10787192Sbp struct thread *td = iod->iod_td; 10875374Sbp 10975374Sbp if (vcp->vc_tdata == NULL) 11075374Sbp return; 11187192Sbp SMB_TRAN_DISCONNECT(vcp, td); 11287192Sbp SMB_TRAN_DONE(vcp, td); 11375374Sbp vcp->vc_tdata = NULL; 11475374Sbp} 11575374Sbp 11675374Sbpstatic void 11775374Sbpsmb_iod_dead(struct smbiod *iod) 11875374Sbp{ 11975374Sbp iod->iod_state = SMBIOD_ST_DEAD; 12075374Sbp smb_iod_closetran(iod); 12175374Sbp smb_iod_invrq(iod); 12275374Sbp} 12375374Sbp 12475374Sbpstatic int 12575374Sbpsmb_iod_connect(struct smbiod *iod) 12675374Sbp{ 12775374Sbp struct smb_vc *vcp = iod->iod_vc; 12887192Sbp struct thread *td = iod->iod_td; 12975374Sbp int error; 13075374Sbp 13175374Sbp SMBIODEBUG("%d\n", iod->iod_state); 13275374Sbp switch(iod->iod_state) { 13375374Sbp case SMBIOD_ST_VCACTIVE: 13475374Sbp SMBERROR("called for already opened connection\n"); 13575374Sbp return EISCONN; 13675374Sbp case SMBIOD_ST_DEAD: 13775374Sbp return ENOTCONN; /* XXX: last error code ? */ 13875374Sbp default: 13975374Sbp break; 14075374Sbp } 14175374Sbp vcp->vc_genid++; 14275374Sbp error = 0; 14375374Sbp itry { 14487192Sbp ithrow(SMB_TRAN_CREATE(vcp, td)); 14575374Sbp SMBIODEBUG("tcreate\n"); 14675374Sbp if (vcp->vc_laddr) { 14787192Sbp ithrow(SMB_TRAN_BIND(vcp, vcp->vc_laddr, td)); 14875374Sbp } 14975374Sbp SMBIODEBUG("tbind\n"); 15087192Sbp ithrow(SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td)); 15175374Sbp SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags); 15275374Sbp iod->iod_state = SMBIOD_ST_TRANACTIVE; 15375374Sbp SMBIODEBUG("tconnect\n"); 15475374Sbp/* vcp->vc_mid = 0;*/ 15575374Sbp ithrow(smb_smb_negotiate(vcp, &iod->iod_scred)); 15675374Sbp SMBIODEBUG("snegotiate\n"); 15775374Sbp ithrow(smb_smb_ssnsetup(vcp, &iod->iod_scred)); 15875374Sbp iod->iod_state = SMBIOD_ST_VCACTIVE; 15975374Sbp SMBIODEBUG("completed\n"); 16075374Sbp smb_iod_invrq(iod); 16175374Sbp } icatch(error) { 16275374Sbp smb_iod_dead(iod); 16375374Sbp } ifinally { 16475374Sbp } iendtry; 16575374Sbp return error; 16675374Sbp} 16775374Sbp 16875374Sbpstatic int 16975374Sbpsmb_iod_disconnect(struct smbiod *iod) 17075374Sbp{ 17175374Sbp struct smb_vc *vcp = iod->iod_vc; 17275374Sbp 17375374Sbp SMBIODEBUG("\n"); 17475374Sbp if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 17575374Sbp smb_smb_ssnclose(vcp, &iod->iod_scred); 17675374Sbp iod->iod_state = SMBIOD_ST_TRANACTIVE; 17775374Sbp } 17875374Sbp vcp->vc_smbuid = SMB_UID_UNKNOWN; 17975374Sbp smb_iod_closetran(iod); 18075374Sbp iod->iod_state = SMBIOD_ST_NOTCONN; 18175374Sbp return 0; 18275374Sbp} 18375374Sbp 18475374Sbpstatic int 18575374Sbpsmb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp) 18675374Sbp{ 18775374Sbp int error; 18875374Sbp 18975374Sbp if (iod->iod_state != SMBIOD_ST_VCACTIVE) { 19075374Sbp if (iod->iod_state != SMBIOD_ST_DEAD) 19175374Sbp return ENOTCONN; 19275374Sbp iod->iod_state = SMBIOD_ST_RECONNECT; 19375374Sbp error = smb_iod_connect(iod); 19475374Sbp if (error) 19575374Sbp return error; 19675374Sbp } 19775374Sbp SMBIODEBUG("tree reconnect\n"); 19875374Sbp SMBS_ST_LOCK(ssp); 19975374Sbp ssp->ss_flags |= SMBS_RECONNECTING; 20075374Sbp SMBS_ST_UNLOCK(ssp); 20175374Sbp error = smb_smb_treeconnect(ssp, &iod->iod_scred); 20275374Sbp SMBS_ST_LOCK(ssp); 20375374Sbp ssp->ss_flags &= ~SMBS_RECONNECTING; 20475374Sbp SMBS_ST_UNLOCK(ssp); 20575374Sbp wakeup(&ssp->ss_vcgenid); 20675374Sbp return error; 20775374Sbp} 20875374Sbp 20975374Sbpstatic int 21075374Sbpsmb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp) 21175374Sbp{ 21287192Sbp struct thread *td = iod->iod_td; 21375374Sbp struct smb_vc *vcp = iod->iod_vc; 21475374Sbp struct smb_share *ssp = rqp->sr_share; 21575374Sbp struct mbuf *m; 21675374Sbp int error; 21775374Sbp 21875374Sbp SMBIODEBUG("iod_state = %d\n", iod->iod_state); 21975374Sbp switch (iod->iod_state) { 22075374Sbp case SMBIOD_ST_NOTCONN: 22175374Sbp smb_iod_rqprocessed(rqp, ENOTCONN); 22275374Sbp return 0; 22375374Sbp case SMBIOD_ST_DEAD: 22475374Sbp iod->iod_state = SMBIOD_ST_RECONNECT; 22575374Sbp return 0; 22675374Sbp case SMBIOD_ST_RECONNECT: 22775374Sbp return 0; 22875374Sbp default: 22975374Sbp break; 23075374Sbp } 23175374Sbp if (rqp->sr_sendcnt == 0) { 23275374Sbp#ifdef movedtoanotherplace 23375374Sbp if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux) 23475374Sbp return 0; 23575374Sbp#endif 23675374Sbp *rqp->sr_rqtid = htoles(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN); 23775374Sbp *rqp->sr_rquid = htoles(vcp ? vcp->vc_smbuid : 0); 23875374Sbp mb_fixhdr(&rqp->sr_rq); 23975374Sbp } 24075374Sbp if (rqp->sr_sendcnt++ > 5) { 24175374Sbp rqp->sr_flags |= SMBR_RESTART; 24275374Sbp smb_iod_rqprocessed(rqp, rqp->sr_lerror); 24375374Sbp /* 24475374Sbp * If all attempts to send a request failed, then 24575374Sbp * something is seriously hosed. 24675374Sbp */ 24775374Sbp return ENOTCONN; 24875374Sbp } 24975374Sbp SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0); 25075374Sbp m_dumpm(rqp->sr_rq.mb_top); 25187565Sarr m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_TRYWAIT); 25287192Sbp error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, td) : ENOBUFS; 25375374Sbp if (error == 0) { 25475374Sbp getnanotime(&rqp->sr_timesent); 25575374Sbp iod->iod_lastrqsent = rqp->sr_timesent; 25675374Sbp rqp->sr_flags |= SMBR_SENT; 25775374Sbp rqp->sr_state = SMBRQ_SENT; 25875374Sbp return 0; 25975374Sbp } 26075374Sbp /* 26175374Sbp * Check for fatal errors 26275374Sbp */ 26375374Sbp if (SMB_TRAN_FATAL(vcp, error)) { 26475374Sbp /* 26575374Sbp * No further attempts should be made 26675374Sbp */ 26775374Sbp return ENOTCONN; 26875374Sbp } 26975374Sbp if (smb_rq_intr(rqp)) 27075374Sbp smb_iod_rqprocessed(rqp, EINTR); 27175374Sbp return 0; 27275374Sbp} 27375374Sbp 27475374Sbp/* 27575374Sbp * Process incoming packets 27675374Sbp */ 27775374Sbpstatic int 27875374Sbpsmb_iod_recvall(struct smbiod *iod) 27975374Sbp{ 28075374Sbp struct smb_vc *vcp = iod->iod_vc; 28187192Sbp struct thread *td = iod->iod_td; 28275374Sbp struct smb_rq *rqp; 28375374Sbp struct mbuf *m; 28475374Sbp u_char *hp; 28575374Sbp u_short mid; 28675374Sbp int error; 28775374Sbp 28875374Sbp switch (iod->iod_state) { 28975374Sbp case SMBIOD_ST_NOTCONN: 29075374Sbp case SMBIOD_ST_DEAD: 29175374Sbp case SMBIOD_ST_RECONNECT: 29275374Sbp return 0; 29375374Sbp default: 29475374Sbp break; 29575374Sbp } 29675374Sbp for (;;) { 29775374Sbp m = NULL; 29887192Sbp error = SMB_TRAN_RECV(vcp, &m, td); 29975374Sbp if (error == EWOULDBLOCK) 30075374Sbp break; 30175374Sbp if (SMB_TRAN_FATAL(vcp, error)) { 30275374Sbp smb_iod_dead(iod); 30375374Sbp break; 30475374Sbp } 30575374Sbp if (error) 30675374Sbp break; 30775374Sbp if (m == NULL) { 30875374Sbp SMBERROR("tran return NULL without error\n"); 30975374Sbp error = EPIPE; 31075374Sbp continue; 31175374Sbp } 31275374Sbp m = m_pullup(m, SMB_HDRLEN); 31375374Sbp if (m == NULL) 31475374Sbp continue; /* wait for a good packet */ 31575374Sbp /* 31675374Sbp * Now we got an entire and possibly invalid SMB packet. 31775374Sbp * Be careful while parsing it. 31875374Sbp */ 31975374Sbp m_dumpm(m); 32075374Sbp hp = mtod(m, u_char*); 32175374Sbp if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) { 32275374Sbp m_freem(m); 32375374Sbp continue; 32475374Sbp } 32575374Sbp mid = SMB_HDRMID(hp); 32675374Sbp SMBSDEBUG("mid %04x\n", (u_int)mid); 32775374Sbp SMB_IOD_RQLOCK(iod); 32875374Sbp TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 32975374Sbp if (rqp->sr_mid != mid) 33075374Sbp continue; 33175374Sbp SMBRQ_SLOCK(rqp); 33275374Sbp if (rqp->sr_rp.md_top == NULL) { 33375374Sbp md_initm(&rqp->sr_rp, m); 33475374Sbp } else { 33575374Sbp if (rqp->sr_flags & SMBR_MULTIPACKET) { 33675374Sbp md_append_record(&rqp->sr_rp, m); 33775374Sbp } else { 33875374Sbp SMBRQ_SUNLOCK(rqp); 33975374Sbp SMBERROR("duplicate response %d (ignored)\n", mid); 34075374Sbp break; 34175374Sbp } 34275374Sbp } 34375374Sbp SMBRQ_SUNLOCK(rqp); 34475374Sbp smb_iod_rqprocessed(rqp, 0); 34575374Sbp break; 34675374Sbp } 34775374Sbp SMB_IOD_RQUNLOCK(iod); 34875374Sbp if (rqp == NULL) { 34975374Sbp SMBERROR("drop resp with mid %d\n", (u_int)mid); 35075374Sbp/* smb_printrqlist(vcp);*/ 35175374Sbp m_freem(m); 35275374Sbp } 35375374Sbp } 35475374Sbp /* 35575374Sbp * check for interrupts 35675374Sbp */ 35775374Sbp SMB_IOD_RQLOCK(iod); 35875374Sbp TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 35987192Sbp if (smb_proc_intr(rqp->sr_cred->scr_td->td_proc)) { 36075374Sbp smb_iod_rqprocessed(rqp, EINTR); 36175374Sbp } 36275374Sbp } 36375374Sbp SMB_IOD_RQUNLOCK(iod); 36475374Sbp return 0; 36575374Sbp} 36675374Sbp 36775374Sbpint 36875374Sbpsmb_iod_request(struct smbiod *iod, int event, void *ident) 36975374Sbp{ 37075374Sbp struct smbiod_event *evp; 37175374Sbp int error; 37275374Sbp 37375374Sbp SMBIODEBUG("\n"); 37475374Sbp evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK); 37575374Sbp evp->ev_type = event; 37675374Sbp evp->ev_ident = ident; 37775374Sbp SMB_IOD_EVLOCK(iod); 37875374Sbp STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link); 37975374Sbp if ((event & SMBIOD_EV_SYNC) == 0) { 38075374Sbp SMB_IOD_EVUNLOCK(iod); 38175374Sbp smb_iod_wakeup(iod); 38275374Sbp return 0; 38375374Sbp } 38475374Sbp smb_iod_wakeup(iod); 38575374Sbp msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0); 38675374Sbp error = evp->ev_error; 38775374Sbp free(evp, M_SMBIOD); 38875374Sbp return error; 38975374Sbp} 39075374Sbp 39175374Sbp/* 39275374Sbp * Place request in the queue. 39375374Sbp * Request from smbiod have a high priority. 39475374Sbp */ 39575374Sbpint 39675374Sbpsmb_iod_addrq(struct smb_rq *rqp) 39775374Sbp{ 39875374Sbp struct smb_vc *vcp = rqp->sr_vc; 39975374Sbp struct smbiod *iod = vcp->vc_iod; 40075374Sbp int error; 40175374Sbp 40275374Sbp SMBIODEBUG("\n"); 40387192Sbp if (rqp->sr_cred->scr_td->td_proc == iod->iod_p) { 40475374Sbp rqp->sr_flags |= SMBR_INTERNAL; 40575374Sbp SMB_IOD_RQLOCK(iod); 40675374Sbp TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link); 40775374Sbp SMB_IOD_RQUNLOCK(iod); 40875374Sbp for (;;) { 40975374Sbp if (smb_iod_sendrq(iod, rqp) != 0) { 41075374Sbp smb_iod_dead(iod); 41175374Sbp break; 41275374Sbp } 41375374Sbp /* 41475374Sbp * we don't need to lock state field here 41575374Sbp */ 41675374Sbp if (rqp->sr_state != SMBRQ_NOTSENT) 41775374Sbp break; 41875374Sbp tsleep(&iod->iod_flags, PWAIT, "90sndw", hz); 41975374Sbp } 42075374Sbp if (rqp->sr_lerror) 42175374Sbp smb_iod_removerq(rqp); 42275374Sbp return rqp->sr_lerror; 42375374Sbp } 42475374Sbp 42575374Sbp switch (iod->iod_state) { 42675374Sbp case SMBIOD_ST_NOTCONN: 42775374Sbp return ENOTCONN; 42875374Sbp case SMBIOD_ST_DEAD: 42975374Sbp error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL); 43075374Sbp if (error) 43175374Sbp return error; 43275374Sbp return EXDEV; 43375374Sbp default: 43475374Sbp break; 43575374Sbp } 43675374Sbp 43775374Sbp SMB_IOD_RQLOCK(iod); 43875374Sbp for (;;) { 43975374Sbp if (vcp->vc_maxmux == 0) { 44075374Sbp SMBERROR("maxmux == 0\n"); 44175374Sbp break; 44275374Sbp } 44375374Sbp if (iod->iod_muxcnt < vcp->vc_maxmux) 44475374Sbp break; 44575374Sbp iod->iod_muxwant++; 44675374Sbp msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod), 44775374Sbp PWAIT, "90mux", 0); 44875374Sbp } 44975374Sbp iod->iod_muxcnt++; 45075374Sbp TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 45175374Sbp SMB_IOD_RQUNLOCK(iod); 45275374Sbp smb_iod_wakeup(iod); 45375374Sbp return 0; 45475374Sbp} 45575374Sbp 45675374Sbpint 45775374Sbpsmb_iod_removerq(struct smb_rq *rqp) 45875374Sbp{ 45975374Sbp struct smb_vc *vcp = rqp->sr_vc; 46075374Sbp struct smbiod *iod = vcp->vc_iod; 46175374Sbp 46275374Sbp SMBIODEBUG("\n"); 46375374Sbp if (rqp->sr_flags & SMBR_INTERNAL) { 46475374Sbp SMB_IOD_RQLOCK(iod); 46575374Sbp TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 46675374Sbp SMB_IOD_RQUNLOCK(iod); 46775374Sbp return 0; 46875374Sbp } 46975374Sbp SMB_IOD_RQLOCK(iod); 47075374Sbp while (rqp->sr_flags & SMBR_XLOCK) { 47175374Sbp rqp->sr_flags |= SMBR_XLOCKWANT; 47275374Sbp msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0); 47375374Sbp } 47475374Sbp TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 47575374Sbp iod->iod_muxcnt--; 47675374Sbp if (iod->iod_muxwant) { 47775374Sbp iod->iod_muxwant--; 47875374Sbp wakeup(&iod->iod_muxwant); 47975374Sbp } 48075374Sbp SMB_IOD_RQUNLOCK(iod); 48175374Sbp return 0; 48275374Sbp} 48375374Sbp 48475374Sbpint 48575374Sbpsmb_iod_waitrq(struct smb_rq *rqp) 48675374Sbp{ 48775374Sbp struct smbiod *iod = rqp->sr_vc->vc_iod; 48875374Sbp int error; 48975374Sbp 49075374Sbp SMBIODEBUG("\n"); 49175374Sbp if (rqp->sr_flags & SMBR_INTERNAL) { 49275374Sbp for (;;) { 49375374Sbp smb_iod_sendall(iod); 49475374Sbp smb_iod_recvall(iod); 49575374Sbp if (rqp->sr_rpgen != rqp->sr_rplast) 49675374Sbp break; 49775374Sbp tsleep(&iod->iod_flags, PWAIT, "90irq", hz); 49875374Sbp } 49975374Sbp smb_iod_removerq(rqp); 50075374Sbp return rqp->sr_lerror; 50175374Sbp 50275374Sbp } 50375374Sbp SMBRQ_SLOCK(rqp); 50475374Sbp if (rqp->sr_rpgen == rqp->sr_rplast) 50575374Sbp msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0); 50675374Sbp rqp->sr_rplast++; 50775374Sbp SMBRQ_SUNLOCK(rqp); 50875374Sbp error = rqp->sr_lerror; 50975374Sbp if (rqp->sr_flags & SMBR_MULTIPACKET) { 51075374Sbp /* 51175374Sbp * If request should stay in the list, then reinsert it 51275374Sbp * at the end of queue so other waiters have chance to concur 51375374Sbp */ 51475374Sbp SMB_IOD_RQLOCK(iod); 51575374Sbp TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 51675374Sbp TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 51775374Sbp SMB_IOD_RQUNLOCK(iod); 51875374Sbp } else 51975374Sbp smb_iod_removerq(rqp); 52075374Sbp return error; 52175374Sbp} 52275374Sbp 52375374Sbp 52475374Sbpstatic int 52575374Sbpsmb_iod_sendall(struct smbiod *iod) 52675374Sbp{ 52775374Sbp struct smb_vc *vcp = iod->iod_vc; 52875374Sbp struct smb_rq *rqp; 52975374Sbp struct timespec ts, tstimeout; 53075374Sbp int herror; 53175374Sbp 53275374Sbp herror = 0; 53375374Sbp /* 53475374Sbp * Loop through the list of requests and send them if possible 53575374Sbp */ 53675374Sbp SMB_IOD_RQLOCK(iod); 53775374Sbp TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 53875374Sbp switch (rqp->sr_state) { 53975374Sbp case SMBRQ_NOTSENT: 54075374Sbp rqp->sr_flags |= SMBR_XLOCK; 54175374Sbp SMB_IOD_RQUNLOCK(iod); 54275374Sbp herror = smb_iod_sendrq(iod, rqp); 54375374Sbp SMB_IOD_RQLOCK(iod); 54475374Sbp rqp->sr_flags &= ~SMBR_XLOCK; 54575374Sbp if (rqp->sr_flags & SMBR_XLOCKWANT) { 54675374Sbp rqp->sr_flags &= ~SMBR_XLOCKWANT; 54775374Sbp wakeup(rqp); 54875374Sbp } 54975374Sbp break; 55075374Sbp case SMBRQ_SENT: 55175374Sbp SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout); 55275374Sbp timespecadd(&tstimeout, &tstimeout); 55375374Sbp getnanotime(&ts); 55475374Sbp timespecsub(&ts, &tstimeout); 55575374Sbp if (timespeccmp(&ts, &rqp->sr_timesent, >)) { 55675374Sbp smb_iod_rqprocessed(rqp, ETIMEDOUT); 55775374Sbp } 55875374Sbp break; 55975374Sbp default: 56097209Speter break; 56175374Sbp } 56275374Sbp if (herror) 56375374Sbp break; 56475374Sbp } 56575374Sbp SMB_IOD_RQUNLOCK(iod); 56675374Sbp if (herror == ENOTCONN) 56775374Sbp smb_iod_dead(iod); 56875374Sbp return 0; 56975374Sbp} 57075374Sbp 57175374Sbp/* 57275374Sbp * "main" function for smbiod daemon 57375374Sbp */ 57475374Sbpstatic __inline void 57575374Sbpsmb_iod_main(struct smbiod *iod) 57675374Sbp{ 57775374Sbp/* struct smb_vc *vcp = iod->iod_vc;*/ 57875374Sbp struct smbiod_event *evp; 57975374Sbp/* struct timespec tsnow;*/ 58075374Sbp int error; 58175374Sbp 58275374Sbp SMBIODEBUG("\n"); 58375374Sbp error = 0; 58475374Sbp 58575374Sbp /* 58675374Sbp * Check all interesting events 58775374Sbp */ 58875374Sbp for (;;) { 58975374Sbp SMB_IOD_EVLOCK(iod); 59075374Sbp evp = STAILQ_FIRST(&iod->iod_evlist); 59175374Sbp if (evp == NULL) { 59275374Sbp SMB_IOD_EVUNLOCK(iod); 59375374Sbp break; 59475374Sbp } 59575374Sbp STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link); 59675374Sbp evp->ev_type |= SMBIOD_EV_PROCESSING; 59775374Sbp SMB_IOD_EVUNLOCK(iod); 59875374Sbp switch (evp->ev_type & SMBIOD_EV_MASK) { 59975374Sbp case SMBIOD_EV_CONNECT: 60075374Sbp iod->iod_state = SMBIOD_ST_RECONNECT; 60175374Sbp evp->ev_error = smb_iod_connect(iod); 60275374Sbp break; 60375374Sbp case SMBIOD_EV_DISCONNECT: 60475374Sbp evp->ev_error = smb_iod_disconnect(iod); 60575374Sbp break; 60675374Sbp case SMBIOD_EV_TREECONNECT: 60775374Sbp evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident); 60875374Sbp break; 60975374Sbp case SMBIOD_EV_SHUTDOWN: 61075374Sbp iod->iod_flags |= SMBIOD_SHUTDOWN; 61175374Sbp break; 61275374Sbp case SMBIOD_EV_NEWRQ: 61375374Sbp break; 61475374Sbp } 61575374Sbp if (evp->ev_type & SMBIOD_EV_SYNC) { 61675374Sbp SMB_IOD_EVLOCK(iod); 61775374Sbp wakeup(evp); 61875374Sbp SMB_IOD_EVUNLOCK(iod); 61975374Sbp } else 62075374Sbp free(evp, M_SMBIOD); 62175374Sbp } 62275374Sbp#if 0 62375374Sbp if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 62475374Sbp getnanotime(&tsnow); 62575374Sbp timespecsub(&tsnow, &iod->iod_pingtimo); 62675374Sbp if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) { 62775374Sbp smb_smb_echo(vcp, &iod->iod_scred); 62875374Sbp } 62975374Sbp } 63075374Sbp#endif 63175374Sbp smb_iod_sendall(iod); 63275374Sbp smb_iod_recvall(iod); 63375374Sbp return; 63475374Sbp} 63575374Sbp 63675374Sbpvoid 63775374Sbpsmb_iod_thread(void *arg) 63875374Sbp{ 63975374Sbp struct smbiod *iod = arg; 64075374Sbp 64175374Sbp mtx_lock(&Giant); 64287192Sbp /* 64387192Sbp * Here we assume that the thread structure will be the same 64487192Sbp * for an entire kthread (kproc, to be more precise) life. 64587192Sbp */ 64687192Sbp iod->iod_td = curthread; 64787192Sbp smb_makescred(&iod->iod_scred, iod->iod_td, NULL); 64875374Sbp while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) { 64975374Sbp smb_iod_main(iod); 65075374Sbp SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo); 65175374Sbp/* mtx_unlock(&Giant, MTX_DEF);*/ 65275374Sbp if (iod->iod_flags & SMBIOD_SHUTDOWN) 65375374Sbp break; 65475374Sbp tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo); 65575374Sbp } 65675374Sbp/* mtx_lock(&Giant, MTX_DEF);*/ 65775374Sbp kthread_exit(0); 65875374Sbp} 65975374Sbp 66075374Sbpint 66175374Sbpsmb_iod_create(struct smb_vc *vcp) 66275374Sbp{ 66375374Sbp struct smbiod *iod; 66475374Sbp int error; 66575374Sbp 66675374Sbp iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK); 66775374Sbp iod->iod_id = smb_iod_next++; 66875374Sbp iod->iod_state = SMBIOD_ST_NOTCONN; 66975374Sbp iod->iod_vc = vcp; 67075374Sbp iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO; 67175374Sbp iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO; 67275374Sbp getnanotime(&iod->iod_lastrqsent); 67375374Sbp vcp->vc_iod = iod; 67475374Sbp smb_sl_init(&iod->iod_rqlock, "90rql"); 67575374Sbp TAILQ_INIT(&iod->iod_rqlist); 67675374Sbp smb_sl_init(&iod->iod_evlock, "90evl"); 67775374Sbp STAILQ_INIT(&iod->iod_evlist); 67887192Sbp error = kthread_create(smb_iod_thread, iod, &iod->iod_p, 67975374Sbp RFNOWAIT, "smbiod%d", iod->iod_id); 68075374Sbp if (error) { 68175374Sbp SMBERROR("can't start smbiod: %d", error); 68275374Sbp free(iod, M_SMBIOD); 68375374Sbp return error; 68475374Sbp } 68575374Sbp return 0; 68675374Sbp} 68775374Sbp 68875374Sbpint 68975374Sbpsmb_iod_destroy(struct smbiod *iod) 69075374Sbp{ 69175374Sbp smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL); 69282045Sbp smb_sl_destroy(&iod->iod_rqlock); 69382045Sbp smb_sl_destroy(&iod->iod_evlock); 69475374Sbp free(iod, M_SMBIOD); 69575374Sbp return 0; 69675374Sbp} 69775374Sbp 69875374Sbpint 69975374Sbpsmb_iod_init(void) 70075374Sbp{ 70175374Sbp return 0; 70275374Sbp} 70375374Sbp 70475374Sbpint 70575374Sbpsmb_iod_done(void) 70675374Sbp{ 70775374Sbp return 0; 70875374Sbp} 70975374Sbp 710