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 /* 228670SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw /* 265331Samw * SMB Node State Machine 275331Samw * ---------------------- 285331Samw * 295331Samw * +----------------------------+ T0 305331Samw * | SMB_NODE_STATE_AVAILABLE |<----------- Creation/Allocation 315331Samw * +----------------------------+ 325331Samw * | 335331Samw * | T1 345331Samw * | 355331Samw * v 365331Samw * +-----------------------------+ T2 375331Samw * | SMB_NODE_STATE_DESTROYING |----------> Deletion/Free 385331Samw * +-----------------------------+ 395331Samw * 405331Samw * Transition T0 415331Samw * 425331Samw * This transition occurs in smb_node_lookup(). If the node looked for is 435331Samw * not found in the has table a new node is created. The reference count is 445331Samw * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE. 455331Samw * 465331Samw * Transition T1 475331Samw * 485331Samw * This transition occurs in smb_node_release(). If the reference count 495331Samw * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more 505331Samw * reference count will be given out for that node. 515331Samw * 525331Samw * Transition T2 535331Samw * 545331Samw * This transition occurs in smb_node_release(). The structure is deleted. 555331Samw * 565331Samw * Comments 575331Samw * -------- 585331Samw * 595331Samw * The reason the smb node has 2 states is the following synchronization 605331Samw * rule: 615331Samw * 625331Samw * There's a mutex embedded in the node used to protect its fields and 635331Samw * there's a lock embedded in the bucket of the hash table the node belongs 645331Samw * to. To increment or to decrement the reference count the mutex must be 655331Samw * entered. To insert the node into the bucket and to remove it from the 665331Samw * bucket the lock must be entered in RW_WRITER mode. When both (mutex and 675331Samw * lock) have to be entered, the lock has always to be entered first then 685331Samw * the mutex. This prevents a deadlock between smb_node_lookup() and 695331Samw * smb_node_release() from occurring. However, in smb_node_release() when the 705331Samw * reference count drops to zero and triggers the deletion of the node, the 715331Samw * mutex has to be released before entering the lock of the bucket (to 725331Samw * remove the node). This creates a window during which the node that is 735331Samw * about to be freed could be given out by smb_node_lookup(). To close that 745331Samw * window the node is moved to the state SMB_NODE_STATE_DESTROYING before 755331Samw * releasing the mutex. That way, even if smb_node_lookup() finds it, the 765331Samw * state will indicate that the node should be treated as non existent (of 775331Samw * course the state of the node should be tested/updated under the 785331Samw * protection of the mutex). 795331Samw */ 805331Samw #include <smbsrv/smb_incl.h> 815331Samw #include <smbsrv/smb_fsops.h> 82*8934SJose.Borrego@Sun.COM #include <smbsrv/smb_kstat.h> 835331Samw #include <sys/pathname.h> 845331Samw #include <sys/sdt.h> 855772Sas200622 #include <sys/nbmlock.h> 865331Samw 87*8934SJose.Borrego@Sun.COM uint32_t smb_is_executable(char *); 88*8934SJose.Borrego@Sun.COM static void smb_node_delete_on_close(smb_node_t *); 89*8934SJose.Borrego@Sun.COM static void smb_node_create_audit_buf(smb_node_t *, int); 90*8934SJose.Borrego@Sun.COM static void smb_node_destroy_audit_buf(smb_node_t *); 91*8934SJose.Borrego@Sun.COM static void smb_node_audit(smb_node_t *); 92*8934SJose.Borrego@Sun.COM static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_attr_t *, 93*8934SJose.Borrego@Sun.COM smb_llist_t *bucket, uint32_t hashkey); 94*8934SJose.Borrego@Sun.COM static void smb_node_free(smb_node_t *); 95*8934SJose.Borrego@Sun.COM static int smb_node_constructor(void *, void *, int); 96*8934SJose.Borrego@Sun.COM static void smb_node_destructor(void *, void *); 97*8934SJose.Borrego@Sun.COM static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *); 985331Samw 995331Samw #define VALIDATE_DIR_NODE(_dir_, _node_) \ 1005331Samw ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \ 1015331Samw ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \ 1025331Samw ASSERT((_dir_)->dir_snode != (_node_)); 1035331Samw 104*8934SJose.Borrego@Sun.COM static kmem_cache_t *smb_node_cache = NULL; 1056139Sjb150015 static boolean_t smb_node_initialized = B_FALSE; 1066139Sjb150015 static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1]; 1076139Sjb150015 1086139Sjb150015 /* 1096139Sjb150015 * smb_node_init 1106139Sjb150015 * 1116139Sjb150015 * Initialization of the SMB node layer. 1126139Sjb150015 * 1136139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 1146139Sjb150015 * thread makes the call. 1156139Sjb150015 */ 1166139Sjb150015 int 1176139Sjb150015 smb_node_init(void) 1186139Sjb150015 { 1196139Sjb150015 int i; 1206139Sjb150015 1216139Sjb150015 if (smb_node_initialized) 1226139Sjb150015 return (0); 123*8934SJose.Borrego@Sun.COM smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE, 124*8934SJose.Borrego@Sun.COM sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor, 125*8934SJose.Borrego@Sun.COM NULL, NULL, NULL, 0); 1266139Sjb150015 1276139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 1286139Sjb150015 smb_llist_constructor(&smb_node_hash_table[i], 1296139Sjb150015 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 1306139Sjb150015 } 1316139Sjb150015 smb_node_initialized = B_TRUE; 1326139Sjb150015 return (0); 1336139Sjb150015 } 1346139Sjb150015 1356139Sjb150015 /* 1366139Sjb150015 * smb_node_fini 1376139Sjb150015 * 1386139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 1396139Sjb150015 * thread makes the call. 1406139Sjb150015 */ 1416139Sjb150015 void 1426139Sjb150015 smb_node_fini(void) 1436139Sjb150015 { 1446139Sjb150015 int i; 1456139Sjb150015 1466139Sjb150015 if (!smb_node_initialized) 1476139Sjb150015 return; 1486139Sjb150015 1496139Sjb150015 #ifdef DEBUG 1506139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 1516139Sjb150015 smb_node_t *node; 1526139Sjb150015 1536139Sjb150015 /* 1546139Sjb150015 * The following sequence is just intended for sanity check. 1556139Sjb150015 * This will have to be modified when the code goes into 1566139Sjb150015 * production. 1576139Sjb150015 * 1586139Sjb150015 * The SMB node hash table should be emtpy at this point. If the 1596139Sjb150015 * hash table is not empty a panic will be triggered. 1606139Sjb150015 * 1616139Sjb150015 * The reason why SMB nodes are still remaining in the hash 1626139Sjb150015 * table is problably due to a mismatch between calls to 1636139Sjb150015 * smb_node_lookup() and smb_node_release(). You must track that 1646139Sjb150015 * down. 1656139Sjb150015 */ 1666139Sjb150015 node = smb_llist_head(&smb_node_hash_table[i]); 1676139Sjb150015 ASSERT(node == NULL); 1686139Sjb150015 } 1696139Sjb150015 #endif 1706139Sjb150015 1716139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 1726139Sjb150015 smb_llist_destructor(&smb_node_hash_table[i]); 1736139Sjb150015 } 174*8934SJose.Borrego@Sun.COM kmem_cache_destroy(smb_node_cache); 175*8934SJose.Borrego@Sun.COM smb_node_cache = NULL; 1766139Sjb150015 smb_node_initialized = B_FALSE; 1776139Sjb150015 } 1786139Sjb150015 1795331Samw /* 1805331Samw * smb_node_lookup() 1815331Samw * 1825331Samw * NOTE: This routine should only be called by the file system interface layer, 1835331Samw * and not by SMB. 1845331Samw * 1855331Samw * smb_node_lookup() is called upon successful lookup, mkdir, and create 1865331Samw * (for both non-streams and streams). In each of these cases, a held vnode is 1878670SJose.Borrego@Sun.COM * passed into this routine. If a new smb_node is created it will take its 1888670SJose.Borrego@Sun.COM * own hold on the vnode. The caller's hold therefore still belongs to, and 1898670SJose.Borrego@Sun.COM * should be released by, the caller. 1905331Samw * 1915331Samw * A reference is taken on the smb_node whether found in the hash table 1925331Samw * or newly created. 1935331Samw * 1945331Samw * If an smb_node needs to be created, a reference is also taken on the 1955331Samw * dir_snode (if passed in). 1965331Samw * 1975331Samw * See smb_node_release() for details on the release of these references. 1985331Samw */ 1995331Samw 2005331Samw /*ARGSUSED*/ 2015331Samw smb_node_t * 2025331Samw smb_node_lookup( 2035331Samw struct smb_request *sr, 2045331Samw struct open_param *op, 2055331Samw cred_t *cred, 2065331Samw vnode_t *vp, 2075331Samw char *od_name, 2085331Samw smb_node_t *dir_snode, 2095331Samw smb_node_t *unnamed_node, 2105331Samw smb_attr_t *attr) 2115331Samw { 2125331Samw smb_llist_t *node_hdr; 2135331Samw smb_node_t *node; 2145331Samw uint32_t hashkey = 0; 2157348SJose.Borrego@Sun.COM fsid_t fsid; 2165331Samw int error; 2175331Samw krw_t lock_mode; 2185331Samw vnode_t *unnamed_vp = NULL; 2195331Samw 2205331Samw /* 2215331Samw * smb_vop_getattr() is called here instead of smb_fsop_getattr(), 2225331Samw * because the node may not yet exist. We also do not want to call 2235331Samw * it with the list lock held. 2245331Samw */ 2255331Samw 2265331Samw if (unnamed_node) 2275331Samw unnamed_vp = unnamed_node->vp; 2285331Samw 2295331Samw /* 2305331Samw * This getattr is performed on behalf of the server 2315331Samw * that's why kcred is used not the user's cred 2325331Samw */ 2335331Samw attr->sa_mask = SMB_AT_ALL; 2345772Sas200622 error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred); 2355331Samw if (error) 2365331Samw return (NULL); 2375331Samw 2387348SJose.Borrego@Sun.COM if (sr && sr->tid_tree) { 2397348SJose.Borrego@Sun.COM /* 2407348SJose.Borrego@Sun.COM * The fsid for a file is that of the tree, even 2417348SJose.Borrego@Sun.COM * if the file resides in a different mountpoint 2427348SJose.Borrego@Sun.COM * under the share. 2437348SJose.Borrego@Sun.COM */ 2447348SJose.Borrego@Sun.COM fsid = SMB_TREE_FSID(sr->tid_tree); 2455331Samw } else { 2467348SJose.Borrego@Sun.COM /* 2477348SJose.Borrego@Sun.COM * This should be getting executed only for the 2487348SJose.Borrego@Sun.COM * tree root smb_node. 2497348SJose.Borrego@Sun.COM */ 2507348SJose.Borrego@Sun.COM fsid = vp->v_vfsp->vfs_fsid; 2515331Samw } 2525331Samw 253*8934SJose.Borrego@Sun.COM node_hdr = smb_node_get_hash(&fsid, attr, &hashkey); 2545331Samw lock_mode = RW_READER; 2555331Samw 2565331Samw smb_llist_enter(node_hdr, lock_mode); 2575331Samw for (;;) { 2585331Samw node = list_head(&node_hdr->ll_list); 2595331Samw while (node) { 2605331Samw ASSERT(node->n_magic == SMB_NODE_MAGIC); 2615331Samw ASSERT(node->n_hash_bucket == node_hdr); 2625331Samw if ((node->n_hashkey == hashkey) && (node->vp == vp)) { 263*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 2645331Samw DTRACE_PROBE1(smb_node_lookup_hit, 2655331Samw smb_node_t *, node); 2665331Samw switch (node->n_state) { 267*8934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 268*8934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 2695331Samw case SMB_NODE_STATE_AVAILABLE: 2705331Samw /* The node was found. */ 2715331Samw node->n_refcnt++; 2725331Samw if ((node->dir_snode == NULL) && 2735331Samw (dir_snode != NULL) && 2745331Samw (strcmp(od_name, "..") != 0) && 2755331Samw (strcmp(od_name, ".") != 0)) { 2765331Samw VALIDATE_DIR_NODE(dir_snode, 2775331Samw node); 2785331Samw node->dir_snode = dir_snode; 2795331Samw smb_node_ref(dir_snode); 2805331Samw } 2815331Samw node->attr = *attr; 2825772Sas200622 node->n_size = attr->sa_vattr.va_size; 2835331Samw 284*8934SJose.Borrego@Sun.COM smb_node_audit(node); 285*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 2865331Samw smb_llist_exit(node_hdr); 2875331Samw return (node); 2885331Samw 2895331Samw case SMB_NODE_STATE_DESTROYING: 2905331Samw /* 2915331Samw * Although the node exists it is about 2925331Samw * to be destroyed. We act as it hasn't 2935331Samw * been found. 2945331Samw */ 295*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 2965331Samw break; 2975331Samw default: 2985331Samw /* 2995331Samw * Although the node exists it is in an 3005331Samw * unknown state. We act as it hasn't 3015331Samw * been found. 3025331Samw */ 3035331Samw ASSERT(0); 304*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 3055331Samw break; 3065331Samw } 3075331Samw } 3085331Samw node = smb_llist_next(node_hdr, node); 3095331Samw } 3105331Samw if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) { 3115331Samw lock_mode = RW_WRITER; 3125331Samw continue; 3135331Samw } 3145331Samw break; 3155331Samw } 316*8934SJose.Borrego@Sun.COM node = smb_node_alloc(od_name, vp, attr, node_hdr, hashkey); 317*8934SJose.Borrego@Sun.COM node->n_orig_uid = crgetuid(sr->user_cr); 3185331Samw 3195331Samw if (op) 3205331Samw node->flags |= smb_is_executable(op->fqi.last_comp); 3215331Samw 3225331Samw if (dir_snode) { 3235331Samw smb_node_ref(dir_snode); 3245331Samw node->dir_snode = dir_snode; 3255331Samw ASSERT(dir_snode->dir_snode != node); 3265331Samw ASSERT((dir_snode->vp->v_xattrdir) || 3275331Samw (dir_snode->vp->v_type == VDIR)); 3285331Samw } 3295331Samw 3305331Samw if (unnamed_node) { 3315331Samw smb_node_ref(unnamed_node); 3325331Samw node->unnamed_stream_node = unnamed_node; 3335331Samw } 3345331Samw 3355331Samw DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node); 336*8934SJose.Borrego@Sun.COM smb_node_audit(node); 3375331Samw smb_llist_insert_head(node_hdr, node); 3385331Samw smb_llist_exit(node_hdr); 3395331Samw return (node); 3405331Samw } 3415331Samw 3425331Samw /* 3435331Samw * smb_stream_node_lookup() 3445331Samw * 3455331Samw * Note: stream_name (the name that will be stored in the "od_name" field 3465331Samw * of a stream's smb_node) is the same as the on-disk name for the stream 3475331Samw * except that it does not have SMB_STREAM_PREFIX prepended. 3485331Samw */ 3495331Samw 3505331Samw smb_node_t * 351*8934SJose.Borrego@Sun.COM smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode, 3525331Samw vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr) 3535331Samw { 3545331Samw smb_node_t *xattrdir_node; 3555331Samw smb_node_t *snode; 3565331Samw smb_attr_t tmp_attr; 3575331Samw 3585331Samw xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR, 3595331Samw fnode, NULL, &tmp_attr); 3605331Samw 3615331Samw if (xattrdir_node == NULL) 3625331Samw return (NULL); 3635331Samw 3645331Samw snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node, 3655331Samw fnode, ret_attr); 3665331Samw 3675331Samw (void) smb_node_release(xattrdir_node); 3685331Samw return (snode); 3695331Samw } 3705331Samw 3715331Samw 3725331Samw /* 3735331Samw * This function should be called whenever a reference is needed on an 3745331Samw * smb_node pointer. The copy of an smb_node pointer from one non-local 3755331Samw * data structure to another requires a reference to be taken on the smb_node 3765331Samw * (unless the usage is localized). Each data structure deallocation routine 3775331Samw * will call smb_node_release() on its smb_node pointers. 3785331Samw * 3795331Samw * In general, an smb_node pointer residing in a structure should never be 3805331Samw * stale. A node pointer may be NULL, however, and care should be taken 3815331Samw * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid. 3825331Samw * Care also needs to be taken with respect to racing deallocations of a 3835331Samw * structure. 3845331Samw */ 3855331Samw void 3865331Samw smb_node_ref(smb_node_t *node) 3875331Samw { 388*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 3895331Samw 390*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 391*8934SJose.Borrego@Sun.COM switch (node->n_state) { 392*8934SJose.Borrego@Sun.COM case SMB_NODE_STATE_AVAILABLE: 393*8934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 394*8934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 395*8934SJose.Borrego@Sun.COM node->n_refcnt++; 396*8934SJose.Borrego@Sun.COM ASSERT(node->n_refcnt); 397*8934SJose.Borrego@Sun.COM DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); 398*8934SJose.Borrego@Sun.COM smb_node_audit(node); 399*8934SJose.Borrego@Sun.COM break; 400*8934SJose.Borrego@Sun.COM default: 401*8934SJose.Borrego@Sun.COM SMB_PANIC(); 402*8934SJose.Borrego@Sun.COM } 403*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 4045331Samw } 4055331Samw 4065331Samw /* 4075331Samw * smb_node_lookup() takes a hold on an smb_node, whether found in the 4085331Samw * hash table or newly created. This hold is expected to be released 4095331Samw * in the following manner. 4105331Samw * 4115331Samw * smb_node_lookup() takes an address of an smb_node pointer. This should 4125331Samw * be getting passed down via a lookup (whether path name or component), mkdir, 4135331Samw * create. If the original smb_node pointer resides in a data structure, then 4145331Samw * the deallocation routine for the data structure is responsible for calling 4155331Samw * smb_node_release() on the smb_node pointer. Alternatively, 4165331Samw * smb_node_release() can be called as soon as the smb_node pointer is no longer 4175331Samw * needed. In this case, callers are responsible for setting an embedded 4185331Samw * pointer to NULL if it is known that the last reference is being released. 4195331Samw * 4205331Samw * If the passed-in address of the smb_node pointer belongs to a local variable, 4215331Samw * then the caller with the local variable should call smb_node_release() 4225331Samw * directly. 4235331Samw * 4245331Samw * smb_node_release() itself will call smb_node_release() on a node's dir_snode, 4255331Samw * as smb_node_lookup() takes a hold on dir_snode. 4265331Samw */ 4275331Samw void 4285331Samw smb_node_release(smb_node_t *node) 4295331Samw { 430*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 4315331Samw 432*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 4335331Samw ASSERT(node->n_refcnt); 4345331Samw DTRACE_PROBE1(smb_node_release, smb_node_t *, node); 4355331Samw if (--node->n_refcnt == 0) { 4365331Samw switch (node->n_state) { 4375331Samw 4385331Samw case SMB_NODE_STATE_AVAILABLE: 4395331Samw node->n_state = SMB_NODE_STATE_DESTROYING; 440*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 4415331Samw 4425331Samw smb_llist_enter(node->n_hash_bucket, RW_WRITER); 4435331Samw smb_llist_remove(node->n_hash_bucket, node); 4445331Samw smb_llist_exit(node->n_hash_bucket); 4455331Samw 4465331Samw /* 4475331Samw * Check if the file was deleted 4485331Samw */ 4495331Samw smb_node_delete_on_close(node); 4505331Samw 4515331Samw if (node->dir_snode) { 4525331Samw ASSERT(node->dir_snode->n_magic == 4535331Samw SMB_NODE_MAGIC); 4545331Samw smb_node_release(node->dir_snode); 4555331Samw } 4565331Samw 4575331Samw if (node->unnamed_stream_node) { 4585331Samw ASSERT(node->unnamed_stream_node->n_magic == 4595331Samw SMB_NODE_MAGIC); 4605331Samw smb_node_release(node->unnamed_stream_node); 4615331Samw } 4625331Samw 463*8934SJose.Borrego@Sun.COM smb_node_free(node); 4645331Samw return; 4655331Samw 4665331Samw default: 467*8934SJose.Borrego@Sun.COM SMB_PANIC(); 4685331Samw } 4695331Samw } 470*8934SJose.Borrego@Sun.COM smb_node_audit(node); 471*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 4725331Samw } 4735331Samw 4745331Samw static void 4755331Samw smb_node_delete_on_close(smb_node_t *node) 4765331Samw { 4775331Samw smb_node_t *d_snode; 4785331Samw int rc = 0; 4795331Samw 4805331Samw d_snode = node->dir_snode; 4815331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 4825331Samw 4835331Samw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 4845331Samw ASSERT(node->od_name != NULL); 4855331Samw if (node->attr.sa_vattr.va_type == VDIR) 4865331Samw rc = smb_fsop_rmdir(0, node->delete_on_close_cred, 4875331Samw d_snode, node->od_name, 1); 4885331Samw else 4895331Samw rc = smb_fsop_remove(0, node->delete_on_close_cred, 4905331Samw d_snode, node->od_name, 1); 4915331Samw smb_cred_rele(node->delete_on_close_cred); 4925331Samw } 4935331Samw if (rc != 0) 4945331Samw cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n", 4955331Samw node->od_name, rc); 4965331Samw DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node); 4975331Samw } 4985331Samw 4995331Samw /* 5005331Samw * smb_node_rename() 5015331Samw * 5025331Samw */ 503*8934SJose.Borrego@Sun.COM void 5045331Samw smb_node_rename( 505*8934SJose.Borrego@Sun.COM smb_node_t *from_dnode, 506*8934SJose.Borrego@Sun.COM smb_node_t *ret_node, 507*8934SJose.Borrego@Sun.COM smb_node_t *to_dnode, 5085331Samw char *to_name) 5095331Samw { 510*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(from_dnode); 511*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(to_dnode); 512*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(ret_node); 5135331Samw 514*8934SJose.Borrego@Sun.COM smb_node_ref(to_dnode); 515*8934SJose.Borrego@Sun.COM mutex_enter(&ret_node->n_mutex); 516*8934SJose.Borrego@Sun.COM switch (ret_node->n_state) { 517*8934SJose.Borrego@Sun.COM case SMB_NODE_STATE_AVAILABLE: 518*8934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 519*8934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 520*8934SJose.Borrego@Sun.COM ret_node->dir_snode = to_dnode; 521*8934SJose.Borrego@Sun.COM mutex_exit(&ret_node->n_mutex); 522*8934SJose.Borrego@Sun.COM ASSERT(to_dnode->dir_snode != ret_node); 523*8934SJose.Borrego@Sun.COM ASSERT((to_dnode->vp->v_xattrdir) || 524*8934SJose.Borrego@Sun.COM (to_dnode->vp->v_type == VDIR)); 525*8934SJose.Borrego@Sun.COM smb_node_release(from_dnode); 526*8934SJose.Borrego@Sun.COM (void) strcpy(ret_node->od_name, to_name); 527*8934SJose.Borrego@Sun.COM /* 528*8934SJose.Borrego@Sun.COM * XXX Need to update attributes? 529*8934SJose.Borrego@Sun.COM */ 530*8934SJose.Borrego@Sun.COM break; 531*8934SJose.Borrego@Sun.COM default: 532*8934SJose.Borrego@Sun.COM SMB_PANIC(); 533*8934SJose.Borrego@Sun.COM } 5345331Samw } 5355331Samw 5365331Samw int 5376139Sjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root) 5385331Samw { 5396139Sjb150015 smb_attr_t va; 5406139Sjb150015 int error; 5416139Sjb150015 uint32_t hashkey; 5426139Sjb150015 smb_llist_t *node_hdr; 5436139Sjb150015 smb_node_t *node; 5445331Samw 5456139Sjb150015 va.sa_mask = SMB_AT_ALL; 5466139Sjb150015 error = smb_vop_getattr(vp, NULL, &va, 0, kcred); 5476139Sjb150015 if (error) { 5486139Sjb150015 VN_RELE(vp); 5496139Sjb150015 return (error); 5506139Sjb150015 } 5516139Sjb150015 552*8934SJose.Borrego@Sun.COM node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &va, &hashkey); 5535331Samw 554*8934SJose.Borrego@Sun.COM node = smb_node_alloc(ROOTVOL, vp, &va, node_hdr, hashkey); 5556139Sjb150015 5566139Sjb150015 sv->si_root_smb_node = node; 557*8934SJose.Borrego@Sun.COM smb_node_audit(node); 5586139Sjb150015 smb_llist_enter(node_hdr, RW_WRITER); 5596139Sjb150015 smb_llist_insert_head(node_hdr, node); 5606139Sjb150015 smb_llist_exit(node_hdr); 5616139Sjb150015 *root = node; 5626139Sjb150015 return (0); 5635331Samw } 5645331Samw 5655331Samw /* 5665331Samw * smb_node_get_size 5675331Samw */ 5686432Sas200622 u_offset_t 5696432Sas200622 smb_node_get_size(smb_node_t *node, smb_attr_t *attr) 5705331Samw { 5716432Sas200622 u_offset_t size; 5725331Samw 5735331Samw if (attr->sa_vattr.va_type == VDIR) 5745331Samw return (0); 5755331Samw 576*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 5775331Samw if (node && (node->flags & NODE_FLAGS_SET_SIZE)) 5785331Samw size = node->n_size; 5795331Samw else 5805331Samw size = attr->sa_vattr.va_size; 581*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5825331Samw return (size); 5835331Samw } 5845331Samw 5855331Samw static int 5865331Samw timeval_cmp(timestruc_t *a, timestruc_t *b) 5875331Samw { 5885331Samw if (a->tv_sec < b->tv_sec) 5895331Samw return (-1); 5905331Samw if (a->tv_sec > b->tv_sec) 5915331Samw return (1); 5925331Samw /* Seconds are equal compare tv_nsec */ 5935331Samw if (a->tv_nsec < b->tv_nsec) 5945331Samw return (-1); 5955331Samw return (a->tv_nsec > b->tv_nsec); 5965331Samw } 5975331Samw 5985331Samw /* 5995331Samw * smb_node_set_time 6005331Samw * 6015331Samw * This function will update the time stored in the node and 6027348SJose.Borrego@Sun.COM * set the appropriate flags. If there is nothing to update, 6037348SJose.Borrego@Sun.COM * the function will return without any updates. The update 6047348SJose.Borrego@Sun.COM * is only in the node level and the attribute in the file system 6057348SJose.Borrego@Sun.COM * will be updated when client close the file. 6065331Samw */ 6075331Samw void 608*8934SJose.Borrego@Sun.COM smb_node_set_time( 609*8934SJose.Borrego@Sun.COM smb_node_t *node, 610*8934SJose.Borrego@Sun.COM timestruc_t *crtime, 611*8934SJose.Borrego@Sun.COM timestruc_t *mtime, 612*8934SJose.Borrego@Sun.COM timestruc_t *atime, 613*8934SJose.Borrego@Sun.COM timestruc_t *ctime, 614*8934SJose.Borrego@Sun.COM uint_t what) 6155331Samw { 6167348SJose.Borrego@Sun.COM if (what == 0) 6175331Samw return; 6185331Samw 6195331Samw if ((what & SMB_AT_CRTIME && crtime == 0) || 6205331Samw (what & SMB_AT_MTIME && mtime == 0) || 6215331Samw (what & SMB_AT_ATIME && atime == 0) || 6227348SJose.Borrego@Sun.COM (what & SMB_AT_CTIME && ctime == 0)) 6235331Samw return; 6247348SJose.Borrego@Sun.COM 625*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 6265331Samw 6275331Samw if ((what & SMB_AT_CRTIME) && 6285331Samw timeval_cmp((timestruc_t *)&node->attr.sa_crtime, 6295331Samw crtime) != 0) { 6305331Samw node->what |= SMB_AT_CRTIME; 6315331Samw node->attr.sa_crtime = *((timestruc_t *)crtime); 6325331Samw } 6335331Samw 6345331Samw if ((what & SMB_AT_MTIME) && 6355331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime, 6365331Samw mtime) != 0) { 6375331Samw node->what |= SMB_AT_MTIME; 6385331Samw node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime); 6395331Samw } 6405331Samw 6415331Samw if ((what & SMB_AT_ATIME) && 6425331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime, 6435331Samw atime) != 0) { 6445331Samw node->what |= SMB_AT_ATIME; 6455331Samw node->attr.sa_vattr.va_atime = *((timestruc_t *)atime); 6465331Samw } 6475331Samw 6485331Samw /* 6495331Samw * The ctime handling is trickier. It has three scenarios. 6505331Samw * 1. Only ctime need to be set and it is the same as the ctime 6515331Samw * stored in the node. (update not necessary) 6525331Samw * 2. The ctime is the same as the ctime stored in the node but 6535331Samw * is not the only time need to be set. (update required) 6545331Samw * 3. The ctime need to be set and is not the same as the ctime 6555331Samw * stored in the node. (update required) 6565331Samw * Unlike other time setting, the ctime needs to be set even when 6575331Samw * it is the same as the ctime in the node if there are other time 6585331Samw * needs to be set (#2). This will ensure the ctime not being 6595331Samw * updated when other times are being updated in the file system. 6605331Samw * 6615331Samw * Retained file rules: 6625331Samw * 6635331Samw * 1. Don't add SMB_AT_CTIME to node->what by default because the 6645331Samw * request will be rejected by filesystem 6655331Samw * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e. 6665331Samw * any request for changing ctime on these files should have 6675331Samw * been already rejected 6685331Samw */ 6695331Samw node->what |= SMB_AT_CTIME; 6705331Samw if (what & SMB_AT_CTIME) { 6715331Samw if ((what == SMB_AT_CTIME) && 6725331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime, 6735331Samw ctime) == 0) { 6745331Samw node->what &= ~SMB_AT_CTIME; 6755331Samw } else { 6765331Samw gethrestime(&node->attr.sa_vattr.va_ctime); 6775331Samw } 6785331Samw } else { 6795331Samw gethrestime(&node->attr.sa_vattr.va_ctime); 6805331Samw } 681*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 6825331Samw } 6835331Samw 6845331Samw 6855331Samw timestruc_t * 6865331Samw smb_node_get_crtime(smb_node_t *node) 6875331Samw { 6885331Samw return ((timestruc_t *)&node->attr.sa_crtime); 6895331Samw } 6905331Samw 6915331Samw timestruc_t * 6925331Samw smb_node_get_atime(smb_node_t *node) 6935331Samw { 6945331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_atime); 6955331Samw } 6965331Samw 6975331Samw timestruc_t * 6985331Samw smb_node_get_ctime(smb_node_t *node) 6995331Samw { 7005331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_ctime); 7015331Samw } 7025331Samw 7035331Samw timestruc_t * 7045331Samw smb_node_get_mtime(smb_node_t *node) 7055331Samw { 7065331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_mtime); 7075331Samw } 7085331Samw 7095331Samw /* 7105331Samw * smb_node_set_dosattr 7115331Samw * 7125331Samw * Parse the specified DOS attributes and, if they have been modified, 7135331Samw * update the node cache. This call should be followed by a 7145331Samw * smb_sync_fsattr() call to write the attribute changes to filesystem. 7155331Samw */ 7165331Samw void 7177052Samw smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr) 7185331Samw { 7197052Samw uint32_t mode = dosattr & (FILE_ATTRIBUTE_ARCHIVE | 7207052Samw FILE_ATTRIBUTE_READONLY | 7217052Samw FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); 7225331Samw 723*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 7245331Samw if (node->attr.sa_dosattr != mode) { 7255331Samw node->attr.sa_dosattr = mode; 7265331Samw node->what |= SMB_AT_DOSATTR; 7275331Samw } 728*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 7295331Samw } 7305331Samw 7315331Samw /* 7327348SJose.Borrego@Sun.COM * smb_node_get_dosattr() 7335331Samw * 7347348SJose.Borrego@Sun.COM * This function is used to provide clients with information as to whether 7357348SJose.Borrego@Sun.COM * the readonly bit is set. Hence both the node attribute cache (which 7367348SJose.Borrego@Sun.COM * reflects the on-disk attributes) and node->readonly_creator (which 7377348SJose.Borrego@Sun.COM * reflects whether a readonly set is pending from a readonly create) are 7387348SJose.Borrego@Sun.COM * checked. In the latter case, the readonly attribute should be visible to 7397348SJose.Borrego@Sun.COM * all clients even though the readonly creator fid is immune to the readonly 7407348SJose.Borrego@Sun.COM * bit until close. 7415331Samw */ 7427348SJose.Borrego@Sun.COM 7435331Samw uint32_t 7445331Samw smb_node_get_dosattr(smb_node_t *node) 7455331Samw { 7467348SJose.Borrego@Sun.COM uint32_t dosattr = node->attr.sa_dosattr; 7477348SJose.Borrego@Sun.COM 7487348SJose.Borrego@Sun.COM if (node->readonly_creator) 7497348SJose.Borrego@Sun.COM dosattr |= FILE_ATTRIBUTE_READONLY; 7507348SJose.Borrego@Sun.COM 7517348SJose.Borrego@Sun.COM if (!dosattr) 7527348SJose.Borrego@Sun.COM dosattr = FILE_ATTRIBUTE_NORMAL; 7537348SJose.Borrego@Sun.COM 7547348SJose.Borrego@Sun.COM return (dosattr); 7555331Samw } 7565331Samw 7575331Samw int 7585331Samw smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr) 7595331Samw { 7605331Samw int rc = -1; 7615331Samw 762*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 7635331Samw if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) && 7645331Samw !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) { 7655331Samw crhold(cr); 7665331Samw node->delete_on_close_cred = cr; 7675331Samw node->flags |= NODE_FLAGS_DELETE_ON_CLOSE; 7685331Samw rc = 0; 7695331Samw } 770*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 7715331Samw return (rc); 7725331Samw } 7735331Samw 7745331Samw void 7755331Samw smb_node_reset_delete_on_close(smb_node_t *node) 7765331Samw { 777*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 7785331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 7795331Samw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 7805331Samw crfree(node->delete_on_close_cred); 7815331Samw node->delete_on_close_cred = NULL; 7825331Samw } 783*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 7845331Samw } 7855772Sas200622 7865772Sas200622 /* 7876771Sjb150015 * smb_node_open_check 7885772Sas200622 * 7895772Sas200622 * check file sharing rules for current open request 7905772Sas200622 * against all existing opens for a file. 7915772Sas200622 * 7925772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 7935772Sas200622 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 7945772Sas200622 */ 7955772Sas200622 uint32_t 796*8934SJose.Borrego@Sun.COM smb_node_open_check( 797*8934SJose.Borrego@Sun.COM smb_node_t *node, 798*8934SJose.Borrego@Sun.COM cred_t *cr, 799*8934SJose.Borrego@Sun.COM uint32_t desired_access, 800*8934SJose.Borrego@Sun.COM uint32_t share_access) 8015772Sas200622 { 8025772Sas200622 smb_ofile_t *of; 8035772Sas200622 uint32_t status; 8045772Sas200622 805*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 8065772Sas200622 8075772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 8085772Sas200622 of = smb_llist_head(&node->n_ofile_list); 8095772Sas200622 while (of) { 8106771Sjb150015 status = smb_ofile_open_check(of, cr, desired_access, 8116771Sjb150015 share_access); 8126771Sjb150015 8136771Sjb150015 switch (status) { 8146771Sjb150015 case NT_STATUS_INVALID_HANDLE: 8156771Sjb150015 case NT_STATUS_SUCCESS: 8166771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 8176771Sjb150015 break; 8186771Sjb150015 default: 8196771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 8205772Sas200622 smb_llist_exit(&node->n_ofile_list); 8215772Sas200622 return (status); 8225772Sas200622 } 8235772Sas200622 } 8246771Sjb150015 8255772Sas200622 smb_llist_exit(&node->n_ofile_list); 8265772Sas200622 return (NT_STATUS_SUCCESS); 8275772Sas200622 } 8285772Sas200622 8295772Sas200622 uint32_t 830*8934SJose.Borrego@Sun.COM smb_node_rename_check(smb_node_t *node) 8315772Sas200622 { 832*8934SJose.Borrego@Sun.COM smb_ofile_t *of; 833*8934SJose.Borrego@Sun.COM uint32_t status; 8345772Sas200622 835*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 8365772Sas200622 8375772Sas200622 /* 8385772Sas200622 * Intra-CIFS check 8395772Sas200622 */ 8405772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 8416771Sjb150015 of = smb_llist_head(&node->n_ofile_list); 8426771Sjb150015 while (of) { 8436771Sjb150015 status = smb_ofile_rename_check(of); 8445772Sas200622 8456771Sjb150015 switch (status) { 8466771Sjb150015 case NT_STATUS_INVALID_HANDLE: 8476771Sjb150015 case NT_STATUS_SUCCESS: 8486771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 8496771Sjb150015 break; 8506771Sjb150015 default: 8516771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 8526771Sjb150015 smb_llist_exit(&node->n_ofile_list); 8536771Sjb150015 return (status); 8545772Sas200622 } 8555772Sas200622 } 8565772Sas200622 smb_llist_exit(&node->n_ofile_list); 8575772Sas200622 8585772Sas200622 /* 8595772Sas200622 * system-wide share check 8605772Sas200622 */ 8615772Sas200622 if (nbl_share_conflict(node->vp, NBL_RENAME, NULL)) 8625772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 8635772Sas200622 else 8645772Sas200622 return (NT_STATUS_SUCCESS); 8655772Sas200622 } 8665772Sas200622 8676771Sjb150015 uint32_t 8685772Sas200622 smb_node_delete_check(smb_node_t *node) 8695772Sas200622 { 870*8934SJose.Borrego@Sun.COM smb_ofile_t *of; 871*8934SJose.Borrego@Sun.COM uint32_t status; 8725772Sas200622 873*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 8745772Sas200622 8755772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 8765772Sas200622 return (NT_STATUS_SUCCESS); 8775772Sas200622 8785772Sas200622 /* 8795772Sas200622 * intra-CIFS check 8805772Sas200622 */ 8815772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 8826771Sjb150015 of = smb_llist_head(&node->n_ofile_list); 8836771Sjb150015 while (of) { 8846771Sjb150015 status = smb_ofile_delete_check(of); 8856771Sjb150015 8866771Sjb150015 switch (status) { 8876771Sjb150015 case NT_STATUS_INVALID_HANDLE: 8886771Sjb150015 case NT_STATUS_SUCCESS: 8896771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 8906771Sjb150015 break; 8916771Sjb150015 default: 8926771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 8935772Sas200622 smb_llist_exit(&node->n_ofile_list); 8946771Sjb150015 return (status); 8955772Sas200622 } 8965772Sas200622 } 8975772Sas200622 smb_llist_exit(&node->n_ofile_list); 8985772Sas200622 8995772Sas200622 /* 9005772Sas200622 * system-wide share check 9015772Sas200622 */ 9025772Sas200622 if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL)) 9035772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9045772Sas200622 else 9055772Sas200622 return (NT_STATUS_SUCCESS); 9065772Sas200622 } 9075772Sas200622 9085772Sas200622 /* 9095772Sas200622 * smb_node_start_crit() 9105772Sas200622 * 9115772Sas200622 * Enter critical region for share reservations. 9125772Sas200622 * See comments above smb_fsop_shrlock(). 9135772Sas200622 */ 9145772Sas200622 9155772Sas200622 void 9165772Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode) 9175772Sas200622 { 918*8934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, mode); 9195772Sas200622 nbl_start_crit(node->vp, mode); 9205772Sas200622 } 9215772Sas200622 9225772Sas200622 /* 9235772Sas200622 * smb_node_end_crit() 9245772Sas200622 * 9255772Sas200622 * Exit critical region for share reservations. 9265772Sas200622 */ 9275772Sas200622 9285772Sas200622 void 9295772Sas200622 smb_node_end_crit(smb_node_t *node) 9305772Sas200622 { 9315772Sas200622 nbl_end_crit(node->vp); 932*8934SJose.Borrego@Sun.COM rw_exit(&node->n_lock); 9335772Sas200622 } 9345772Sas200622 9355772Sas200622 int 9365772Sas200622 smb_node_in_crit(smb_node_t *node) 9375772Sas200622 { 938*8934SJose.Borrego@Sun.COM return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock)); 939*8934SJose.Borrego@Sun.COM } 940*8934SJose.Borrego@Sun.COM 941*8934SJose.Borrego@Sun.COM void 942*8934SJose.Borrego@Sun.COM smb_node_rdlock(smb_node_t *node) 943*8934SJose.Borrego@Sun.COM { 944*8934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, RW_READER); 945*8934SJose.Borrego@Sun.COM } 946*8934SJose.Borrego@Sun.COM 947*8934SJose.Borrego@Sun.COM void 948*8934SJose.Borrego@Sun.COM smb_node_wrlock(smb_node_t *node) 949*8934SJose.Borrego@Sun.COM { 950*8934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, RW_WRITER); 951*8934SJose.Borrego@Sun.COM } 952*8934SJose.Borrego@Sun.COM 953*8934SJose.Borrego@Sun.COM void 954*8934SJose.Borrego@Sun.COM smb_node_unlock(smb_node_t *node) 955*8934SJose.Borrego@Sun.COM { 956*8934SJose.Borrego@Sun.COM rw_exit(&node->n_lock); 957*8934SJose.Borrego@Sun.COM } 958*8934SJose.Borrego@Sun.COM 959*8934SJose.Borrego@Sun.COM uint32_t 960*8934SJose.Borrego@Sun.COM smb_node_get_ofile_count(smb_node_t *node) 961*8934SJose.Borrego@Sun.COM { 962*8934SJose.Borrego@Sun.COM uint32_t cntr; 963*8934SJose.Borrego@Sun.COM 964*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 965*8934SJose.Borrego@Sun.COM 966*8934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_READER); 967*8934SJose.Borrego@Sun.COM cntr = smb_llist_get_count(&node->n_ofile_list); 968*8934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 969*8934SJose.Borrego@Sun.COM return (cntr); 970*8934SJose.Borrego@Sun.COM } 971*8934SJose.Borrego@Sun.COM 972*8934SJose.Borrego@Sun.COM void 973*8934SJose.Borrego@Sun.COM smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of) 974*8934SJose.Borrego@Sun.COM { 975*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 976*8934SJose.Borrego@Sun.COM 977*8934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_WRITER); 978*8934SJose.Borrego@Sun.COM smb_llist_insert_tail(&node->n_ofile_list, of); 979*8934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 980*8934SJose.Borrego@Sun.COM } 981*8934SJose.Borrego@Sun.COM 982*8934SJose.Borrego@Sun.COM void 983*8934SJose.Borrego@Sun.COM smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of) 984*8934SJose.Borrego@Sun.COM { 985*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 986*8934SJose.Borrego@Sun.COM 987*8934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_WRITER); 988*8934SJose.Borrego@Sun.COM smb_llist_remove(&node->n_ofile_list, of); 989*8934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 990*8934SJose.Borrego@Sun.COM } 991*8934SJose.Borrego@Sun.COM 992*8934SJose.Borrego@Sun.COM void 993*8934SJose.Borrego@Sun.COM smb_node_inc_open_ofiles(smb_node_t *node) 994*8934SJose.Borrego@Sun.COM { 995*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 996*8934SJose.Borrego@Sun.COM 997*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 998*8934SJose.Borrego@Sun.COM node->n_open_count++; 999*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 1000*8934SJose.Borrego@Sun.COM } 1001*8934SJose.Borrego@Sun.COM 1002*8934SJose.Borrego@Sun.COM void 1003*8934SJose.Borrego@Sun.COM smb_node_dec_open_ofiles(smb_node_t *node) 1004*8934SJose.Borrego@Sun.COM { 1005*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 1006*8934SJose.Borrego@Sun.COM 1007*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 1008*8934SJose.Borrego@Sun.COM node->n_open_count--; 1009*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 1010*8934SJose.Borrego@Sun.COM } 1011*8934SJose.Borrego@Sun.COM 1012*8934SJose.Borrego@Sun.COM uint32_t 1013*8934SJose.Borrego@Sun.COM smb_node_get_open_ofiles(smb_node_t *node) 1014*8934SJose.Borrego@Sun.COM { 1015*8934SJose.Borrego@Sun.COM uint32_t cnt; 1016*8934SJose.Borrego@Sun.COM 1017*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 1018*8934SJose.Borrego@Sun.COM 1019*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 1020*8934SJose.Borrego@Sun.COM cnt = node->n_open_count; 1021*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 1022*8934SJose.Borrego@Sun.COM return (cnt); 10235772Sas200622 } 1024*8934SJose.Borrego@Sun.COM 1025*8934SJose.Borrego@Sun.COM /* 1026*8934SJose.Borrego@Sun.COM * smb_node_alloc 1027*8934SJose.Borrego@Sun.COM */ 1028*8934SJose.Borrego@Sun.COM static smb_node_t * 1029*8934SJose.Borrego@Sun.COM smb_node_alloc( 1030*8934SJose.Borrego@Sun.COM char *od_name, 1031*8934SJose.Borrego@Sun.COM vnode_t *vp, 1032*8934SJose.Borrego@Sun.COM smb_attr_t *attr, 1033*8934SJose.Borrego@Sun.COM smb_llist_t *bucket, 1034*8934SJose.Borrego@Sun.COM uint32_t hashkey) 1035*8934SJose.Borrego@Sun.COM { 1036*8934SJose.Borrego@Sun.COM smb_node_t *node; 1037*8934SJose.Borrego@Sun.COM 1038*8934SJose.Borrego@Sun.COM node = kmem_cache_alloc(smb_node_cache, KM_SLEEP); 1039*8934SJose.Borrego@Sun.COM 1040*8934SJose.Borrego@Sun.COM if (node->n_audit_buf != NULL) 1041*8934SJose.Borrego@Sun.COM node->n_audit_buf->anb_index = 0; 1042*8934SJose.Borrego@Sun.COM 1043*8934SJose.Borrego@Sun.COM node->attr = *attr; 1044*8934SJose.Borrego@Sun.COM node->flags = NODE_FLAGS_ATTR_VALID; 1045*8934SJose.Borrego@Sun.COM node->n_size = node->attr.sa_vattr.va_size; 1046*8934SJose.Borrego@Sun.COM VN_HOLD(vp); 1047*8934SJose.Borrego@Sun.COM node->vp = vp; 1048*8934SJose.Borrego@Sun.COM node->n_refcnt = 1; 1049*8934SJose.Borrego@Sun.COM node->n_hash_bucket = bucket; 1050*8934SJose.Borrego@Sun.COM node->n_hashkey = hashkey; 1051*8934SJose.Borrego@Sun.COM node->n_orig_uid = 0; 1052*8934SJose.Borrego@Sun.COM node->readonly_creator = NULL; 1053*8934SJose.Borrego@Sun.COM node->waiting_event = 0; 1054*8934SJose.Borrego@Sun.COM node->what = 0; 1055*8934SJose.Borrego@Sun.COM node->n_open_count = 0; 1056*8934SJose.Borrego@Sun.COM node->dir_snode = NULL; 1057*8934SJose.Borrego@Sun.COM node->unnamed_stream_node = NULL; 1058*8934SJose.Borrego@Sun.COM node->delete_on_close_cred = NULL; 1059*8934SJose.Borrego@Sun.COM 1060*8934SJose.Borrego@Sun.COM (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); 1061*8934SJose.Borrego@Sun.COM if (strcmp(od_name, XATTR_DIR) == 0) 1062*8934SJose.Borrego@Sun.COM node->flags |= NODE_XATTR_DIR; 1063*8934SJose.Borrego@Sun.COM 1064*8934SJose.Borrego@Sun.COM node->n_state = SMB_NODE_STATE_AVAILABLE; 1065*8934SJose.Borrego@Sun.COM node->n_magic = SMB_NODE_MAGIC; 1066*8934SJose.Borrego@Sun.COM return (node); 1067*8934SJose.Borrego@Sun.COM } 1068*8934SJose.Borrego@Sun.COM 1069*8934SJose.Borrego@Sun.COM /* 1070*8934SJose.Borrego@Sun.COM * smb_node_free 1071*8934SJose.Borrego@Sun.COM */ 1072*8934SJose.Borrego@Sun.COM static void 1073*8934SJose.Borrego@Sun.COM smb_node_free(smb_node_t *node) 1074*8934SJose.Borrego@Sun.COM { 1075*8934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 1076*8934SJose.Borrego@Sun.COM 1077*8934SJose.Borrego@Sun.COM node->n_magic = 0; 1078*8934SJose.Borrego@Sun.COM VERIFY(!list_link_active(&node->n_lnd)); 1079*8934SJose.Borrego@Sun.COM VERIFY(node->n_lock_list.ll_count == 0); 1080*8934SJose.Borrego@Sun.COM VERIFY(node->n_ofile_list.ll_count == 0); 1081*8934SJose.Borrego@Sun.COM VERIFY(node->n_oplock.ol_xthread == NULL); 1082*8934SJose.Borrego@Sun.COM VERIFY(node->n_oplock.ol_waiters_count == 0); 1083*8934SJose.Borrego@Sun.COM VN_RELE(node->vp); 1084*8934SJose.Borrego@Sun.COM kmem_cache_free(smb_node_cache, node); 1085*8934SJose.Borrego@Sun.COM } 1086*8934SJose.Borrego@Sun.COM 1087*8934SJose.Borrego@Sun.COM /* 1088*8934SJose.Borrego@Sun.COM * smb_node_constructor 1089*8934SJose.Borrego@Sun.COM */ 1090*8934SJose.Borrego@Sun.COM static int 1091*8934SJose.Borrego@Sun.COM smb_node_constructor(void *buf, void *un, int kmflags) 1092*8934SJose.Borrego@Sun.COM { 1093*8934SJose.Borrego@Sun.COM _NOTE(ARGUNUSED(kmflags, un)) 1094*8934SJose.Borrego@Sun.COM 1095*8934SJose.Borrego@Sun.COM smb_node_t *node = (smb_node_t *)buf; 1096*8934SJose.Borrego@Sun.COM 1097*8934SJose.Borrego@Sun.COM bzero(node, sizeof (smb_node_t)); 1098*8934SJose.Borrego@Sun.COM 1099*8934SJose.Borrego@Sun.COM smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 1100*8934SJose.Borrego@Sun.COM offsetof(smb_ofile_t, f_nnd)); 1101*8934SJose.Borrego@Sun.COM smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 1102*8934SJose.Borrego@Sun.COM offsetof(smb_lock_t, l_lnd)); 1103*8934SJose.Borrego@Sun.COM cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL); 1104*8934SJose.Borrego@Sun.COM rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL); 1105*8934SJose.Borrego@Sun.COM mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL); 1106*8934SJose.Borrego@Sun.COM smb_node_create_audit_buf(node, kmflags); 1107*8934SJose.Borrego@Sun.COM return (0); 1108*8934SJose.Borrego@Sun.COM } 1109*8934SJose.Borrego@Sun.COM 1110*8934SJose.Borrego@Sun.COM /* 1111*8934SJose.Borrego@Sun.COM * smb_node_destructor 1112*8934SJose.Borrego@Sun.COM */ 1113*8934SJose.Borrego@Sun.COM static void 1114*8934SJose.Borrego@Sun.COM smb_node_destructor(void *buf, void *un) 1115*8934SJose.Borrego@Sun.COM { 1116*8934SJose.Borrego@Sun.COM _NOTE(ARGUNUSED(un)) 1117*8934SJose.Borrego@Sun.COM 1118*8934SJose.Borrego@Sun.COM smb_node_t *node = (smb_node_t *)buf; 1119*8934SJose.Borrego@Sun.COM 1120*8934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(node); 1121*8934SJose.Borrego@Sun.COM mutex_destroy(&node->n_mutex); 1122*8934SJose.Borrego@Sun.COM rw_destroy(&node->n_lock); 1123*8934SJose.Borrego@Sun.COM cv_destroy(&node->n_oplock.ol_cv); 1124*8934SJose.Borrego@Sun.COM smb_llist_destructor(&node->n_lock_list); 1125*8934SJose.Borrego@Sun.COM smb_llist_destructor(&node->n_ofile_list); 1126*8934SJose.Borrego@Sun.COM } 1127*8934SJose.Borrego@Sun.COM 1128*8934SJose.Borrego@Sun.COM /* 1129*8934SJose.Borrego@Sun.COM * smb_node_create_audit_buf 1130*8934SJose.Borrego@Sun.COM */ 1131*8934SJose.Borrego@Sun.COM static void 1132*8934SJose.Borrego@Sun.COM smb_node_create_audit_buf(smb_node_t *node, int kmflags) 1133*8934SJose.Borrego@Sun.COM { 1134*8934SJose.Borrego@Sun.COM smb_audit_buf_node_t *abn; 1135*8934SJose.Borrego@Sun.COM 1136*8934SJose.Borrego@Sun.COM if (smb_audit_flags & SMB_AUDIT_NODE) { 1137*8934SJose.Borrego@Sun.COM abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags); 1138*8934SJose.Borrego@Sun.COM abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1; 1139*8934SJose.Borrego@Sun.COM node->n_audit_buf = abn; 1140*8934SJose.Borrego@Sun.COM } 1141*8934SJose.Borrego@Sun.COM } 1142*8934SJose.Borrego@Sun.COM 1143*8934SJose.Borrego@Sun.COM /* 1144*8934SJose.Borrego@Sun.COM * smb_node_destroy_audit_buf 1145*8934SJose.Borrego@Sun.COM */ 1146*8934SJose.Borrego@Sun.COM static void 1147*8934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(smb_node_t *node) 1148*8934SJose.Borrego@Sun.COM { 1149*8934SJose.Borrego@Sun.COM if (node->n_audit_buf != NULL) { 1150*8934SJose.Borrego@Sun.COM kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t)); 1151*8934SJose.Borrego@Sun.COM node->n_audit_buf = NULL; 1152*8934SJose.Borrego@Sun.COM } 1153*8934SJose.Borrego@Sun.COM } 1154*8934SJose.Borrego@Sun.COM 1155*8934SJose.Borrego@Sun.COM /* 1156*8934SJose.Borrego@Sun.COM * smb_node_audit 1157*8934SJose.Borrego@Sun.COM * 1158*8934SJose.Borrego@Sun.COM * This function saves the calling stack in the audit buffer of the node passed 1159*8934SJose.Borrego@Sun.COM * in. 1160*8934SJose.Borrego@Sun.COM */ 1161*8934SJose.Borrego@Sun.COM static void 1162*8934SJose.Borrego@Sun.COM smb_node_audit(smb_node_t *node) 1163*8934SJose.Borrego@Sun.COM { 1164*8934SJose.Borrego@Sun.COM smb_audit_buf_node_t *abn; 1165*8934SJose.Borrego@Sun.COM smb_audit_record_node_t *anr; 1166*8934SJose.Borrego@Sun.COM 1167*8934SJose.Borrego@Sun.COM if (node->n_audit_buf) { 1168*8934SJose.Borrego@Sun.COM abn = node->n_audit_buf; 1169*8934SJose.Borrego@Sun.COM anr = abn->anb_records; 1170*8934SJose.Borrego@Sun.COM anr += abn->anb_index; 1171*8934SJose.Borrego@Sun.COM abn->anb_index++; 1172*8934SJose.Borrego@Sun.COM abn->anb_index &= abn->anb_max_index; 1173*8934SJose.Borrego@Sun.COM anr->anr_refcnt = node->n_refcnt; 1174*8934SJose.Borrego@Sun.COM anr->anr_depth = getpcstack(anr->anr_stack, 1175*8934SJose.Borrego@Sun.COM SMB_AUDIT_STACK_DEPTH); 1176*8934SJose.Borrego@Sun.COM } 1177*8934SJose.Borrego@Sun.COM } 1178*8934SJose.Borrego@Sun.COM 1179*8934SJose.Borrego@Sun.COM static smb_llist_t * 1180*8934SJose.Borrego@Sun.COM smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey) 1181*8934SJose.Borrego@Sun.COM { 1182*8934SJose.Borrego@Sun.COM uint32_t hashkey; 1183*8934SJose.Borrego@Sun.COM 1184*8934SJose.Borrego@Sun.COM hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid; 1185*8934SJose.Borrego@Sun.COM hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 1186*8934SJose.Borrego@Sun.COM *phashkey = hashkey; 1187*8934SJose.Borrego@Sun.COM return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]); 1188*8934SJose.Borrego@Sun.COM } 1189