1*5331Samw /* 2*5331Samw * CDDL HEADER START 3*5331Samw * 4*5331Samw * The contents of this file are subject to the terms of the 5*5331Samw * Common Development and Distribution License (the "License"). 6*5331Samw * You may not use this file except in compliance with the License. 7*5331Samw * 8*5331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5331Samw * or http://www.opensolaris.org/os/licensing. 10*5331Samw * See the License for the specific language governing permissions 11*5331Samw * and limitations under the License. 12*5331Samw * 13*5331Samw * When distributing Covered Code, include this CDDL HEADER in each 14*5331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5331Samw * If applicable, add the following below this CDDL HEADER, with the 16*5331Samw * fields enclosed by brackets "[]" replaced with your own identifying 17*5331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 18*5331Samw * 19*5331Samw * CDDL HEADER END 20*5331Samw */ 21*5331Samw /* 22*5331Samw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*5331Samw * Use is subject to license terms. 24*5331Samw */ 25*5331Samw 26*5331Samw #pragma ident "%Z%%M% %I% %E% SMI" 27*5331Samw 28*5331Samw /* 29*5331Samw * General Structures Layout 30*5331Samw * ------------------------- 31*5331Samw * 32*5331Samw * This is a simplified diagram showing the relationship between most of the 33*5331Samw * main structures. 34*5331Samw * 35*5331Samw * +-------------------+ 36*5331Samw * | SMB_INFO | 37*5331Samw * +-------------------+ 38*5331Samw * | 39*5331Samw * | 40*5331Samw * v 41*5331Samw * +-------------------+ +-------------------+ +-------------------+ 42*5331Samw * | SESSION |<----->| SESSION |......| SESSION | 43*5331Samw * +-------------------+ +-------------------+ +-------------------+ 44*5331Samw * | 45*5331Samw * | 46*5331Samw * v 47*5331Samw * +-------------------+ +-------------------+ +-------------------+ 48*5331Samw * | USER |<----->| USER |......| USER | 49*5331Samw * +-------------------+ +-------------------+ +-------------------+ 50*5331Samw * | 51*5331Samw * | 52*5331Samw * v 53*5331Samw * +-------------------+ +-------------------+ +-------------------+ 54*5331Samw * | TREE |<----->| TREE |......| TREE | 55*5331Samw * +-------------------+ +-------------------+ +-------------------+ 56*5331Samw * | | 57*5331Samw * | | 58*5331Samw * | v 59*5331Samw * | +-------+ +-------+ +-------+ 60*5331Samw * | | OFILE |<----->| OFILE |......| OFILE | 61*5331Samw * | +-------+ +-------+ +-------+ 62*5331Samw * | 63*5331Samw * | 64*5331Samw * v 65*5331Samw * +-------+ +------+ +------+ 66*5331Samw * | ODIR |<----->| ODIR |......| ODIR | 67*5331Samw * +-------+ +------+ +------+ 68*5331Samw * 69*5331Samw * 70*5331Samw * Odir State Machine 71*5331Samw * ------------------ 72*5331Samw * 73*5331Samw * +-------------------------+ T0 74*5331Samw * | SMB_ODIR_STATE_OPEN |<----------- Creation/Allocation 75*5331Samw * +-------------------------+ 76*5331Samw * | 77*5331Samw * | T1 78*5331Samw * | 79*5331Samw * v 80*5331Samw * +-------------------------+ 81*5331Samw * | SMB_ODIR_STATE_CLOSING | 82*5331Samw * +-------------------------+ 83*5331Samw * | 84*5331Samw * | T2 85*5331Samw * | 86*5331Samw * v 87*5331Samw * +-------------------------+ T3 88*5331Samw * | SMB_ODIR_STATE_CLOSED |----------> Deletion/Free 89*5331Samw * +-------------------------+ 90*5331Samw * 91*5331Samw * SMB_ODIR_STATE_OPEN 92*5331Samw * 93*5331Samw * While in this state: 94*5331Samw * - The odir is queued in the list of odirs of its tree. 95*5331Samw * - References will be given out if the odir is looked up. 96*5331Samw * 97*5331Samw * SMB_ODIR_STATE_CLOSING 98*5331Samw * 99*5331Samw * While in this state: 100*5331Samw * - The odir is queued in the list of odirs of its tree. 101*5331Samw * - References will not be given out if the odir is looked up. 102*5331Samw * - The odir is closed. 103*5331Samw * - The resources associated with the odir remain. 104*5331Samw * 105*5331Samw * SMB_ODIR_STATE_CLOSED 106*5331Samw * 107*5331Samw * While in this state: 108*5331Samw * - The odir is queued in the list of odirs of its tree. 109*5331Samw * - References will not be given out if the odir is looked up. 110*5331Samw * - The resources associated with the odir remain. 111*5331Samw * 112*5331Samw * Transition T0 113*5331Samw * 114*5331Samw * This transition occurs in smb_odir_open(). A new odir is created and 115*5331Samw * added to the list of odirs of a tree. 116*5331Samw * 117*5331Samw * Transition T1 118*5331Samw * 119*5331Samw * This transition occurs in smb_odir_close(). 120*5331Samw * 121*5331Samw * Transition T2 122*5331Samw * 123*5331Samw * This transition occurs in smb_odir_release(). The resources associated 124*5331Samw * with the odir are freed as well as the odir structure. For the 125*5331Samw * transition to occur, the odir must be in the SMB_ODIR_STATE_CLOSED 126*5331Samw * state and the reference count be zero. 127*5331Samw * 128*5331Samw * Comments 129*5331Samw * -------- 130*5331Samw * 131*5331Samw * The state machine of the odir structures is controlled by 3 elements: 132*5331Samw * - The list of odirs of the tree it belongs to. 133*5331Samw * - The mutex embedded in the structure itself. 134*5331Samw * - The reference count. 135*5331Samw * 136*5331Samw * There's a mutex embedded in the odir structure used to protect its fields 137*5331Samw * and there's a lock embedded in the list of odirs of a tree. To 138*5331Samw * increment or to decrement the reference count the mutex must be entered. 139*5331Samw * To insert the odir into the list of odirs of the tree and to remove 140*5331Samw * the odir from it, the lock must be entered in RW_WRITER mode. 141*5331Samw * 142*5331Samw * Rules of access to a odir structure: 143*5331Samw * 144*5331Samw * 1) In order to avoid deadlocks, when both (mutex and lock of the odir 145*5331Samw * list) have to be entered, the lock must be entered first. 146*5331Samw * 147*5331Samw * 2) All actions applied to an odir require a reference count. 148*5331Samw * 149*5331Samw * 3) There are 2 ways of getting a reference count. One is when the odir 150*5331Samw * is opened. The other when the odir is looked up. This translates 151*5331Samw * into 2 functions: smb_odir_open() and smb_odir_lookup_by_fid(). 152*5331Samw * 153*5331Samw * It should be noted that the reference count of an odir registers the 154*5331Samw * number of references to the odir in other structures (such as an smb 155*5331Samw * request). The reference count is not incremented in these 2 instances: 156*5331Samw * 157*5331Samw * 1) The odir is open. An odir is anchored by his state. If there's 158*5331Samw * no activity involving an odir currently open, the reference count 159*5331Samw * of that odir is zero. 160*5331Samw * 161*5331Samw * 2) The odir is queued in the list of odirs of its tree. The fact of 162*5331Samw * being queued in that list is NOT registered by incrementing the 163*5331Samw * reference count. 164*5331Samw */ 165*5331Samw #include <smbsrv/smb_incl.h> 166*5331Samw #include <smbsrv/smb_kproto.h> 167*5331Samw #include <smbsrv/smb_fsops.h> 168*5331Samw 169*5331Samw /* Static functions defined further down this file. */ 170*5331Samw static void smb_odir_delete(smb_odir_t *of); 171*5331Samw static smb_odir_t *smb_odir_close_and_next(smb_odir_t *od); 172*5331Samw 173*5331Samw #include <smbsrv/smb_incl.h> 174*5331Samw #include <smbsrv/smb_fsops.h> 175*5331Samw 176*5331Samw /* 177*5331Samw * smb_odir_open 178*5331Samw */ 179*5331Samw smb_odir_t * 180*5331Samw smb_odir_open( 181*5331Samw smb_tree_t *tree, 182*5331Samw smb_node_t *node, 183*5331Samw char *pattern, 184*5331Samw uint16_t pid, 185*5331Samw unsigned short sattr) 186*5331Samw { 187*5331Samw smb_odir_t *dir; 188*5331Samw 189*5331Samw ASSERT(tree); 190*5331Samw ASSERT(tree->t_magic == SMB_TREE_MAGIC); 191*5331Samw ASSERT(node); 192*5331Samw ASSERT(node->n_magic == SMB_NODE_MAGIC); 193*5331Samw ASSERT(pattern); 194*5331Samw 195*5331Samw if (strlen(pattern) >= sizeof (dir->d_pattern)) { 196*5331Samw return (NULL); 197*5331Samw } 198*5331Samw 199*5331Samw dir = kmem_cache_alloc(smb_info.si_cache_odir, KM_SLEEP); 200*5331Samw bzero(dir, sizeof (smb_odir_t)); 201*5331Samw dir->d_refcnt = 1; 202*5331Samw dir->d_session = tree->t_session; 203*5331Samw dir->d_user = tree->t_user; 204*5331Samw dir->d_tree = tree; 205*5331Samw (void) strlcpy(dir->d_pattern, pattern, sizeof (dir->d_pattern)); 206*5331Samw dir->d_wildcards = smb_convert_unicode_wildcards(pattern); 207*5331Samw dir->d_state = SMB_ODIR_STATE_OPEN; 208*5331Samw 209*5331Samw if (smb_idpool_alloc(&dir->d_tree->t_sid_pool, &dir->d_sid)) { 210*5331Samw kmem_cache_free(smb_info.si_cache_odir, dir); 211*5331Samw return (NULL); 212*5331Samw } 213*5331Samw mutex_init(&dir->d_mutex, NULL, MUTEX_DEFAULT, NULL); 214*5331Samw dir->d_sattr = sattr; 215*5331Samw dir->d_opened_by_pid = pid; 216*5331Samw dir->d_dir_snode = node; 217*5331Samw dir->d_state = SMB_ODIR_STATE_OPEN; 218*5331Samw dir->d_magic = SMB_ODIR_MAGIC; 219*5331Samw 220*5331Samw smb_llist_enter(&tree->t_odir_list, RW_WRITER); 221*5331Samw smb_llist_insert_tail(&tree->t_odir_list, dir); 222*5331Samw smb_llist_exit(&tree->t_odir_list); 223*5331Samw 224*5331Samw atomic_inc_32(&tree->t_session->s_dir_cnt); 225*5331Samw return (dir); 226*5331Samw } 227*5331Samw 228*5331Samw /* 229*5331Samw * smb_odir_close 230*5331Samw */ 231*5331Samw void 232*5331Samw smb_odir_close( 233*5331Samw smb_odir_t *od) 234*5331Samw { 235*5331Samw ASSERT(od); 236*5331Samw ASSERT(od->d_magic == SMB_ODIR_MAGIC); 237*5331Samw 238*5331Samw mutex_enter(&od->d_mutex); 239*5331Samw ASSERT(od->d_refcnt); 240*5331Samw switch (od->d_state) { 241*5331Samw case SMB_ODIR_STATE_OPEN: 242*5331Samw od->d_state = SMB_ODIR_STATE_CLOSED; 243*5331Samw break; 244*5331Samw case SMB_ODIR_STATE_CLOSING: 245*5331Samw case SMB_ODIR_STATE_CLOSED: 246*5331Samw break; 247*5331Samw default: 248*5331Samw ASSERT(0); 249*5331Samw break; 250*5331Samw } 251*5331Samw mutex_exit(&od->d_mutex); 252*5331Samw } 253*5331Samw 254*5331Samw /* 255*5331Samw * smb_odir_close_all 256*5331Samw * 257*5331Samw * 258*5331Samw */ 259*5331Samw void 260*5331Samw smb_odir_close_all( 261*5331Samw smb_tree_t *tree) 262*5331Samw { 263*5331Samw smb_odir_t *od; 264*5331Samw 265*5331Samw ASSERT(tree); 266*5331Samw ASSERT(tree->t_magic == SMB_TREE_MAGIC); 267*5331Samw 268*5331Samw smb_llist_enter(&tree->t_odir_list, RW_READER); 269*5331Samw od = smb_llist_head(&tree->t_odir_list); 270*5331Samw while (od) { 271*5331Samw ASSERT(od->d_magic == SMB_ODIR_MAGIC); 272*5331Samw ASSERT(od->d_tree == tree); 273*5331Samw od = smb_odir_close_and_next(od); 274*5331Samw } 275*5331Samw smb_llist_exit(&tree->t_odir_list); 276*5331Samw } 277*5331Samw 278*5331Samw /* 279*5331Samw * smb_odir_close_all_by_pid 280*5331Samw * 281*5331Samw * 282*5331Samw */ 283*5331Samw void 284*5331Samw smb_odir_close_all_by_pid( 285*5331Samw smb_tree_t *tree, 286*5331Samw uint16_t pid) 287*5331Samw { 288*5331Samw smb_odir_t *od; 289*5331Samw 290*5331Samw ASSERT(tree); 291*5331Samw ASSERT(tree->t_magic == SMB_TREE_MAGIC); 292*5331Samw 293*5331Samw smb_llist_enter(&tree->t_odir_list, RW_READER); 294*5331Samw od = smb_llist_head(&tree->t_odir_list); 295*5331Samw while (od) { 296*5331Samw ASSERT(od->d_magic == SMB_ODIR_MAGIC); 297*5331Samw ASSERT(od->d_tree == tree); 298*5331Samw if (od->d_opened_by_pid == pid) { 299*5331Samw od = smb_odir_close_and_next(od); 300*5331Samw } else { 301*5331Samw od = smb_llist_next(&tree->t_odir_list, od); 302*5331Samw } 303*5331Samw } 304*5331Samw smb_llist_exit(&tree->t_odir_list); 305*5331Samw } 306*5331Samw 307*5331Samw /* 308*5331Samw * smb_odir_release 309*5331Samw */ 310*5331Samw void 311*5331Samw smb_odir_release( 312*5331Samw smb_odir_t *od) 313*5331Samw { 314*5331Samw ASSERT(od); 315*5331Samw ASSERT(od->d_magic == SMB_ODIR_MAGIC); 316*5331Samw 317*5331Samw mutex_enter(&od->d_mutex); 318*5331Samw ASSERT(od->d_refcnt); 319*5331Samw od->d_refcnt--; 320*5331Samw switch (od->d_state) { 321*5331Samw case SMB_ODIR_STATE_CLOSING: 322*5331Samw case SMB_ODIR_STATE_OPEN: 323*5331Samw break; 324*5331Samw 325*5331Samw case SMB_ODIR_STATE_CLOSED: 326*5331Samw if (od->d_refcnt == 0) { 327*5331Samw mutex_exit(&od->d_mutex); 328*5331Samw smb_odir_delete(od); 329*5331Samw return; 330*5331Samw } 331*5331Samw break; 332*5331Samw 333*5331Samw default: 334*5331Samw ASSERT(0); 335*5331Samw break; 336*5331Samw } 337*5331Samw mutex_exit(&od->d_mutex); 338*5331Samw } 339*5331Samw 340*5331Samw /* 341*5331Samw * smb_odir_lookup_by_sid 342*5331Samw */ 343*5331Samw smb_odir_t * 344*5331Samw smb_odir_lookup_by_sid( 345*5331Samw smb_tree_t *tree, 346*5331Samw uint16_t sid) 347*5331Samw { 348*5331Samw smb_llist_t *od_list; 349*5331Samw smb_odir_t *od; 350*5331Samw 351*5331Samw ASSERT(tree); 352*5331Samw ASSERT(tree->t_magic == SMB_TREE_MAGIC); 353*5331Samw 354*5331Samw od_list = &tree->t_odir_list; 355*5331Samw 356*5331Samw smb_llist_enter(od_list, RW_READER); 357*5331Samw od = smb_llist_head(od_list); 358*5331Samw while (od) { 359*5331Samw ASSERT(od->d_magic == SMB_ODIR_MAGIC); 360*5331Samw ASSERT(od->d_tree == tree); 361*5331Samw if (od->d_sid == sid) { 362*5331Samw mutex_enter(&od->d_mutex); 363*5331Samw if (od->d_state != SMB_ODIR_STATE_OPEN) { 364*5331Samw mutex_exit(&od->d_mutex); 365*5331Samw smb_llist_exit(od_list); 366*5331Samw return (NULL); 367*5331Samw } 368*5331Samw od->d_refcnt++; 369*5331Samw mutex_exit(&od->d_mutex); 370*5331Samw break; 371*5331Samw } 372*5331Samw od = smb_llist_next(od_list, od); 373*5331Samw } 374*5331Samw smb_llist_exit(od_list); 375*5331Samw return (od); 376*5331Samw } 377*5331Samw 378*5331Samw /* *************************** Static Functions ***************************** */ 379*5331Samw 380*5331Samw /* 381*5331Samw * smb_odir_close_and_next 382*5331Samw * 383*5331Samw * This function closes the directory passed in (if appropriate) and returns the 384*5331Samw * next directory in the list of directories of the tree of the directory passed 385*5331Samw * in. It requires that the list of directories of the tree be entered in 386*5331Samw * RW_READER mode before being called. 387*5331Samw */ 388*5331Samw static smb_odir_t * 389*5331Samw smb_odir_close_and_next( 390*5331Samw smb_odir_t *od) 391*5331Samw { 392*5331Samw smb_odir_t *next_od; 393*5331Samw smb_tree_t *tree; 394*5331Samw 395*5331Samw ASSERT(od); 396*5331Samw ASSERT(od->d_magic == SMB_ODIR_MAGIC); 397*5331Samw 398*5331Samw mutex_enter(&od->d_mutex); 399*5331Samw switch (od->d_state) { 400*5331Samw case SMB_ODIR_STATE_OPEN: 401*5331Samw /* The directory is still opened. */ 402*5331Samw od->d_refcnt++; 403*5331Samw ASSERT(od->d_refcnt); 404*5331Samw tree = od->d_tree; 405*5331Samw mutex_exit(&od->d_mutex); 406*5331Samw smb_llist_exit(&od->d_tree->t_odir_list); 407*5331Samw smb_odir_close(od); 408*5331Samw smb_odir_release(od); 409*5331Samw smb_llist_enter(&tree->t_odir_list, RW_READER); 410*5331Samw next_od = smb_llist_head(&tree->t_odir_list); 411*5331Samw break; 412*5331Samw case SMB_ODIR_STATE_CLOSING: 413*5331Samw case SMB_ODIR_STATE_CLOSED: 414*5331Samw /* 415*5331Samw * The odir exists but is closed or is in the process 416*5331Samw * of being closed. 417*5331Samw */ 418*5331Samw mutex_exit(&od->d_mutex); 419*5331Samw next_od = smb_llist_next(&od->d_tree->t_odir_list, od); 420*5331Samw break; 421*5331Samw default: 422*5331Samw ASSERT(0); 423*5331Samw mutex_exit(&od->d_mutex); 424*5331Samw next_od = smb_llist_next(&od->d_tree->t_odir_list, od); 425*5331Samw break; 426*5331Samw } 427*5331Samw return (next_od); 428*5331Samw } 429*5331Samw 430*5331Samw /* 431*5331Samw * smb_odir_delete 432*5331Samw */ 433*5331Samw static void 434*5331Samw smb_odir_delete( 435*5331Samw smb_odir_t *od) 436*5331Samw { 437*5331Samw ASSERT(od); 438*5331Samw ASSERT(od->d_magic == SMB_ODIR_MAGIC); 439*5331Samw ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED); 440*5331Samw ASSERT(od->d_refcnt == 0); 441*5331Samw 442*5331Samw /* 443*5331Samw * Let's remove the odir from the list of odirs of the tree. This has 444*5331Samw * to be done before any resources associated with the odir are 445*5331Samw * released. 446*5331Samw */ 447*5331Samw smb_llist_enter(&od->d_tree->t_odir_list, RW_WRITER); 448*5331Samw smb_llist_remove(&od->d_tree->t_odir_list, od); 449*5331Samw smb_llist_exit(&od->d_tree->t_odir_list); 450*5331Samw 451*5331Samw smb_node_release(od->d_dir_snode); 452*5331Samw atomic_dec_32(&od->d_tree->t_session->s_dir_cnt); 453*5331Samw smb_idpool_free(&od->d_tree->t_sid_pool, od->d_sid); 454*5331Samw mutex_destroy(&od->d_mutex); 455*5331Samw kmem_cache_free(smb_info.si_cache_odir, od); 456*5331Samw } 457