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