1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * General Structures Layout 30 * ------------------------- 31 * 32 * This is a simplified diagram showing the relationship between most of the 33 * main structures. 34 * 35 * +-------------------+ 36 * | SMB_SERVER | 37 * +-------------------+ 38 * | 39 * | 40 * v 41 * +-------------------+ +-------------------+ +-------------------+ 42 * | SESSION |<----->| SESSION |......| SESSION | 43 * +-------------------+ +-------------------+ +-------------------+ 44 * | 45 * | 46 * v 47 * +-------------------+ +-------------------+ +-------------------+ 48 * | USER |<----->| USER |......| USER | 49 * +-------------------+ +-------------------+ +-------------------+ 50 * | 51 * | 52 * v 53 * +-------------------+ +-------------------+ +-------------------+ 54 * | TREE |<----->| TREE |......| TREE | 55 * +-------------------+ +-------------------+ +-------------------+ 56 * | | 57 * | | 58 * | v 59 * | +-------+ +-------+ +-------+ 60 * | | OFILE |<----->| OFILE |......| OFILE | 61 * | +-------+ +-------+ +-------+ 62 * | 63 * | 64 * v 65 * +-------+ +------+ +------+ 66 * | ODIR |<----->| ODIR |......| ODIR | 67 * +-------+ +------+ +------+ 68 * 69 * 70 * Module Interface Overview 71 * ------------------------- 72 * 73 * 74 * +===================================+ 75 * | smbd daemon | 76 * +===================================+ 77 * | | ^ 78 * | | | 79 * User | | | 80 * -----------|--------------|----------------|-------------------------------- 81 * Kernel | | | 82 * | | | 83 * | | | 84 * +=========|==============|================|=================+ 85 * | v v | | 86 * | +-----------+ +--------------------+ +------------------+ | 87 * | | IO | | Kernel Door Server | | User Door Servers| | 88 * | | Interface | | Interface | | Interface | | 89 * | +-----------+ +--------------------+ +------------------+ | 90 * | | | ^ ^ | 91 * | v v | | | +=========+ 92 * | +-----------------------------------+ | | | | 93 * | + SMB Server Management (this file) |<------------------| ZFS | 94 * | +-----------------------------------+ | | | | 95 * | | | | Module | 96 * | +-----------------------------------+ | | | | 97 * | + SMB Server Internal Layers |------+ | +=========+ 98 * | +-----------------------------------+ | 99 * | | 100 * | | 101 * +===========================================================+ 102 * 103 * 104 * Server State Machine 105 * -------------------- 106 * | 107 * | T0 108 * | 109 * v 110 * +-----------------------------+ 111 * | SMB_SERVER_STATE_CREATED | 112 * +-----------------------------+ 113 * | 114 * | T1 115 * | 116 * v 117 * +-----------------------------+ 118 * | SMB_SERVER_STATE_CONFIGURED | 119 * +-----------------------------+ 120 * | 121 * | T2 122 * | 123 * v 124 * +-----------------------------+ 125 * | SMB_SERVER_STATE_RUNNING | 126 * +-----------------------------+ 127 * | 128 * | T3 129 * | 130 * v 131 * +-----------------------------+ 132 * | SMB_SERVER_STATE_DELETING | 133 * +-----------------------------+ 134 * | 135 * | 136 * | 137 * v 138 * 139 * States 140 * ------ 141 * 142 * SMB_SERVER_STATE_CREATED 143 * 144 * This is the state of the server just after creation. 145 * 146 * SMB_SERVER_STATE_CONFIGURED 147 * 148 * The server has been configured. 149 * 150 * SMB_SERVER_STATE_RUNNING 151 * 152 * The server has been started. While in this state the threads listening on 153 * the sockets car be started. The smbd daemon does so through an Ioctl: 154 * 155 * smb_drv_ioctl(SMB_IOC_NBT_LISTEN) --> smb_server_nbt_listen() 156 * smb_drv_ioctl(SMB_IOC_TCP_LISTEN) --> smb_server_nbt_listen() 157 * 158 * When a client establishes a connection the thread listening leaves 159 * temporarily the kernel. While in user space it creates a thread for the 160 * new session. It then returns to kernel with the result of the thread 161 * creation. If the creation failed the new session context is destroyed 162 * before returning listening. 163 * 164 * The new created thread enters the kernel though an Ioctl: 165 * 166 * smb_drv_ioctl(SMB_IOC_NBT_RECEIVE) --> smb_server_nbt_receive() 167 * smb_drv_ioctl(SMB_IOC_TCP_RECEIVE) --> smb_server_tcp_receive() 168 * 169 * SMB_SERVER_STATE_STOPPING 170 * 171 * The threads listening on the NBT and TCP sockets are being terminated. 172 * 173 * 174 * Transitions 175 * ----------- 176 * 177 * Transition T0 178 * 179 * The daemon smbd triggers its creation by opening the smbsrv device. If 180 * the zone where the daemon lives doesn't have an smb server yet it is 181 * created. 182 * 183 * smb_drv_open() --> smb_server_create() 184 * 185 * Transition T1 186 * 187 * This transition occurs in smb_server_configure(). It is triggered by the 188 * daemon through an Ioctl. 189 * 190 * smb_drv_ioctl(SMB_IOC_CONFIG) --> smb_server_configure() 191 * 192 * Transition T2 193 * 194 * This transition occurs in smb_server_start(). It is triggered by the 195 * daemon through an Ioctl. 196 * 197 * smb_drv_ioctl(SMB_IOC_START) --> smb_server_start() 198 * 199 * Transition T3 200 * 201 * This transition occurs in smb_server_delete(). It is triggered by the 202 * daemon when closing the smbsrv device 203 * 204 * smb_drv_close() --> smb_server_delete() 205 * 206 * Comments 207 * -------- 208 * 209 * This files assumes that there will one SMB server per zone. For now the 210 * smb server works only in global zone. There's nothing in this file preventing 211 * an smb server from being created in a non global zone. That limitation is 212 * enforced in user space. 213 */ 214 215 #include <sys/strsubr.h> 216 #include <sys/cmn_err.h> 217 #include <sys/priv.h> 218 #include <sys/socketvar.h> 219 #include <sys/zone.h> 220 #include <smbsrv/smb_kproto.h> 221 #include <smbsrv/netbios.h> 222 #include <smbsrv/smb_incl.h> 223 #include <smbsrv/cifs.h> 224 #include <smbsrv/smb_fsops.h> 225 #include <smbsrv/lmshare.h> 226 #include <smbsrv/smb_door_svc.h> 227 #include <smbsrv/smb_kstat.h> 228 229 extern void smb_dispatch_kstat_init(void); 230 extern void smb_dispatch_kstat_fini(void); 231 extern void smb_reply_notify_change_request(smb_request_t *); 232 233 static int smb_server_kstat_init(smb_server_t *); 234 static void smb_server_kstat_fini(smb_server_t *); 235 static int smb_server_kstat_update_info(kstat_t *, int); 236 static void smb_server_timers(smb_thread_t *, void *); 237 static int smb_server_listen(smb_server_t *, smb_listener_daemon_t *, 238 in_port_t, int); 239 static int smb_server_lookup(smb_server_t **); 240 static void smb_server_release(smb_server_t *); 241 static int smb_server_ulist_geti(smb_session_list_t *, int, smb_dr_user_ctx_t *, 242 int); 243 static void smb_server_store_cfg(smb_server_t *, smb_kmod_cfg_t *); 244 static void smb_server_stop(smb_server_t *); 245 static int smb_server_fsop_start(smb_server_t *); 246 static void smb_server_fsop_stop(smb_server_t *); 247 248 static smb_llist_t smb_servers; 249 250 /* 251 * ***************************************************************************** 252 * **************** Functions called from the device interface ***************** 253 * ***************************************************************************** 254 * 255 * These functions determine the relevant smb server to which the call apply. 256 */ 257 258 /* 259 * smb_server_svc_init 260 * 261 * This function must called from smb_drv_attach(). 262 */ 263 int 264 smb_server_svc_init(void) 265 { 266 int rc = 0; 267 268 while (rc == 0) { 269 if (rc = smb_vop_init()) 270 continue; 271 if (rc = smb_node_init()) 272 continue; 273 if (rc = smb_fem_init()) 274 continue; 275 if (rc = smb_notify_init()) 276 continue; 277 if (rc = smb_net_init()) 278 continue; 279 if (rc = smb_kdoor_srv_start()) 280 continue; 281 smb_llist_constructor(&smb_servers, sizeof (smb_server_t), 282 offsetof(smb_server_t, sv_lnd)); 283 return (0); 284 } 285 smb_net_fini(); 286 smb_notify_fini(); 287 smb_fem_fini(); 288 smb_node_fini(); 289 smb_vop_fini(); 290 return (rc); 291 } 292 293 /* 294 * smb_server_svc_fini 295 * 296 * This function must called from smb_drv_detach(). It will fail if servers 297 * still exist. 298 */ 299 int 300 smb_server_svc_fini(void) 301 { 302 int rc = EBUSY; 303 304 if (smb_llist_get_count(&smb_servers) == 0) { 305 smb_kdoor_srv_stop(); 306 smb_net_fini(); 307 smb_notify_fini(); 308 smb_fem_fini(); 309 smb_node_fini(); 310 smb_vop_fini(); 311 smb_llist_destructor(&smb_servers); 312 rc = 0; 313 } 314 return (rc); 315 } 316 317 /* 318 * smb_server_create 319 * 320 * This function will fail if there's already a server associated with the 321 * caller's zone. 322 */ 323 int 324 smb_server_create(void) 325 { 326 zoneid_t zid; 327 smb_server_t *sv; 328 329 zid = getzoneid(); 330 331 smb_llist_enter(&smb_servers, RW_WRITER); 332 sv = smb_llist_head(&smb_servers); 333 while (sv) { 334 ASSERT(sv->sv_magic == SMB_SERVER_MAGIC); 335 if (sv->sv_zid == zid) { 336 smb_llist_exit(&smb_servers); 337 return (EEXIST); 338 } 339 sv = smb_llist_next(&smb_servers, sv); 340 } 341 342 sv = kmem_zalloc(sizeof (smb_server_t), KM_NOSLEEP); 343 if (sv == NULL) { 344 smb_llist_exit(&smb_servers); 345 return (ENOMEM); 346 } 347 348 smb_llist_constructor(&sv->sv_vfs_list, sizeof (smb_vfs_t), 349 offsetof(smb_vfs_t, sv_lnd)); 350 351 smb_session_list_constructor(&sv->sv_nbt_daemon.ld_session_list); 352 smb_session_list_constructor(&sv->sv_tcp_daemon.ld_session_list); 353 354 sv->si_cache_vfs = kmem_cache_create("smb_vfs_cache", 355 sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 356 sv->si_cache_request = kmem_cache_create("smb_request_cache", 357 sizeof (smb_request_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 358 sv->si_cache_session = kmem_cache_create("smb_session_cache", 359 sizeof (smb_session_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 360 sv->si_cache_user = kmem_cache_create("smb_user_cache", 361 sizeof (smb_user_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 362 sv->si_cache_tree = kmem_cache_create("smb_tree_cache", 363 sizeof (smb_tree_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 364 sv->si_cache_ofile = kmem_cache_create("smb_ofile_cache", 365 sizeof (smb_ofile_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 366 sv->si_cache_odir = kmem_cache_create("smb_odir_cache", 367 sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 368 sv->si_cache_node = kmem_cache_create("smb_node_cache", 369 sizeof (smb_node_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 370 371 smb_thread_init(&sv->si_thread_timers, 372 "smb_timers", smb_server_timers, sv, 373 NULL, NULL); 374 375 sv->sv_pid = curproc->p_pid; 376 377 smb_winpipe_init(); 378 (void) smb_server_kstat_init(sv); 379 380 mutex_init(&sv->sv_mutex, NULL, MUTEX_DEFAULT, NULL); 381 cv_init(&sv->sv_cv, NULL, CV_DEFAULT, NULL); 382 sv->sv_state = SMB_SERVER_STATE_CREATED; 383 sv->sv_magic = SMB_SERVER_MAGIC; 384 sv->sv_zid = zid; 385 386 smb_llist_insert_tail(&smb_servers, sv); 387 smb_llist_exit(&smb_servers); 388 return (0); 389 } 390 391 /* 392 * smb_server_delete 393 * 394 * This function will delete the server passed in. It will make sure that all 395 * activity associated that server has ceased before destroying it. 396 */ 397 int 398 smb_server_delete(void) 399 { 400 smb_server_t *sv; 401 int rc; 402 403 rc = smb_server_lookup(&sv); 404 if (rc != 0) 405 return (rc); 406 407 mutex_enter(&sv->sv_mutex); 408 switch (sv->sv_state) { 409 case SMB_SERVER_STATE_RUNNING: 410 { 411 boolean_t nbt = B_FALSE; 412 boolean_t tcp = B_FALSE; 413 414 if (sv->sv_nbt_daemon.ld_kth) { 415 tsignal(sv->sv_nbt_daemon.ld_kth, SIGINT); 416 nbt = B_TRUE; 417 } 418 if (sv->sv_tcp_daemon.ld_kth) { 419 tsignal(sv->sv_tcp_daemon.ld_kth, SIGINT); 420 tcp = B_TRUE; 421 } 422 sv->sv_state = SMB_SERVER_STATE_DELETING; 423 mutex_exit(&sv->sv_mutex); 424 if (nbt) 425 thread_join(sv->sv_nbt_daemon.ld_ktdid); 426 if (tcp) 427 thread_join(sv->sv_tcp_daemon.ld_ktdid); 428 mutex_enter(&sv->sv_mutex); 429 break; 430 } 431 case SMB_SERVER_STATE_CONFIGURED: 432 case SMB_SERVER_STATE_CREATED: 433 sv->sv_state = SMB_SERVER_STATE_DELETING; 434 break; 435 default: 436 ASSERT(sv->sv_state == SMB_SERVER_STATE_DELETING); 437 mutex_exit(&sv->sv_mutex); 438 smb_server_release(sv); 439 return (ENOTTY); 440 } 441 442 ASSERT(sv->sv_state == SMB_SERVER_STATE_DELETING); 443 444 sv->sv_refcnt--; 445 while (sv->sv_refcnt) 446 cv_wait(&sv->sv_cv, &sv->sv_mutex); 447 448 mutex_exit(&sv->sv_mutex); 449 450 smb_llist_enter(&smb_servers, RW_WRITER); 451 smb_llist_remove(&smb_servers, sv); 452 smb_llist_exit(&smb_servers); 453 454 smb_server_stop(sv); 455 rw_destroy(&sv->sv_cfg_lock); 456 smb_winpipe_fini(); 457 smb_server_kstat_fini(sv); 458 smb_llist_destructor(&sv->sv_vfs_list); 459 kmem_cache_destroy(sv->si_cache_vfs); 460 kmem_cache_destroy(sv->si_cache_request); 461 kmem_cache_destroy(sv->si_cache_session); 462 kmem_cache_destroy(sv->si_cache_user); 463 kmem_cache_destroy(sv->si_cache_tree); 464 kmem_cache_destroy(sv->si_cache_ofile); 465 kmem_cache_destroy(sv->si_cache_odir); 466 kmem_cache_destroy(sv->si_cache_node); 467 468 taskq_destroy(sv->sv_thread_pool); 469 smb_thread_destroy(&sv->si_thread_timers); 470 mutex_destroy(&sv->sv_mutex); 471 cv_destroy(&sv->sv_cv); 472 sv->sv_magic = 0; 473 kmem_free(sv, sizeof (smb_server_t)); 474 475 return (0); 476 } 477 478 /* 479 * smb_server_configure 480 */ 481 int 482 smb_server_configure(smb_kmod_cfg_t *cfg) 483 { 484 int rc = 0; 485 smb_server_t *sv; 486 487 rc = smb_server_lookup(&sv); 488 if (rc) 489 return (rc); 490 491 mutex_enter(&sv->sv_mutex); 492 switch (sv->sv_state) { 493 case SMB_SERVER_STATE_CREATED: 494 smb_server_store_cfg(sv, cfg); 495 sv->sv_state = SMB_SERVER_STATE_CONFIGURED; 496 break; 497 498 case SMB_SERVER_STATE_CONFIGURED: 499 smb_server_store_cfg(sv, cfg); 500 break; 501 502 case SMB_SERVER_STATE_RUNNING: 503 rw_enter(&sv->sv_cfg_lock, RW_WRITER); 504 smb_server_store_cfg(sv, cfg); 505 rw_exit(&sv->sv_cfg_lock); 506 break; 507 508 default: 509 ASSERT(sv->sv_state == SMB_SERVER_STATE_DELETING); 510 rc = EFAULT; 511 break; 512 } 513 mutex_exit(&sv->sv_mutex); 514 515 smb_server_release(sv); 516 517 return (rc); 518 } 519 520 /* 521 * smb_server_start 522 */ 523 int 524 smb_server_start(struct smb_io_start *io_start) 525 { 526 int rc = 0; 527 smb_server_t *sv; 528 529 rc = smb_server_lookup(&sv); 530 if (rc) 531 return (rc); 532 533 mutex_enter(&sv->sv_mutex); 534 switch (sv->sv_state) { 535 case SMB_SERVER_STATE_CONFIGURED: 536 537 sv->sv_thread_pool = taskq_create("smb_workers", 538 sv->sv_cfg.skc_maxworkers, SMB_WORKER_PRIORITY, 539 sv->sv_cfg.skc_maxworkers, INT_MAX, 540 TASKQ_DYNAMIC|TASKQ_PREPOPULATE); 541 542 sv->sv_session = smb_session_create(NULL, 0, sv); 543 if (sv->sv_session == NULL) { 544 rc = ENOMEM; 545 break; 546 } 547 548 if (rc = smb_server_fsop_start(sv)) 549 break; 550 ASSERT(sv->sv_lmshrd == NULL); 551 sv->sv_lmshrd = lmshrd_kclient_init(io_start->lmshrd); 552 if (sv->sv_lmshrd == NULL) 553 break; 554 if (rc = smb_kdoor_clnt_start(io_start->udoor)) 555 break; 556 if (rc = smb_kdoor_srv_set_dwncall()) 557 break; 558 if (rc = smb_thread_start(&sv->si_thread_timers)) 559 break; 560 /* 561 * XXX We give up the NET_MAC_AWARE privilege because it keeps 562 * us from re-opening the connection when there are leftover TCP 563 * connections in TCPS_TIME_WAIT state. There seem to be some 564 * security ramifications around reestablishing a connection 565 * while possessing the NET_MAC_AWARE privilege. 566 * 567 * This approach may cause problems when we try to support 568 * zones. An alternative would be to retry the connection setup 569 * for a fixed period of time until the stale connections clear 570 * up but that implies we would be offline for a couple minutes 571 * every time the service is restarted with active connections. 572 */ 573 rc = setpflags(NET_MAC_AWARE, 0, CRED()); 574 if (rc) { 575 cmn_err(CE_WARN, 576 "Cannot remove NET_MAC_AWARE privilege"); 577 break; 578 } 579 if (rc = smb_winpipe_open(io_start->winpipe)) { 580 cmn_err(CE_WARN, "Cannot open winpipe door"); 581 break; 582 } 583 sv->sv_state = SMB_SERVER_STATE_RUNNING; 584 mutex_exit(&sv->sv_mutex); 585 smb_server_release(sv); 586 return (0); 587 default: 588 ASSERT((sv->sv_state == SMB_SERVER_STATE_CREATED) || 589 (sv->sv_state == SMB_SERVER_STATE_RUNNING) || 590 (sv->sv_state == SMB_SERVER_STATE_DELETING)); 591 mutex_exit(&sv->sv_mutex); 592 smb_server_release(sv); 593 return (ENOTTY); 594 } 595 596 smb_server_stop(sv); 597 mutex_exit(&sv->sv_mutex); 598 smb_server_release(sv); 599 return (rc); 600 } 601 602 /* 603 * smb_server_nbt_listen: SMB-over-NetBIOS service 604 * 605 * Traditional SMB service over NetBIOS (port 139), which requires 606 * that a NetBIOS session be established. 607 */ 608 int 609 smb_server_nbt_listen(int error) 610 { 611 smb_server_t *sv; 612 int rc; 613 614 rc = smb_server_lookup(&sv); 615 if (rc) 616 return (rc); 617 618 mutex_enter(&sv->sv_mutex); 619 switch (sv->sv_state) { 620 case SMB_SERVER_STATE_RUNNING: 621 if ((sv->sv_nbt_daemon.ld_kth != NULL) && 622 (sv->sv_nbt_daemon.ld_kth != curthread)) { 623 mutex_exit(&sv->sv_mutex); 624 return (EACCES); 625 } else { 626 sv->sv_nbt_daemon.ld_kth = curthread; 627 sv->sv_nbt_daemon.ld_ktdid = curthread->t_did; 628 } 629 break; 630 default: 631 ASSERT((sv->sv_state == SMB_SERVER_STATE_CREATED) || 632 (sv->sv_state == SMB_SERVER_STATE_CONFIGURED) || 633 (sv->sv_state == SMB_SERVER_STATE_DELETING)); 634 mutex_exit(&sv->sv_mutex); 635 smb_server_release(sv); 636 return (EFAULT); 637 } 638 mutex_exit(&sv->sv_mutex); 639 640 rc = smb_server_listen(sv, &sv->sv_nbt_daemon, SSN_SRVC_TCP_PORT, 641 error); 642 643 if (rc) { 644 mutex_enter(&sv->sv_mutex); 645 sv->sv_nbt_daemon.ld_kth = NULL; 646 mutex_exit(&sv->sv_mutex); 647 } 648 649 smb_server_release(sv); 650 651 return (rc); 652 } 653 654 int 655 smb_server_tcp_listen(int error) 656 { 657 smb_server_t *sv; 658 int rc; 659 660 rc = smb_server_lookup(&sv); 661 if (rc) 662 return (rc); 663 664 mutex_enter(&sv->sv_mutex); 665 switch (sv->sv_state) { 666 case SMB_SERVER_STATE_RUNNING: 667 if ((sv->sv_tcp_daemon.ld_kth) && 668 (sv->sv_tcp_daemon.ld_kth != curthread)) { 669 mutex_exit(&sv->sv_mutex); 670 return (EACCES); 671 } else { 672 sv->sv_tcp_daemon.ld_kth = curthread; 673 sv->sv_tcp_daemon.ld_ktdid = curthread->t_did; 674 } 675 break; 676 default: 677 ASSERT((sv->sv_state == SMB_SERVER_STATE_CREATED) || 678 (sv->sv_state == SMB_SERVER_STATE_CONFIGURED) || 679 (sv->sv_state == SMB_SERVER_STATE_DELETING)); 680 mutex_exit(&sv->sv_mutex); 681 return (EFAULT); 682 } 683 mutex_exit(&sv->sv_mutex); 684 685 rc = smb_server_listen(sv, &sv->sv_tcp_daemon, SMB_SRVC_TCP_PORT, 686 error); 687 688 if (rc) { 689 mutex_enter(&sv->sv_mutex); 690 sv->sv_tcp_daemon.ld_kth = NULL; 691 mutex_exit(&sv->sv_mutex); 692 } 693 694 smb_server_release(sv); 695 696 return (rc); 697 } 698 699 /* 700 * smb_server_nbt_receive 701 */ 702 int 703 smb_server_nbt_receive(void) 704 { 705 int rc; 706 smb_server_t *sv; 707 708 rc = smb_server_lookup(&sv); 709 if (rc) 710 return (rc); 711 712 rc = smb_session_daemon(&sv->sv_nbt_daemon.ld_session_list); 713 714 smb_server_release(sv); 715 716 return (rc); 717 } 718 719 /* 720 * smb_server_tcp_receive 721 */ 722 int 723 smb_server_tcp_receive(void) 724 { 725 int rc; 726 smb_server_t *sv; 727 728 rc = smb_server_lookup(&sv); 729 if (rc) 730 return (rc); 731 732 rc = smb_session_daemon(&sv->sv_tcp_daemon.ld_session_list); 733 734 smb_server_release(sv); 735 736 return (rc); 737 } 738 739 int 740 smb_server_set_gmtoff(uint32_t goff) 741 { 742 int rc; 743 smb_server_t *sv; 744 745 746 rc = smb_server_lookup(&sv); 747 if (rc) 748 return (rc); 749 750 sv->si_gmtoff = goff; 751 752 smb_server_release(sv); 753 754 return (rc); 755 } 756 757 /* 758 * ***************************************************************************** 759 * ****************** Functions called from the door interface ***************** 760 * ***************************************************************************** 761 * 762 * These functions determine the relevant smb server to which the call apply. 763 */ 764 765 uint32_t 766 smb_server_get_user_count(void) 767 { 768 smb_server_t *sv; 769 uint32_t counter = 0; 770 771 if (smb_server_lookup(&sv)) 772 return (0); 773 774 counter = (uint32_t)sv->sv_open_users; 775 776 smb_server_release(sv); 777 778 return (counter); 779 } 780 781 uint32_t 782 smb_server_get_session_count(void) 783 { 784 smb_server_t *sv; 785 uint32_t counter = 0; 786 787 if (smb_server_lookup(&sv)) 788 return (0); 789 790 rw_enter(&sv->sv_nbt_daemon.ld_session_list.se_lock, RW_READER); 791 counter = sv->sv_nbt_daemon.ld_session_list.se_act.count; 792 rw_exit(&sv->sv_nbt_daemon.ld_session_list.se_lock); 793 rw_enter(&sv->sv_tcp_daemon.ld_session_list.se_lock, RW_READER); 794 counter += sv->sv_tcp_daemon.ld_session_list.se_act.count; 795 rw_exit(&sv->sv_tcp_daemon.ld_session_list.se_lock); 796 797 smb_server_release(sv); 798 799 return (counter); 800 } 801 802 /* 803 * smb_session_disconnect_share 804 * 805 * Disconnects the specified share. This function should be called after the 806 * share passed in has been made unavailable by the "share manager". 807 */ 808 void 809 smb_server_disconnect_share(char *sharename) 810 { 811 smb_server_t *sv; 812 813 if (smb_server_lookup(&sv)) 814 return; 815 816 smb_session_disconnect_share(&sv->sv_nbt_daemon.ld_session_list, 817 sharename); 818 smb_session_disconnect_share(&sv->sv_tcp_daemon.ld_session_list, 819 sharename); 820 821 smb_server_release(sv); 822 } 823 824 void 825 smb_server_disconnect_volume(fs_desc_t *fsd) 826 { 827 smb_server_t *sv; 828 829 if (smb_server_lookup(&sv)) 830 return; 831 832 smb_session_disconnect_volume(&sv->sv_nbt_daemon.ld_session_list, fsd); 833 smb_session_disconnect_volume(&sv->sv_tcp_daemon.ld_session_list, fsd); 834 835 smb_server_release(sv); 836 } 837 838 int 839 smb_server_dr_ulist_get(int offset, smb_dr_ulist_t *dr_ulist, int max_cnt) 840 { 841 smb_server_t *sv; 842 843 if (!dr_ulist) 844 return (-1); 845 846 if (smb_server_lookup(&sv)) 847 return (-1); 848 849 dr_ulist->dul_cnt = 850 smb_server_ulist_geti(&sv->sv_nbt_daemon.ld_session_list, 851 offset, dr_ulist->dul_users, max_cnt); 852 dr_ulist->dul_cnt += 853 smb_server_ulist_geti(&sv->sv_tcp_daemon.ld_session_list, 854 offset - dr_ulist->dul_cnt, &dr_ulist->dul_users[dr_ulist->dul_cnt], 855 max_cnt); 856 857 return (dr_ulist->dul_cnt); 858 } 859 860 /* 861 * smb_server_share_export() 862 * 863 * This function handles kernel processing at share enable time. 864 * 865 * At share-enable time (LMSHRD_ADD), the file system corresponding to 866 * the share is checked for characteristics that are required for SMB 867 * sharing. If this check passes, then a hold is taken on the root vnode 868 * of the file system (or a reference count on the corresponding smb_vfs_t 869 * is bumped), preventing an unmount. (See smb_vfs_hold()). 870 */ 871 872 int 873 smb_server_share_export(char *path) 874 { 875 smb_server_t *sv; 876 int error; 877 smb_node_t *fnode = NULL; 878 smb_node_t *dnode; 879 smb_attr_t ret_attr; 880 char last_comp[MAXNAMELEN]; 881 smb_request_t *sr; 882 883 if (smb_server_lookup(&sv)) 884 return (EINVAL); 885 886 sr = smb_request_alloc(sv->sv_session, 0); 887 if (sr == NULL) { 888 smb_server_release(sv); 889 return (ENOMEM); 890 } 891 892 sr->user_cr = kcred; 893 894 error = smb_pathname_reduce(sr, kcred, path, NULL, NULL, &dnode, 895 last_comp); 896 897 if (error) { 898 smb_request_free(sr); 899 smb_server_release(sv); 900 return (error); 901 } 902 903 error = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, NULL, dnode, 904 last_comp, &fnode, &ret_attr, NULL, NULL); 905 906 smb_node_release(dnode); 907 908 if (error) { 909 smb_request_free(sr); 910 smb_server_release(sv); 911 return (error); 912 } 913 914 ASSERT(fnode->vp && fnode->vp->v_vfsp); 915 916 #ifdef SMB_ENFORCE_NODEV 917 if (vfs_optionisset(fnode->vp->v_vfsp, MNTOPT_NODEVICES, NULL) == 0) 918 return (EINVAL); 919 #endif /* SMB_ENFORCE_NODEV */ 920 921 if (!smb_vfs_hold(sv, fnode->vp->v_vfsp)) { 922 smb_node_release(fnode); 923 smb_request_free(sr); 924 smb_server_release(sv); 925 return (ENOMEM); 926 } 927 928 /* 929 * The refcount on the smb_vfs has been incremented. 930 * If it wasn't already, a hold has also been taken 931 * on the root vnode of the file system. 932 */ 933 934 smb_node_release(fnode); 935 smb_request_free(sr); 936 smb_server_release(sv); 937 return (0); 938 } 939 940 941 942 /* 943 * smb_server_share_unexport() 944 * 945 * This function handles kernel processing at share disable time. 946 * 947 * At share-disable time (LMSHRD_DELETE), the reference count on the 948 * corresponding smb_vfs_t is decremented. If this is the last share 949 * on the file system, the hold on the root vnode of the file system 950 * will be released. (See smb_vfs_rele().) 951 */ 952 953 int 954 smb_server_share_unexport(char *path, char *sharename) 955 { 956 smb_server_t *sv; 957 int error; 958 smb_node_t *fnode = NULL; 959 smb_node_t *dnode; 960 smb_attr_t ret_attr; 961 char last_comp[MAXNAMELEN]; 962 smb_request_t *sr; 963 964 if (smb_server_lookup(&sv)) 965 return (EINVAL); 966 967 sr = smb_request_alloc(sv->sv_session, 0); 968 if (sr == NULL) { 969 smb_server_release(sv); 970 return (ENOMEM); 971 } 972 sr->user_cr = kcred; 973 974 error = smb_pathname_reduce(sr, kcred, path, NULL, NULL, &dnode, 975 last_comp); 976 977 if (error) { 978 smb_request_free(sr); 979 smb_server_release(sv); 980 return (error); 981 } 982 983 error = smb_fsop_lookup(sr, kcred, SMB_FOLLOW_LINKS, NULL, dnode, 984 last_comp, &fnode, &ret_attr, NULL, NULL); 985 986 smb_node_release(dnode); 987 988 if (error) { 989 smb_request_free(sr); 990 smb_server_release(sv); 991 return (error); 992 } 993 994 ASSERT(fnode->vp && fnode->vp->v_vfsp); 995 996 smb_session_disconnect_share(&sv->sv_nbt_daemon.ld_session_list, 997 sharename); 998 smb_session_disconnect_share(&sv->sv_tcp_daemon.ld_session_list, 999 sharename); 1000 smb_vfs_rele(sv, fnode->vp->v_vfsp); 1001 smb_node_release(fnode); 1002 smb_request_free(sr); 1003 smb_server_release(sv); 1004 return (0); 1005 } 1006 1007 /* 1008 * This is a special interface that will be utilized by ZFS to cause a share to 1009 * be added/removed. 1010 * 1011 * arg is either a lmshare_info_t or share_name from userspace. 1012 * It will need to be copied into the kernel. It is lmshare_info_t 1013 * for add operations and share_name for delete operations. 1014 */ 1015 int 1016 smb_server_share(void *arg, boolean_t add_share) 1017 { 1018 smb_server_t *sv; 1019 int rc; 1020 1021 rc = smb_server_lookup(&sv); 1022 if (rc == 0) { 1023 mutex_enter(&sv->sv_mutex); 1024 if (sv->sv_state == SMB_SERVER_STATE_RUNNING) { 1025 mutex_exit(&sv->sv_mutex); 1026 rc = lmshrd_share_upcall(sv->sv_lmshrd, arg, add_share); 1027 } else { 1028 mutex_exit(&sv->sv_mutex); 1029 rc = EPERM; 1030 } 1031 smb_server_release(sv); 1032 } 1033 return (rc); 1034 } 1035 1036 /* 1037 * ***************************************************************************** 1038 * **************** Functions called from the internal layers ****************** 1039 * ***************************************************************************** 1040 * 1041 * These functions are provided the relevant smb server by the caller. 1042 */ 1043 1044 void 1045 smb_server_reconnection_check(smb_server_t *sv, smb_session_t *session) 1046 { 1047 ASSERT(sv == session->s_server); 1048 1049 smb_session_reconnection_check(&sv->sv_nbt_daemon.ld_session_list, 1050 session); 1051 smb_session_reconnection_check(&sv->sv_tcp_daemon.ld_session_list, 1052 session); 1053 } 1054 1055 void 1056 smb_server_get_cfg(smb_server_t *sv, smb_kmod_cfg_t *cfg) 1057 { 1058 rw_enter(&sv->sv_cfg_lock, RW_READER); 1059 bcopy(&sv->sv_cfg, cfg, sizeof (*cfg)); 1060 rw_exit(&sv->sv_cfg_lock); 1061 } 1062 1063 /* 1064 * ***************************************************************************** 1065 * *************************** Static Functions ******************************** 1066 * ***************************************************************************** 1067 */ 1068 1069 static void 1070 smb_server_timers(smb_thread_t *thread, void *arg) 1071 { 1072 smb_server_t *sv = (smb_server_t *)arg; 1073 1074 ASSERT(sv != NULL); 1075 1076 while (smb_thread_continue_timedwait(thread, 1 /* Seconds */)) { 1077 smb_session_timers(&sv->sv_nbt_daemon.ld_session_list); 1078 smb_session_timers(&sv->sv_tcp_daemon.ld_session_list); 1079 } 1080 } 1081 1082 /* 1083 * smb_server_kstat_init 1084 */ 1085 static int 1086 smb_server_kstat_init(smb_server_t *sv) 1087 { 1088 (void) snprintf(sv->sv_ksp_name, sizeof (sv->sv_ksp_name), "%s%d", 1089 SMBSRV_KSTAT_NAME, sv->sv_zid); 1090 1091 sv->sv_ksp = kstat_create(SMBSRV_KSTAT_MODULE, 0, sv->sv_ksp_name, 1092 SMBSRV_KSTAT_CLASS, KSTAT_TYPE_NAMED, 1093 sizeof (sv->sv_ks_data) / sizeof (kstat_named_t), 1094 KSTAT_FLAG_VIRTUAL); 1095 1096 if (sv->sv_ksp) { 1097 (void) strlcpy(sv->sv_ks_data.state.name, "state", 1098 sizeof (sv->sv_ks_data.state.name)); 1099 sv->sv_ks_data.state.data_type = KSTAT_DATA_UINT32; 1100 (void) strlcpy(sv->sv_ks_data.open_files.name, "open_files", 1101 sizeof (sv->sv_ks_data.open_files.name)); 1102 sv->sv_ks_data.open_files.data_type = KSTAT_DATA_UINT32; 1103 (void) strlcpy(sv->sv_ks_data.open_trees.name, "connections", 1104 sizeof (sv->sv_ks_data.open_trees.name)); 1105 sv->sv_ks_data.open_trees.data_type = KSTAT_DATA_UINT32; 1106 (void) strlcpy(sv->sv_ks_data.open_users.name, "sessions", 1107 sizeof (sv->sv_ks_data.open_users.name)); 1108 sv->sv_ks_data.open_users.data_type = KSTAT_DATA_UINT32; 1109 1110 mutex_init(&sv->sv_ksp_mutex, NULL, MUTEX_DEFAULT, NULL); 1111 sv->sv_ksp->ks_lock = &sv->sv_ksp_mutex; 1112 sv->sv_ksp->ks_data = (void *)&sv->sv_ks_data; 1113 sv->sv_ksp->ks_update = smb_server_kstat_update_info; 1114 kstat_install(sv->sv_ksp); 1115 } 1116 1117 /* create and initialize smb kstats - smb_dispatch stats */ 1118 smb_dispatch_kstat_init(); 1119 1120 return (0); 1121 } 1122 1123 /* 1124 * smb_server_kstat_fini 1125 */ 1126 static void 1127 smb_server_kstat_fini(smb_server_t *sv) 1128 { 1129 if (sv->sv_ksp) { 1130 kstat_delete(sv->sv_ksp); 1131 mutex_destroy(&sv->sv_ksp_mutex); 1132 sv->sv_ksp = NULL; 1133 } 1134 smb_dispatch_kstat_fini(); 1135 } 1136 1137 /* ARGSUSED */ 1138 static int 1139 smb_server_kstat_update_info(kstat_t *ksp, int rw) 1140 { 1141 smb_server_t *sv; 1142 1143 if (rw == KSTAT_WRITE) { 1144 return (EACCES); 1145 } else { 1146 ASSERT(MUTEX_HELD(ksp->ks_lock)); 1147 1148 _NOTE(LINTED("pointer cast may result in improper alignment")) 1149 sv = (smb_server_t *)((uint8_t *)(ksp->ks_data) - 1150 offsetof(smb_server_t, sv_ks_data)); 1151 1152 ASSERT(sv->sv_magic == SMB_SERVER_MAGIC); 1153 1154 sv->sv_ks_data.state.value.ui32 = sv->sv_state; 1155 sv->sv_ks_data.open_files.value.ui32 = sv->sv_open_files; 1156 sv->sv_ks_data.open_trees.value.ui32 = sv->sv_open_trees; 1157 sv->sv_ks_data.open_users.value.ui32 = sv->sv_open_users; 1158 } 1159 return (0); 1160 } 1161 1162 /* 1163 * smb_server_stop 1164 * 1165 * The mutex of the server must have been entered before calling this function. 1166 */ 1167 static void 1168 smb_server_stop(smb_server_t *sv) 1169 { 1170 ASSERT(sv->sv_magic == SMB_SERVER_MAGIC); 1171 1172 smb_winpipe_close(); 1173 smb_thread_stop(&sv->si_thread_timers); 1174 smb_kdoor_clnt_stop(); 1175 lmshrd_kclient_fini(sv->sv_lmshrd); 1176 smb_server_fsop_stop(sv); 1177 if (sv->sv_session) { 1178 smb_session_delete(sv->sv_session); 1179 sv->sv_session = NULL; 1180 } 1181 } 1182 1183 static int 1184 smb_server_listen( 1185 smb_server_t *sv, 1186 smb_listener_daemon_t *ld, 1187 in_port_t port, 1188 int pthread_create_error) 1189 { 1190 int rc; 1191 struct sonode *s_so; 1192 uint32_t on = 1; 1193 smb_session_t *session; 1194 1195 if (pthread_create_error) { 1196 /* 1197 * Delete the last session created. The user space thread 1198 * creation failed. 1199 */ 1200 smb_session_list_delete_tail(&ld->ld_session_list); 1201 } 1202 1203 if (ld->ld_so == NULL) { 1204 /* First time listener */ 1205 ld->ld_sin.sin_family = AF_INET; 1206 ld->ld_sin.sin_port = htons(port); 1207 ld->ld_sin.sin_addr.s_addr = htonl(INADDR_ANY); 1208 ld->ld_so = smb_socreate(AF_INET, SOCK_STREAM, 0); 1209 1210 if (ld->ld_so) { 1211 1212 (void) sosetsockopt(ld->ld_so, SOL_SOCKET, 1213 SO_REUSEADDR, (const void *)&on, sizeof (on)); 1214 1215 rc = sobind(ld->ld_so, (struct sockaddr *)&ld->ld_sin, 1216 sizeof (ld->ld_sin), 0, 0); 1217 1218 if (rc == 0) { 1219 rc = solisten(ld->ld_so, 20); 1220 if (rc < 0) { 1221 cmn_err(CE_WARN, 1222 "Port %d: listen failed", port); 1223 smb_soshutdown(ld->ld_so); 1224 smb_sodestroy(ld->ld_so); 1225 ld->ld_so = NULL; 1226 return (rc); 1227 } 1228 } else { 1229 cmn_err(CE_WARN, 1230 "Port %d: bind failed", port); 1231 smb_soshutdown(ld->ld_so); 1232 smb_sodestroy(ld->ld_so); 1233 ld->ld_so = NULL; 1234 return (rc); 1235 } 1236 } else { 1237 cmn_err(CE_WARN, 1238 "Port %d: socket create failed", port); 1239 return (ENOMEM); 1240 } 1241 } 1242 1243 DTRACE_PROBE1(so__wait__accept, struct sonode *, ld->ld_so); 1244 1245 for (;;) { 1246 rc = soaccept(ld->ld_so, 0, &s_so); 1247 if (rc == 0) { 1248 uint32_t txbuf_size = 128*1024; 1249 uint32_t on = 1; 1250 1251 DTRACE_PROBE1(so__accept, struct sonode *, s_so); 1252 1253 (void) sosetsockopt(s_so, IPPROTO_TCP, TCP_NODELAY, 1254 (const void *)&on, sizeof (on)); 1255 (void) sosetsockopt(s_so, SOL_SOCKET, SO_KEEPALIVE, 1256 (const void *)&on, sizeof (on)); 1257 (void) sosetsockopt(s_so, SOL_SOCKET, SO_SNDBUF, 1258 (const void *)&txbuf_size, sizeof (txbuf_size)); 1259 /* 1260 * Create a session for this connection. 1261 */ 1262 session = smb_session_create(s_so, port, sv); 1263 if (session) { 1264 smb_session_list_append(&ld->ld_session_list, 1265 session); 1266 break; 1267 } else { 1268 smb_soshutdown(s_so); 1269 smb_sodestroy(s_so); 1270 } 1271 continue; 1272 } 1273 smb_session_list_signal(&ld->ld_session_list); 1274 smb_soshutdown(ld->ld_so); 1275 smb_sodestroy(ld->ld_so); 1276 ld->ld_so = NULL; 1277 break; 1278 } 1279 1280 return (rc); 1281 } 1282 1283 /* 1284 * smb_server_lookup 1285 * 1286 * This function tries to find the server associated with the zone of the 1287 * caller. 1288 */ 1289 static int 1290 smb_server_lookup(smb_server_t **psv) 1291 { 1292 zoneid_t zid; 1293 smb_server_t *sv; 1294 1295 zid = getzoneid(); 1296 1297 smb_llist_enter(&smb_servers, RW_READER); 1298 sv = smb_llist_head(&smb_servers); 1299 while (sv) { 1300 ASSERT(sv->sv_magic == SMB_SERVER_MAGIC); 1301 if (sv->sv_zid == zid) { 1302 mutex_enter(&sv->sv_mutex); 1303 if (sv->sv_state != SMB_SERVER_STATE_DELETING) { 1304 sv->sv_refcnt++; 1305 mutex_exit(&sv->sv_mutex); 1306 smb_llist_exit(&smb_servers); 1307 *psv = sv; 1308 return (0); 1309 } 1310 mutex_exit(&sv->sv_mutex); 1311 break; 1312 } 1313 sv = smb_llist_next(&smb_servers, sv); 1314 } 1315 smb_llist_exit(&smb_servers); 1316 return (EPERM); 1317 } 1318 1319 /* 1320 * smb_server_release 1321 * 1322 * This function decrements the reference count of the server and signals its 1323 * condition variable if the state of the server is SMB_SERVER_STATE_DELETING. 1324 */ 1325 static void 1326 smb_server_release(smb_server_t *sv) 1327 { 1328 ASSERT(sv->sv_magic == SMB_SERVER_MAGIC); 1329 1330 mutex_enter(&sv->sv_mutex); 1331 ASSERT(sv->sv_refcnt); 1332 sv->sv_refcnt--; 1333 if ((sv->sv_refcnt == 0) && (sv->sv_state == SMB_SERVER_STATE_DELETING)) 1334 cv_signal(&sv->sv_cv); 1335 mutex_exit(&sv->sv_mutex); 1336 } 1337 1338 static int 1339 smb_server_ulist_geti( 1340 smb_session_list_t *se, 1341 int offset, 1342 smb_dr_user_ctx_t *uinfo, 1343 int max_cnt) 1344 { 1345 smb_session_t *sn = NULL; 1346 smb_user_t *user; 1347 smb_llist_t *ulist; 1348 int cnt = 0, skip = 0; 1349 1350 rw_enter(&se->se_lock, RW_READER); 1351 sn = list_head(&se->se_act.lst); 1352 while (sn && (cnt < max_cnt)) { 1353 ASSERT(sn->s_magic == SMB_SESSION_MAGIC); 1354 ulist = &sn->s_user_list; 1355 smb_llist_enter(ulist, RW_READER); 1356 user = smb_llist_head(ulist); 1357 while (user && (cnt < max_cnt)) { 1358 ASSERT(user->u_magic == SMB_USER_MAGIC); 1359 mutex_enter(&user->u_mutex); 1360 if (user->u_state == SMB_USER_STATE_LOGGED_IN) { 1361 if (skip++ < offset) { 1362 mutex_exit(&user->u_mutex); 1363 user = smb_llist_next(ulist, user); 1364 continue; 1365 } 1366 1367 if (smb_dr_user_create(uinfo, sn->s_kid, 1368 user->u_uid, user->u_domain, user->u_name, 1369 sn->workstation, sn->ipaddr, sn->native_os, 1370 user->u_logon_time, user->u_flags) != 0) { 1371 mutex_exit(&user->u_mutex); 1372 user = smb_llist_next(ulist, user); 1373 continue; 1374 } 1375 uinfo++; 1376 cnt++; 1377 } 1378 mutex_exit(&user->u_mutex); 1379 user = smb_llist_next(ulist, user); 1380 } 1381 smb_llist_exit(ulist); 1382 } 1383 rw_exit(&se->se_lock); 1384 return (cnt); 1385 } 1386 1387 static void 1388 smb_server_store_cfg(smb_server_t *sv, smb_kmod_cfg_t *cfg) 1389 { 1390 if (cfg->skc_maxconnections == 0) 1391 cfg->skc_maxconnections = 0xFFFFFFFF; 1392 1393 /* 1394 * XXX should not override configuration. 1395 * For now, this disables server side 1396 * signing regardless of configuration. 1397 */ 1398 cfg->skc_signing_enable = 0; 1399 cfg->skc_signing_required = 0; 1400 cfg->skc_signing_check = 0; 1401 1402 smb_session_correct_keep_alive_values( 1403 &sv->sv_nbt_daemon.ld_session_list, cfg->skc_keepalive); 1404 smb_session_correct_keep_alive_values( 1405 &sv->sv_tcp_daemon.ld_session_list, cfg->skc_keepalive); 1406 1407 /* 1408 * XXX The following code was pulled from smb_oplock_init. 1409 * It should be combined with with the config process if 1410 * this info will be stored with the configuration or with 1411 * the smb_fsop_start function if the data will be stored 1412 * in the root of the fs. 1413 */ 1414 1415 /* 1416 * XXX oplock enable flag. 1417 * Should be stored in extended attribute in root of fs 1418 * or a ZFS user-defined property. 1419 */ 1420 if (cfg->skc_oplock_enable == 0) { 1421 cmn_err(CE_NOTE, "SmbOplocks: disabled"); 1422 } 1423 1424 bcopy(cfg, &sv->sv_cfg, sizeof (sv->sv_cfg)); 1425 } 1426 1427 static int 1428 smb_server_fsop_start(smb_server_t *sv) 1429 { 1430 int error; 1431 1432 error = smb_node_root_init(rootdir, sv, &sv->si_root_smb_node); 1433 if (error != 0) 1434 sv->si_root_smb_node = NULL; 1435 1436 return (error); 1437 } 1438 1439 static void 1440 smb_server_fsop_stop(smb_server_t *sv) 1441 { 1442 if (sv->si_root_smb_node != NULL) { 1443 smb_vfs_rele_all(sv); 1444 smb_node_release(sv->si_root_smb_node); 1445 sv->si_root_smb_node = NULL; 1446 } 1447 } 1448