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