smb_iod.c revision 116339
1/* 2 * Copyright (c) 2000-2001 Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: head/sys/netsmb/smb_iod.c 116339 2003-06-14 15:45:34Z tjr $"); 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/endian.h> 39#include <sys/proc.h> 40#include <sys/kernel.h> 41#include <sys/kthread.h> 42#include <sys/malloc.h> 43#include <sys/mbuf.h> 44#include <sys/unistd.h> 45 46#include <netsmb/smb.h> 47#include <netsmb/smb_conn.h> 48#include <netsmb/smb_rq.h> 49#include <netsmb/smb_tran.h> 50#include <netsmb/smb_trantcp.h> 51 52 53#define SMBIOD_SLEEP_TIMO 2 54#define SMBIOD_PING_TIMO 60 /* seconds */ 55 56#define SMB_IOD_EVLOCKPTR(iod) (&((iod)->iod_evlock)) 57#define SMB_IOD_EVLOCK(iod) smb_sl_lock(&((iod)->iod_evlock)) 58#define SMB_IOD_EVUNLOCK(iod) smb_sl_unlock(&((iod)->iod_evlock)) 59 60#define SMB_IOD_RQLOCKPTR(iod) (&((iod)->iod_rqlock)) 61#define SMB_IOD_RQLOCK(iod) smb_sl_lock(&((iod)->iod_rqlock)) 62#define SMB_IOD_RQUNLOCK(iod) smb_sl_unlock(&((iod)->iod_rqlock)) 63 64#define smb_iod_wakeup(iod) wakeup(&(iod)->iod_flags) 65 66 67static MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon"); 68 69static int smb_iod_next; 70 71static int smb_iod_sendall(struct smbiod *iod); 72static int smb_iod_disconnect(struct smbiod *iod); 73static void smb_iod_thread(void *); 74 75static __inline void 76smb_iod_rqprocessed(struct smb_rq *rqp, int error) 77{ 78 SMBRQ_SLOCK(rqp); 79 rqp->sr_lerror = error; 80 rqp->sr_rpgen++; 81 rqp->sr_state = SMBRQ_NOTIFIED; 82 wakeup(&rqp->sr_state); 83 SMBRQ_SUNLOCK(rqp); 84} 85 86static void 87smb_iod_invrq(struct smbiod *iod) 88{ 89 struct smb_rq *rqp; 90 91 /* 92 * Invalidate all outstanding requests for this connection 93 */ 94 SMB_IOD_RQLOCK(iod); 95 TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 96 if (rqp->sr_flags & SMBR_INTERNAL) 97 SMBRQ_SUNLOCK(rqp); 98 rqp->sr_flags |= SMBR_RESTART; 99 smb_iod_rqprocessed(rqp, ENOTCONN); 100 } 101 SMB_IOD_RQUNLOCK(iod); 102} 103 104static void 105smb_iod_closetran(struct smbiod *iod) 106{ 107 struct smb_vc *vcp = iod->iod_vc; 108 struct thread *td = iod->iod_td; 109 110 if (vcp->vc_tdata == NULL) 111 return; 112 SMB_TRAN_DISCONNECT(vcp, td); 113 SMB_TRAN_DONE(vcp, td); 114 vcp->vc_tdata = NULL; 115} 116 117static void 118smb_iod_dead(struct smbiod *iod) 119{ 120 iod->iod_state = SMBIOD_ST_DEAD; 121 smb_iod_closetran(iod); 122 smb_iod_invrq(iod); 123} 124 125static int 126smb_iod_connect(struct smbiod *iod) 127{ 128 struct smb_vc *vcp = iod->iod_vc; 129 struct thread *td = iod->iod_td; 130 int error; 131 132 SMBIODEBUG("%d\n", iod->iod_state); 133 switch(iod->iod_state) { 134 case SMBIOD_ST_VCACTIVE: 135 SMBERROR("called for already opened connection\n"); 136 return EISCONN; 137 case SMBIOD_ST_DEAD: 138 return ENOTCONN; /* XXX: last error code ? */ 139 default: 140 break; 141 } 142 vcp->vc_genid++; 143 error = 0; 144 itry { 145 ithrow(SMB_TRAN_CREATE(vcp, td)); 146 SMBIODEBUG("tcreate\n"); 147 if (vcp->vc_laddr) { 148 ithrow(SMB_TRAN_BIND(vcp, vcp->vc_laddr, td)); 149 } 150 SMBIODEBUG("tbind\n"); 151 ithrow(SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td)); 152 SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags); 153 iod->iod_state = SMBIOD_ST_TRANACTIVE; 154 SMBIODEBUG("tconnect\n"); 155/* vcp->vc_mid = 0;*/ 156 ithrow(smb_smb_negotiate(vcp, &iod->iod_scred)); 157 SMBIODEBUG("snegotiate\n"); 158 ithrow(smb_smb_ssnsetup(vcp, &iod->iod_scred)); 159 iod->iod_state = SMBIOD_ST_VCACTIVE; 160 SMBIODEBUG("completed\n"); 161 smb_iod_invrq(iod); 162 } icatch(error) { 163 smb_iod_dead(iod); 164 } ifinally { 165 } iendtry; 166 return error; 167} 168 169static int 170smb_iod_disconnect(struct smbiod *iod) 171{ 172 struct smb_vc *vcp = iod->iod_vc; 173 174 SMBIODEBUG("\n"); 175 if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 176 smb_smb_ssnclose(vcp, &iod->iod_scred); 177 iod->iod_state = SMBIOD_ST_TRANACTIVE; 178 } 179 vcp->vc_smbuid = SMB_UID_UNKNOWN; 180 smb_iod_closetran(iod); 181 iod->iod_state = SMBIOD_ST_NOTCONN; 182 return 0; 183} 184 185static int 186smb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp) 187{ 188 int error; 189 190 if (iod->iod_state != SMBIOD_ST_VCACTIVE) { 191 if (iod->iod_state != SMBIOD_ST_DEAD) 192 return ENOTCONN; 193 iod->iod_state = SMBIOD_ST_RECONNECT; 194 error = smb_iod_connect(iod); 195 if (error) 196 return error; 197 } 198 SMBIODEBUG("tree reconnect\n"); 199 SMBS_ST_LOCK(ssp); 200 ssp->ss_flags |= SMBS_RECONNECTING; 201 SMBS_ST_UNLOCK(ssp); 202 error = smb_smb_treeconnect(ssp, &iod->iod_scred); 203 SMBS_ST_LOCK(ssp); 204 ssp->ss_flags &= ~SMBS_RECONNECTING; 205 SMBS_ST_UNLOCK(ssp); 206 wakeup(&ssp->ss_vcgenid); 207 return error; 208} 209 210static int 211smb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp) 212{ 213 struct thread *td = iod->iod_td; 214 struct smb_vc *vcp = iod->iod_vc; 215 struct smb_share *ssp = rqp->sr_share; 216 struct mbuf *m; 217 int error; 218 219 SMBIODEBUG("iod_state = %d\n", iod->iod_state); 220 switch (iod->iod_state) { 221 case SMBIOD_ST_NOTCONN: 222 smb_iod_rqprocessed(rqp, ENOTCONN); 223 return 0; 224 case SMBIOD_ST_DEAD: 225 iod->iod_state = SMBIOD_ST_RECONNECT; 226 return 0; 227 case SMBIOD_ST_RECONNECT: 228 return 0; 229 default: 230 break; 231 } 232 if (rqp->sr_sendcnt == 0) { 233#ifdef movedtoanotherplace 234 if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux) 235 return 0; 236#endif 237 *rqp->sr_rqtid = htole16(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN); 238 *rqp->sr_rquid = htole16(vcp ? vcp->vc_smbuid : 0); 239 mb_fixhdr(&rqp->sr_rq); 240 } 241 if (rqp->sr_sendcnt++ > 5) { 242 rqp->sr_flags |= SMBR_RESTART; 243 smb_iod_rqprocessed(rqp, rqp->sr_lerror); 244 /* 245 * If all attempts to send a request failed, then 246 * something is seriously hosed. 247 */ 248 return ENOTCONN; 249 } 250 SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0); 251 m_dumpm(rqp->sr_rq.mb_top); 252 m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_TRYWAIT); 253 error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, td) : ENOBUFS; 254 if (error == 0) { 255 getnanotime(&rqp->sr_timesent); 256 iod->iod_lastrqsent = rqp->sr_timesent; 257 rqp->sr_flags |= SMBR_SENT; 258 rqp->sr_state = SMBRQ_SENT; 259 return 0; 260 } 261 /* 262 * Check for fatal errors 263 */ 264 if (SMB_TRAN_FATAL(vcp, error)) { 265 /* 266 * No further attempts should be made 267 */ 268 return ENOTCONN; 269 } 270 if (smb_rq_intr(rqp)) 271 smb_iod_rqprocessed(rqp, EINTR); 272 return 0; 273} 274 275/* 276 * Process incoming packets 277 */ 278static int 279smb_iod_recvall(struct smbiod *iod) 280{ 281 struct smb_vc *vcp = iod->iod_vc; 282 struct thread *td = iod->iod_td; 283 struct smb_rq *rqp; 284 struct mbuf *m; 285 u_char *hp; 286 u_short mid; 287 int error; 288 289 switch (iod->iod_state) { 290 case SMBIOD_ST_NOTCONN: 291 case SMBIOD_ST_DEAD: 292 case SMBIOD_ST_RECONNECT: 293 return 0; 294 default: 295 break; 296 } 297 for (;;) { 298 m = NULL; 299 error = SMB_TRAN_RECV(vcp, &m, td); 300 if (error == EWOULDBLOCK) 301 break; 302 if (SMB_TRAN_FATAL(vcp, error)) { 303 smb_iod_dead(iod); 304 break; 305 } 306 if (error) 307 break; 308 if (m == NULL) { 309 SMBERROR("tran return NULL without error\n"); 310 error = EPIPE; 311 continue; 312 } 313 m = m_pullup(m, SMB_HDRLEN); 314 if (m == NULL) 315 continue; /* wait for a good packet */ 316 /* 317 * Now we got an entire and possibly invalid SMB packet. 318 * Be careful while parsing it. 319 */ 320 m_dumpm(m); 321 hp = mtod(m, u_char*); 322 if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) { 323 m_freem(m); 324 continue; 325 } 326 mid = SMB_HDRMID(hp); 327 SMBSDEBUG("mid %04x\n", (u_int)mid); 328 SMB_IOD_RQLOCK(iod); 329 TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 330 if (rqp->sr_mid != mid) 331 continue; 332 SMBRQ_SLOCK(rqp); 333 if (rqp->sr_rp.md_top == NULL) { 334 md_initm(&rqp->sr_rp, m); 335 } else { 336 if (rqp->sr_flags & SMBR_MULTIPACKET) { 337 md_append_record(&rqp->sr_rp, m); 338 } else { 339 SMBRQ_SUNLOCK(rqp); 340 SMBERROR("duplicate response %d (ignored)\n", mid); 341 break; 342 } 343 } 344 SMBRQ_SUNLOCK(rqp); 345 smb_iod_rqprocessed(rqp, 0); 346 break; 347 } 348 SMB_IOD_RQUNLOCK(iod); 349 if (rqp == NULL) { 350 SMBERROR("drop resp with mid %d\n", (u_int)mid); 351/* smb_printrqlist(vcp);*/ 352 m_freem(m); 353 } 354 } 355 /* 356 * check for interrupts 357 */ 358 SMB_IOD_RQLOCK(iod); 359 TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 360 if (smb_td_intr(rqp->sr_cred->scr_td)) { 361 smb_iod_rqprocessed(rqp, EINTR); 362 } 363 } 364 SMB_IOD_RQUNLOCK(iod); 365 return 0; 366} 367 368int 369smb_iod_request(struct smbiod *iod, int event, void *ident) 370{ 371 struct smbiod_event *evp; 372 int error; 373 374 SMBIODEBUG("\n"); 375 evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK); 376 evp->ev_type = event; 377 evp->ev_ident = ident; 378 SMB_IOD_EVLOCK(iod); 379 STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link); 380 if ((event & SMBIOD_EV_SYNC) == 0) { 381 SMB_IOD_EVUNLOCK(iod); 382 smb_iod_wakeup(iod); 383 return 0; 384 } 385 smb_iod_wakeup(iod); 386 msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0); 387 error = evp->ev_error; 388 free(evp, M_SMBIOD); 389 return error; 390} 391 392/* 393 * Place request in the queue. 394 * Request from smbiod have a high priority. 395 */ 396int 397smb_iod_addrq(struct smb_rq *rqp) 398{ 399 struct smb_vc *vcp = rqp->sr_vc; 400 struct smbiod *iod = vcp->vc_iod; 401 int error; 402 403 SMBIODEBUG("\n"); 404 if (rqp->sr_cred->scr_td != NULL && 405 rqp->sr_cred->scr_td->td_proc == iod->iod_p) { 406 rqp->sr_flags |= SMBR_INTERNAL; 407 SMB_IOD_RQLOCK(iod); 408 TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link); 409 SMB_IOD_RQUNLOCK(iod); 410 for (;;) { 411 if (smb_iod_sendrq(iod, rqp) != 0) { 412 smb_iod_dead(iod); 413 break; 414 } 415 /* 416 * we don't need to lock state field here 417 */ 418 if (rqp->sr_state != SMBRQ_NOTSENT) 419 break; 420 tsleep(&iod->iod_flags, PWAIT, "90sndw", hz); 421 } 422 if (rqp->sr_lerror) 423 smb_iod_removerq(rqp); 424 return rqp->sr_lerror; 425 } 426 427 switch (iod->iod_state) { 428 case SMBIOD_ST_NOTCONN: 429 return ENOTCONN; 430 case SMBIOD_ST_DEAD: 431 error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL); 432 if (error) 433 return error; 434 return EXDEV; 435 default: 436 break; 437 } 438 439 SMB_IOD_RQLOCK(iod); 440 for (;;) { 441 if (vcp->vc_maxmux == 0) { 442 SMBERROR("maxmux == 0\n"); 443 break; 444 } 445 if (iod->iod_muxcnt < vcp->vc_maxmux) 446 break; 447 iod->iod_muxwant++; 448 msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod), 449 PWAIT, "90mux", 0); 450 } 451 iod->iod_muxcnt++; 452 TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 453 SMB_IOD_RQUNLOCK(iod); 454 smb_iod_wakeup(iod); 455 return 0; 456} 457 458int 459smb_iod_removerq(struct smb_rq *rqp) 460{ 461 struct smb_vc *vcp = rqp->sr_vc; 462 struct smbiod *iod = vcp->vc_iod; 463 464 SMBIODEBUG("\n"); 465 if (rqp->sr_flags & SMBR_INTERNAL) { 466 SMB_IOD_RQLOCK(iod); 467 TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 468 SMB_IOD_RQUNLOCK(iod); 469 return 0; 470 } 471 SMB_IOD_RQLOCK(iod); 472 while (rqp->sr_flags & SMBR_XLOCK) { 473 rqp->sr_flags |= SMBR_XLOCKWANT; 474 msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0); 475 } 476 TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 477 iod->iod_muxcnt--; 478 if (iod->iod_muxwant) { 479 iod->iod_muxwant--; 480 wakeup(&iod->iod_muxwant); 481 } 482 SMB_IOD_RQUNLOCK(iod); 483 return 0; 484} 485 486int 487smb_iod_waitrq(struct smb_rq *rqp) 488{ 489 struct smbiod *iod = rqp->sr_vc->vc_iod; 490 int error; 491 492 SMBIODEBUG("\n"); 493 if (rqp->sr_flags & SMBR_INTERNAL) { 494 for (;;) { 495 smb_iod_sendall(iod); 496 smb_iod_recvall(iod); 497 if (rqp->sr_rpgen != rqp->sr_rplast) 498 break; 499 tsleep(&iod->iod_flags, PWAIT, "90irq", hz); 500 } 501 smb_iod_removerq(rqp); 502 return rqp->sr_lerror; 503 504 } 505 SMBRQ_SLOCK(rqp); 506 if (rqp->sr_rpgen == rqp->sr_rplast) 507 msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0); 508 rqp->sr_rplast++; 509 SMBRQ_SUNLOCK(rqp); 510 error = rqp->sr_lerror; 511 if (rqp->sr_flags & SMBR_MULTIPACKET) { 512 /* 513 * If request should stay in the list, then reinsert it 514 * at the end of queue so other waiters have chance to concur 515 */ 516 SMB_IOD_RQLOCK(iod); 517 TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link); 518 TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link); 519 SMB_IOD_RQUNLOCK(iod); 520 } else 521 smb_iod_removerq(rqp); 522 return error; 523} 524 525 526static int 527smb_iod_sendall(struct smbiod *iod) 528{ 529 struct smb_vc *vcp = iod->iod_vc; 530 struct smb_rq *rqp; 531 struct timespec ts, tstimeout; 532 int herror; 533 534 herror = 0; 535 /* 536 * Loop through the list of requests and send them if possible 537 */ 538 SMB_IOD_RQLOCK(iod); 539 TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) { 540 switch (rqp->sr_state) { 541 case SMBRQ_NOTSENT: 542 rqp->sr_flags |= SMBR_XLOCK; 543 SMB_IOD_RQUNLOCK(iod); 544 herror = smb_iod_sendrq(iod, rqp); 545 SMB_IOD_RQLOCK(iod); 546 rqp->sr_flags &= ~SMBR_XLOCK; 547 if (rqp->sr_flags & SMBR_XLOCKWANT) { 548 rqp->sr_flags &= ~SMBR_XLOCKWANT; 549 wakeup(rqp); 550 } 551 break; 552 case SMBRQ_SENT: 553 SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout); 554 timespecadd(&tstimeout, &tstimeout); 555 getnanotime(&ts); 556 timespecsub(&ts, &tstimeout); 557 if (timespeccmp(&ts, &rqp->sr_timesent, >)) { 558 smb_iod_rqprocessed(rqp, ETIMEDOUT); 559 } 560 break; 561 default: 562 break; 563 } 564 if (herror) 565 break; 566 } 567 SMB_IOD_RQUNLOCK(iod); 568 if (herror == ENOTCONN) 569 smb_iod_dead(iod); 570 return 0; 571} 572 573/* 574 * "main" function for smbiod daemon 575 */ 576static __inline void 577smb_iod_main(struct smbiod *iod) 578{ 579/* struct smb_vc *vcp = iod->iod_vc;*/ 580 struct smbiod_event *evp; 581/* struct timespec tsnow;*/ 582 int error; 583 584 SMBIODEBUG("\n"); 585 error = 0; 586 587 /* 588 * Check all interesting events 589 */ 590 for (;;) { 591 SMB_IOD_EVLOCK(iod); 592 evp = STAILQ_FIRST(&iod->iod_evlist); 593 if (evp == NULL) { 594 SMB_IOD_EVUNLOCK(iod); 595 break; 596 } 597 STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link); 598 evp->ev_type |= SMBIOD_EV_PROCESSING; 599 SMB_IOD_EVUNLOCK(iod); 600 switch (evp->ev_type & SMBIOD_EV_MASK) { 601 case SMBIOD_EV_CONNECT: 602 iod->iod_state = SMBIOD_ST_RECONNECT; 603 evp->ev_error = smb_iod_connect(iod); 604 break; 605 case SMBIOD_EV_DISCONNECT: 606 evp->ev_error = smb_iod_disconnect(iod); 607 break; 608 case SMBIOD_EV_TREECONNECT: 609 evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident); 610 break; 611 case SMBIOD_EV_SHUTDOWN: 612 iod->iod_flags |= SMBIOD_SHUTDOWN; 613 break; 614 case SMBIOD_EV_NEWRQ: 615 break; 616 } 617 if (evp->ev_type & SMBIOD_EV_SYNC) { 618 SMB_IOD_EVLOCK(iod); 619 wakeup(evp); 620 SMB_IOD_EVUNLOCK(iod); 621 } else 622 free(evp, M_SMBIOD); 623 } 624#if 0 625 if (iod->iod_state == SMBIOD_ST_VCACTIVE) { 626 getnanotime(&tsnow); 627 timespecsub(&tsnow, &iod->iod_pingtimo); 628 if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) { 629 smb_smb_echo(vcp, &iod->iod_scred); 630 } 631 } 632#endif 633 smb_iod_sendall(iod); 634 smb_iod_recvall(iod); 635 return; 636} 637 638void 639smb_iod_thread(void *arg) 640{ 641 struct smbiod *iod = arg; 642 643 mtx_lock(&Giant); 644 /* 645 * Here we assume that the thread structure will be the same 646 * for an entire kthread (kproc, to be more precise) life. 647 */ 648 iod->iod_td = curthread; 649 smb_makescred(&iod->iod_scred, iod->iod_td, NULL); 650 while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) { 651 smb_iod_main(iod); 652 SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo); 653/* mtx_unlock(&Giant, MTX_DEF);*/ 654 if (iod->iod_flags & SMBIOD_SHUTDOWN) 655 break; 656 tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo); 657 } 658/* mtx_lock(&Giant, MTX_DEF);*/ 659 kthread_exit(0); 660} 661 662int 663smb_iod_create(struct smb_vc *vcp) 664{ 665 struct smbiod *iod; 666 int error; 667 668 iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK); 669 iod->iod_id = smb_iod_next++; 670 iod->iod_state = SMBIOD_ST_NOTCONN; 671 iod->iod_vc = vcp; 672 iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO; 673 iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO; 674 getnanotime(&iod->iod_lastrqsent); 675 vcp->vc_iod = iod; 676 smb_sl_init(&iod->iod_rqlock, "90rql"); 677 TAILQ_INIT(&iod->iod_rqlist); 678 smb_sl_init(&iod->iod_evlock, "90evl"); 679 STAILQ_INIT(&iod->iod_evlist); 680 error = kthread_create(smb_iod_thread, iod, &iod->iod_p, 681 RFNOWAIT, 0, "smbiod%d", iod->iod_id); 682 if (error) { 683 SMBERROR("can't start smbiod: %d", error); 684 free(iod, M_SMBIOD); 685 return error; 686 } 687 return 0; 688} 689 690int 691smb_iod_destroy(struct smbiod *iod) 692{ 693 smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL); 694 smb_sl_destroy(&iod->iod_rqlock); 695 smb_sl_destroy(&iod->iod_evlock); 696 free(iod, M_SMBIOD); 697 return 0; 698} 699 700int 701smb_iod_init(void) 702{ 703 return 0; 704} 705 706int 707smb_iod_done(void) 708{ 709 return 0; 710} 711 712