15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 26*7348SJose.Borrego@Sun.COM #pragma ident "@(#)smb_node.c 1.9 08/08/07 SMI" 275331Samw 285331Samw /* 295331Samw * SMB Node State Machine 305331Samw * ---------------------- 315331Samw * 325331Samw * +----------------------------+ T0 335331Samw * | SMB_NODE_STATE_AVAILABLE |<----------- Creation/Allocation 345331Samw * +----------------------------+ 355331Samw * | 365331Samw * | T1 375331Samw * | 385331Samw * v 395331Samw * +-----------------------------+ T2 405331Samw * | SMB_NODE_STATE_DESTROYING |----------> Deletion/Free 415331Samw * +-----------------------------+ 425331Samw * 435331Samw * Transition T0 445331Samw * 455331Samw * This transition occurs in smb_node_lookup(). If the node looked for is 465331Samw * not found in the has table a new node is created. The reference count is 475331Samw * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE. 485331Samw * 495331Samw * Transition T1 505331Samw * 515331Samw * This transition occurs in smb_node_release(). If the reference count 525331Samw * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more 535331Samw * reference count will be given out for that node. 545331Samw * 555331Samw * Transition T2 565331Samw * 575331Samw * This transition occurs in smb_node_release(). The structure is deleted. 585331Samw * 595331Samw * Comments 605331Samw * -------- 615331Samw * 625331Samw * The reason the smb node has 2 states is the following synchronization 635331Samw * rule: 645331Samw * 655331Samw * There's a mutex embedded in the node used to protect its fields and 665331Samw * there's a lock embedded in the bucket of the hash table the node belongs 675331Samw * to. To increment or to decrement the reference count the mutex must be 685331Samw * entered. To insert the node into the bucket and to remove it from the 695331Samw * bucket the lock must be entered in RW_WRITER mode. When both (mutex and 705331Samw * lock) have to be entered, the lock has always to be entered first then 715331Samw * the mutex. This prevents a deadlock between smb_node_lookup() and 725331Samw * smb_node_release() from occurring. However, in smb_node_release() when the 735331Samw * reference count drops to zero and triggers the deletion of the node, the 745331Samw * mutex has to be released before entering the lock of the bucket (to 755331Samw * remove the node). This creates a window during which the node that is 765331Samw * about to be freed could be given out by smb_node_lookup(). To close that 775331Samw * window the node is moved to the state SMB_NODE_STATE_DESTROYING before 785331Samw * releasing the mutex. That way, even if smb_node_lookup() finds it, the 795331Samw * state will indicate that the node should be treated as non existent (of 805331Samw * course the state of the node should be tested/updated under the 815331Samw * protection of the mutex). 825331Samw */ 835331Samw #include <smbsrv/smb_incl.h> 845331Samw #include <smbsrv/smb_fsops.h> 855331Samw #include <sys/pathname.h> 865331Samw #include <sys/sdt.h> 875772Sas200622 #include <sys/nbmlock.h> 885331Samw 895331Samw uint32_t smb_is_executable(char *path); 905331Samw static void smb_node_delete_on_close(smb_node_t *node); 915331Samw 925331Samw #define VALIDATE_DIR_NODE(_dir_, _node_) \ 935331Samw ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \ 945331Samw ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \ 955331Samw ASSERT((_dir_)->dir_snode != (_node_)); 965331Samw 976139Sjb150015 static boolean_t smb_node_initialized = B_FALSE; 986139Sjb150015 static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1]; 996139Sjb150015 1006139Sjb150015 /* 1016139Sjb150015 * smb_node_init 1026139Sjb150015 * 1036139Sjb150015 * Initialization of the SMB node layer. 1046139Sjb150015 * 1056139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 1066139Sjb150015 * thread makes the call. 1076139Sjb150015 */ 1086139Sjb150015 int 1096139Sjb150015 smb_node_init(void) 1106139Sjb150015 { 1116139Sjb150015 int i; 1126139Sjb150015 1136139Sjb150015 if (smb_node_initialized) 1146139Sjb150015 return (0); 1156139Sjb150015 1166139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 1176139Sjb150015 smb_llist_constructor(&smb_node_hash_table[i], 1186139Sjb150015 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 1196139Sjb150015 } 1206139Sjb150015 smb_node_initialized = B_TRUE; 1216139Sjb150015 return (0); 1226139Sjb150015 } 1236139Sjb150015 1246139Sjb150015 /* 1256139Sjb150015 * smb_node_fini 1266139Sjb150015 * 1276139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 1286139Sjb150015 * thread makes the call. 1296139Sjb150015 */ 1306139Sjb150015 void 1316139Sjb150015 smb_node_fini(void) 1326139Sjb150015 { 1336139Sjb150015 int i; 1346139Sjb150015 1356139Sjb150015 if (!smb_node_initialized) 1366139Sjb150015 return; 1376139Sjb150015 1386139Sjb150015 #ifdef DEBUG 1396139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 1406139Sjb150015 smb_node_t *node; 1416139Sjb150015 1426139Sjb150015 /* 1436139Sjb150015 * The following sequence is just intended for sanity check. 1446139Sjb150015 * This will have to be modified when the code goes into 1456139Sjb150015 * production. 1466139Sjb150015 * 1476139Sjb150015 * The SMB node hash table should be emtpy at this point. If the 1486139Sjb150015 * hash table is not empty a panic will be triggered. 1496139Sjb150015 * 1506139Sjb150015 * The reason why SMB nodes are still remaining in the hash 1516139Sjb150015 * table is problably due to a mismatch between calls to 1526139Sjb150015 * smb_node_lookup() and smb_node_release(). You must track that 1536139Sjb150015 * down. 1546139Sjb150015 */ 1556139Sjb150015 node = smb_llist_head(&smb_node_hash_table[i]); 1566139Sjb150015 ASSERT(node == NULL); 1576139Sjb150015 } 1586139Sjb150015 #endif 1596139Sjb150015 1606139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 1616139Sjb150015 smb_llist_destructor(&smb_node_hash_table[i]); 1626139Sjb150015 } 1636139Sjb150015 smb_node_initialized = B_FALSE; 1646139Sjb150015 } 1656139Sjb150015 1665331Samw /* 1675331Samw * smb_node_lookup() 1685331Samw * 1695331Samw * NOTE: This routine should only be called by the file system interface layer, 1705331Samw * and not by SMB. 1715331Samw * 1725331Samw * smb_node_lookup() is called upon successful lookup, mkdir, and create 1735331Samw * (for both non-streams and streams). In each of these cases, a held vnode is 1745331Samw * passed into this routine. If an smb_node already exists for this vnode, 1755331Samw * the vp is released. Otherwise, a new smb_node will be created and the 1765331Samw * reference will be held until the refcnt on the node goes to 0 (see 1775331Samw * smb_node_release()). 1785331Samw * 1795331Samw * A reference is taken on the smb_node whether found in the hash table 1805331Samw * or newly created. 1815331Samw * 1825331Samw * If an smb_node needs to be created, a reference is also taken on the 1835331Samw * dir_snode (if passed in). 1845331Samw * 1855331Samw * See smb_node_release() for details on the release of these references. 1865331Samw */ 1875331Samw 1885331Samw /*ARGSUSED*/ 1895331Samw smb_node_t * 1905331Samw smb_node_lookup( 1915331Samw struct smb_request *sr, 1925331Samw struct open_param *op, 1935331Samw cred_t *cred, 1945331Samw vnode_t *vp, 1955331Samw char *od_name, 1965331Samw smb_node_t *dir_snode, 1975331Samw smb_node_t *unnamed_node, 1985331Samw smb_attr_t *attr) 1995331Samw { 2005331Samw smb_llist_t *node_hdr; 2015331Samw smb_node_t *node; 2025331Samw uint32_t hashkey = 0; 203*7348SJose.Borrego@Sun.COM fsid_t fsid; 2045331Samw int error; 2055331Samw krw_t lock_mode; 2065331Samw vnode_t *unnamed_vp = NULL; 2075331Samw 2085331Samw /* 2095331Samw * smb_vop_getattr() is called here instead of smb_fsop_getattr(), 2105331Samw * because the node may not yet exist. We also do not want to call 2115331Samw * it with the list lock held. 2125331Samw */ 2135331Samw 2145331Samw if (unnamed_node) 2155331Samw unnamed_vp = unnamed_node->vp; 2165331Samw 2175331Samw /* 2185331Samw * This getattr is performed on behalf of the server 2195331Samw * that's why kcred is used not the user's cred 2205331Samw */ 2215331Samw attr->sa_mask = SMB_AT_ALL; 2225772Sas200622 error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred); 2235331Samw if (error) 2245331Samw return (NULL); 2255331Samw 226*7348SJose.Borrego@Sun.COM if (sr && sr->tid_tree) { 227*7348SJose.Borrego@Sun.COM /* 228*7348SJose.Borrego@Sun.COM * The fsid for a file is that of the tree, even 229*7348SJose.Borrego@Sun.COM * if the file resides in a different mountpoint 230*7348SJose.Borrego@Sun.COM * under the share. 231*7348SJose.Borrego@Sun.COM */ 232*7348SJose.Borrego@Sun.COM fsid = SMB_TREE_FSID(sr->tid_tree); 2335331Samw } else { 234*7348SJose.Borrego@Sun.COM /* 235*7348SJose.Borrego@Sun.COM * This should be getting executed only for the 236*7348SJose.Borrego@Sun.COM * tree root smb_node. 237*7348SJose.Borrego@Sun.COM */ 238*7348SJose.Borrego@Sun.COM fsid = vp->v_vfsp->vfs_fsid; 2395331Samw } 2405331Samw 241*7348SJose.Borrego@Sun.COM hashkey = fsid.val[0] + attr->sa_vattr.va_nodeid; 2425331Samw hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 2436139Sjb150015 node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]; 2445331Samw lock_mode = RW_READER; 2455331Samw 2465331Samw smb_llist_enter(node_hdr, lock_mode); 2475331Samw for (;;) { 2485331Samw node = list_head(&node_hdr->ll_list); 2495331Samw while (node) { 2505331Samw ASSERT(node->n_magic == SMB_NODE_MAGIC); 2515331Samw ASSERT(node->n_hash_bucket == node_hdr); 2525331Samw if ((node->n_hashkey == hashkey) && (node->vp == vp)) { 2535331Samw smb_rwx_xenter(&node->n_lock); 2545331Samw DTRACE_PROBE1(smb_node_lookup_hit, 2555331Samw smb_node_t *, node); 2565331Samw switch (node->n_state) { 2575331Samw case SMB_NODE_STATE_AVAILABLE: 2585331Samw /* The node was found. */ 2595331Samw node->n_refcnt++; 2605331Samw if ((node->dir_snode == NULL) && 2615331Samw (dir_snode != NULL) && 2625331Samw (strcmp(od_name, "..") != 0) && 2635331Samw (strcmp(od_name, ".") != 0)) { 2645331Samw VALIDATE_DIR_NODE(dir_snode, 2655331Samw node); 2665331Samw node->dir_snode = dir_snode; 2675331Samw smb_node_ref(dir_snode); 2685331Samw } 2695331Samw node->attr = *attr; 2705772Sas200622 node->n_size = attr->sa_vattr.va_size; 2715331Samw 2725331Samw smb_audit_node(node); 2735331Samw smb_rwx_xexit(&node->n_lock); 2745331Samw smb_llist_exit(node_hdr); 2755331Samw VN_RELE(vp); 2765331Samw return (node); 2775331Samw 2785331Samw case SMB_NODE_STATE_DESTROYING: 2795331Samw /* 2805331Samw * Although the node exists it is about 2815331Samw * to be destroyed. We act as it hasn't 2825331Samw * been found. 2835331Samw */ 2845331Samw smb_rwx_xexit(&node->n_lock); 2855331Samw break; 2865331Samw default: 2875331Samw /* 2885331Samw * Although the node exists it is in an 2895331Samw * unknown state. We act as it hasn't 2905331Samw * been found. 2915331Samw */ 2925331Samw ASSERT(0); 2935331Samw smb_rwx_xexit(&node->n_lock); 2945331Samw break; 2955331Samw } 2965331Samw } 2975331Samw node = smb_llist_next(node_hdr, node); 2985331Samw } 2995331Samw if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) { 3005331Samw lock_mode = RW_WRITER; 3015331Samw continue; 3025331Samw } 3035331Samw break; 3045331Samw } 3056139Sjb150015 node = kmem_cache_alloc(sr->sr_server->si_cache_node, KM_SLEEP); 3065331Samw bzero(node, sizeof (smb_node_t)); 3075331Samw 3085331Samw node->n_state = SMB_NODE_STATE_AVAILABLE; 3095331Samw node->n_hash_bucket = node_hdr; 3106139Sjb150015 node->n_sr = sr; 3116139Sjb150015 node->vp = vp; 3126139Sjb150015 node->n_hashkey = hashkey; 3136139Sjb150015 node->n_refcnt = 1; 3146139Sjb150015 node->attr = *attr; 3156139Sjb150015 node->flags |= NODE_FLAGS_ATTR_VALID; 3166139Sjb150015 node->n_size = node->attr.sa_vattr.va_size; 3176139Sjb150015 node->n_orig_session_id = sr->session->s_kid; 3186139Sjb150015 node->n_orig_uid = crgetuid(sr->user_cr); 3196139Sjb150015 node->n_cache = sr->sr_server->si_cache_node; 3205331Samw 3216139Sjb150015 ASSERT(od_name); 3226139Sjb150015 (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); 3236139Sjb150015 3245331Samw smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 3255331Samw offsetof(smb_ofile_t, f_nnd)); 3265331Samw smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 3275331Samw offsetof(smb_lock_t, l_lnd)); 3285331Samw 3295331Samw 3305967Scp160787 if (strcmp(od_name, XATTR_DIR) == 0) 3315967Scp160787 node->flags |= NODE_XATTR_DIR; 3325331Samw if (op) 3335331Samw node->flags |= smb_is_executable(op->fqi.last_comp); 3345331Samw 3355331Samw if (dir_snode) { 3365331Samw smb_node_ref(dir_snode); 3375331Samw node->dir_snode = dir_snode; 3385331Samw ASSERT(dir_snode->dir_snode != node); 3395331Samw ASSERT((dir_snode->vp->v_xattrdir) || 3405331Samw (dir_snode->vp->v_type == VDIR)); 3415331Samw } 3425331Samw 3435331Samw if (unnamed_node) { 3445331Samw smb_node_ref(unnamed_node); 3455331Samw node->unnamed_stream_node = unnamed_node; 3465331Samw } 3475331Samw 3485331Samw smb_rwx_init(&node->n_lock); 3495331Samw node->n_magic = SMB_NODE_MAGIC; 3505331Samw smb_audit_buf_node_create(node); 3515331Samw DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node); 3525331Samw smb_audit_node(node); 3535331Samw smb_llist_insert_head(node_hdr, node); 3546139Sjb150015 3555331Samw smb_llist_exit(node_hdr); 3565331Samw return (node); 3575331Samw } 3585331Samw 3595331Samw /* 3605331Samw * smb_stream_node_lookup() 3615331Samw * 3625331Samw * Note: stream_name (the name that will be stored in the "od_name" field 3635331Samw * of a stream's smb_node) is the same as the on-disk name for the stream 3645331Samw * except that it does not have SMB_STREAM_PREFIX prepended. 3655331Samw */ 3665331Samw 3675331Samw smb_node_t * 3685331Samw smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode, 3695331Samw vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr) 3705331Samw { 3715331Samw smb_node_t *xattrdir_node; 3725331Samw smb_node_t *snode; 3735331Samw smb_attr_t tmp_attr; 3745331Samw 3755331Samw xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR, 3765331Samw fnode, NULL, &tmp_attr); 3775331Samw 3785331Samw if (xattrdir_node == NULL) 3795331Samw return (NULL); 3805331Samw 3815331Samw snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node, 3825331Samw fnode, ret_attr); 3835331Samw 3845331Samw /* 3855331Samw * The following VN_HOLD is necessary because the caller will VN_RELE 3865331Samw * xattrdirvp in the case of an error. (xattrdir_node has the original 3875331Samw * hold on the vnode, which the smb_node_release() call below will 3885331Samw * release.) 3895331Samw */ 3905331Samw if (snode == NULL) { 3915331Samw VN_HOLD(xattrdirvp); 3925331Samw } 3935331Samw (void) smb_node_release(xattrdir_node); 3945331Samw return (snode); 3955331Samw } 3965331Samw 3975331Samw 3985331Samw /* 3995331Samw * This function should be called whenever a reference is needed on an 4005331Samw * smb_node pointer. The copy of an smb_node pointer from one non-local 4015331Samw * data structure to another requires a reference to be taken on the smb_node 4025331Samw * (unless the usage is localized). Each data structure deallocation routine 4035331Samw * will call smb_node_release() on its smb_node pointers. 4045331Samw * 4055331Samw * In general, an smb_node pointer residing in a structure should never be 4065331Samw * stale. A node pointer may be NULL, however, and care should be taken 4075331Samw * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid. 4085331Samw * Care also needs to be taken with respect to racing deallocations of a 4095331Samw * structure. 4105331Samw */ 4115331Samw 4125331Samw void 4135331Samw smb_node_ref(smb_node_t *node) 4145331Samw { 4155331Samw ASSERT(node); 4165331Samw ASSERT(node->n_magic == SMB_NODE_MAGIC); 4175331Samw ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 4185331Samw 4195331Samw smb_rwx_xenter(&node->n_lock); 4205331Samw node->n_refcnt++; 4215331Samw ASSERT(node->n_refcnt); 4225331Samw DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); 4235331Samw smb_audit_node(node); 4245331Samw smb_rwx_xexit(&node->n_lock); 4255331Samw } 4265331Samw 4275331Samw /* 4285331Samw * smb_node_lookup() takes a hold on an smb_node, whether found in the 4295331Samw * hash table or newly created. This hold is expected to be released 4305331Samw * in the following manner. 4315331Samw * 4325331Samw * smb_node_lookup() takes an address of an smb_node pointer. This should 4335331Samw * be getting passed down via a lookup (whether path name or component), mkdir, 4345331Samw * create. If the original smb_node pointer resides in a data structure, then 4355331Samw * the deallocation routine for the data structure is responsible for calling 4365331Samw * smb_node_release() on the smb_node pointer. Alternatively, 4375331Samw * smb_node_release() can be called as soon as the smb_node pointer is no longer 4385331Samw * needed. In this case, callers are responsible for setting an embedded 4395331Samw * pointer to NULL if it is known that the last reference is being released. 4405331Samw * 4415331Samw * If the passed-in address of the smb_node pointer belongs to a local variable, 4425331Samw * then the caller with the local variable should call smb_node_release() 4435331Samw * directly. 4445331Samw * 4455331Samw * smb_node_release() itself will call smb_node_release() on a node's dir_snode, 4465331Samw * as smb_node_lookup() takes a hold on dir_snode. 4475331Samw */ 4485331Samw void 4495331Samw smb_node_release(smb_node_t *node) 4505331Samw { 4515331Samw ASSERT(node); 4525331Samw ASSERT(node->n_magic == SMB_NODE_MAGIC); 4535331Samw 4545331Samw smb_rwx_xenter(&node->n_lock); 4555331Samw ASSERT(node->n_refcnt); 4565331Samw DTRACE_PROBE1(smb_node_release, smb_node_t *, node); 4575331Samw if (--node->n_refcnt == 0) { 4585331Samw switch (node->n_state) { 4595331Samw 4605331Samw case SMB_NODE_STATE_AVAILABLE: 4615331Samw node->n_state = SMB_NODE_STATE_DESTROYING; 4625331Samw smb_rwx_xexit(&node->n_lock); 4635331Samw 4645331Samw smb_llist_enter(node->n_hash_bucket, RW_WRITER); 4655331Samw smb_llist_remove(node->n_hash_bucket, node); 4665331Samw smb_llist_exit(node->n_hash_bucket); 4675331Samw 4685331Samw /* 4695331Samw * Check if the file was deleted 4705331Samw */ 4715331Samw smb_node_delete_on_close(node); 4725331Samw node->n_magic = (uint32_t)~SMB_NODE_MAGIC; 4735331Samw 4745331Samw /* These lists should be empty. */ 4755331Samw smb_llist_destructor(&node->n_ofile_list); 4765331Samw smb_llist_destructor(&node->n_lock_list); 4775331Samw 4785331Samw if (node->dir_snode) { 4795331Samw ASSERT(node->dir_snode->n_magic == 4805331Samw SMB_NODE_MAGIC); 4815331Samw smb_node_release(node->dir_snode); 4825331Samw } 4835331Samw 4845331Samw if (node->unnamed_stream_node) { 4855331Samw ASSERT(node->unnamed_stream_node->n_magic == 4865331Samw SMB_NODE_MAGIC); 4875331Samw smb_node_release(node->unnamed_stream_node); 4885331Samw } 4895331Samw 4905331Samw ASSERT(node->vp); 4915331Samw VN_RELE(node->vp); 4925331Samw 4935331Samw smb_audit_buf_node_destroy(node); 4945331Samw smb_rwx_destroy(&node->n_lock); 4956139Sjb150015 kmem_cache_free(node->n_cache, node); 4965331Samw return; 4975331Samw 4985331Samw default: 4995331Samw ASSERT(0); 5005331Samw break; 5015331Samw } 5025331Samw } 5035331Samw smb_audit_node(node); 5045331Samw smb_rwx_xexit(&node->n_lock); 5055331Samw } 5065331Samw 5075331Samw static void 5085331Samw smb_node_delete_on_close(smb_node_t *node) 5095331Samw { 5105331Samw smb_node_t *d_snode; 5115331Samw int rc = 0; 5125331Samw 5135331Samw d_snode = node->dir_snode; 5145331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 5155331Samw 5165331Samw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 5175331Samw ASSERT(node->od_name != NULL); 5185331Samw if (node->attr.sa_vattr.va_type == VDIR) 5195331Samw rc = smb_fsop_rmdir(0, node->delete_on_close_cred, 5205331Samw d_snode, node->od_name, 1); 5215331Samw else 5225331Samw rc = smb_fsop_remove(0, node->delete_on_close_cred, 5235331Samw d_snode, node->od_name, 1); 5245331Samw smb_cred_rele(node->delete_on_close_cred); 5255331Samw } 5265331Samw if (rc != 0) 5275331Samw cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n", 5285331Samw node->od_name, rc); 5295331Samw DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node); 5305331Samw } 5315331Samw 5325331Samw /* 5335331Samw * smb_node_rename() 5345331Samw * 5355331Samw */ 5365331Samw int 5375331Samw smb_node_rename( 5385331Samw smb_node_t *from_dir_snode, 5395331Samw smb_node_t *ret_snode, 5405331Samw smb_node_t *to_dir_snode, 5415331Samw char *to_name) 5425331Samw { 5435331Samw ASSERT(from_dir_snode); 5445331Samw ASSERT(to_dir_snode); 5455331Samw ASSERT(ret_snode); 5465331Samw ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 5475331Samw ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 5485331Samw ASSERT(ret_snode->n_magic == SMB_NODE_MAGIC); 5495331Samw ASSERT(from_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE); 5505331Samw ASSERT(to_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE); 5515331Samw ASSERT(ret_snode->n_state == SMB_NODE_STATE_AVAILABLE); 5525331Samw 5535331Samw smb_node_ref(to_dir_snode); 5545331Samw smb_rwx_xenter(&ret_snode->n_lock); 5555331Samw ret_snode->dir_snode = to_dir_snode; 5565331Samw smb_rwx_xexit(&ret_snode->n_lock); 5575331Samw ASSERT(to_dir_snode->dir_snode != ret_snode); 5585331Samw ASSERT((to_dir_snode->vp->v_xattrdir) || 5595331Samw (to_dir_snode->vp->v_type == VDIR)); 5605331Samw smb_node_release(from_dir_snode); 5615331Samw 5625331Samw (void) strcpy(ret_snode->od_name, to_name); 5635331Samw 5645331Samw /* 5655331Samw * XXX Need to update attributes? 5665331Samw */ 5675331Samw 5685331Samw return (0); 5695331Samw } 5705331Samw 5715331Samw int 5726139Sjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root) 5735331Samw { 5746139Sjb150015 smb_attr_t va; 5756139Sjb150015 int error; 5766139Sjb150015 uint32_t hashkey; 5776139Sjb150015 smb_llist_t *node_hdr; 5786139Sjb150015 smb_node_t *node; 5795331Samw 5805331Samw /* 5815331Samw * Take an explicit hold on rootdir. This goes with the 5825331Samw * corresponding release in smb_node_root_fini()/smb_node_release(). 5835331Samw */ 5846139Sjb150015 VN_HOLD(vp); 5855331Samw 5866139Sjb150015 va.sa_mask = SMB_AT_ALL; 5876139Sjb150015 error = smb_vop_getattr(vp, NULL, &va, 0, kcred); 5886139Sjb150015 if (error) { 5896139Sjb150015 VN_RELE(vp); 5906139Sjb150015 return (error); 5916139Sjb150015 } 5926139Sjb150015 5936139Sjb150015 hashkey = vp->v_vfsp->vfs_fsid.val[0] + va.sa_vattr.va_nodeid; 5946139Sjb150015 hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 5956139Sjb150015 node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]; 5966139Sjb150015 5976139Sjb150015 node = kmem_cache_alloc(sv->si_cache_node, KM_SLEEP); 5986139Sjb150015 bzero(node, sizeof (smb_node_t)); 5995331Samw 6006139Sjb150015 node->n_state = SMB_NODE_STATE_AVAILABLE; 6016139Sjb150015 node->n_hash_bucket = node_hdr; 6026139Sjb150015 node->vp = vp; 6036139Sjb150015 node->n_hashkey = hashkey; 6046139Sjb150015 node->n_refcnt = 1; 6056139Sjb150015 node->attr = va; 6066139Sjb150015 node->flags |= NODE_FLAGS_ATTR_VALID; 6076139Sjb150015 node->n_size = node->attr.sa_vattr.va_size; 6086139Sjb150015 node->n_cache = sv->si_cache_node; 6096139Sjb150015 (void) strlcpy(node->od_name, ROOTVOL, sizeof (node->od_name)); 6106139Sjb150015 6116139Sjb150015 smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 6126139Sjb150015 offsetof(smb_ofile_t, f_nnd)); 6136139Sjb150015 smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 6146139Sjb150015 offsetof(smb_lock_t, l_lnd)); 6156139Sjb150015 6166139Sjb150015 smb_rwx_init(&node->n_lock); 6176139Sjb150015 node->n_magic = SMB_NODE_MAGIC; 6186139Sjb150015 smb_audit_buf_node_create(node); 6196139Sjb150015 6206139Sjb150015 sv->si_root_smb_node = node; 6216139Sjb150015 6226139Sjb150015 smb_audit_node(node); 6236139Sjb150015 smb_llist_enter(node_hdr, RW_WRITER); 6246139Sjb150015 smb_llist_insert_head(node_hdr, node); 6256139Sjb150015 smb_llist_exit(node_hdr); 6266139Sjb150015 6276139Sjb150015 *root = node; 6286139Sjb150015 6296139Sjb150015 return (0); 6305331Samw } 6315331Samw 6325331Samw /* 6335331Samw * smb_node_get_size 6345331Samw */ 6356432Sas200622 u_offset_t 6366432Sas200622 smb_node_get_size(smb_node_t *node, smb_attr_t *attr) 6375331Samw { 6386432Sas200622 u_offset_t size; 6395331Samw 6405331Samw if (attr->sa_vattr.va_type == VDIR) 6415331Samw return (0); 6425331Samw 6435331Samw smb_rwx_xenter(&node->n_lock); 6445331Samw if (node && (node->flags & NODE_FLAGS_SET_SIZE)) 6455331Samw size = node->n_size; 6465331Samw else 6475331Samw size = attr->sa_vattr.va_size; 6485331Samw smb_rwx_xexit(&node->n_lock); 6495331Samw return (size); 6505331Samw } 6515331Samw 6525331Samw static int 6535331Samw timeval_cmp(timestruc_t *a, timestruc_t *b) 6545331Samw { 6555331Samw if (a->tv_sec < b->tv_sec) 6565331Samw return (-1); 6575331Samw if (a->tv_sec > b->tv_sec) 6585331Samw return (1); 6595331Samw /* Seconds are equal compare tv_nsec */ 6605331Samw if (a->tv_nsec < b->tv_nsec) 6615331Samw return (-1); 6625331Samw return (a->tv_nsec > b->tv_nsec); 6635331Samw } 6645331Samw 6655331Samw /* 6665331Samw * smb_node_set_time 6675331Samw * 6685331Samw * This function will update the time stored in the node and 669*7348SJose.Borrego@Sun.COM * set the appropriate flags. If there is nothing to update, 670*7348SJose.Borrego@Sun.COM * the function will return without any updates. The update 671*7348SJose.Borrego@Sun.COM * is only in the node level and the attribute in the file system 672*7348SJose.Borrego@Sun.COM * will be updated when client close the file. 6735331Samw */ 6745331Samw void 6755331Samw smb_node_set_time(struct smb_node *node, struct timestruc *crtime, 6765331Samw struct timestruc *mtime, struct timestruc *atime, 6775331Samw struct timestruc *ctime, unsigned int what) 6785331Samw { 679*7348SJose.Borrego@Sun.COM if (what == 0) 6805331Samw return; 6815331Samw 6825331Samw if ((what & SMB_AT_CRTIME && crtime == 0) || 6835331Samw (what & SMB_AT_MTIME && mtime == 0) || 6845331Samw (what & SMB_AT_ATIME && atime == 0) || 685*7348SJose.Borrego@Sun.COM (what & SMB_AT_CTIME && ctime == 0)) 6865331Samw return; 687*7348SJose.Borrego@Sun.COM 688*7348SJose.Borrego@Sun.COM smb_rwx_xenter(&node->n_lock); 6895331Samw 6905331Samw if ((what & SMB_AT_CRTIME) && 6915331Samw timeval_cmp((timestruc_t *)&node->attr.sa_crtime, 6925331Samw crtime) != 0) { 6935331Samw node->what |= SMB_AT_CRTIME; 6945331Samw node->attr.sa_crtime = *((timestruc_t *)crtime); 6955331Samw } 6965331Samw 6975331Samw if ((what & SMB_AT_MTIME) && 6985331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime, 6995331Samw mtime) != 0) { 7005331Samw node->what |= SMB_AT_MTIME; 7015331Samw node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime); 7025331Samw } 7035331Samw 7045331Samw if ((what & SMB_AT_ATIME) && 7055331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime, 7065331Samw atime) != 0) { 7075331Samw node->what |= SMB_AT_ATIME; 7085331Samw node->attr.sa_vattr.va_atime = *((timestruc_t *)atime); 7095331Samw } 7105331Samw 7115331Samw /* 7125331Samw * The ctime handling is trickier. It has three scenarios. 7135331Samw * 1. Only ctime need to be set and it is the same as the ctime 7145331Samw * stored in the node. (update not necessary) 7155331Samw * 2. The ctime is the same as the ctime stored in the node but 7165331Samw * is not the only time need to be set. (update required) 7175331Samw * 3. The ctime need to be set and is not the same as the ctime 7185331Samw * stored in the node. (update required) 7195331Samw * Unlike other time setting, the ctime needs to be set even when 7205331Samw * it is the same as the ctime in the node if there are other time 7215331Samw * needs to be set (#2). This will ensure the ctime not being 7225331Samw * updated when other times are being updated in the file system. 7235331Samw * 7245331Samw * Retained file rules: 7255331Samw * 7265331Samw * 1. Don't add SMB_AT_CTIME to node->what by default because the 7275331Samw * request will be rejected by filesystem 7285331Samw * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e. 7295331Samw * any request for changing ctime on these files should have 7305331Samw * been already rejected 7315331Samw */ 7325331Samw node->what |= SMB_AT_CTIME; 7335331Samw if (what & SMB_AT_CTIME) { 7345331Samw if ((what == SMB_AT_CTIME) && 7355331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime, 7365331Samw ctime) == 0) { 7375331Samw node->what &= ~SMB_AT_CTIME; 7385331Samw } else { 7395331Samw gethrestime(&node->attr.sa_vattr.va_ctime); 7405331Samw } 7415331Samw } else { 7425331Samw gethrestime(&node->attr.sa_vattr.va_ctime); 7435331Samw } 7445331Samw smb_rwx_xexit(&node->n_lock); 7455331Samw } 7465331Samw 7475331Samw 7485331Samw timestruc_t * 7495331Samw smb_node_get_crtime(smb_node_t *node) 7505331Samw { 7515331Samw return ((timestruc_t *)&node->attr.sa_crtime); 7525331Samw } 7535331Samw 7545331Samw timestruc_t * 7555331Samw smb_node_get_atime(smb_node_t *node) 7565331Samw { 7575331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_atime); 7585331Samw } 7595331Samw 7605331Samw timestruc_t * 7615331Samw smb_node_get_ctime(smb_node_t *node) 7625331Samw { 7635331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_ctime); 7645331Samw } 7655331Samw 7665331Samw timestruc_t * 7675331Samw smb_node_get_mtime(smb_node_t *node) 7685331Samw { 7695331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_mtime); 7705331Samw } 7715331Samw 7725331Samw /* 7735331Samw * smb_node_set_dosattr 7745331Samw * 7755331Samw * Parse the specified DOS attributes and, if they have been modified, 7765331Samw * update the node cache. This call should be followed by a 7775331Samw * smb_sync_fsattr() call to write the attribute changes to filesystem. 7785331Samw */ 7795331Samw void 7807052Samw smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr) 7815331Samw { 7827052Samw uint32_t mode = dosattr & (FILE_ATTRIBUTE_ARCHIVE | 7837052Samw FILE_ATTRIBUTE_READONLY | 7847052Samw FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); 7855331Samw 7865331Samw smb_rwx_xenter(&node->n_lock); 7875331Samw if (node->attr.sa_dosattr != mode) { 7885331Samw node->attr.sa_dosattr = mode; 7895331Samw node->what |= SMB_AT_DOSATTR; 7905331Samw } 7915331Samw smb_rwx_xexit(&node->n_lock); 7925331Samw } 7935331Samw 7945331Samw /* 795*7348SJose.Borrego@Sun.COM * smb_node_get_dosattr() 7965331Samw * 797*7348SJose.Borrego@Sun.COM * This function is used to provide clients with information as to whether 798*7348SJose.Borrego@Sun.COM * the readonly bit is set. Hence both the node attribute cache (which 799*7348SJose.Borrego@Sun.COM * reflects the on-disk attributes) and node->readonly_creator (which 800*7348SJose.Borrego@Sun.COM * reflects whether a readonly set is pending from a readonly create) are 801*7348SJose.Borrego@Sun.COM * checked. In the latter case, the readonly attribute should be visible to 802*7348SJose.Borrego@Sun.COM * all clients even though the readonly creator fid is immune to the readonly 803*7348SJose.Borrego@Sun.COM * bit until close. 8045331Samw */ 805*7348SJose.Borrego@Sun.COM 8065331Samw uint32_t 8075331Samw smb_node_get_dosattr(smb_node_t *node) 8085331Samw { 809*7348SJose.Borrego@Sun.COM uint32_t dosattr = node->attr.sa_dosattr; 810*7348SJose.Borrego@Sun.COM 811*7348SJose.Borrego@Sun.COM if (node->readonly_creator) 812*7348SJose.Borrego@Sun.COM dosattr |= FILE_ATTRIBUTE_READONLY; 813*7348SJose.Borrego@Sun.COM 814*7348SJose.Borrego@Sun.COM if (!dosattr) 815*7348SJose.Borrego@Sun.COM dosattr = FILE_ATTRIBUTE_NORMAL; 816*7348SJose.Borrego@Sun.COM 817*7348SJose.Borrego@Sun.COM return (dosattr); 8185331Samw } 8195331Samw 8205331Samw int 8215331Samw smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr) 8225331Samw { 8235331Samw int rc = -1; 8245331Samw 8255331Samw smb_rwx_xenter(&node->n_lock); 8265331Samw if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) && 8275331Samw !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) { 8285331Samw crhold(cr); 8295331Samw node->delete_on_close_cred = cr; 8305331Samw node->flags |= NODE_FLAGS_DELETE_ON_CLOSE; 8315331Samw rc = 0; 8325331Samw } 8335331Samw smb_rwx_xexit(&node->n_lock); 8345331Samw return (rc); 8355331Samw } 8365331Samw 8375331Samw void 8385331Samw smb_node_reset_delete_on_close(smb_node_t *node) 8395331Samw { 8405331Samw smb_rwx_xenter(&node->n_lock); 8415331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 8425331Samw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 8435331Samw crfree(node->delete_on_close_cred); 8445331Samw node->delete_on_close_cred = NULL; 8455331Samw } 8465331Samw smb_rwx_xexit(&node->n_lock); 8475331Samw } 8485772Sas200622 8495772Sas200622 /* 8506771Sjb150015 * smb_node_open_check 8515772Sas200622 * 8525772Sas200622 * check file sharing rules for current open request 8535772Sas200622 * against all existing opens for a file. 8545772Sas200622 * 8555772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 8565772Sas200622 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 8575772Sas200622 */ 8585772Sas200622 uint32_t 8595772Sas200622 smb_node_open_check(struct smb_node *node, cred_t *cr, 8605772Sas200622 uint32_t desired_access, uint32_t share_access) 8615772Sas200622 { 8625772Sas200622 smb_ofile_t *of; 8635772Sas200622 uint32_t status; 8645772Sas200622 8655772Sas200622 ASSERT(node); 8665772Sas200622 ASSERT(node->n_magic == SMB_NODE_MAGIC); 8675772Sas200622 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 8685772Sas200622 8695772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 8705772Sas200622 of = smb_llist_head(&node->n_ofile_list); 8715772Sas200622 while (of) { 8726771Sjb150015 status = smb_ofile_open_check(of, cr, desired_access, 8736771Sjb150015 share_access); 8746771Sjb150015 8756771Sjb150015 switch (status) { 8766771Sjb150015 case NT_STATUS_INVALID_HANDLE: 8776771Sjb150015 case NT_STATUS_SUCCESS: 8786771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 8796771Sjb150015 break; 8806771Sjb150015 default: 8816771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 8825772Sas200622 smb_llist_exit(&node->n_ofile_list); 8835772Sas200622 return (status); 8845772Sas200622 } 8855772Sas200622 } 8866771Sjb150015 8875772Sas200622 smb_llist_exit(&node->n_ofile_list); 8885772Sas200622 return (NT_STATUS_SUCCESS); 8895772Sas200622 } 8905772Sas200622 8915772Sas200622 uint32_t 8925772Sas200622 smb_node_rename_check(struct smb_node *node) 8935772Sas200622 { 8946771Sjb150015 struct smb_ofile *of; 8956771Sjb150015 uint32_t status; 8965772Sas200622 8975772Sas200622 ASSERT(node); 8985772Sas200622 ASSERT(node->n_magic == SMB_NODE_MAGIC); 8995772Sas200622 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 9005772Sas200622 9015772Sas200622 /* 9025772Sas200622 * Intra-CIFS check 9035772Sas200622 */ 9045772Sas200622 9055772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 9066771Sjb150015 of = smb_llist_head(&node->n_ofile_list); 9076771Sjb150015 while (of) { 9086771Sjb150015 status = smb_ofile_rename_check(of); 9095772Sas200622 9106771Sjb150015 switch (status) { 9116771Sjb150015 case NT_STATUS_INVALID_HANDLE: 9126771Sjb150015 case NT_STATUS_SUCCESS: 9136771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 9146771Sjb150015 break; 9156771Sjb150015 default: 9166771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 9176771Sjb150015 smb_llist_exit(&node->n_ofile_list); 9186771Sjb150015 return (status); 9195772Sas200622 } 9205772Sas200622 } 9215772Sas200622 smb_llist_exit(&node->n_ofile_list); 9225772Sas200622 9235772Sas200622 /* 9245772Sas200622 * system-wide share check 9255772Sas200622 */ 9265772Sas200622 9275772Sas200622 if (nbl_share_conflict(node->vp, NBL_RENAME, NULL)) 9285772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9295772Sas200622 else 9305772Sas200622 return (NT_STATUS_SUCCESS); 9315772Sas200622 } 9325772Sas200622 9336771Sjb150015 uint32_t 9345772Sas200622 smb_node_delete_check(smb_node_t *node) 9355772Sas200622 { 9366771Sjb150015 smb_ofile_t *of; 9376771Sjb150015 uint32_t status; 9385772Sas200622 9395772Sas200622 ASSERT(node); 9405772Sas200622 ASSERT(node->n_magic == SMB_NODE_MAGIC); 9415772Sas200622 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 9425772Sas200622 9435772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 9445772Sas200622 return (NT_STATUS_SUCCESS); 9455772Sas200622 9465772Sas200622 /* 9475772Sas200622 * intra-CIFS check 9485772Sas200622 */ 9495772Sas200622 9505772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 9516771Sjb150015 of = smb_llist_head(&node->n_ofile_list); 9526771Sjb150015 while (of) { 9536771Sjb150015 status = smb_ofile_delete_check(of); 9546771Sjb150015 9556771Sjb150015 switch (status) { 9566771Sjb150015 case NT_STATUS_INVALID_HANDLE: 9576771Sjb150015 case NT_STATUS_SUCCESS: 9586771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 9596771Sjb150015 break; 9606771Sjb150015 default: 9616771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 9625772Sas200622 smb_llist_exit(&node->n_ofile_list); 9636771Sjb150015 return (status); 9645772Sas200622 } 9655772Sas200622 } 9665772Sas200622 smb_llist_exit(&node->n_ofile_list); 9675772Sas200622 9685772Sas200622 /* 9695772Sas200622 * system-wide share check 9705772Sas200622 */ 9715772Sas200622 9725772Sas200622 if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL)) 9735772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9745772Sas200622 else 9755772Sas200622 return (NT_STATUS_SUCCESS); 9765772Sas200622 } 9775772Sas200622 9785772Sas200622 /* 9795772Sas200622 * smb_node_start_crit() 9805772Sas200622 * 9815772Sas200622 * Enter critical region for share reservations. 9825772Sas200622 * See comments above smb_fsop_shrlock(). 9835772Sas200622 */ 9845772Sas200622 9855772Sas200622 void 9865772Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode) 9875772Sas200622 { 9885772Sas200622 rw_enter(&node->n_share_lock, mode); 9895772Sas200622 nbl_start_crit(node->vp, mode); 9905772Sas200622 } 9915772Sas200622 9925772Sas200622 /* 9935772Sas200622 * smb_node_end_crit() 9945772Sas200622 * 9955772Sas200622 * Exit critical region for share reservations. 9965772Sas200622 */ 9975772Sas200622 9985772Sas200622 void 9995772Sas200622 smb_node_end_crit(smb_node_t *node) 10005772Sas200622 { 10015772Sas200622 nbl_end_crit(node->vp); 10025772Sas200622 rw_exit(&node->n_share_lock); 10035772Sas200622 } 10045772Sas200622 10055772Sas200622 int 10065772Sas200622 smb_node_in_crit(smb_node_t *node) 10075772Sas200622 { 10085772Sas200622 return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_share_lock)); 10095772Sas200622 } 1010