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