1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 227f667e74Sjose borrego * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw /* 26da6c28aaSamw * SMB Node State Machine 27da6c28aaSamw * ---------------------- 28da6c28aaSamw * 29fc724630SAlan Wright * 30fc724630SAlan Wright * +----------- Creation/Allocation 31da6c28aaSamw * | 32fc724630SAlan Wright * | T0 33da6c28aaSamw * | 34da6c28aaSamw * v 35fc724630SAlan Wright * +----------------------------+ T1 36fc724630SAlan Wright * | SMB_NODE_STATE_AVAILABLE |--------------------+ 37fc724630SAlan Wright * +----------------------------+ | 38fc724630SAlan Wright * | ^ | 39fc724630SAlan Wright * | | v 40fc724630SAlan Wright * | | T2 +-------------------------------+ 41fc724630SAlan Wright * | |<---------| SMB_NODE_STATE_OPLOCK_GRANTED | 42fc724630SAlan Wright * | | +-------------------------------+ 43fc724630SAlan Wright * | T5 | | 44fc724630SAlan Wright * | | | T3 45fc724630SAlan Wright * | | v 46fc724630SAlan Wright * | | T4 +--------------------------------+ 47fc724630SAlan Wright * | +----------| SMB_NODE_STATE_OPLOCK_BREAKING | 48fc724630SAlan Wright * | +--------------------------------+ 49fc724630SAlan Wright * | 50fc724630SAlan Wright * v 51da6c28aaSamw * +-----------------------------+ 52fc724630SAlan Wright * | SMB_NODE_STATE_DESTROYING | 53fc724630SAlan Wright * +-----------------------------+ 54fc724630SAlan Wright * | 55fc724630SAlan Wright * | 56fc724630SAlan Wright * | T6 57fc724630SAlan Wright * | 58fc724630SAlan Wright * +----------> Deletion/Free 59da6c28aaSamw * 60da6c28aaSamw * Transition T0 61da6c28aaSamw * 62da6c28aaSamw * This transition occurs in smb_node_lookup(). If the node looked for is 63da6c28aaSamw * not found in the has table a new node is created. The reference count is 64da6c28aaSamw * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE. 65da6c28aaSamw * 66da6c28aaSamw * Transition T1 67da6c28aaSamw * 68fc724630SAlan Wright * This transition occurs smb_oplock_acquire() during an OPEN. 69fc724630SAlan Wright * 70fc724630SAlan Wright * Transition T2 71fc724630SAlan Wright * 72fc724630SAlan Wright * This transition occurs in smb_oplock_release(). The events triggering 73fc724630SAlan Wright * it are: 74fc724630SAlan Wright * 75fc724630SAlan Wright * - LockingAndX sent by the client that was granted the oplock. 76fc724630SAlan Wright * - Closing of the file. 77fc724630SAlan Wright * 78fc724630SAlan Wright * Transition T3 79fc724630SAlan Wright * 80fc724630SAlan Wright * This transition occurs in smb_oplock_break(). The events triggering 81fc724630SAlan Wright * it are: 82fc724630SAlan Wright * 83fc724630SAlan Wright * - Another client wants to open the file. 84fc724630SAlan Wright * - A client is trying to delete the file. 85fc724630SAlan Wright * - A client is trying to rename the file. 86fc724630SAlan Wright * - A client is trying to set/modify the file attributes. 87fc724630SAlan Wright * 88fc724630SAlan Wright * Transition T4 89fc724630SAlan Wright * 90fc724630SAlan Wright * This transition occurs in smb_oplock_release or smb_oplock_break(). The 91fc724630SAlan Wright * events triggering it are: 92fc724630SAlan Wright * 93fc724630SAlan Wright * - The client that was granting the oplock releases it (close or 94fc724630SAlan Wright * LockingAndx). 95fc724630SAlan Wright * - The time alloted to release the oplock expired. 96fc724630SAlan Wright * 97fc724630SAlan Wright * Transition T5 98fc724630SAlan Wright * 99da6c28aaSamw * This transition occurs in smb_node_release(). If the reference count 100da6c28aaSamw * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more 101da6c28aaSamw * reference count will be given out for that node. 102da6c28aaSamw * 103fc724630SAlan Wright * Transition T6 104da6c28aaSamw * 105da6c28aaSamw * This transition occurs in smb_node_release(). The structure is deleted. 106da6c28aaSamw * 107da6c28aaSamw * Comments 108da6c28aaSamw * -------- 109da6c28aaSamw * 110da6c28aaSamw * The reason the smb node has 2 states is the following synchronization 111da6c28aaSamw * rule: 112da6c28aaSamw * 113da6c28aaSamw * There's a mutex embedded in the node used to protect its fields and 114da6c28aaSamw * there's a lock embedded in the bucket of the hash table the node belongs 115da6c28aaSamw * to. To increment or to decrement the reference count the mutex must be 116da6c28aaSamw * entered. To insert the node into the bucket and to remove it from the 117da6c28aaSamw * bucket the lock must be entered in RW_WRITER mode. When both (mutex and 118da6c28aaSamw * lock) have to be entered, the lock has always to be entered first then 119da6c28aaSamw * the mutex. This prevents a deadlock between smb_node_lookup() and 120da6c28aaSamw * smb_node_release() from occurring. However, in smb_node_release() when the 121da6c28aaSamw * reference count drops to zero and triggers the deletion of the node, the 122da6c28aaSamw * mutex has to be released before entering the lock of the bucket (to 123da6c28aaSamw * remove the node). This creates a window during which the node that is 124da6c28aaSamw * about to be freed could be given out by smb_node_lookup(). To close that 125da6c28aaSamw * window the node is moved to the state SMB_NODE_STATE_DESTROYING before 126da6c28aaSamw * releasing the mutex. That way, even if smb_node_lookup() finds it, the 127da6c28aaSamw * state will indicate that the node should be treated as non existent (of 128da6c28aaSamw * course the state of the node should be tested/updated under the 129da6c28aaSamw * protection of the mutex). 130da6c28aaSamw */ 131da6c28aaSamw #include <smbsrv/smb_incl.h> 132da6c28aaSamw #include <smbsrv/smb_fsops.h> 1332c2961f8Sjose borrego #include <smbsrv/smb_kstat.h> 134da6c28aaSamw #include <sys/pathname.h> 135da6c28aaSamw #include <sys/sdt.h> 136dc20a302Sas200622 #include <sys/nbmlock.h> 137da6c28aaSamw 1382c2961f8Sjose borrego uint32_t smb_is_executable(char *); 1392c2961f8Sjose borrego static void smb_node_delete_on_close(smb_node_t *); 1402c2961f8Sjose borrego static void smb_node_create_audit_buf(smb_node_t *, int); 1412c2961f8Sjose borrego static void smb_node_destroy_audit_buf(smb_node_t *); 1422c2961f8Sjose borrego static void smb_node_audit(smb_node_t *); 1432c2961f8Sjose borrego static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_attr_t *, 1442c2961f8Sjose borrego smb_llist_t *bucket, uint32_t hashkey); 1452c2961f8Sjose borrego static void smb_node_free(smb_node_t *); 1462c2961f8Sjose borrego static int smb_node_constructor(void *, void *, int); 1472c2961f8Sjose borrego static void smb_node_destructor(void *, void *); 1482c2961f8Sjose borrego static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *); 149da6c28aaSamw 150da6c28aaSamw #define VALIDATE_DIR_NODE(_dir_, _node_) \ 151da6c28aaSamw ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \ 152da6c28aaSamw ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \ 153da6c28aaSamw ASSERT((_dir_)->dir_snode != (_node_)); 154da6c28aaSamw 1552c2961f8Sjose borrego static kmem_cache_t *smb_node_cache = NULL; 156faa1795aSjb150015 static boolean_t smb_node_initialized = B_FALSE; 157faa1795aSjb150015 static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1]; 158faa1795aSjb150015 159faa1795aSjb150015 /* 160faa1795aSjb150015 * smb_node_init 161faa1795aSjb150015 * 162faa1795aSjb150015 * Initialization of the SMB node layer. 163faa1795aSjb150015 * 164faa1795aSjb150015 * This function is not multi-thread safe. The caller must make sure only one 165faa1795aSjb150015 * thread makes the call. 166faa1795aSjb150015 */ 167faa1795aSjb150015 int 168faa1795aSjb150015 smb_node_init(void) 169faa1795aSjb150015 { 170faa1795aSjb150015 int i; 171faa1795aSjb150015 172faa1795aSjb150015 if (smb_node_initialized) 173faa1795aSjb150015 return (0); 1742c2961f8Sjose borrego smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE, 1752c2961f8Sjose borrego sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor, 1762c2961f8Sjose borrego NULL, NULL, NULL, 0); 177faa1795aSjb150015 178faa1795aSjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 179faa1795aSjb150015 smb_llist_constructor(&smb_node_hash_table[i], 180faa1795aSjb150015 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 181faa1795aSjb150015 } 182faa1795aSjb150015 smb_node_initialized = B_TRUE; 183faa1795aSjb150015 return (0); 184faa1795aSjb150015 } 185faa1795aSjb150015 186faa1795aSjb150015 /* 187faa1795aSjb150015 * smb_node_fini 188faa1795aSjb150015 * 189faa1795aSjb150015 * This function is not multi-thread safe. The caller must make sure only one 190faa1795aSjb150015 * thread makes the call. 191faa1795aSjb150015 */ 192faa1795aSjb150015 void 193faa1795aSjb150015 smb_node_fini(void) 194faa1795aSjb150015 { 195faa1795aSjb150015 int i; 196faa1795aSjb150015 197faa1795aSjb150015 if (!smb_node_initialized) 198faa1795aSjb150015 return; 199faa1795aSjb150015 200faa1795aSjb150015 #ifdef DEBUG 201faa1795aSjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 202faa1795aSjb150015 smb_node_t *node; 203faa1795aSjb150015 204faa1795aSjb150015 /* 205faa1795aSjb150015 * The following sequence is just intended for sanity check. 206faa1795aSjb150015 * This will have to be modified when the code goes into 207faa1795aSjb150015 * production. 208faa1795aSjb150015 * 209faa1795aSjb150015 * The SMB node hash table should be emtpy at this point. If the 210faa1795aSjb150015 * hash table is not empty a panic will be triggered. 211faa1795aSjb150015 * 212faa1795aSjb150015 * The reason why SMB nodes are still remaining in the hash 213faa1795aSjb150015 * table is problably due to a mismatch between calls to 214faa1795aSjb150015 * smb_node_lookup() and smb_node_release(). You must track that 215faa1795aSjb150015 * down. 216faa1795aSjb150015 */ 217faa1795aSjb150015 node = smb_llist_head(&smb_node_hash_table[i]); 218faa1795aSjb150015 ASSERT(node == NULL); 219faa1795aSjb150015 } 220faa1795aSjb150015 #endif 221faa1795aSjb150015 222faa1795aSjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 223faa1795aSjb150015 smb_llist_destructor(&smb_node_hash_table[i]); 224faa1795aSjb150015 } 2252c2961f8Sjose borrego kmem_cache_destroy(smb_node_cache); 2262c2961f8Sjose borrego smb_node_cache = NULL; 227faa1795aSjb150015 smb_node_initialized = B_FALSE; 228faa1795aSjb150015 } 229faa1795aSjb150015 230da6c28aaSamw /* 231da6c28aaSamw * smb_node_lookup() 232da6c28aaSamw * 233da6c28aaSamw * NOTE: This routine should only be called by the file system interface layer, 234da6c28aaSamw * and not by SMB. 235da6c28aaSamw * 236da6c28aaSamw * smb_node_lookup() is called upon successful lookup, mkdir, and create 237da6c28aaSamw * (for both non-streams and streams). In each of these cases, a held vnode is 2387f667e74Sjose borrego * passed into this routine. If a new smb_node is created it will take its 2397f667e74Sjose borrego * own hold on the vnode. The caller's hold therefore still belongs to, and 2407f667e74Sjose borrego * should be released by, the caller. 241da6c28aaSamw * 242da6c28aaSamw * A reference is taken on the smb_node whether found in the hash table 243da6c28aaSamw * or newly created. 244da6c28aaSamw * 245da6c28aaSamw * If an smb_node needs to be created, a reference is also taken on the 246da6c28aaSamw * dir_snode (if passed in). 247da6c28aaSamw * 248da6c28aaSamw * See smb_node_release() for details on the release of these references. 249da6c28aaSamw */ 250da6c28aaSamw 251da6c28aaSamw /*ARGSUSED*/ 252da6c28aaSamw smb_node_t * 253da6c28aaSamw smb_node_lookup( 254da6c28aaSamw struct smb_request *sr, 255da6c28aaSamw struct open_param *op, 256da6c28aaSamw cred_t *cred, 257da6c28aaSamw vnode_t *vp, 258da6c28aaSamw char *od_name, 259da6c28aaSamw smb_node_t *dir_snode, 260da6c28aaSamw smb_node_t *unnamed_node, 261da6c28aaSamw smb_attr_t *attr) 262da6c28aaSamw { 263da6c28aaSamw smb_llist_t *node_hdr; 264da6c28aaSamw smb_node_t *node; 265da6c28aaSamw uint32_t hashkey = 0; 266c8ec8eeaSjose borrego fsid_t fsid; 267da6c28aaSamw int error; 268da6c28aaSamw krw_t lock_mode; 269da6c28aaSamw vnode_t *unnamed_vp = NULL; 270da6c28aaSamw 271da6c28aaSamw /* 272da6c28aaSamw * smb_vop_getattr() is called here instead of smb_fsop_getattr(), 273da6c28aaSamw * because the node may not yet exist. We also do not want to call 274da6c28aaSamw * it with the list lock held. 275da6c28aaSamw */ 276da6c28aaSamw 277da6c28aaSamw if (unnamed_node) 278da6c28aaSamw unnamed_vp = unnamed_node->vp; 279da6c28aaSamw 280da6c28aaSamw /* 281da6c28aaSamw * This getattr is performed on behalf of the server 282da6c28aaSamw * that's why kcred is used not the user's cred 283da6c28aaSamw */ 284da6c28aaSamw attr->sa_mask = SMB_AT_ALL; 285dc20a302Sas200622 error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred); 286da6c28aaSamw if (error) 287da6c28aaSamw return (NULL); 288da6c28aaSamw 289c8ec8eeaSjose borrego if (sr && sr->tid_tree) { 290da6c28aaSamw /* 291c8ec8eeaSjose borrego * The fsid for a file is that of the tree, even 292da6c28aaSamw * if the file resides in a different mountpoint 293da6c28aaSamw * under the share. 294da6c28aaSamw */ 295c8ec8eeaSjose borrego fsid = SMB_TREE_FSID(sr->tid_tree); 296da6c28aaSamw } else { 297da6c28aaSamw /* 298da6c28aaSamw * This should be getting executed only for the 299c8ec8eeaSjose borrego * tree root smb_node. 300da6c28aaSamw */ 301c8ec8eeaSjose borrego fsid = vp->v_vfsp->vfs_fsid; 302da6c28aaSamw } 303da6c28aaSamw 3042c2961f8Sjose borrego node_hdr = smb_node_get_hash(&fsid, attr, &hashkey); 305da6c28aaSamw lock_mode = RW_READER; 306da6c28aaSamw 307da6c28aaSamw smb_llist_enter(node_hdr, lock_mode); 308da6c28aaSamw for (;;) { 309da6c28aaSamw node = list_head(&node_hdr->ll_list); 310da6c28aaSamw while (node) { 311da6c28aaSamw ASSERT(node->n_magic == SMB_NODE_MAGIC); 312da6c28aaSamw ASSERT(node->n_hash_bucket == node_hdr); 313da6c28aaSamw if ((node->n_hashkey == hashkey) && (node->vp == vp)) { 3142c2961f8Sjose borrego mutex_enter(&node->n_mutex); 315da6c28aaSamw DTRACE_PROBE1(smb_node_lookup_hit, 316da6c28aaSamw smb_node_t *, node); 317da6c28aaSamw switch (node->n_state) { 3182c2961f8Sjose borrego case SMB_NODE_STATE_OPLOCK_GRANTED: 3192c2961f8Sjose borrego case SMB_NODE_STATE_OPLOCK_BREAKING: 320da6c28aaSamw case SMB_NODE_STATE_AVAILABLE: 321da6c28aaSamw /* The node was found. */ 322da6c28aaSamw node->n_refcnt++; 323da6c28aaSamw if ((node->dir_snode == NULL) && 324da6c28aaSamw (dir_snode != NULL) && 325da6c28aaSamw (strcmp(od_name, "..") != 0) && 326da6c28aaSamw (strcmp(od_name, ".") != 0)) { 327da6c28aaSamw VALIDATE_DIR_NODE(dir_snode, 328da6c28aaSamw node); 329da6c28aaSamw node->dir_snode = dir_snode; 330da6c28aaSamw smb_node_ref(dir_snode); 331da6c28aaSamw } 332da6c28aaSamw node->attr = *attr; 333dc20a302Sas200622 node->n_size = attr->sa_vattr.va_size; 334da6c28aaSamw 3352c2961f8Sjose borrego smb_node_audit(node); 3362c2961f8Sjose borrego mutex_exit(&node->n_mutex); 337da6c28aaSamw smb_llist_exit(node_hdr); 338da6c28aaSamw return (node); 339da6c28aaSamw 340da6c28aaSamw case SMB_NODE_STATE_DESTROYING: 341da6c28aaSamw /* 342da6c28aaSamw * Although the node exists it is about 343da6c28aaSamw * to be destroyed. We act as it hasn't 344da6c28aaSamw * been found. 345da6c28aaSamw */ 3462c2961f8Sjose borrego mutex_exit(&node->n_mutex); 347da6c28aaSamw break; 348da6c28aaSamw default: 349da6c28aaSamw /* 350da6c28aaSamw * Although the node exists it is in an 351da6c28aaSamw * unknown state. We act as it hasn't 352da6c28aaSamw * been found. 353da6c28aaSamw */ 354da6c28aaSamw ASSERT(0); 3552c2961f8Sjose borrego mutex_exit(&node->n_mutex); 356da6c28aaSamw break; 357da6c28aaSamw } 358da6c28aaSamw } 359da6c28aaSamw node = smb_llist_next(node_hdr, node); 360da6c28aaSamw } 361da6c28aaSamw if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) { 362da6c28aaSamw lock_mode = RW_WRITER; 363da6c28aaSamw continue; 364da6c28aaSamw } 365da6c28aaSamw break; 366da6c28aaSamw } 3672c2961f8Sjose borrego node = smb_node_alloc(od_name, vp, attr, node_hdr, hashkey); 368faa1795aSjb150015 node->n_orig_uid = crgetuid(sr->user_cr); 369da6c28aaSamw 370da6c28aaSamw if (op) 371da6c28aaSamw node->flags |= smb_is_executable(op->fqi.last_comp); 372da6c28aaSamw 373da6c28aaSamw if (dir_snode) { 374da6c28aaSamw smb_node_ref(dir_snode); 375da6c28aaSamw node->dir_snode = dir_snode; 376da6c28aaSamw ASSERT(dir_snode->dir_snode != node); 377da6c28aaSamw ASSERT((dir_snode->vp->v_xattrdir) || 378da6c28aaSamw (dir_snode->vp->v_type == VDIR)); 379da6c28aaSamw } 380da6c28aaSamw 381da6c28aaSamw if (unnamed_node) { 382da6c28aaSamw smb_node_ref(unnamed_node); 383da6c28aaSamw node->unnamed_stream_node = unnamed_node; 384da6c28aaSamw } 385da6c28aaSamw 386da6c28aaSamw DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node); 3872c2961f8Sjose borrego smb_node_audit(node); 388da6c28aaSamw smb_llist_insert_head(node_hdr, node); 389da6c28aaSamw smb_llist_exit(node_hdr); 390da6c28aaSamw return (node); 391da6c28aaSamw } 392da6c28aaSamw 393da6c28aaSamw /* 394da6c28aaSamw * smb_stream_node_lookup() 395da6c28aaSamw * 396da6c28aaSamw * Note: stream_name (the name that will be stored in the "od_name" field 397da6c28aaSamw * of a stream's smb_node) is the same as the on-disk name for the stream 398da6c28aaSamw * except that it does not have SMB_STREAM_PREFIX prepended. 399da6c28aaSamw */ 400da6c28aaSamw 401da6c28aaSamw smb_node_t * 4022c2961f8Sjose borrego smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode, 403da6c28aaSamw vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr) 404da6c28aaSamw { 405da6c28aaSamw smb_node_t *xattrdir_node; 406da6c28aaSamw smb_node_t *snode; 407da6c28aaSamw smb_attr_t tmp_attr; 408da6c28aaSamw 409da6c28aaSamw xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR, 410da6c28aaSamw fnode, NULL, &tmp_attr); 411da6c28aaSamw 412da6c28aaSamw if (xattrdir_node == NULL) 413da6c28aaSamw return (NULL); 414da6c28aaSamw 415da6c28aaSamw snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node, 416da6c28aaSamw fnode, ret_attr); 417da6c28aaSamw 418da6c28aaSamw (void) smb_node_release(xattrdir_node); 419da6c28aaSamw return (snode); 420da6c28aaSamw } 421da6c28aaSamw 422da6c28aaSamw 423da6c28aaSamw /* 424da6c28aaSamw * This function should be called whenever a reference is needed on an 425da6c28aaSamw * smb_node pointer. The copy of an smb_node pointer from one non-local 426da6c28aaSamw * data structure to another requires a reference to be taken on the smb_node 427da6c28aaSamw * (unless the usage is localized). Each data structure deallocation routine 428da6c28aaSamw * will call smb_node_release() on its smb_node pointers. 429da6c28aaSamw * 430da6c28aaSamw * In general, an smb_node pointer residing in a structure should never be 431da6c28aaSamw * stale. A node pointer may be NULL, however, and care should be taken 432da6c28aaSamw * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid. 433da6c28aaSamw * Care also needs to be taken with respect to racing deallocations of a 434da6c28aaSamw * structure. 435da6c28aaSamw */ 436da6c28aaSamw void 437da6c28aaSamw smb_node_ref(smb_node_t *node) 438da6c28aaSamw { 4392c2961f8Sjose borrego SMB_NODE_VALID(node); 440da6c28aaSamw 4412c2961f8Sjose borrego mutex_enter(&node->n_mutex); 4422c2961f8Sjose borrego switch (node->n_state) { 4432c2961f8Sjose borrego case SMB_NODE_STATE_AVAILABLE: 4442c2961f8Sjose borrego case SMB_NODE_STATE_OPLOCK_GRANTED: 4452c2961f8Sjose borrego case SMB_NODE_STATE_OPLOCK_BREAKING: 446da6c28aaSamw node->n_refcnt++; 447da6c28aaSamw ASSERT(node->n_refcnt); 448da6c28aaSamw DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); 4492c2961f8Sjose borrego smb_node_audit(node); 4502c2961f8Sjose borrego break; 4512c2961f8Sjose borrego default: 4522c2961f8Sjose borrego SMB_PANIC(); 4532c2961f8Sjose borrego } 4542c2961f8Sjose borrego mutex_exit(&node->n_mutex); 455da6c28aaSamw } 456da6c28aaSamw 457da6c28aaSamw /* 458da6c28aaSamw * smb_node_lookup() takes a hold on an smb_node, whether found in the 459da6c28aaSamw * hash table or newly created. This hold is expected to be released 460da6c28aaSamw * in the following manner. 461da6c28aaSamw * 462da6c28aaSamw * smb_node_lookup() takes an address of an smb_node pointer. This should 463da6c28aaSamw * be getting passed down via a lookup (whether path name or component), mkdir, 464da6c28aaSamw * create. If the original smb_node pointer resides in a data structure, then 465da6c28aaSamw * the deallocation routine for the data structure is responsible for calling 466da6c28aaSamw * smb_node_release() on the smb_node pointer. Alternatively, 467da6c28aaSamw * smb_node_release() can be called as soon as the smb_node pointer is no longer 468da6c28aaSamw * needed. In this case, callers are responsible for setting an embedded 469da6c28aaSamw * pointer to NULL if it is known that the last reference is being released. 470da6c28aaSamw * 471da6c28aaSamw * If the passed-in address of the smb_node pointer belongs to a local variable, 472da6c28aaSamw * then the caller with the local variable should call smb_node_release() 473da6c28aaSamw * directly. 474da6c28aaSamw * 475da6c28aaSamw * smb_node_release() itself will call smb_node_release() on a node's dir_snode, 476da6c28aaSamw * as smb_node_lookup() takes a hold on dir_snode. 477da6c28aaSamw */ 478da6c28aaSamw void 479da6c28aaSamw smb_node_release(smb_node_t *node) 480da6c28aaSamw { 4812c2961f8Sjose borrego SMB_NODE_VALID(node); 482da6c28aaSamw 4832c2961f8Sjose borrego mutex_enter(&node->n_mutex); 484da6c28aaSamw ASSERT(node->n_refcnt); 485da6c28aaSamw DTRACE_PROBE1(smb_node_release, smb_node_t *, node); 486da6c28aaSamw if (--node->n_refcnt == 0) { 487da6c28aaSamw switch (node->n_state) { 488da6c28aaSamw 489da6c28aaSamw case SMB_NODE_STATE_AVAILABLE: 490da6c28aaSamw node->n_state = SMB_NODE_STATE_DESTROYING; 4912c2961f8Sjose borrego mutex_exit(&node->n_mutex); 492da6c28aaSamw 493da6c28aaSamw smb_llist_enter(node->n_hash_bucket, RW_WRITER); 494da6c28aaSamw smb_llist_remove(node->n_hash_bucket, node); 495da6c28aaSamw smb_llist_exit(node->n_hash_bucket); 496da6c28aaSamw 497da6c28aaSamw /* 498da6c28aaSamw * Check if the file was deleted 499da6c28aaSamw */ 500da6c28aaSamw smb_node_delete_on_close(node); 501da6c28aaSamw 502da6c28aaSamw if (node->dir_snode) { 503da6c28aaSamw ASSERT(node->dir_snode->n_magic == 504da6c28aaSamw SMB_NODE_MAGIC); 505da6c28aaSamw smb_node_release(node->dir_snode); 506da6c28aaSamw } 507da6c28aaSamw 508da6c28aaSamw if (node->unnamed_stream_node) { 509da6c28aaSamw ASSERT(node->unnamed_stream_node->n_magic == 510da6c28aaSamw SMB_NODE_MAGIC); 511da6c28aaSamw smb_node_release(node->unnamed_stream_node); 512da6c28aaSamw } 513da6c28aaSamw 5142c2961f8Sjose borrego smb_node_free(node); 515da6c28aaSamw return; 516da6c28aaSamw 517da6c28aaSamw default: 5182c2961f8Sjose borrego SMB_PANIC(); 519da6c28aaSamw } 520da6c28aaSamw } 5212c2961f8Sjose borrego smb_node_audit(node); 5222c2961f8Sjose borrego mutex_exit(&node->n_mutex); 523da6c28aaSamw } 524da6c28aaSamw 525da6c28aaSamw static void 526da6c28aaSamw smb_node_delete_on_close(smb_node_t *node) 527da6c28aaSamw { 528da6c28aaSamw smb_node_t *d_snode; 529da6c28aaSamw int rc = 0; 530*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States uint32_t flags = 0; 531da6c28aaSamw 532da6c28aaSamw d_snode = node->dir_snode; 533da6c28aaSamw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 534da6c28aaSamw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 535*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags = node->n_delete_on_close_flags; 536da6c28aaSamw ASSERT(node->od_name != NULL); 537*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 538da6c28aaSamw if (node->attr.sa_vattr.va_type == VDIR) 539da6c28aaSamw rc = smb_fsop_rmdir(0, node->delete_on_close_cred, 540*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States d_snode, node->od_name, flags); 541da6c28aaSamw else 542da6c28aaSamw rc = smb_fsop_remove(0, node->delete_on_close_cred, 543*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States d_snode, node->od_name, flags); 544da6c28aaSamw smb_cred_rele(node->delete_on_close_cred); 545da6c28aaSamw } 546da6c28aaSamw if (rc != 0) 547da6c28aaSamw cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n", 548da6c28aaSamw node->od_name, rc); 549da6c28aaSamw DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node); 550da6c28aaSamw } 551da6c28aaSamw 552da6c28aaSamw /* 553da6c28aaSamw * smb_node_rename() 554da6c28aaSamw * 555da6c28aaSamw */ 5562c2961f8Sjose borrego void 557da6c28aaSamw smb_node_rename( 5582c2961f8Sjose borrego smb_node_t *from_dnode, 5592c2961f8Sjose borrego smb_node_t *ret_node, 5602c2961f8Sjose borrego smb_node_t *to_dnode, 561da6c28aaSamw char *to_name) 562da6c28aaSamw { 5632c2961f8Sjose borrego SMB_NODE_VALID(from_dnode); 5642c2961f8Sjose borrego SMB_NODE_VALID(to_dnode); 5652c2961f8Sjose borrego SMB_NODE_VALID(ret_node); 566da6c28aaSamw 5672c2961f8Sjose borrego smb_node_ref(to_dnode); 5682c2961f8Sjose borrego mutex_enter(&ret_node->n_mutex); 5692c2961f8Sjose borrego switch (ret_node->n_state) { 5702c2961f8Sjose borrego case SMB_NODE_STATE_AVAILABLE: 5712c2961f8Sjose borrego case SMB_NODE_STATE_OPLOCK_GRANTED: 5722c2961f8Sjose borrego case SMB_NODE_STATE_OPLOCK_BREAKING: 5732c2961f8Sjose borrego ret_node->dir_snode = to_dnode; 5742c2961f8Sjose borrego mutex_exit(&ret_node->n_mutex); 5752c2961f8Sjose borrego ASSERT(to_dnode->dir_snode != ret_node); 5762c2961f8Sjose borrego ASSERT((to_dnode->vp->v_xattrdir) || 5772c2961f8Sjose borrego (to_dnode->vp->v_type == VDIR)); 5782c2961f8Sjose borrego smb_node_release(from_dnode); 5792c2961f8Sjose borrego (void) strcpy(ret_node->od_name, to_name); 580da6c28aaSamw /* 581da6c28aaSamw * XXX Need to update attributes? 582da6c28aaSamw */ 5832c2961f8Sjose borrego break; 5842c2961f8Sjose borrego default: 5852c2961f8Sjose borrego SMB_PANIC(); 5862c2961f8Sjose borrego } 587da6c28aaSamw } 588da6c28aaSamw 589da6c28aaSamw int 590faa1795aSjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root) 591da6c28aaSamw { 592da6c28aaSamw smb_attr_t va; 593faa1795aSjb150015 int error; 594faa1795aSjb150015 uint32_t hashkey; 595faa1795aSjb150015 smb_llist_t *node_hdr; 596faa1795aSjb150015 smb_node_t *node; 597da6c28aaSamw 598faa1795aSjb150015 va.sa_mask = SMB_AT_ALL; 599faa1795aSjb150015 error = smb_vop_getattr(vp, NULL, &va, 0, kcred); 600faa1795aSjb150015 if (error) { 601faa1795aSjb150015 VN_RELE(vp); 602faa1795aSjb150015 return (error); 603faa1795aSjb150015 } 604da6c28aaSamw 6052c2961f8Sjose borrego node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &va, &hashkey); 606faa1795aSjb150015 6072c2961f8Sjose borrego node = smb_node_alloc(ROOTVOL, vp, &va, node_hdr, hashkey); 608faa1795aSjb150015 609faa1795aSjb150015 sv->si_root_smb_node = node; 6102c2961f8Sjose borrego smb_node_audit(node); 611faa1795aSjb150015 smb_llist_enter(node_hdr, RW_WRITER); 612faa1795aSjb150015 smb_llist_insert_head(node_hdr, node); 613faa1795aSjb150015 smb_llist_exit(node_hdr); 614faa1795aSjb150015 *root = node; 615da6c28aaSamw return (0); 616da6c28aaSamw } 617da6c28aaSamw 618da6c28aaSamw /* 619da6c28aaSamw * smb_node_get_size 620da6c28aaSamw */ 6216537f381Sas200622 u_offset_t 6226537f381Sas200622 smb_node_get_size(smb_node_t *node, smb_attr_t *attr) 623da6c28aaSamw { 6246537f381Sas200622 u_offset_t size; 625da6c28aaSamw 626da6c28aaSamw if (attr->sa_vattr.va_type == VDIR) 627da6c28aaSamw return (0); 628da6c28aaSamw 6292c2961f8Sjose borrego mutex_enter(&node->n_mutex); 630da6c28aaSamw if (node && (node->flags & NODE_FLAGS_SET_SIZE)) 631da6c28aaSamw size = node->n_size; 632da6c28aaSamw else 633da6c28aaSamw size = attr->sa_vattr.va_size; 6342c2961f8Sjose borrego mutex_exit(&node->n_mutex); 635da6c28aaSamw return (size); 636da6c28aaSamw } 637da6c28aaSamw 638da6c28aaSamw static int 639da6c28aaSamw timeval_cmp(timestruc_t *a, timestruc_t *b) 640da6c28aaSamw { 641da6c28aaSamw if (a->tv_sec < b->tv_sec) 642da6c28aaSamw return (-1); 643da6c28aaSamw if (a->tv_sec > b->tv_sec) 644da6c28aaSamw return (1); 645da6c28aaSamw /* Seconds are equal compare tv_nsec */ 646da6c28aaSamw if (a->tv_nsec < b->tv_nsec) 647da6c28aaSamw return (-1); 648da6c28aaSamw return (a->tv_nsec > b->tv_nsec); 649da6c28aaSamw } 650da6c28aaSamw 651da6c28aaSamw /* 652da6c28aaSamw * smb_node_set_time 653da6c28aaSamw * 654da6c28aaSamw * This function will update the time stored in the node and 655c8ec8eeaSjose borrego * set the appropriate flags. If there is nothing to update, 656c8ec8eeaSjose borrego * the function will return without any updates. The update 657c8ec8eeaSjose borrego * is only in the node level and the attribute in the file system 658c8ec8eeaSjose borrego * will be updated when client close the file. 659da6c28aaSamw */ 660da6c28aaSamw void 6612c2961f8Sjose borrego smb_node_set_time( 6622c2961f8Sjose borrego smb_node_t *node, 6632c2961f8Sjose borrego timestruc_t *crtime, 6642c2961f8Sjose borrego timestruc_t *mtime, 6652c2961f8Sjose borrego timestruc_t *atime, 6662c2961f8Sjose borrego timestruc_t *ctime, 6672c2961f8Sjose borrego uint_t what) 668da6c28aaSamw { 669c8ec8eeaSjose borrego if (what == 0) 670da6c28aaSamw return; 671da6c28aaSamw 672da6c28aaSamw if ((what & SMB_AT_CRTIME && crtime == 0) || 673da6c28aaSamw (what & SMB_AT_MTIME && mtime == 0) || 674da6c28aaSamw (what & SMB_AT_ATIME && atime == 0) || 675c8ec8eeaSjose borrego (what & SMB_AT_CTIME && ctime == 0)) 676da6c28aaSamw return; 677c8ec8eeaSjose borrego 6782c2961f8Sjose borrego mutex_enter(&node->n_mutex); 679da6c28aaSamw 680da6c28aaSamw if ((what & SMB_AT_CRTIME) && 681da6c28aaSamw timeval_cmp((timestruc_t *)&node->attr.sa_crtime, 682da6c28aaSamw crtime) != 0) { 683da6c28aaSamw node->what |= SMB_AT_CRTIME; 684da6c28aaSamw node->attr.sa_crtime = *((timestruc_t *)crtime); 685da6c28aaSamw } 686da6c28aaSamw 687da6c28aaSamw if ((what & SMB_AT_MTIME) && 688da6c28aaSamw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime, 689da6c28aaSamw mtime) != 0) { 690da6c28aaSamw node->what |= SMB_AT_MTIME; 691da6c28aaSamw node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime); 692da6c28aaSamw } 693da6c28aaSamw 694da6c28aaSamw if ((what & SMB_AT_ATIME) && 695da6c28aaSamw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime, 696da6c28aaSamw atime) != 0) { 697da6c28aaSamw node->what |= SMB_AT_ATIME; 698da6c28aaSamw node->attr.sa_vattr.va_atime = *((timestruc_t *)atime); 699da6c28aaSamw } 700da6c28aaSamw 701da6c28aaSamw /* 702da6c28aaSamw * The ctime handling is trickier. It has three scenarios. 703da6c28aaSamw * 1. Only ctime need to be set and it is the same as the ctime 704da6c28aaSamw * stored in the node. (update not necessary) 705da6c28aaSamw * 2. The ctime is the same as the ctime stored in the node but 706da6c28aaSamw * is not the only time need to be set. (update required) 707da6c28aaSamw * 3. The ctime need to be set and is not the same as the ctime 708da6c28aaSamw * stored in the node. (update required) 709da6c28aaSamw * Unlike other time setting, the ctime needs to be set even when 710da6c28aaSamw * it is the same as the ctime in the node if there are other time 711da6c28aaSamw * needs to be set (#2). This will ensure the ctime not being 712da6c28aaSamw * updated when other times are being updated in the file system. 713da6c28aaSamw * 714da6c28aaSamw * Retained file rules: 715da6c28aaSamw * 716da6c28aaSamw * 1. Don't add SMB_AT_CTIME to node->what by default because the 717da6c28aaSamw * request will be rejected by filesystem 718da6c28aaSamw * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e. 719da6c28aaSamw * any request for changing ctime on these files should have 720da6c28aaSamw * been already rejected 721da6c28aaSamw */ 722da6c28aaSamw node->what |= SMB_AT_CTIME; 723da6c28aaSamw if (what & SMB_AT_CTIME) { 724da6c28aaSamw if ((what == SMB_AT_CTIME) && 725da6c28aaSamw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime, 726da6c28aaSamw ctime) == 0) { 727da6c28aaSamw node->what &= ~SMB_AT_CTIME; 728da6c28aaSamw } else { 729da6c28aaSamw gethrestime(&node->attr.sa_vattr.va_ctime); 730da6c28aaSamw } 731da6c28aaSamw } else { 732da6c28aaSamw gethrestime(&node->attr.sa_vattr.va_ctime); 733da6c28aaSamw } 7342c2961f8Sjose borrego mutex_exit(&node->n_mutex); 735da6c28aaSamw } 736da6c28aaSamw 737da6c28aaSamw 738da6c28aaSamw timestruc_t * 739da6c28aaSamw smb_node_get_crtime(smb_node_t *node) 740da6c28aaSamw { 741da6c28aaSamw return ((timestruc_t *)&node->attr.sa_crtime); 742da6c28aaSamw } 743da6c28aaSamw 744da6c28aaSamw timestruc_t * 745da6c28aaSamw smb_node_get_atime(smb_node_t *node) 746da6c28aaSamw { 747da6c28aaSamw return ((timestruc_t *)&node->attr.sa_vattr.va_atime); 748da6c28aaSamw } 749da6c28aaSamw 750da6c28aaSamw timestruc_t * 751da6c28aaSamw smb_node_get_ctime(smb_node_t *node) 752da6c28aaSamw { 753da6c28aaSamw return ((timestruc_t *)&node->attr.sa_vattr.va_ctime); 754da6c28aaSamw } 755da6c28aaSamw 756da6c28aaSamw timestruc_t * 757da6c28aaSamw smb_node_get_mtime(smb_node_t *node) 758da6c28aaSamw { 759da6c28aaSamw return ((timestruc_t *)&node->attr.sa_vattr.va_mtime); 760da6c28aaSamw } 761da6c28aaSamw 762da6c28aaSamw /* 763da6c28aaSamw * smb_node_set_dosattr 764da6c28aaSamw * 765da6c28aaSamw * Parse the specified DOS attributes and, if they have been modified, 766da6c28aaSamw * update the node cache. This call should be followed by a 767da6c28aaSamw * smb_sync_fsattr() call to write the attribute changes to filesystem. 768da6c28aaSamw */ 769da6c28aaSamw void 7703db3f65cSamw smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr) 771da6c28aaSamw { 7723db3f65cSamw uint32_t mode = dosattr & (FILE_ATTRIBUTE_ARCHIVE | 7733db3f65cSamw FILE_ATTRIBUTE_READONLY | 7743db3f65cSamw FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); 775da6c28aaSamw 7762c2961f8Sjose borrego mutex_enter(&node->n_mutex); 777da6c28aaSamw if (node->attr.sa_dosattr != mode) { 778da6c28aaSamw node->attr.sa_dosattr = mode; 779da6c28aaSamw node->what |= SMB_AT_DOSATTR; 780da6c28aaSamw } 7812c2961f8Sjose borrego mutex_exit(&node->n_mutex); 782da6c28aaSamw } 783da6c28aaSamw 784da6c28aaSamw /* 785c8ec8eeaSjose borrego * smb_node_get_dosattr() 786da6c28aaSamw * 787c8ec8eeaSjose borrego * This function is used to provide clients with information as to whether 788c8ec8eeaSjose borrego * the readonly bit is set. Hence both the node attribute cache (which 789c8ec8eeaSjose borrego * reflects the on-disk attributes) and node->readonly_creator (which 790c8ec8eeaSjose borrego * reflects whether a readonly set is pending from a readonly create) are 791c8ec8eeaSjose borrego * checked. In the latter case, the readonly attribute should be visible to 792c8ec8eeaSjose borrego * all clients even though the readonly creator fid is immune to the readonly 793c8ec8eeaSjose borrego * bit until close. 794da6c28aaSamw */ 795c8ec8eeaSjose borrego 796da6c28aaSamw uint32_t 797da6c28aaSamw smb_node_get_dosattr(smb_node_t *node) 798da6c28aaSamw { 799c8ec8eeaSjose borrego uint32_t dosattr = node->attr.sa_dosattr; 800c8ec8eeaSjose borrego 801c8ec8eeaSjose borrego if (node->readonly_creator) 802c8ec8eeaSjose borrego dosattr |= FILE_ATTRIBUTE_READONLY; 803c8ec8eeaSjose borrego 804c8ec8eeaSjose borrego if (!dosattr) 805c8ec8eeaSjose borrego dosattr = FILE_ATTRIBUTE_NORMAL; 806c8ec8eeaSjose borrego 807c8ec8eeaSjose borrego return (dosattr); 808da6c28aaSamw } 809da6c28aaSamw 810*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /* 811*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * When DeleteOnClose is set on an smb_node, the common open code will 812*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * reject subsequent open requests for the file. Observation of Windows 813*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 2000 indicates that subsequent opens should be allowed (assuming 814*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * there would be no sharing violation) until the file is closed using 815*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * the fid on which the DeleteOnClose was requested. 816*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 817*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * If there are multiple opens with delete-on-close create options, 818*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * whichever the first file handle is closed will trigger the node to be 819*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * marked as delete-on-close. The credentials of that ofile will be used 820*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * as the delete-on-close credentials of the node. 821*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States */ 822da6c28aaSamw int 823*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags) 824da6c28aaSamw { 825da6c28aaSamw int rc = -1; 826da6c28aaSamw 8272c2961f8Sjose borrego mutex_enter(&node->n_mutex); 828da6c28aaSamw if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) && 829da6c28aaSamw !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) { 830da6c28aaSamw crhold(cr); 831da6c28aaSamw node->delete_on_close_cred = cr; 832*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States node->n_delete_on_close_flags = flags; 833da6c28aaSamw node->flags |= NODE_FLAGS_DELETE_ON_CLOSE; 834da6c28aaSamw rc = 0; 835da6c28aaSamw } 8362c2961f8Sjose borrego mutex_exit(&node->n_mutex); 837da6c28aaSamw return (rc); 838da6c28aaSamw } 839da6c28aaSamw 840da6c28aaSamw void 841da6c28aaSamw smb_node_reset_delete_on_close(smb_node_t *node) 842da6c28aaSamw { 8432c2961f8Sjose borrego mutex_enter(&node->n_mutex); 844da6c28aaSamw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 845da6c28aaSamw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 846da6c28aaSamw crfree(node->delete_on_close_cred); 847da6c28aaSamw node->delete_on_close_cred = NULL; 848*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States node->n_delete_on_close_flags = 0; 849da6c28aaSamw } 8502c2961f8Sjose borrego mutex_exit(&node->n_mutex); 851da6c28aaSamw } 852dc20a302Sas200622 853dc20a302Sas200622 /* 8543ad684d6Sjb150015 * smb_node_open_check 855dc20a302Sas200622 * 856dc20a302Sas200622 * check file sharing rules for current open request 857dc20a302Sas200622 * against all existing opens for a file. 858dc20a302Sas200622 * 859dc20a302Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 860dc20a302Sas200622 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 861dc20a302Sas200622 */ 862dc20a302Sas200622 uint32_t 8632c2961f8Sjose borrego smb_node_open_check( 8642c2961f8Sjose borrego smb_node_t *node, 8652c2961f8Sjose borrego cred_t *cr, 8662c2961f8Sjose borrego uint32_t desired_access, 8672c2961f8Sjose borrego uint32_t share_access) 868dc20a302Sas200622 { 869dc20a302Sas200622 smb_ofile_t *of; 870dc20a302Sas200622 uint32_t status; 871dc20a302Sas200622 8722c2961f8Sjose borrego SMB_NODE_VALID(node); 873dc20a302Sas200622 874dc20a302Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 875dc20a302Sas200622 of = smb_llist_head(&node->n_ofile_list); 876dc20a302Sas200622 while (of) { 8773ad684d6Sjb150015 status = smb_ofile_open_check(of, cr, desired_access, 8783ad684d6Sjb150015 share_access); 8793ad684d6Sjb150015 8803ad684d6Sjb150015 switch (status) { 8813ad684d6Sjb150015 case NT_STATUS_INVALID_HANDLE: 8823ad684d6Sjb150015 case NT_STATUS_SUCCESS: 8833ad684d6Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 8843ad684d6Sjb150015 break; 8853ad684d6Sjb150015 default: 8863ad684d6Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 887dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 888dc20a302Sas200622 return (status); 889dc20a302Sas200622 } 890dc20a302Sas200622 } 8913ad684d6Sjb150015 892dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 893dc20a302Sas200622 return (NT_STATUS_SUCCESS); 894dc20a302Sas200622 } 895dc20a302Sas200622 896dc20a302Sas200622 uint32_t 8972c2961f8Sjose borrego smb_node_rename_check(smb_node_t *node) 898dc20a302Sas200622 { 8992c2961f8Sjose borrego smb_ofile_t *of; 9003ad684d6Sjb150015 uint32_t status; 901dc20a302Sas200622 9022c2961f8Sjose borrego SMB_NODE_VALID(node); 903dc20a302Sas200622 904dc20a302Sas200622 /* 905dc20a302Sas200622 * Intra-CIFS check 906dc20a302Sas200622 */ 907dc20a302Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 9083ad684d6Sjb150015 of = smb_llist_head(&node->n_ofile_list); 9093ad684d6Sjb150015 while (of) { 9103ad684d6Sjb150015 status = smb_ofile_rename_check(of); 911dc20a302Sas200622 9123ad684d6Sjb150015 switch (status) { 9133ad684d6Sjb150015 case NT_STATUS_INVALID_HANDLE: 9143ad684d6Sjb150015 case NT_STATUS_SUCCESS: 9153ad684d6Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 9163ad684d6Sjb150015 break; 9173ad684d6Sjb150015 default: 9183ad684d6Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 919dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 9203ad684d6Sjb150015 return (status); 921dc20a302Sas200622 } 922dc20a302Sas200622 } 923dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 924dc20a302Sas200622 925dc20a302Sas200622 /* 926dc20a302Sas200622 * system-wide share check 927dc20a302Sas200622 */ 928dc20a302Sas200622 if (nbl_share_conflict(node->vp, NBL_RENAME, NULL)) 929dc20a302Sas200622 return (NT_STATUS_SHARING_VIOLATION); 930dc20a302Sas200622 else 931dc20a302Sas200622 return (NT_STATUS_SUCCESS); 932dc20a302Sas200622 } 933dc20a302Sas200622 9343ad684d6Sjb150015 uint32_t 935dc20a302Sas200622 smb_node_delete_check(smb_node_t *node) 936dc20a302Sas200622 { 9373ad684d6Sjb150015 smb_ofile_t *of; 9383ad684d6Sjb150015 uint32_t status; 939dc20a302Sas200622 9402c2961f8Sjose borrego SMB_NODE_VALID(node); 941dc20a302Sas200622 942dc20a302Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 943dc20a302Sas200622 return (NT_STATUS_SUCCESS); 944dc20a302Sas200622 945dc20a302Sas200622 /* 946dc20a302Sas200622 * intra-CIFS check 947dc20a302Sas200622 */ 948dc20a302Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 9493ad684d6Sjb150015 of = smb_llist_head(&node->n_ofile_list); 9503ad684d6Sjb150015 while (of) { 9513ad684d6Sjb150015 status = smb_ofile_delete_check(of); 9523ad684d6Sjb150015 9533ad684d6Sjb150015 switch (status) { 9543ad684d6Sjb150015 case NT_STATUS_INVALID_HANDLE: 9553ad684d6Sjb150015 case NT_STATUS_SUCCESS: 9563ad684d6Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 9573ad684d6Sjb150015 break; 9583ad684d6Sjb150015 default: 9593ad684d6Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 960dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 9613ad684d6Sjb150015 return (status); 962dc20a302Sas200622 } 963dc20a302Sas200622 } 964dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 965dc20a302Sas200622 966dc20a302Sas200622 /* 967dc20a302Sas200622 * system-wide share check 968dc20a302Sas200622 */ 969dc20a302Sas200622 if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL)) 970dc20a302Sas200622 return (NT_STATUS_SHARING_VIOLATION); 971dc20a302Sas200622 else 972dc20a302Sas200622 return (NT_STATUS_SUCCESS); 973dc20a302Sas200622 } 974dc20a302Sas200622 975dc20a302Sas200622 /* 976dc20a302Sas200622 * smb_node_start_crit() 977dc20a302Sas200622 * 978dc20a302Sas200622 * Enter critical region for share reservations. 979dc20a302Sas200622 * See comments above smb_fsop_shrlock(). 980dc20a302Sas200622 */ 981dc20a302Sas200622 982dc20a302Sas200622 void 983dc20a302Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode) 984dc20a302Sas200622 { 9852c2961f8Sjose borrego rw_enter(&node->n_lock, mode); 986dc20a302Sas200622 nbl_start_crit(node->vp, mode); 987dc20a302Sas200622 } 988dc20a302Sas200622 989dc20a302Sas200622 /* 990dc20a302Sas200622 * smb_node_end_crit() 991dc20a302Sas200622 * 992dc20a302Sas200622 * Exit critical region for share reservations. 993dc20a302Sas200622 */ 994dc20a302Sas200622 995dc20a302Sas200622 void 996dc20a302Sas200622 smb_node_end_crit(smb_node_t *node) 997dc20a302Sas200622 { 998dc20a302Sas200622 nbl_end_crit(node->vp); 9992c2961f8Sjose borrego rw_exit(&node->n_lock); 1000dc20a302Sas200622 } 1001dc20a302Sas200622 1002dc20a302Sas200622 int 1003dc20a302Sas200622 smb_node_in_crit(smb_node_t *node) 1004dc20a302Sas200622 { 10052c2961f8Sjose borrego return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock)); 10062c2961f8Sjose borrego } 10072c2961f8Sjose borrego 10082c2961f8Sjose borrego void 10092c2961f8Sjose borrego smb_node_rdlock(smb_node_t *node) 10102c2961f8Sjose borrego { 10112c2961f8Sjose borrego rw_enter(&node->n_lock, RW_READER); 10122c2961f8Sjose borrego } 10132c2961f8Sjose borrego 10142c2961f8Sjose borrego void 10152c2961f8Sjose borrego smb_node_wrlock(smb_node_t *node) 10162c2961f8Sjose borrego { 10172c2961f8Sjose borrego rw_enter(&node->n_lock, RW_WRITER); 10182c2961f8Sjose borrego } 10192c2961f8Sjose borrego 10202c2961f8Sjose borrego void 10212c2961f8Sjose borrego smb_node_unlock(smb_node_t *node) 10222c2961f8Sjose borrego { 10232c2961f8Sjose borrego rw_exit(&node->n_lock); 10242c2961f8Sjose borrego } 10252c2961f8Sjose borrego 10262c2961f8Sjose borrego uint32_t 10272c2961f8Sjose borrego smb_node_get_ofile_count(smb_node_t *node) 10282c2961f8Sjose borrego { 10292c2961f8Sjose borrego uint32_t cntr; 10302c2961f8Sjose borrego 10312c2961f8Sjose borrego SMB_NODE_VALID(node); 10322c2961f8Sjose borrego 10332c2961f8Sjose borrego smb_llist_enter(&node->n_ofile_list, RW_READER); 10342c2961f8Sjose borrego cntr = smb_llist_get_count(&node->n_ofile_list); 10352c2961f8Sjose borrego smb_llist_exit(&node->n_ofile_list); 10362c2961f8Sjose borrego return (cntr); 10372c2961f8Sjose borrego } 10382c2961f8Sjose borrego 10392c2961f8Sjose borrego void 10402c2961f8Sjose borrego smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of) 10412c2961f8Sjose borrego { 10422c2961f8Sjose borrego SMB_NODE_VALID(node); 10432c2961f8Sjose borrego 10442c2961f8Sjose borrego smb_llist_enter(&node->n_ofile_list, RW_WRITER); 10452c2961f8Sjose borrego smb_llist_insert_tail(&node->n_ofile_list, of); 10462c2961f8Sjose borrego smb_llist_exit(&node->n_ofile_list); 10472c2961f8Sjose borrego } 10482c2961f8Sjose borrego 10492c2961f8Sjose borrego void 10502c2961f8Sjose borrego smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of) 10512c2961f8Sjose borrego { 10522c2961f8Sjose borrego SMB_NODE_VALID(node); 10532c2961f8Sjose borrego 10542c2961f8Sjose borrego smb_llist_enter(&node->n_ofile_list, RW_WRITER); 10552c2961f8Sjose borrego smb_llist_remove(&node->n_ofile_list, of); 10562c2961f8Sjose borrego smb_llist_exit(&node->n_ofile_list); 10572c2961f8Sjose borrego } 10582c2961f8Sjose borrego 10592c2961f8Sjose borrego void 10602c2961f8Sjose borrego smb_node_inc_open_ofiles(smb_node_t *node) 10612c2961f8Sjose borrego { 10622c2961f8Sjose borrego SMB_NODE_VALID(node); 10632c2961f8Sjose borrego 10642c2961f8Sjose borrego mutex_enter(&node->n_mutex); 10652c2961f8Sjose borrego node->n_open_count++; 10662c2961f8Sjose borrego mutex_exit(&node->n_mutex); 10672c2961f8Sjose borrego } 10682c2961f8Sjose borrego 10692c2961f8Sjose borrego void 10702c2961f8Sjose borrego smb_node_dec_open_ofiles(smb_node_t *node) 10712c2961f8Sjose borrego { 10722c2961f8Sjose borrego SMB_NODE_VALID(node); 10732c2961f8Sjose borrego 10742c2961f8Sjose borrego mutex_enter(&node->n_mutex); 10752c2961f8Sjose borrego node->n_open_count--; 10762c2961f8Sjose borrego mutex_exit(&node->n_mutex); 10772c2961f8Sjose borrego } 10782c2961f8Sjose borrego 10792c2961f8Sjose borrego uint32_t 10802c2961f8Sjose borrego smb_node_get_open_ofiles(smb_node_t *node) 10812c2961f8Sjose borrego { 10822c2961f8Sjose borrego uint32_t cnt; 10832c2961f8Sjose borrego 10842c2961f8Sjose borrego SMB_NODE_VALID(node); 10852c2961f8Sjose borrego 10862c2961f8Sjose borrego mutex_enter(&node->n_mutex); 10872c2961f8Sjose borrego cnt = node->n_open_count; 10882c2961f8Sjose borrego mutex_exit(&node->n_mutex); 10892c2961f8Sjose borrego return (cnt); 10902c2961f8Sjose borrego } 10912c2961f8Sjose borrego 10922c2961f8Sjose borrego /* 10932c2961f8Sjose borrego * smb_node_alloc 10942c2961f8Sjose borrego */ 10952c2961f8Sjose borrego static smb_node_t * 10962c2961f8Sjose borrego smb_node_alloc( 10972c2961f8Sjose borrego char *od_name, 10982c2961f8Sjose borrego vnode_t *vp, 10992c2961f8Sjose borrego smb_attr_t *attr, 11002c2961f8Sjose borrego smb_llist_t *bucket, 11012c2961f8Sjose borrego uint32_t hashkey) 11022c2961f8Sjose borrego { 11032c2961f8Sjose borrego smb_node_t *node; 11042c2961f8Sjose borrego 11052c2961f8Sjose borrego node = kmem_cache_alloc(smb_node_cache, KM_SLEEP); 11062c2961f8Sjose borrego 11072c2961f8Sjose borrego if (node->n_audit_buf != NULL) 11082c2961f8Sjose borrego node->n_audit_buf->anb_index = 0; 11092c2961f8Sjose borrego 11102c2961f8Sjose borrego node->attr = *attr; 11112c2961f8Sjose borrego node->flags = NODE_FLAGS_ATTR_VALID; 11122c2961f8Sjose borrego node->n_size = node->attr.sa_vattr.va_size; 11132c2961f8Sjose borrego VN_HOLD(vp); 11142c2961f8Sjose borrego node->vp = vp; 11152c2961f8Sjose borrego node->n_refcnt = 1; 11162c2961f8Sjose borrego node->n_hash_bucket = bucket; 11172c2961f8Sjose borrego node->n_hashkey = hashkey; 11182c2961f8Sjose borrego node->n_orig_uid = 0; 11192c2961f8Sjose borrego node->readonly_creator = NULL; 11202c2961f8Sjose borrego node->waiting_event = 0; 11212c2961f8Sjose borrego node->what = 0; 11222c2961f8Sjose borrego node->n_open_count = 0; 11232c2961f8Sjose borrego node->dir_snode = NULL; 11242c2961f8Sjose borrego node->unnamed_stream_node = NULL; 11252c2961f8Sjose borrego node->delete_on_close_cred = NULL; 1126*8b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States node->n_delete_on_close_flags = 0; 11272c2961f8Sjose borrego 11282c2961f8Sjose borrego (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); 11292c2961f8Sjose borrego if (strcmp(od_name, XATTR_DIR) == 0) 11302c2961f8Sjose borrego node->flags |= NODE_XATTR_DIR; 11312c2961f8Sjose borrego 11322c2961f8Sjose borrego node->n_state = SMB_NODE_STATE_AVAILABLE; 11332c2961f8Sjose borrego node->n_magic = SMB_NODE_MAGIC; 11342c2961f8Sjose borrego return (node); 11352c2961f8Sjose borrego } 11362c2961f8Sjose borrego 11372c2961f8Sjose borrego /* 11382c2961f8Sjose borrego * smb_node_free 11392c2961f8Sjose borrego */ 11402c2961f8Sjose borrego static void 11412c2961f8Sjose borrego smb_node_free(smb_node_t *node) 11422c2961f8Sjose borrego { 11432c2961f8Sjose borrego SMB_NODE_VALID(node); 11442c2961f8Sjose borrego 11452c2961f8Sjose borrego node->n_magic = 0; 11462c2961f8Sjose borrego VERIFY(!list_link_active(&node->n_lnd)); 11472c2961f8Sjose borrego VERIFY(node->n_lock_list.ll_count == 0); 11482c2961f8Sjose borrego VERIFY(node->n_ofile_list.ll_count == 0); 11492c2961f8Sjose borrego VERIFY(node->n_oplock.ol_xthread == NULL); 1150fc724630SAlan Wright VERIFY(mutex_owner(&node->n_mutex) == NULL); 1151fc724630SAlan Wright VERIFY(!RW_LOCK_HELD(&node->n_lock)); 11522c2961f8Sjose borrego VN_RELE(node->vp); 11532c2961f8Sjose borrego kmem_cache_free(smb_node_cache, node); 11542c2961f8Sjose borrego } 11552c2961f8Sjose borrego 11562c2961f8Sjose borrego /* 11572c2961f8Sjose borrego * smb_node_constructor 11582c2961f8Sjose borrego */ 11592c2961f8Sjose borrego static int 11602c2961f8Sjose borrego smb_node_constructor(void *buf, void *un, int kmflags) 11612c2961f8Sjose borrego { 11622c2961f8Sjose borrego _NOTE(ARGUNUSED(kmflags, un)) 11632c2961f8Sjose borrego 11642c2961f8Sjose borrego smb_node_t *node = (smb_node_t *)buf; 11652c2961f8Sjose borrego 11662c2961f8Sjose borrego bzero(node, sizeof (smb_node_t)); 11672c2961f8Sjose borrego 11682c2961f8Sjose borrego smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 11692c2961f8Sjose borrego offsetof(smb_ofile_t, f_nnd)); 11702c2961f8Sjose borrego smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 11712c2961f8Sjose borrego offsetof(smb_lock_t, l_lnd)); 11722c2961f8Sjose borrego cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL); 11732c2961f8Sjose borrego rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL); 11742c2961f8Sjose borrego mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL); 11752c2961f8Sjose borrego smb_node_create_audit_buf(node, kmflags); 11762c2961f8Sjose borrego return (0); 11772c2961f8Sjose borrego } 11782c2961f8Sjose borrego 11792c2961f8Sjose borrego /* 11802c2961f8Sjose borrego * smb_node_destructor 11812c2961f8Sjose borrego */ 11822c2961f8Sjose borrego static void 11832c2961f8Sjose borrego smb_node_destructor(void *buf, void *un) 11842c2961f8Sjose borrego { 11852c2961f8Sjose borrego _NOTE(ARGUNUSED(un)) 11862c2961f8Sjose borrego 11872c2961f8Sjose borrego smb_node_t *node = (smb_node_t *)buf; 11882c2961f8Sjose borrego 11892c2961f8Sjose borrego smb_node_destroy_audit_buf(node); 11902c2961f8Sjose borrego mutex_destroy(&node->n_mutex); 11912c2961f8Sjose borrego rw_destroy(&node->n_lock); 11922c2961f8Sjose borrego cv_destroy(&node->n_oplock.ol_cv); 11932c2961f8Sjose borrego smb_llist_destructor(&node->n_lock_list); 11942c2961f8Sjose borrego smb_llist_destructor(&node->n_ofile_list); 11952c2961f8Sjose borrego } 11962c2961f8Sjose borrego 11972c2961f8Sjose borrego /* 11982c2961f8Sjose borrego * smb_node_create_audit_buf 11992c2961f8Sjose borrego */ 12002c2961f8Sjose borrego static void 12012c2961f8Sjose borrego smb_node_create_audit_buf(smb_node_t *node, int kmflags) 12022c2961f8Sjose borrego { 12032c2961f8Sjose borrego smb_audit_buf_node_t *abn; 12042c2961f8Sjose borrego 12052c2961f8Sjose borrego if (smb_audit_flags & SMB_AUDIT_NODE) { 12062c2961f8Sjose borrego abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags); 12072c2961f8Sjose borrego abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1; 12082c2961f8Sjose borrego node->n_audit_buf = abn; 12092c2961f8Sjose borrego } 12102c2961f8Sjose borrego } 12112c2961f8Sjose borrego 12122c2961f8Sjose borrego /* 12132c2961f8Sjose borrego * smb_node_destroy_audit_buf 12142c2961f8Sjose borrego */ 12152c2961f8Sjose borrego static void 12162c2961f8Sjose borrego smb_node_destroy_audit_buf(smb_node_t *node) 12172c2961f8Sjose borrego { 12182c2961f8Sjose borrego if (node->n_audit_buf != NULL) { 12192c2961f8Sjose borrego kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t)); 12202c2961f8Sjose borrego node->n_audit_buf = NULL; 12212c2961f8Sjose borrego } 12222c2961f8Sjose borrego } 12232c2961f8Sjose borrego 12242c2961f8Sjose borrego /* 12252c2961f8Sjose borrego * smb_node_audit 12262c2961f8Sjose borrego * 12272c2961f8Sjose borrego * This function saves the calling stack in the audit buffer of the node passed 12282c2961f8Sjose borrego * in. 12292c2961f8Sjose borrego */ 12302c2961f8Sjose borrego static void 12312c2961f8Sjose borrego smb_node_audit(smb_node_t *node) 12322c2961f8Sjose borrego { 12332c2961f8Sjose borrego smb_audit_buf_node_t *abn; 12342c2961f8Sjose borrego smb_audit_record_node_t *anr; 12352c2961f8Sjose borrego 12362c2961f8Sjose borrego if (node->n_audit_buf) { 12372c2961f8Sjose borrego abn = node->n_audit_buf; 12382c2961f8Sjose borrego anr = abn->anb_records; 12392c2961f8Sjose borrego anr += abn->anb_index; 12402c2961f8Sjose borrego abn->anb_index++; 12412c2961f8Sjose borrego abn->anb_index &= abn->anb_max_index; 12422c2961f8Sjose borrego anr->anr_refcnt = node->n_refcnt; 12432c2961f8Sjose borrego anr->anr_depth = getpcstack(anr->anr_stack, 12442c2961f8Sjose borrego SMB_AUDIT_STACK_DEPTH); 12452c2961f8Sjose borrego } 12462c2961f8Sjose borrego } 12472c2961f8Sjose borrego 12482c2961f8Sjose borrego static smb_llist_t * 12492c2961f8Sjose borrego smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey) 12502c2961f8Sjose borrego { 12512c2961f8Sjose borrego uint32_t hashkey; 12522c2961f8Sjose borrego 12532c2961f8Sjose borrego hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid; 12542c2961f8Sjose borrego hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 12552c2961f8Sjose borrego *phashkey = hashkey; 12562c2961f8Sjose borrego return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]); 1257dc20a302Sas200622 } 1258