smb_iod.c revision 119376
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 */ 32116189Sobrien 33116189Sobrien#include <sys/cdefs.h> 34116189Sobrien__FBSDID("$FreeBSD: head/sys/netsmb/smb_iod.c 119376 2003-08-23 21:43:33Z marcel $"); 3575374Sbp 3675374Sbp#include <sys/param.h> 3775374Sbp#include <sys/systm.h> 3895533Smike#include <sys/endian.h> 3975374Sbp#include <sys/proc.h> 4075374Sbp#include <sys/kernel.h> 4175374Sbp#include <sys/kthread.h> 4275374Sbp#include <sys/malloc.h> 4375374Sbp#include <sys/mbuf.h> 4475374Sbp#include <sys/unistd.h> 4575374Sbp 4675374Sbp#include <netsmb/smb.h> 4775374Sbp#include <netsmb/smb_conn.h> 4875374Sbp#include <netsmb/smb_rq.h> 4975374Sbp#include <netsmb/smb_tran.h> 5075374Sbp#include <netsmb/smb_trantcp.h> 5175374Sbp 5275374Sbp 5375374Sbp#define SMBIOD_SLEEP_TIMO 2 5475374Sbp#define SMBIOD_PING_TIMO 60 /* seconds */ 5575374Sbp 5675374Sbp#define SMB_IOD_EVLOCKPTR(iod) (&((iod)->iod_evlock)) 5775374Sbp#define SMB_IOD_EVLOCK(iod) smb_sl_lock(&((iod)->iod_evlock)) 5875374Sbp#define SMB_IOD_EVUNLOCK(iod) smb_sl_unlock(&((iod)->iod_evlock)) 5975374Sbp 6075374Sbp#define SMB_IOD_RQLOCKPTR(iod) (&((iod)->iod_rqlock)) 6175374Sbp#define SMB_IOD_RQLOCK(iod) smb_sl_lock(&((iod)->iod_rqlock)) 6275374Sbp#define SMB_IOD_RQUNLOCK(iod) smb_sl_unlock(&((iod)->iod_rqlock)) 6375374Sbp 6475374Sbp#define smb_iod_wakeup(iod) wakeup(&(iod)->iod_flags) 6575374Sbp 6675374Sbp 6775374Sbpstatic MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon"); 6875374Sbp 6975374Sbpstatic int smb_iod_next; 7075374Sbp 7175374Sbpstatic int smb_iod_sendall(struct smbiod *iod); 7275374Sbpstatic int smb_iod_disconnect(struct smbiod *iod); 7375374Sbpstatic void smb_iod_thread(void *); 7475374Sbp 7575374Sbpstatic __inline void 7675374Sbpsmb_iod_rqprocessed(struct smb_rq *rqp, int error) 7775374Sbp{ 7875374Sbp SMBRQ_SLOCK(rqp); 7975374Sbp rqp->sr_lerror = error; 8075374Sbp rqp->sr_rpgen++; 8175374Sbp rqp->sr_state = SMBRQ_NOTIFIED; 8275374Sbp wakeup(&rqp->sr_state); 8375374Sbp SMBRQ_SUNLOCK(rqp); 8475374Sbp} 8575374Sbp 8675374Sbpstatic void 8775374Sbpsmb_iod_invrq(struct smbiod *iod) 8875374Sbp{ 8975374Sbp struct smb_rq *rqp; 9075374Sbp 9175374Sbp /* 9282045Sbp * Invalidate all outstanding requests for this connection 9375374Sbp */ 9475374Sbp SMB_IOD_RQLOCK(iod); 9575374Sbp TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 9675374Sbp if (rqp->sr_flags & SMBR_INTERNAL) 9775374Sbp SMBRQ_SUNLOCK(rqp); 9875374Sbp rqp->sr_flags |= SMBR_RESTART; 9975374Sbp smb_iod_rqprocessed(rqp, ENOTCONN); 10075374Sbp } 10175374Sbp SMB_IOD_RQUNLOCK(iod); 10275374Sbp} 10375374Sbp 10475374Sbpstatic void 10575374Sbpsmb_iod_closetran(struct smbiod *iod) 10675374Sbp{ 10775374Sbp struct smb_vc *vcp = iod->iod_vc; 10887192Sbp struct thread *td = iod->iod_td; 10975374Sbp 11075374Sbp if (vcp->vc_tdata == NULL) 11175374Sbp return; 11287192Sbp SMB_TRAN_DISCONNECT(vcp, td); 11387192Sbp SMB_TRAN_DONE(vcp, td); 11475374Sbp vcp->vc_tdata = NULL; 11575374Sbp} 11675374Sbp 11775374Sbpstatic void 11875374Sbpsmb_iod_dead(struct smbiod *iod) 11975374Sbp{ 12075374Sbp iod->iod_state = SMBIOD_ST_DEAD; 12175374Sbp smb_iod_closetran(iod); 12275374Sbp smb_iod_invrq(iod); 12375374Sbp} 12475374Sbp 12575374Sbpstatic int 12675374Sbpsmb_iod_connect(struct smbiod *iod) 12775374Sbp{ 12875374Sbp struct smb_vc *vcp = iod->iod_vc; 12987192Sbp struct thread *td = iod->iod_td; 13075374Sbp int error; 13175374Sbp 13275374Sbp SMBIODEBUG("%d\n", iod->iod_state); 13375374Sbp switch(iod->iod_state) { 13475374Sbp case SMBIOD_ST_VCACTIVE: 13575374Sbp SMBERROR("called for already opened connection\n"); 13675374Sbp return EISCONN; 13775374Sbp case SMBIOD_ST_DEAD: 13875374Sbp return ENOTCONN; /* XXX: last error code ? */ 13975374Sbp default: 14075374Sbp break; 14175374Sbp } 14275374Sbp vcp->vc_genid++; 14375374Sbp error = 0; 144119376Smarcel 145119376Smarcel error = (int)SMB_TRAN_CREATE(vcp, td); 146119376Smarcel if (error) 147119376Smarcel goto fail; 148119376Smarcel SMBIODEBUG("tcreate\n"); 149119376Smarcel if (vcp->vc_laddr) { 150119376Smarcel error = (int)SMB_TRAN_BIND(vcp, vcp->vc_laddr, td); 151119376Smarcel if (error) 152119376Smarcel goto fail; 153119376Smarcel } 154119376Smarcel SMBIODEBUG("tbind\n"); 155119376Smarcel error = (int)SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td); 156119376Smarcel if (error) 157119376Smarcel goto fail; 158119376Smarcel SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags); 159119376Smarcel iod->iod_state = SMBIOD_ST_TRANACTIVE; 160119376Smarcel SMBIODEBUG("tconnect\n"); 161119376Smarcel /* vcp->vc_mid = 0;*/ 162119376Smarcel error = (int)smb_smb_negotiate(vcp, &iod->iod_scred); 163119376Smarcel if (error) 164119376Smarcel goto fail; 165119376Smarcel SMBIODEBUG("snegotiate\n"); 166119376Smarcel error = (int)smb_smb_ssnsetup(vcp, &iod->iod_scred); 167119376Smarcel if (error) 168119376Smarcel goto fail; 169119376Smarcel iod->iod_state = SMBIOD_ST_VCACTIVE; 170119376Smarcel SMBIODEBUG("completed\n"); 171119376Smarcel smb_iod_invrq(iod); 172119376Smarcel return (0); 173119376Smarcel 174119376Smarcel fail: 175119376Smarcel smb_iod_dead(iod); 176119376Smarcel return (error); 17775374Sbp} 17875374Sbp 17975374Sbpstatic int 18075374Sbpsmb_iod_disconnect(struct smbiod *iod) 18175374Sbp{ 18275374Sbp struct smb_vc *vcp = iod->iod_vc; 18375374Sbp 18475374Sbp SMBIODEBUG("\n"); 18575374Sbp if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 18675374Sbp smb_smb_ssnclose(vcp, &iod->iod_scred); 18775374Sbp iod->iod_state = SMBIOD_ST_TRANACTIVE; 18875374Sbp } 18975374Sbp vcp->vc_smbuid = SMB_UID_UNKNOWN; 19075374Sbp smb_iod_closetran(iod); 19175374Sbp iod->iod_state = SMBIOD_ST_NOTCONN; 19275374Sbp return 0; 19375374Sbp} 19475374Sbp 19575374Sbpstatic int 19675374Sbpsmb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp) 19775374Sbp{ 19875374Sbp int error; 19975374Sbp 20075374Sbp if (iod->iod_state != SMBIOD_ST_VCACTIVE) { 20175374Sbp if (iod->iod_state != SMBIOD_ST_DEAD) 20275374Sbp return ENOTCONN; 20375374Sbp iod->iod_state = SMBIOD_ST_RECONNECT; 20475374Sbp error = smb_iod_connect(iod); 20575374Sbp if (error) 20675374Sbp return error; 20775374Sbp } 20875374Sbp SMBIODEBUG("tree reconnect\n"); 20975374Sbp SMBS_ST_LOCK(ssp); 21075374Sbp ssp->ss_flags |= SMBS_RECONNECTING; 21175374Sbp SMBS_ST_UNLOCK(ssp); 21275374Sbp error = smb_smb_treeconnect(ssp, &iod->iod_scred); 21375374Sbp SMBS_ST_LOCK(ssp); 21475374Sbp ssp->ss_flags &= ~SMBS_RECONNECTING; 21575374Sbp SMBS_ST_UNLOCK(ssp); 21675374Sbp wakeup(&ssp->ss_vcgenid); 21775374Sbp return error; 21875374Sbp} 21975374Sbp 22075374Sbpstatic int 22175374Sbpsmb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp) 22275374Sbp{ 22387192Sbp struct thread *td = iod->iod_td; 22475374Sbp struct smb_vc *vcp = iod->iod_vc; 22575374Sbp struct smb_share *ssp = rqp->sr_share; 22675374Sbp struct mbuf *m; 22775374Sbp int error; 22875374Sbp 22975374Sbp SMBIODEBUG("iod_state = %d\n", iod->iod_state); 23075374Sbp switch (iod->iod_state) { 23175374Sbp case SMBIOD_ST_NOTCONN: 23275374Sbp smb_iod_rqprocessed(rqp, ENOTCONN); 23375374Sbp return 0; 23475374Sbp case SMBIOD_ST_DEAD: 23575374Sbp iod->iod_state = SMBIOD_ST_RECONNECT; 23675374Sbp return 0; 23775374Sbp case SMBIOD_ST_RECONNECT: 23875374Sbp return 0; 23975374Sbp default: 24075374Sbp break; 24175374Sbp } 24275374Sbp if (rqp->sr_sendcnt == 0) { 24375374Sbp#ifdef movedtoanotherplace 24475374Sbp if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux) 24575374Sbp return 0; 24675374Sbp#endif 247107940Srobert *rqp->sr_rqtid = htole16(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN); 248107940Srobert *rqp->sr_rquid = htole16(vcp ? vcp->vc_smbuid : 0); 24975374Sbp mb_fixhdr(&rqp->sr_rq); 25075374Sbp } 25175374Sbp if (rqp->sr_sendcnt++ > 5) { 25275374Sbp rqp->sr_flags |= SMBR_RESTART; 25375374Sbp smb_iod_rqprocessed(rqp, rqp->sr_lerror); 25475374Sbp /* 25575374Sbp * If all attempts to send a request failed, then 25675374Sbp * something is seriously hosed. 25775374Sbp */ 25875374Sbp return ENOTCONN; 25975374Sbp } 26075374Sbp SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0); 26175374Sbp m_dumpm(rqp->sr_rq.mb_top); 262111119Simp m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_TRYWAIT); 26387192Sbp error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, td) : ENOBUFS; 26475374Sbp if (error == 0) { 26575374Sbp getnanotime(&rqp->sr_timesent); 26675374Sbp iod->iod_lastrqsent = rqp->sr_timesent; 26775374Sbp rqp->sr_flags |= SMBR_SENT; 26875374Sbp rqp->sr_state = SMBRQ_SENT; 26975374Sbp return 0; 27075374Sbp } 27175374Sbp /* 27275374Sbp * Check for fatal errors 27375374Sbp */ 27475374Sbp if (SMB_TRAN_FATAL(vcp, error)) { 27575374Sbp /* 27675374Sbp * No further attempts should be made 27775374Sbp */ 27875374Sbp return ENOTCONN; 27975374Sbp } 28075374Sbp if (smb_rq_intr(rqp)) 28175374Sbp smb_iod_rqprocessed(rqp, EINTR); 28275374Sbp return 0; 28375374Sbp} 28475374Sbp 28575374Sbp/* 28675374Sbp * Process incoming packets 28775374Sbp */ 28875374Sbpstatic int 28975374Sbpsmb_iod_recvall(struct smbiod *iod) 29075374Sbp{ 29175374Sbp struct smb_vc *vcp = iod->iod_vc; 29287192Sbp struct thread *td = iod->iod_td; 29375374Sbp struct smb_rq *rqp; 29475374Sbp struct mbuf *m; 29575374Sbp u_char *hp; 29675374Sbp u_short mid; 29775374Sbp int error; 29875374Sbp 29975374Sbp switch (iod->iod_state) { 30075374Sbp case SMBIOD_ST_NOTCONN: 30175374Sbp case SMBIOD_ST_DEAD: 30275374Sbp case SMBIOD_ST_RECONNECT: 30375374Sbp return 0; 30475374Sbp default: 30575374Sbp break; 30675374Sbp } 30775374Sbp for (;;) { 30875374Sbp m = NULL; 30987192Sbp error = SMB_TRAN_RECV(vcp, &m, td); 31075374Sbp if (error == EWOULDBLOCK) 31175374Sbp break; 31275374Sbp if (SMB_TRAN_FATAL(vcp, error)) { 31375374Sbp smb_iod_dead(iod); 31475374Sbp break; 31575374Sbp } 31675374Sbp if (error) 31775374Sbp break; 31875374Sbp if (m == NULL) { 31975374Sbp SMBERROR("tran return NULL without error\n"); 32075374Sbp error = EPIPE; 32175374Sbp continue; 32275374Sbp } 32375374Sbp m = m_pullup(m, SMB_HDRLEN); 32475374Sbp if (m == NULL) 32575374Sbp continue; /* wait for a good packet */ 32675374Sbp /* 32775374Sbp * Now we got an entire and possibly invalid SMB packet. 32875374Sbp * Be careful while parsing it. 32975374Sbp */ 33075374Sbp m_dumpm(m); 33175374Sbp hp = mtod(m, u_char*); 33275374Sbp if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) { 33375374Sbp m_freem(m); 33475374Sbp continue; 33575374Sbp } 33675374Sbp mid = SMB_HDRMID(hp); 33775374Sbp SMBSDEBUG("mid %04x\n", (u_int)mid); 33875374Sbp SMB_IOD_RQLOCK(iod); 33975374Sbp TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 34075374Sbp if (rqp->sr_mid != mid) 34175374Sbp continue; 34275374Sbp SMBRQ_SLOCK(rqp); 34375374Sbp if (rqp->sr_rp.md_top == NULL) { 34475374Sbp md_initm(&rqp->sr_rp, m); 34575374Sbp } else { 34675374Sbp if (rqp->sr_flags & SMBR_MULTIPACKET) { 34775374Sbp md_append_record(&rqp->sr_rp, m); 34875374Sbp } else { 34975374Sbp SMBRQ_SUNLOCK(rqp); 35075374Sbp SMBERROR("duplicate response %d (ignored)\n", mid); 35175374Sbp break; 35275374Sbp } 35375374Sbp } 35475374Sbp SMBRQ_SUNLOCK(rqp); 35575374Sbp smb_iod_rqprocessed(rqp, 0); 35675374Sbp break; 35775374Sbp } 35875374Sbp SMB_IOD_RQUNLOCK(iod); 35975374Sbp if (rqp == NULL) { 36075374Sbp SMBERROR("drop resp with mid %d\n", (u_int)mid); 36175374Sbp/* smb_printrqlist(vcp);*/ 36275374Sbp m_freem(m); 36375374Sbp } 36475374Sbp } 36575374Sbp /* 36675374Sbp * check for interrupts 36775374Sbp */ 36875374Sbp SMB_IOD_RQLOCK(iod); 36975374Sbp TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 370112888Sjeff if (smb_td_intr(rqp->sr_cred->scr_td)) { 37175374Sbp smb_iod_rqprocessed(rqp, EINTR); 37275374Sbp } 37375374Sbp } 37475374Sbp SMB_IOD_RQUNLOCK(iod); 37575374Sbp return 0; 37675374Sbp} 37775374Sbp 37875374Sbpint 37975374Sbpsmb_iod_request(struct smbiod *iod, int event, void *ident) 38075374Sbp{ 38175374Sbp struct smbiod_event *evp; 38275374Sbp int error; 38375374Sbp 38475374Sbp SMBIODEBUG("\n"); 385111119Simp evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK); 38675374Sbp evp->ev_type = event; 38775374Sbp evp->ev_ident = ident; 38875374Sbp SMB_IOD_EVLOCK(iod); 38975374Sbp STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link); 39075374Sbp if ((event & SMBIOD_EV_SYNC) == 0) { 39175374Sbp SMB_IOD_EVUNLOCK(iod); 39275374Sbp smb_iod_wakeup(iod); 39375374Sbp return 0; 39475374Sbp } 39575374Sbp smb_iod_wakeup(iod); 39675374Sbp msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0); 39775374Sbp error = evp->ev_error; 39875374Sbp free(evp, M_SMBIOD); 39975374Sbp return error; 40075374Sbp} 40175374Sbp 40275374Sbp/* 40375374Sbp * Place request in the queue. 40475374Sbp * Request from smbiod have a high priority. 40575374Sbp */ 40675374Sbpint 40775374Sbpsmb_iod_addrq(struct smb_rq *rqp) 40875374Sbp{ 40975374Sbp struct smb_vc *vcp = rqp->sr_vc; 41075374Sbp struct smbiod *iod = vcp->vc_iod; 41175374Sbp int error; 41275374Sbp 41375374Sbp SMBIODEBUG("\n"); 414116339Stjr if (rqp->sr_cred->scr_td != NULL && 415116339Stjr rqp->sr_cred->scr_td->td_proc == iod->iod_p) { 41675374Sbp rqp->sr_flags |= SMBR_INTERNAL; 41775374Sbp SMB_IOD_RQLOCK(iod); 41875374Sbp TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link); 41975374Sbp SMB_IOD_RQUNLOCK(iod); 42075374Sbp for (;;) { 42175374Sbp if (smb_iod_sendrq(iod, rqp) != 0) { 42275374Sbp smb_iod_dead(iod); 42375374Sbp break; 42475374Sbp } 42575374Sbp /* 42675374Sbp * we don't need to lock state field here 42775374Sbp */ 42875374Sbp if (rqp->sr_state != SMBRQ_NOTSENT) 42975374Sbp break; 43075374Sbp tsleep(&iod->iod_flags, PWAIT, "90sndw", hz); 43175374Sbp } 43275374Sbp if (rqp->sr_lerror) 43375374Sbp smb_iod_removerq(rqp); 43475374Sbp return rqp->sr_lerror; 43575374Sbp } 43675374Sbp 43775374Sbp switch (iod->iod_state) { 43875374Sbp case SMBIOD_ST_NOTCONN: 43975374Sbp return ENOTCONN; 44075374Sbp case SMBIOD_ST_DEAD: 44175374Sbp error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL); 44275374Sbp if (error) 44375374Sbp return error; 44475374Sbp return EXDEV; 44575374Sbp default: 44675374Sbp break; 44775374Sbp } 44875374Sbp 44975374Sbp SMB_IOD_RQLOCK(iod); 45075374Sbp for (;;) { 45175374Sbp if (vcp->vc_maxmux == 0) { 45275374Sbp SMBERROR("maxmux == 0\n"); 45375374Sbp break; 45475374Sbp } 45575374Sbp if (iod->iod_muxcnt < vcp->vc_maxmux) 45675374Sbp break; 45775374Sbp iod->iod_muxwant++; 45875374Sbp msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod), 45975374Sbp PWAIT, "90mux", 0); 46075374Sbp } 46175374Sbp iod->iod_muxcnt++; 46275374Sbp TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 46375374Sbp SMB_IOD_RQUNLOCK(iod); 46475374Sbp smb_iod_wakeup(iod); 46575374Sbp return 0; 46675374Sbp} 46775374Sbp 46875374Sbpint 46975374Sbpsmb_iod_removerq(struct smb_rq *rqp) 47075374Sbp{ 47175374Sbp struct smb_vc *vcp = rqp->sr_vc; 47275374Sbp struct smbiod *iod = vcp->vc_iod; 47375374Sbp 47475374Sbp SMBIODEBUG("\n"); 47575374Sbp if (rqp->sr_flags & SMBR_INTERNAL) { 47675374Sbp SMB_IOD_RQLOCK(iod); 47775374Sbp TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 47875374Sbp SMB_IOD_RQUNLOCK(iod); 47975374Sbp return 0; 48075374Sbp } 48175374Sbp SMB_IOD_RQLOCK(iod); 48275374Sbp while (rqp->sr_flags & SMBR_XLOCK) { 48375374Sbp rqp->sr_flags |= SMBR_XLOCKWANT; 48475374Sbp msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0); 48575374Sbp } 48675374Sbp TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 48775374Sbp iod->iod_muxcnt--; 48875374Sbp if (iod->iod_muxwant) { 48975374Sbp iod->iod_muxwant--; 49075374Sbp wakeup(&iod->iod_muxwant); 49175374Sbp } 49275374Sbp SMB_IOD_RQUNLOCK(iod); 49375374Sbp return 0; 49475374Sbp} 49575374Sbp 49675374Sbpint 49775374Sbpsmb_iod_waitrq(struct smb_rq *rqp) 49875374Sbp{ 49975374Sbp struct smbiod *iod = rqp->sr_vc->vc_iod; 50075374Sbp int error; 50175374Sbp 50275374Sbp SMBIODEBUG("\n"); 50375374Sbp if (rqp->sr_flags & SMBR_INTERNAL) { 50475374Sbp for (;;) { 50575374Sbp smb_iod_sendall(iod); 50675374Sbp smb_iod_recvall(iod); 50775374Sbp if (rqp->sr_rpgen != rqp->sr_rplast) 50875374Sbp break; 50975374Sbp tsleep(&iod->iod_flags, PWAIT, "90irq", hz); 51075374Sbp } 51175374Sbp smb_iod_removerq(rqp); 51275374Sbp return rqp->sr_lerror; 51375374Sbp 51475374Sbp } 51575374Sbp SMBRQ_SLOCK(rqp); 51675374Sbp if (rqp->sr_rpgen == rqp->sr_rplast) 51775374Sbp msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0); 51875374Sbp rqp->sr_rplast++; 51975374Sbp SMBRQ_SUNLOCK(rqp); 52075374Sbp error = rqp->sr_lerror; 52175374Sbp if (rqp->sr_flags & SMBR_MULTIPACKET) { 52275374Sbp /* 52375374Sbp * If request should stay in the list, then reinsert it 52475374Sbp * at the end of queue so other waiters have chance to concur 52575374Sbp */ 52675374Sbp SMB_IOD_RQLOCK(iod); 52775374Sbp TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 52875374Sbp TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 52975374Sbp SMB_IOD_RQUNLOCK(iod); 53075374Sbp } else 53175374Sbp smb_iod_removerq(rqp); 53275374Sbp return error; 53375374Sbp} 53475374Sbp 53575374Sbp 53675374Sbpstatic int 53775374Sbpsmb_iod_sendall(struct smbiod *iod) 53875374Sbp{ 53975374Sbp struct smb_vc *vcp = iod->iod_vc; 54075374Sbp struct smb_rq *rqp; 54175374Sbp struct timespec ts, tstimeout; 54275374Sbp int herror; 54375374Sbp 54475374Sbp herror = 0; 54575374Sbp /* 54675374Sbp * Loop through the list of requests and send them if possible 54775374Sbp */ 54875374Sbp SMB_IOD_RQLOCK(iod); 54975374Sbp TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 55075374Sbp switch (rqp->sr_state) { 55175374Sbp case SMBRQ_NOTSENT: 55275374Sbp rqp->sr_flags |= SMBR_XLOCK; 55375374Sbp SMB_IOD_RQUNLOCK(iod); 55475374Sbp herror = smb_iod_sendrq(iod, rqp); 55575374Sbp SMB_IOD_RQLOCK(iod); 55675374Sbp rqp->sr_flags &= ~SMBR_XLOCK; 55775374Sbp if (rqp->sr_flags & SMBR_XLOCKWANT) { 55875374Sbp rqp->sr_flags &= ~SMBR_XLOCKWANT; 55975374Sbp wakeup(rqp); 56075374Sbp } 56175374Sbp break; 56275374Sbp case SMBRQ_SENT: 56375374Sbp SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout); 56475374Sbp timespecadd(&tstimeout, &tstimeout); 56575374Sbp getnanotime(&ts); 56675374Sbp timespecsub(&ts, &tstimeout); 56775374Sbp if (timespeccmp(&ts, &rqp->sr_timesent, >)) { 56875374Sbp smb_iod_rqprocessed(rqp, ETIMEDOUT); 56975374Sbp } 57075374Sbp break; 57175374Sbp default: 57297209Speter break; 57375374Sbp } 57475374Sbp if (herror) 57575374Sbp break; 57675374Sbp } 57775374Sbp SMB_IOD_RQUNLOCK(iod); 57875374Sbp if (herror == ENOTCONN) 57975374Sbp smb_iod_dead(iod); 58075374Sbp return 0; 58175374Sbp} 58275374Sbp 58375374Sbp/* 58475374Sbp * "main" function for smbiod daemon 58575374Sbp */ 58675374Sbpstatic __inline void 58775374Sbpsmb_iod_main(struct smbiod *iod) 58875374Sbp{ 58975374Sbp/* struct smb_vc *vcp = iod->iod_vc;*/ 59075374Sbp struct smbiod_event *evp; 59175374Sbp/* struct timespec tsnow;*/ 59275374Sbp int error; 59375374Sbp 59475374Sbp SMBIODEBUG("\n"); 59575374Sbp error = 0; 59675374Sbp 59775374Sbp /* 59875374Sbp * Check all interesting events 59975374Sbp */ 60075374Sbp for (;;) { 60175374Sbp SMB_IOD_EVLOCK(iod); 60275374Sbp evp = STAILQ_FIRST(&iod->iod_evlist); 60375374Sbp if (evp == NULL) { 60475374Sbp SMB_IOD_EVUNLOCK(iod); 60575374Sbp break; 60675374Sbp } 60775374Sbp STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link); 60875374Sbp evp->ev_type |= SMBIOD_EV_PROCESSING; 60975374Sbp SMB_IOD_EVUNLOCK(iod); 61075374Sbp switch (evp->ev_type & SMBIOD_EV_MASK) { 61175374Sbp case SMBIOD_EV_CONNECT: 61275374Sbp iod->iod_state = SMBIOD_ST_RECONNECT; 61375374Sbp evp->ev_error = smb_iod_connect(iod); 61475374Sbp break; 61575374Sbp case SMBIOD_EV_DISCONNECT: 61675374Sbp evp->ev_error = smb_iod_disconnect(iod); 61775374Sbp break; 61875374Sbp case SMBIOD_EV_TREECONNECT: 61975374Sbp evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident); 62075374Sbp break; 62175374Sbp case SMBIOD_EV_SHUTDOWN: 62275374Sbp iod->iod_flags |= SMBIOD_SHUTDOWN; 62375374Sbp break; 62475374Sbp case SMBIOD_EV_NEWRQ: 62575374Sbp break; 62675374Sbp } 62775374Sbp if (evp->ev_type & SMBIOD_EV_SYNC) { 62875374Sbp SMB_IOD_EVLOCK(iod); 62975374Sbp wakeup(evp); 63075374Sbp SMB_IOD_EVUNLOCK(iod); 63175374Sbp } else 63275374Sbp free(evp, M_SMBIOD); 63375374Sbp } 63475374Sbp#if 0 63575374Sbp if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 63675374Sbp getnanotime(&tsnow); 63775374Sbp timespecsub(&tsnow, &iod->iod_pingtimo); 63875374Sbp if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) { 63975374Sbp smb_smb_echo(vcp, &iod->iod_scred); 64075374Sbp } 64175374Sbp } 64275374Sbp#endif 64375374Sbp smb_iod_sendall(iod); 64475374Sbp smb_iod_recvall(iod); 64575374Sbp return; 64675374Sbp} 64775374Sbp 64875374Sbpvoid 64975374Sbpsmb_iod_thread(void *arg) 65075374Sbp{ 65175374Sbp struct smbiod *iod = arg; 65275374Sbp 65375374Sbp mtx_lock(&Giant); 65487192Sbp /* 65587192Sbp * Here we assume that the thread structure will be the same 65687192Sbp * for an entire kthread (kproc, to be more precise) life. 65787192Sbp */ 65887192Sbp iod->iod_td = curthread; 65987192Sbp smb_makescred(&iod->iod_scred, iod->iod_td, NULL); 66075374Sbp while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) { 66175374Sbp smb_iod_main(iod); 66275374Sbp SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo); 66375374Sbp/* mtx_unlock(&Giant, MTX_DEF);*/ 66475374Sbp if (iod->iod_flags & SMBIOD_SHUTDOWN) 66575374Sbp break; 66675374Sbp tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo); 66775374Sbp } 66875374Sbp/* mtx_lock(&Giant, MTX_DEF);*/ 66975374Sbp kthread_exit(0); 67075374Sbp} 67175374Sbp 67275374Sbpint 67375374Sbpsmb_iod_create(struct smb_vc *vcp) 67475374Sbp{ 67575374Sbp struct smbiod *iod; 67675374Sbp int error; 67775374Sbp 678111119Simp iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK); 67975374Sbp iod->iod_id = smb_iod_next++; 68075374Sbp iod->iod_state = SMBIOD_ST_NOTCONN; 68175374Sbp iod->iod_vc = vcp; 68275374Sbp iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO; 68375374Sbp iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO; 68475374Sbp getnanotime(&iod->iod_lastrqsent); 68575374Sbp vcp->vc_iod = iod; 68675374Sbp smb_sl_init(&iod->iod_rqlock, "90rql"); 68775374Sbp TAILQ_INIT(&iod->iod_rqlist); 68875374Sbp smb_sl_init(&iod->iod_evlock, "90evl"); 68975374Sbp STAILQ_INIT(&iod->iod_evlist); 69087192Sbp error = kthread_create(smb_iod_thread, iod, &iod->iod_p, 691104354Sscottl RFNOWAIT, 0, "smbiod%d", iod->iod_id); 69275374Sbp if (error) { 69375374Sbp SMBERROR("can't start smbiod: %d", error); 69475374Sbp free(iod, M_SMBIOD); 69575374Sbp return error; 69675374Sbp } 69775374Sbp return 0; 69875374Sbp} 69975374Sbp 70075374Sbpint 70175374Sbpsmb_iod_destroy(struct smbiod *iod) 70275374Sbp{ 70375374Sbp smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL); 70482045Sbp smb_sl_destroy(&iod->iod_rqlock); 70582045Sbp smb_sl_destroy(&iod->iod_evlock); 70675374Sbp free(iod, M_SMBIOD); 70775374Sbp return 0; 70875374Sbp} 70975374Sbp 71075374Sbpint 71175374Sbpsmb_iod_init(void) 71275374Sbp{ 71375374Sbp return 0; 71475374Sbp} 71575374Sbp 71675374Sbpint 71775374Sbpsmb_iod_done(void) 71875374Sbp{ 71975374Sbp return 0; 72075374Sbp} 72175374Sbp 722