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 * 299021Samw@Sun.COM * 309021Samw@Sun.COM * +----------- Creation/Allocation 315331Samw * | 329021Samw@Sun.COM * | T0 335331Samw * | 345331Samw * v 359021Samw@Sun.COM * +----------------------------+ T1 369021Samw@Sun.COM * | SMB_NODE_STATE_AVAILABLE |--------------------+ 379021Samw@Sun.COM * +----------------------------+ | 389021Samw@Sun.COM * | ^ | 399021Samw@Sun.COM * | | v 409021Samw@Sun.COM * | | T2 +-------------------------------+ 419021Samw@Sun.COM * | |<---------| SMB_NODE_STATE_OPLOCK_GRANTED | 429021Samw@Sun.COM * | | +-------------------------------+ 439021Samw@Sun.COM * | T5 | | 449021Samw@Sun.COM * | | | T3 459021Samw@Sun.COM * | | v 469021Samw@Sun.COM * | | T4 +--------------------------------+ 479021Samw@Sun.COM * | +----------| SMB_NODE_STATE_OPLOCK_BREAKING | 489021Samw@Sun.COM * | +--------------------------------+ 499021Samw@Sun.COM * | 509021Samw@Sun.COM * v 515331Samw * +-----------------------------+ 529021Samw@Sun.COM * | SMB_NODE_STATE_DESTROYING | 539021Samw@Sun.COM * +-----------------------------+ 549021Samw@Sun.COM * | 559021Samw@Sun.COM * | 569021Samw@Sun.COM * | T6 579021Samw@Sun.COM * | 589021Samw@Sun.COM * +----------> Deletion/Free 595331Samw * 605331Samw * Transition T0 615331Samw * 625331Samw * This transition occurs in smb_node_lookup(). If the node looked for is 635331Samw * not found in the has table a new node is created. The reference count is 645331Samw * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE. 655331Samw * 665331Samw * Transition T1 675331Samw * 689021Samw@Sun.COM * This transition occurs smb_oplock_acquire() during an OPEN. 699021Samw@Sun.COM * 709021Samw@Sun.COM * Transition T2 719021Samw@Sun.COM * 729021Samw@Sun.COM * This transition occurs in smb_oplock_release(). The events triggering 739021Samw@Sun.COM * it are: 749021Samw@Sun.COM * 759021Samw@Sun.COM * - LockingAndX sent by the client that was granted the oplock. 769021Samw@Sun.COM * - Closing of the file. 779021Samw@Sun.COM * 789021Samw@Sun.COM * Transition T3 799021Samw@Sun.COM * 809021Samw@Sun.COM * This transition occurs in smb_oplock_break(). The events triggering 819021Samw@Sun.COM * it are: 829021Samw@Sun.COM * 839021Samw@Sun.COM * - Another client wants to open the file. 849021Samw@Sun.COM * - A client is trying to delete the file. 859021Samw@Sun.COM * - A client is trying to rename the file. 869021Samw@Sun.COM * - A client is trying to set/modify the file attributes. 879021Samw@Sun.COM * 889021Samw@Sun.COM * Transition T4 899021Samw@Sun.COM * 909021Samw@Sun.COM * This transition occurs in smb_oplock_release or smb_oplock_break(). The 919021Samw@Sun.COM * events triggering it are: 929021Samw@Sun.COM * 939021Samw@Sun.COM * - The client that was granting the oplock releases it (close or 949021Samw@Sun.COM * LockingAndx). 959021Samw@Sun.COM * - The time alloted to release the oplock expired. 969021Samw@Sun.COM * 979021Samw@Sun.COM * Transition T5 989021Samw@Sun.COM * 995331Samw * This transition occurs in smb_node_release(). If the reference count 1005331Samw * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more 1015331Samw * reference count will be given out for that node. 1025331Samw * 1039021Samw@Sun.COM * Transition T6 1045331Samw * 1055331Samw * This transition occurs in smb_node_release(). The structure is deleted. 1065331Samw * 1075331Samw * Comments 1085331Samw * -------- 1095331Samw * 1105331Samw * The reason the smb node has 2 states is the following synchronization 1115331Samw * rule: 1125331Samw * 1135331Samw * There's a mutex embedded in the node used to protect its fields and 1145331Samw * there's a lock embedded in the bucket of the hash table the node belongs 1155331Samw * to. To increment or to decrement the reference count the mutex must be 1165331Samw * entered. To insert the node into the bucket and to remove it from the 1175331Samw * bucket the lock must be entered in RW_WRITER mode. When both (mutex and 1185331Samw * lock) have to be entered, the lock has always to be entered first then 1195331Samw * the mutex. This prevents a deadlock between smb_node_lookup() and 1205331Samw * smb_node_release() from occurring. However, in smb_node_release() when the 1215331Samw * reference count drops to zero and triggers the deletion of the node, the 1225331Samw * mutex has to be released before entering the lock of the bucket (to 1235331Samw * remove the node). This creates a window during which the node that is 1245331Samw * about to be freed could be given out by smb_node_lookup(). To close that 1255331Samw * window the node is moved to the state SMB_NODE_STATE_DESTROYING before 1265331Samw * releasing the mutex. That way, even if smb_node_lookup() finds it, the 1275331Samw * state will indicate that the node should be treated as non existent (of 1285331Samw * course the state of the node should be tested/updated under the 1295331Samw * protection of the mutex). 1305331Samw */ 1315331Samw #include <smbsrv/smb_incl.h> 1325331Samw #include <smbsrv/smb_fsops.h> 1338934SJose.Borrego@Sun.COM #include <smbsrv/smb_kstat.h> 1345331Samw #include <sys/pathname.h> 1355331Samw #include <sys/sdt.h> 1365772Sas200622 #include <sys/nbmlock.h> 1375331Samw 1388934SJose.Borrego@Sun.COM uint32_t smb_is_executable(char *); 1398934SJose.Borrego@Sun.COM static void smb_node_delete_on_close(smb_node_t *); 1408934SJose.Borrego@Sun.COM static void smb_node_create_audit_buf(smb_node_t *, int); 1418934SJose.Borrego@Sun.COM static void smb_node_destroy_audit_buf(smb_node_t *); 1428934SJose.Borrego@Sun.COM static void smb_node_audit(smb_node_t *); 1438934SJose.Borrego@Sun.COM static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_attr_t *, 1448934SJose.Borrego@Sun.COM smb_llist_t *bucket, uint32_t hashkey); 1458934SJose.Borrego@Sun.COM static void smb_node_free(smb_node_t *); 1468934SJose.Borrego@Sun.COM static int smb_node_constructor(void *, void *, int); 1478934SJose.Borrego@Sun.COM static void smb_node_destructor(void *, void *); 1488934SJose.Borrego@Sun.COM static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *); 1495331Samw 1505331Samw #define VALIDATE_DIR_NODE(_dir_, _node_) \ 1515331Samw ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \ 1525331Samw ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \ 1535331Samw ASSERT((_dir_)->dir_snode != (_node_)); 1545331Samw 1558934SJose.Borrego@Sun.COM static kmem_cache_t *smb_node_cache = NULL; 1566139Sjb150015 static boolean_t smb_node_initialized = B_FALSE; 1576139Sjb150015 static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1]; 1586139Sjb150015 1596139Sjb150015 /* 1606139Sjb150015 * smb_node_init 1616139Sjb150015 * 1626139Sjb150015 * Initialization of the SMB node layer. 1636139Sjb150015 * 1646139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 1656139Sjb150015 * thread makes the call. 1666139Sjb150015 */ 1676139Sjb150015 int 1686139Sjb150015 smb_node_init(void) 1696139Sjb150015 { 1706139Sjb150015 int i; 1716139Sjb150015 1726139Sjb150015 if (smb_node_initialized) 1736139Sjb150015 return (0); 1748934SJose.Borrego@Sun.COM smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE, 1758934SJose.Borrego@Sun.COM sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor, 1768934SJose.Borrego@Sun.COM NULL, NULL, NULL, 0); 1776139Sjb150015 1786139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 1796139Sjb150015 smb_llist_constructor(&smb_node_hash_table[i], 1806139Sjb150015 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 1816139Sjb150015 } 1826139Sjb150015 smb_node_initialized = B_TRUE; 1836139Sjb150015 return (0); 1846139Sjb150015 } 1856139Sjb150015 1866139Sjb150015 /* 1876139Sjb150015 * smb_node_fini 1886139Sjb150015 * 1896139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 1906139Sjb150015 * thread makes the call. 1916139Sjb150015 */ 1926139Sjb150015 void 1936139Sjb150015 smb_node_fini(void) 1946139Sjb150015 { 1956139Sjb150015 int i; 1966139Sjb150015 1976139Sjb150015 if (!smb_node_initialized) 1986139Sjb150015 return; 1996139Sjb150015 2006139Sjb150015 #ifdef DEBUG 2016139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 2026139Sjb150015 smb_node_t *node; 2036139Sjb150015 2046139Sjb150015 /* 2056139Sjb150015 * The following sequence is just intended for sanity check. 2066139Sjb150015 * This will have to be modified when the code goes into 2076139Sjb150015 * production. 2086139Sjb150015 * 2096139Sjb150015 * The SMB node hash table should be emtpy at this point. If the 2106139Sjb150015 * hash table is not empty a panic will be triggered. 2116139Sjb150015 * 2126139Sjb150015 * The reason why SMB nodes are still remaining in the hash 2136139Sjb150015 * table is problably due to a mismatch between calls to 2146139Sjb150015 * smb_node_lookup() and smb_node_release(). You must track that 2156139Sjb150015 * down. 2166139Sjb150015 */ 2176139Sjb150015 node = smb_llist_head(&smb_node_hash_table[i]); 2186139Sjb150015 ASSERT(node == NULL); 2196139Sjb150015 } 2206139Sjb150015 #endif 2216139Sjb150015 2226139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 2236139Sjb150015 smb_llist_destructor(&smb_node_hash_table[i]); 2246139Sjb150015 } 2258934SJose.Borrego@Sun.COM kmem_cache_destroy(smb_node_cache); 2268934SJose.Borrego@Sun.COM smb_node_cache = NULL; 2276139Sjb150015 smb_node_initialized = B_FALSE; 2286139Sjb150015 } 2296139Sjb150015 2305331Samw /* 2315331Samw * smb_node_lookup() 2325331Samw * 2335331Samw * NOTE: This routine should only be called by the file system interface layer, 2345331Samw * and not by SMB. 2355331Samw * 2365331Samw * smb_node_lookup() is called upon successful lookup, mkdir, and create 2375331Samw * (for both non-streams and streams). In each of these cases, a held vnode is 2388670SJose.Borrego@Sun.COM * passed into this routine. If a new smb_node is created it will take its 2398670SJose.Borrego@Sun.COM * own hold on the vnode. The caller's hold therefore still belongs to, and 2408670SJose.Borrego@Sun.COM * should be released by, the caller. 2415331Samw * 2425331Samw * A reference is taken on the smb_node whether found in the hash table 2435331Samw * or newly created. 2445331Samw * 2455331Samw * If an smb_node needs to be created, a reference is also taken on the 2465331Samw * dir_snode (if passed in). 2475331Samw * 2485331Samw * See smb_node_release() for details on the release of these references. 2495331Samw */ 2505331Samw 2515331Samw /*ARGSUSED*/ 2525331Samw smb_node_t * 2535331Samw smb_node_lookup( 2545331Samw struct smb_request *sr, 2555331Samw struct open_param *op, 2565331Samw cred_t *cred, 2575331Samw vnode_t *vp, 2585331Samw char *od_name, 2595331Samw smb_node_t *dir_snode, 2605331Samw smb_node_t *unnamed_node, 2615331Samw smb_attr_t *attr) 2625331Samw { 2635331Samw smb_llist_t *node_hdr; 2645331Samw smb_node_t *node; 2655331Samw uint32_t hashkey = 0; 2667348SJose.Borrego@Sun.COM fsid_t fsid; 2675331Samw int error; 2685331Samw krw_t lock_mode; 2695331Samw vnode_t *unnamed_vp = NULL; 2705331Samw 2715331Samw /* 2725331Samw * smb_vop_getattr() is called here instead of smb_fsop_getattr(), 2735331Samw * because the node may not yet exist. We also do not want to call 2745331Samw * it with the list lock held. 2755331Samw */ 2765331Samw 2775331Samw if (unnamed_node) 2785331Samw unnamed_vp = unnamed_node->vp; 2795331Samw 2805331Samw /* 2815331Samw * This getattr is performed on behalf of the server 2825331Samw * that's why kcred is used not the user's cred 2835331Samw */ 2845331Samw attr->sa_mask = SMB_AT_ALL; 2855772Sas200622 error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred); 2865331Samw if (error) 2875331Samw return (NULL); 2885331Samw 2897348SJose.Borrego@Sun.COM if (sr && sr->tid_tree) { 2907348SJose.Borrego@Sun.COM /* 2917348SJose.Borrego@Sun.COM * The fsid for a file is that of the tree, even 2927348SJose.Borrego@Sun.COM * if the file resides in a different mountpoint 2937348SJose.Borrego@Sun.COM * under the share. 2947348SJose.Borrego@Sun.COM */ 2957348SJose.Borrego@Sun.COM fsid = SMB_TREE_FSID(sr->tid_tree); 2965331Samw } else { 2977348SJose.Borrego@Sun.COM /* 2987348SJose.Borrego@Sun.COM * This should be getting executed only for the 2997348SJose.Borrego@Sun.COM * tree root smb_node. 3007348SJose.Borrego@Sun.COM */ 3017348SJose.Borrego@Sun.COM fsid = vp->v_vfsp->vfs_fsid; 3025331Samw } 3035331Samw 3048934SJose.Borrego@Sun.COM node_hdr = smb_node_get_hash(&fsid, attr, &hashkey); 3055331Samw lock_mode = RW_READER; 3065331Samw 3075331Samw smb_llist_enter(node_hdr, lock_mode); 3085331Samw for (;;) { 3095331Samw node = list_head(&node_hdr->ll_list); 3105331Samw while (node) { 3115331Samw ASSERT(node->n_magic == SMB_NODE_MAGIC); 3125331Samw ASSERT(node->n_hash_bucket == node_hdr); 3135331Samw if ((node->n_hashkey == hashkey) && (node->vp == vp)) { 3148934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 3155331Samw DTRACE_PROBE1(smb_node_lookup_hit, 3165331Samw smb_node_t *, node); 3175331Samw switch (node->n_state) { 3188934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 3198934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 3205331Samw case SMB_NODE_STATE_AVAILABLE: 3215331Samw /* The node was found. */ 3225331Samw node->n_refcnt++; 3235331Samw if ((node->dir_snode == NULL) && 3245331Samw (dir_snode != NULL) && 3255331Samw (strcmp(od_name, "..") != 0) && 3265331Samw (strcmp(od_name, ".") != 0)) { 3275331Samw VALIDATE_DIR_NODE(dir_snode, 3285331Samw node); 3295331Samw node->dir_snode = dir_snode; 3305331Samw smb_node_ref(dir_snode); 3315331Samw } 3325331Samw node->attr = *attr; 3335772Sas200622 node->n_size = attr->sa_vattr.va_size; 3345331Samw 3358934SJose.Borrego@Sun.COM smb_node_audit(node); 3368934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 3375331Samw smb_llist_exit(node_hdr); 3385331Samw return (node); 3395331Samw 3405331Samw case SMB_NODE_STATE_DESTROYING: 3415331Samw /* 3425331Samw * Although the node exists it is about 3435331Samw * to be destroyed. We act as it hasn't 3445331Samw * been found. 3455331Samw */ 3468934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 3475331Samw break; 3485331Samw default: 3495331Samw /* 3505331Samw * Although the node exists it is in an 3515331Samw * unknown state. We act as it hasn't 3525331Samw * been found. 3535331Samw */ 3545331Samw ASSERT(0); 3558934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 3565331Samw break; 3575331Samw } 3585331Samw } 3595331Samw node = smb_llist_next(node_hdr, node); 3605331Samw } 3615331Samw if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) { 3625331Samw lock_mode = RW_WRITER; 3635331Samw continue; 3645331Samw } 3655331Samw break; 3665331Samw } 3678934SJose.Borrego@Sun.COM node = smb_node_alloc(od_name, vp, attr, node_hdr, hashkey); 3688934SJose.Borrego@Sun.COM node->n_orig_uid = crgetuid(sr->user_cr); 3695331Samw 3705331Samw if (op) 3715331Samw node->flags |= smb_is_executable(op->fqi.last_comp); 3725331Samw 3735331Samw if (dir_snode) { 3745331Samw smb_node_ref(dir_snode); 3755331Samw node->dir_snode = dir_snode; 3765331Samw ASSERT(dir_snode->dir_snode != node); 3775331Samw ASSERT((dir_snode->vp->v_xattrdir) || 3785331Samw (dir_snode->vp->v_type == VDIR)); 3795331Samw } 3805331Samw 3815331Samw if (unnamed_node) { 3825331Samw smb_node_ref(unnamed_node); 3835331Samw node->unnamed_stream_node = unnamed_node; 3845331Samw } 3855331Samw 3865331Samw DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node); 3878934SJose.Borrego@Sun.COM smb_node_audit(node); 3885331Samw smb_llist_insert_head(node_hdr, node); 3895331Samw smb_llist_exit(node_hdr); 3905331Samw return (node); 3915331Samw } 3925331Samw 3935331Samw /* 3945331Samw * smb_stream_node_lookup() 3955331Samw * 3965331Samw * Note: stream_name (the name that will be stored in the "od_name" field 3975331Samw * of a stream's smb_node) is the same as the on-disk name for the stream 3985331Samw * except that it does not have SMB_STREAM_PREFIX prepended. 3995331Samw */ 4005331Samw 4015331Samw smb_node_t * 4028934SJose.Borrego@Sun.COM smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode, 4035331Samw vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr) 4045331Samw { 4055331Samw smb_node_t *xattrdir_node; 4065331Samw smb_node_t *snode; 4075331Samw smb_attr_t tmp_attr; 4085331Samw 4095331Samw xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR, 4105331Samw fnode, NULL, &tmp_attr); 4115331Samw 4125331Samw if (xattrdir_node == NULL) 4135331Samw return (NULL); 4145331Samw 4155331Samw snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node, 4165331Samw fnode, ret_attr); 4175331Samw 4185331Samw (void) smb_node_release(xattrdir_node); 4195331Samw return (snode); 4205331Samw } 4215331Samw 4225331Samw 4235331Samw /* 4245331Samw * This function should be called whenever a reference is needed on an 4255331Samw * smb_node pointer. The copy of an smb_node pointer from one non-local 4265331Samw * data structure to another requires a reference to be taken on the smb_node 4275331Samw * (unless the usage is localized). Each data structure deallocation routine 4285331Samw * will call smb_node_release() on its smb_node pointers. 4295331Samw * 4305331Samw * In general, an smb_node pointer residing in a structure should never be 4315331Samw * stale. A node pointer may be NULL, however, and care should be taken 4325331Samw * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid. 4335331Samw * Care also needs to be taken with respect to racing deallocations of a 4345331Samw * structure. 4355331Samw */ 4365331Samw void 4375331Samw smb_node_ref(smb_node_t *node) 4385331Samw { 4398934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 4405331Samw 4418934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 4428934SJose.Borrego@Sun.COM switch (node->n_state) { 4438934SJose.Borrego@Sun.COM case SMB_NODE_STATE_AVAILABLE: 4448934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 4458934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 4468934SJose.Borrego@Sun.COM node->n_refcnt++; 4478934SJose.Borrego@Sun.COM ASSERT(node->n_refcnt); 4488934SJose.Borrego@Sun.COM DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); 4498934SJose.Borrego@Sun.COM smb_node_audit(node); 4508934SJose.Borrego@Sun.COM break; 4518934SJose.Borrego@Sun.COM default: 4528934SJose.Borrego@Sun.COM SMB_PANIC(); 4538934SJose.Borrego@Sun.COM } 4548934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 4555331Samw } 4565331Samw 4575331Samw /* 4585331Samw * smb_node_lookup() takes a hold on an smb_node, whether found in the 4595331Samw * hash table or newly created. This hold is expected to be released 4605331Samw * in the following manner. 4615331Samw * 4625331Samw * smb_node_lookup() takes an address of an smb_node pointer. This should 4635331Samw * be getting passed down via a lookup (whether path name or component), mkdir, 4645331Samw * create. If the original smb_node pointer resides in a data structure, then 4655331Samw * the deallocation routine for the data structure is responsible for calling 4665331Samw * smb_node_release() on the smb_node pointer. Alternatively, 4675331Samw * smb_node_release() can be called as soon as the smb_node pointer is no longer 4685331Samw * needed. In this case, callers are responsible for setting an embedded 4695331Samw * pointer to NULL if it is known that the last reference is being released. 4705331Samw * 4715331Samw * If the passed-in address of the smb_node pointer belongs to a local variable, 4725331Samw * then the caller with the local variable should call smb_node_release() 4735331Samw * directly. 4745331Samw * 4755331Samw * smb_node_release() itself will call smb_node_release() on a node's dir_snode, 4765331Samw * as smb_node_lookup() takes a hold on dir_snode. 4775331Samw */ 4785331Samw void 4795331Samw smb_node_release(smb_node_t *node) 4805331Samw { 4818934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 4825331Samw 4838934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 4845331Samw ASSERT(node->n_refcnt); 4855331Samw DTRACE_PROBE1(smb_node_release, smb_node_t *, node); 4865331Samw if (--node->n_refcnt == 0) { 4875331Samw switch (node->n_state) { 4885331Samw 4895331Samw case SMB_NODE_STATE_AVAILABLE: 4905331Samw node->n_state = SMB_NODE_STATE_DESTROYING; 4918934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 4925331Samw 4935331Samw smb_llist_enter(node->n_hash_bucket, RW_WRITER); 4945331Samw smb_llist_remove(node->n_hash_bucket, node); 4955331Samw smb_llist_exit(node->n_hash_bucket); 4965331Samw 4975331Samw /* 4985331Samw * Check if the file was deleted 4995331Samw */ 5005331Samw smb_node_delete_on_close(node); 5015331Samw 5025331Samw if (node->dir_snode) { 5035331Samw ASSERT(node->dir_snode->n_magic == 5045331Samw SMB_NODE_MAGIC); 5055331Samw smb_node_release(node->dir_snode); 5065331Samw } 5075331Samw 5085331Samw if (node->unnamed_stream_node) { 5095331Samw ASSERT(node->unnamed_stream_node->n_magic == 5105331Samw SMB_NODE_MAGIC); 5115331Samw smb_node_release(node->unnamed_stream_node); 5125331Samw } 5135331Samw 5148934SJose.Borrego@Sun.COM smb_node_free(node); 5155331Samw return; 5165331Samw 5175331Samw default: 5188934SJose.Borrego@Sun.COM SMB_PANIC(); 5195331Samw } 5205331Samw } 5218934SJose.Borrego@Sun.COM smb_node_audit(node); 5228934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5235331Samw } 5245331Samw 5255331Samw static void 5265331Samw smb_node_delete_on_close(smb_node_t *node) 5275331Samw { 5285331Samw smb_node_t *d_snode; 5295331Samw int rc = 0; 530*9231SAfshin.Ardakani@Sun.COM uint32_t flags = 0; 5315331Samw 5325331Samw d_snode = node->dir_snode; 5335331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 534*9231SAfshin.Ardakani@Sun.COM node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 535*9231SAfshin.Ardakani@Sun.COM flags = node->n_delete_on_close_flags; 536*9231SAfshin.Ardakani@Sun.COM ASSERT(node->od_name != NULL); 5375331Samw 5385331Samw if (node->attr.sa_vattr.va_type == VDIR) 5395331Samw rc = smb_fsop_rmdir(0, node->delete_on_close_cred, 540*9231SAfshin.Ardakani@Sun.COM d_snode, node->od_name, flags); 5415331Samw else 5425331Samw rc = smb_fsop_remove(0, node->delete_on_close_cred, 543*9231SAfshin.Ardakani@Sun.COM d_snode, node->od_name, flags); 5445331Samw smb_cred_rele(node->delete_on_close_cred); 5455331Samw } 5465331Samw if (rc != 0) 5475331Samw cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n", 5485331Samw node->od_name, rc); 5495331Samw DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node); 5505331Samw } 5515331Samw 5525331Samw /* 5535331Samw * smb_node_rename() 5545331Samw * 5555331Samw */ 5568934SJose.Borrego@Sun.COM void 5575331Samw smb_node_rename( 5588934SJose.Borrego@Sun.COM smb_node_t *from_dnode, 5598934SJose.Borrego@Sun.COM smb_node_t *ret_node, 5608934SJose.Borrego@Sun.COM smb_node_t *to_dnode, 5615331Samw char *to_name) 5625331Samw { 5638934SJose.Borrego@Sun.COM SMB_NODE_VALID(from_dnode); 5648934SJose.Borrego@Sun.COM SMB_NODE_VALID(to_dnode); 5658934SJose.Borrego@Sun.COM SMB_NODE_VALID(ret_node); 5665331Samw 5678934SJose.Borrego@Sun.COM smb_node_ref(to_dnode); 5688934SJose.Borrego@Sun.COM mutex_enter(&ret_node->n_mutex); 5698934SJose.Borrego@Sun.COM switch (ret_node->n_state) { 5708934SJose.Borrego@Sun.COM case SMB_NODE_STATE_AVAILABLE: 5718934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 5728934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 5738934SJose.Borrego@Sun.COM ret_node->dir_snode = to_dnode; 5748934SJose.Borrego@Sun.COM mutex_exit(&ret_node->n_mutex); 5758934SJose.Borrego@Sun.COM ASSERT(to_dnode->dir_snode != ret_node); 5768934SJose.Borrego@Sun.COM ASSERT((to_dnode->vp->v_xattrdir) || 5778934SJose.Borrego@Sun.COM (to_dnode->vp->v_type == VDIR)); 5788934SJose.Borrego@Sun.COM smb_node_release(from_dnode); 5798934SJose.Borrego@Sun.COM (void) strcpy(ret_node->od_name, to_name); 5808934SJose.Borrego@Sun.COM /* 5818934SJose.Borrego@Sun.COM * XXX Need to update attributes? 5828934SJose.Borrego@Sun.COM */ 5838934SJose.Borrego@Sun.COM break; 5848934SJose.Borrego@Sun.COM default: 5858934SJose.Borrego@Sun.COM SMB_PANIC(); 5868934SJose.Borrego@Sun.COM } 5875331Samw } 5885331Samw 5895331Samw int 5906139Sjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root) 5915331Samw { 5926139Sjb150015 smb_attr_t va; 5936139Sjb150015 int error; 5946139Sjb150015 uint32_t hashkey; 5956139Sjb150015 smb_llist_t *node_hdr; 5966139Sjb150015 smb_node_t *node; 5975331Samw 5986139Sjb150015 va.sa_mask = SMB_AT_ALL; 5996139Sjb150015 error = smb_vop_getattr(vp, NULL, &va, 0, kcred); 6006139Sjb150015 if (error) { 6016139Sjb150015 VN_RELE(vp); 6026139Sjb150015 return (error); 6036139Sjb150015 } 6046139Sjb150015 6058934SJose.Borrego@Sun.COM node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &va, &hashkey); 6065331Samw 6078934SJose.Borrego@Sun.COM node = smb_node_alloc(ROOTVOL, vp, &va, node_hdr, hashkey); 6086139Sjb150015 6096139Sjb150015 sv->si_root_smb_node = node; 6108934SJose.Borrego@Sun.COM smb_node_audit(node); 6116139Sjb150015 smb_llist_enter(node_hdr, RW_WRITER); 6126139Sjb150015 smb_llist_insert_head(node_hdr, node); 6136139Sjb150015 smb_llist_exit(node_hdr); 6146139Sjb150015 *root = node; 6156139Sjb150015 return (0); 6165331Samw } 6175331Samw 6185331Samw /* 6195331Samw * smb_node_get_size 6205331Samw */ 6216432Sas200622 u_offset_t 6226432Sas200622 smb_node_get_size(smb_node_t *node, smb_attr_t *attr) 6235331Samw { 6246432Sas200622 u_offset_t size; 6255331Samw 6265331Samw if (attr->sa_vattr.va_type == VDIR) 6275331Samw return (0); 6285331Samw 6298934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 6305331Samw if (node && (node->flags & NODE_FLAGS_SET_SIZE)) 6315331Samw size = node->n_size; 6325331Samw else 6335331Samw size = attr->sa_vattr.va_size; 6348934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 6355331Samw return (size); 6365331Samw } 6375331Samw 6385331Samw static int 6395331Samw timeval_cmp(timestruc_t *a, timestruc_t *b) 6405331Samw { 6415331Samw if (a->tv_sec < b->tv_sec) 6425331Samw return (-1); 6435331Samw if (a->tv_sec > b->tv_sec) 6445331Samw return (1); 6455331Samw /* Seconds are equal compare tv_nsec */ 6465331Samw if (a->tv_nsec < b->tv_nsec) 6475331Samw return (-1); 6485331Samw return (a->tv_nsec > b->tv_nsec); 6495331Samw } 6505331Samw 6515331Samw /* 6525331Samw * smb_node_set_time 6535331Samw * 6545331Samw * This function will update the time stored in the node and 6557348SJose.Borrego@Sun.COM * set the appropriate flags. If there is nothing to update, 6567348SJose.Borrego@Sun.COM * the function will return without any updates. The update 6577348SJose.Borrego@Sun.COM * is only in the node level and the attribute in the file system 6587348SJose.Borrego@Sun.COM * will be updated when client close the file. 6595331Samw */ 6605331Samw void 6618934SJose.Borrego@Sun.COM smb_node_set_time( 6628934SJose.Borrego@Sun.COM smb_node_t *node, 6638934SJose.Borrego@Sun.COM timestruc_t *crtime, 6648934SJose.Borrego@Sun.COM timestruc_t *mtime, 6658934SJose.Borrego@Sun.COM timestruc_t *atime, 6668934SJose.Borrego@Sun.COM timestruc_t *ctime, 6678934SJose.Borrego@Sun.COM uint_t what) 6685331Samw { 6697348SJose.Borrego@Sun.COM if (what == 0) 6705331Samw return; 6715331Samw 6725331Samw if ((what & SMB_AT_CRTIME && crtime == 0) || 6735331Samw (what & SMB_AT_MTIME && mtime == 0) || 6745331Samw (what & SMB_AT_ATIME && atime == 0) || 6757348SJose.Borrego@Sun.COM (what & SMB_AT_CTIME && ctime == 0)) 6765331Samw return; 6777348SJose.Borrego@Sun.COM 6788934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 6795331Samw 6805331Samw if ((what & SMB_AT_CRTIME) && 6815331Samw timeval_cmp((timestruc_t *)&node->attr.sa_crtime, 6825331Samw crtime) != 0) { 6835331Samw node->what |= SMB_AT_CRTIME; 6845331Samw node->attr.sa_crtime = *((timestruc_t *)crtime); 6855331Samw } 6865331Samw 6875331Samw if ((what & SMB_AT_MTIME) && 6885331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime, 6895331Samw mtime) != 0) { 6905331Samw node->what |= SMB_AT_MTIME; 6915331Samw node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime); 6925331Samw } 6935331Samw 6945331Samw if ((what & SMB_AT_ATIME) && 6955331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime, 6965331Samw atime) != 0) { 6975331Samw node->what |= SMB_AT_ATIME; 6985331Samw node->attr.sa_vattr.va_atime = *((timestruc_t *)atime); 6995331Samw } 7005331Samw 7015331Samw /* 7025331Samw * The ctime handling is trickier. It has three scenarios. 7035331Samw * 1. Only ctime need to be set and it is the same as the ctime 7045331Samw * stored in the node. (update not necessary) 7055331Samw * 2. The ctime is the same as the ctime stored in the node but 7065331Samw * is not the only time need to be set. (update required) 7075331Samw * 3. The ctime need to be set and is not the same as the ctime 7085331Samw * stored in the node. (update required) 7095331Samw * Unlike other time setting, the ctime needs to be set even when 7105331Samw * it is the same as the ctime in the node if there are other time 7115331Samw * needs to be set (#2). This will ensure the ctime not being 7125331Samw * updated when other times are being updated in the file system. 7135331Samw * 7145331Samw * Retained file rules: 7155331Samw * 7165331Samw * 1. Don't add SMB_AT_CTIME to node->what by default because the 7175331Samw * request will be rejected by filesystem 7185331Samw * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e. 7195331Samw * any request for changing ctime on these files should have 7205331Samw * been already rejected 7215331Samw */ 7225331Samw node->what |= SMB_AT_CTIME; 7235331Samw if (what & SMB_AT_CTIME) { 7245331Samw if ((what == SMB_AT_CTIME) && 7255331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime, 7265331Samw ctime) == 0) { 7275331Samw node->what &= ~SMB_AT_CTIME; 7285331Samw } else { 7295331Samw gethrestime(&node->attr.sa_vattr.va_ctime); 7305331Samw } 7315331Samw } else { 7325331Samw gethrestime(&node->attr.sa_vattr.va_ctime); 7335331Samw } 7348934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 7355331Samw } 7365331Samw 7375331Samw 7385331Samw timestruc_t * 7395331Samw smb_node_get_crtime(smb_node_t *node) 7405331Samw { 7415331Samw return ((timestruc_t *)&node->attr.sa_crtime); 7425331Samw } 7435331Samw 7445331Samw timestruc_t * 7455331Samw smb_node_get_atime(smb_node_t *node) 7465331Samw { 7475331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_atime); 7485331Samw } 7495331Samw 7505331Samw timestruc_t * 7515331Samw smb_node_get_ctime(smb_node_t *node) 7525331Samw { 7535331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_ctime); 7545331Samw } 7555331Samw 7565331Samw timestruc_t * 7575331Samw smb_node_get_mtime(smb_node_t *node) 7585331Samw { 7595331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_mtime); 7605331Samw } 7615331Samw 7625331Samw /* 7635331Samw * smb_node_set_dosattr 7645331Samw * 7655331Samw * Parse the specified DOS attributes and, if they have been modified, 7665331Samw * update the node cache. This call should be followed by a 7675331Samw * smb_sync_fsattr() call to write the attribute changes to filesystem. 7685331Samw */ 7695331Samw void 7707052Samw smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr) 7715331Samw { 7727052Samw uint32_t mode = dosattr & (FILE_ATTRIBUTE_ARCHIVE | 7737052Samw FILE_ATTRIBUTE_READONLY | 7747052Samw FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); 7755331Samw 7768934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 7775331Samw if (node->attr.sa_dosattr != mode) { 7785331Samw node->attr.sa_dosattr = mode; 7795331Samw node->what |= SMB_AT_DOSATTR; 7805331Samw } 7818934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 7825331Samw } 7835331Samw 7845331Samw /* 7857348SJose.Borrego@Sun.COM * smb_node_get_dosattr() 7865331Samw * 7877348SJose.Borrego@Sun.COM * This function is used to provide clients with information as to whether 7887348SJose.Borrego@Sun.COM * the readonly bit is set. Hence both the node attribute cache (which 7897348SJose.Borrego@Sun.COM * reflects the on-disk attributes) and node->readonly_creator (which 7907348SJose.Borrego@Sun.COM * reflects whether a readonly set is pending from a readonly create) are 7917348SJose.Borrego@Sun.COM * checked. In the latter case, the readonly attribute should be visible to 7927348SJose.Borrego@Sun.COM * all clients even though the readonly creator fid is immune to the readonly 7937348SJose.Borrego@Sun.COM * bit until close. 7945331Samw */ 7957348SJose.Borrego@Sun.COM 7965331Samw uint32_t 7975331Samw smb_node_get_dosattr(smb_node_t *node) 7985331Samw { 7997348SJose.Borrego@Sun.COM uint32_t dosattr = node->attr.sa_dosattr; 8007348SJose.Borrego@Sun.COM 8017348SJose.Borrego@Sun.COM if (node->readonly_creator) 8027348SJose.Borrego@Sun.COM dosattr |= FILE_ATTRIBUTE_READONLY; 8037348SJose.Borrego@Sun.COM 8047348SJose.Borrego@Sun.COM if (!dosattr) 8057348SJose.Borrego@Sun.COM dosattr = FILE_ATTRIBUTE_NORMAL; 8067348SJose.Borrego@Sun.COM 8077348SJose.Borrego@Sun.COM return (dosattr); 8085331Samw } 8095331Samw 810*9231SAfshin.Ardakani@Sun.COM /* 811*9231SAfshin.Ardakani@Sun.COM * When DeleteOnClose is set on an smb_node, the common open code will 812*9231SAfshin.Ardakani@Sun.COM * reject subsequent open requests for the file. Observation of Windows 813*9231SAfshin.Ardakani@Sun.COM * 2000 indicates that subsequent opens should be allowed (assuming 814*9231SAfshin.Ardakani@Sun.COM * there would be no sharing violation) until the file is closed using 815*9231SAfshin.Ardakani@Sun.COM * the fid on which the DeleteOnClose was requested. 816*9231SAfshin.Ardakani@Sun.COM * 817*9231SAfshin.Ardakani@Sun.COM * If there are multiple opens with delete-on-close create options, 818*9231SAfshin.Ardakani@Sun.COM * whichever the first file handle is closed will trigger the node to be 819*9231SAfshin.Ardakani@Sun.COM * marked as delete-on-close. The credentials of that ofile will be used 820*9231SAfshin.Ardakani@Sun.COM * as the delete-on-close credentials of the node. 821*9231SAfshin.Ardakani@Sun.COM */ 8225331Samw int 823*9231SAfshin.Ardakani@Sun.COM smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags) 8245331Samw { 8255331Samw int rc = -1; 8265331Samw 8278934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 8285331Samw if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) && 8295331Samw !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) { 8305331Samw crhold(cr); 8315331Samw node->delete_on_close_cred = cr; 832*9231SAfshin.Ardakani@Sun.COM node->n_delete_on_close_flags = flags; 8335331Samw node->flags |= NODE_FLAGS_DELETE_ON_CLOSE; 8345331Samw rc = 0; 8355331Samw } 8368934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 8375331Samw return (rc); 8385331Samw } 8395331Samw 8405331Samw void 8415331Samw smb_node_reset_delete_on_close(smb_node_t *node) 8425331Samw { 8438934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 8445331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 8455331Samw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 8465331Samw crfree(node->delete_on_close_cred); 8475331Samw node->delete_on_close_cred = NULL; 848*9231SAfshin.Ardakani@Sun.COM node->n_delete_on_close_flags = 0; 8495331Samw } 8508934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 8515331Samw } 8525772Sas200622 8535772Sas200622 /* 8546771Sjb150015 * smb_node_open_check 8555772Sas200622 * 8565772Sas200622 * check file sharing rules for current open request 8575772Sas200622 * against all existing opens for a file. 8585772Sas200622 * 8595772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 8605772Sas200622 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 8615772Sas200622 */ 8625772Sas200622 uint32_t 8638934SJose.Borrego@Sun.COM smb_node_open_check( 8648934SJose.Borrego@Sun.COM smb_node_t *node, 8658934SJose.Borrego@Sun.COM cred_t *cr, 8668934SJose.Borrego@Sun.COM uint32_t desired_access, 8678934SJose.Borrego@Sun.COM uint32_t share_access) 8685772Sas200622 { 8695772Sas200622 smb_ofile_t *of; 8705772Sas200622 uint32_t status; 8715772Sas200622 8728934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 8735772Sas200622 8745772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 8755772Sas200622 of = smb_llist_head(&node->n_ofile_list); 8765772Sas200622 while (of) { 8776771Sjb150015 status = smb_ofile_open_check(of, cr, desired_access, 8786771Sjb150015 share_access); 8796771Sjb150015 8806771Sjb150015 switch (status) { 8816771Sjb150015 case NT_STATUS_INVALID_HANDLE: 8826771Sjb150015 case NT_STATUS_SUCCESS: 8836771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 8846771Sjb150015 break; 8856771Sjb150015 default: 8866771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 8875772Sas200622 smb_llist_exit(&node->n_ofile_list); 8885772Sas200622 return (status); 8895772Sas200622 } 8905772Sas200622 } 8916771Sjb150015 8925772Sas200622 smb_llist_exit(&node->n_ofile_list); 8935772Sas200622 return (NT_STATUS_SUCCESS); 8945772Sas200622 } 8955772Sas200622 8965772Sas200622 uint32_t 8978934SJose.Borrego@Sun.COM smb_node_rename_check(smb_node_t *node) 8985772Sas200622 { 8998934SJose.Borrego@Sun.COM smb_ofile_t *of; 9008934SJose.Borrego@Sun.COM uint32_t status; 9015772Sas200622 9028934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9035772Sas200622 9045772Sas200622 /* 9055772Sas200622 * Intra-CIFS check 9065772Sas200622 */ 9075772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 9086771Sjb150015 of = smb_llist_head(&node->n_ofile_list); 9096771Sjb150015 while (of) { 9106771Sjb150015 status = smb_ofile_rename_check(of); 9115772Sas200622 9126771Sjb150015 switch (status) { 9136771Sjb150015 case NT_STATUS_INVALID_HANDLE: 9146771Sjb150015 case NT_STATUS_SUCCESS: 9156771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 9166771Sjb150015 break; 9176771Sjb150015 default: 9186771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 9196771Sjb150015 smb_llist_exit(&node->n_ofile_list); 9206771Sjb150015 return (status); 9215772Sas200622 } 9225772Sas200622 } 9235772Sas200622 smb_llist_exit(&node->n_ofile_list); 9245772Sas200622 9255772Sas200622 /* 9265772Sas200622 * system-wide share check 9275772Sas200622 */ 9285772Sas200622 if (nbl_share_conflict(node->vp, NBL_RENAME, NULL)) 9295772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9305772Sas200622 else 9315772Sas200622 return (NT_STATUS_SUCCESS); 9325772Sas200622 } 9335772Sas200622 9346771Sjb150015 uint32_t 9355772Sas200622 smb_node_delete_check(smb_node_t *node) 9365772Sas200622 { 9378934SJose.Borrego@Sun.COM smb_ofile_t *of; 9388934SJose.Borrego@Sun.COM uint32_t status; 9395772Sas200622 9408934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9415772Sas200622 9425772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 9435772Sas200622 return (NT_STATUS_SUCCESS); 9445772Sas200622 9455772Sas200622 /* 9465772Sas200622 * intra-CIFS check 9475772Sas200622 */ 9485772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 9496771Sjb150015 of = smb_llist_head(&node->n_ofile_list); 9506771Sjb150015 while (of) { 9516771Sjb150015 status = smb_ofile_delete_check(of); 9526771Sjb150015 9536771Sjb150015 switch (status) { 9546771Sjb150015 case NT_STATUS_INVALID_HANDLE: 9556771Sjb150015 case NT_STATUS_SUCCESS: 9566771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 9576771Sjb150015 break; 9586771Sjb150015 default: 9596771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 9605772Sas200622 smb_llist_exit(&node->n_ofile_list); 9616771Sjb150015 return (status); 9625772Sas200622 } 9635772Sas200622 } 9645772Sas200622 smb_llist_exit(&node->n_ofile_list); 9655772Sas200622 9665772Sas200622 /* 9675772Sas200622 * system-wide share check 9685772Sas200622 */ 9695772Sas200622 if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL)) 9705772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9715772Sas200622 else 9725772Sas200622 return (NT_STATUS_SUCCESS); 9735772Sas200622 } 9745772Sas200622 9755772Sas200622 /* 9765772Sas200622 * smb_node_start_crit() 9775772Sas200622 * 9785772Sas200622 * Enter critical region for share reservations. 9795772Sas200622 * See comments above smb_fsop_shrlock(). 9805772Sas200622 */ 9815772Sas200622 9825772Sas200622 void 9835772Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode) 9845772Sas200622 { 9858934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, mode); 9865772Sas200622 nbl_start_crit(node->vp, mode); 9875772Sas200622 } 9885772Sas200622 9895772Sas200622 /* 9905772Sas200622 * smb_node_end_crit() 9915772Sas200622 * 9925772Sas200622 * Exit critical region for share reservations. 9935772Sas200622 */ 9945772Sas200622 9955772Sas200622 void 9965772Sas200622 smb_node_end_crit(smb_node_t *node) 9975772Sas200622 { 9985772Sas200622 nbl_end_crit(node->vp); 9998934SJose.Borrego@Sun.COM rw_exit(&node->n_lock); 10005772Sas200622 } 10015772Sas200622 10025772Sas200622 int 10035772Sas200622 smb_node_in_crit(smb_node_t *node) 10045772Sas200622 { 10058934SJose.Borrego@Sun.COM return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock)); 10068934SJose.Borrego@Sun.COM } 10078934SJose.Borrego@Sun.COM 10088934SJose.Borrego@Sun.COM void 10098934SJose.Borrego@Sun.COM smb_node_rdlock(smb_node_t *node) 10108934SJose.Borrego@Sun.COM { 10118934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, RW_READER); 10128934SJose.Borrego@Sun.COM } 10138934SJose.Borrego@Sun.COM 10148934SJose.Borrego@Sun.COM void 10158934SJose.Borrego@Sun.COM smb_node_wrlock(smb_node_t *node) 10168934SJose.Borrego@Sun.COM { 10178934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, RW_WRITER); 10188934SJose.Borrego@Sun.COM } 10198934SJose.Borrego@Sun.COM 10208934SJose.Borrego@Sun.COM void 10218934SJose.Borrego@Sun.COM smb_node_unlock(smb_node_t *node) 10228934SJose.Borrego@Sun.COM { 10238934SJose.Borrego@Sun.COM rw_exit(&node->n_lock); 10248934SJose.Borrego@Sun.COM } 10258934SJose.Borrego@Sun.COM 10268934SJose.Borrego@Sun.COM uint32_t 10278934SJose.Borrego@Sun.COM smb_node_get_ofile_count(smb_node_t *node) 10288934SJose.Borrego@Sun.COM { 10298934SJose.Borrego@Sun.COM uint32_t cntr; 10308934SJose.Borrego@Sun.COM 10318934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 10328934SJose.Borrego@Sun.COM 10338934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_READER); 10348934SJose.Borrego@Sun.COM cntr = smb_llist_get_count(&node->n_ofile_list); 10358934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 10368934SJose.Borrego@Sun.COM return (cntr); 10378934SJose.Borrego@Sun.COM } 10388934SJose.Borrego@Sun.COM 10398934SJose.Borrego@Sun.COM void 10408934SJose.Borrego@Sun.COM smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of) 10418934SJose.Borrego@Sun.COM { 10428934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 10438934SJose.Borrego@Sun.COM 10448934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_WRITER); 10458934SJose.Borrego@Sun.COM smb_llist_insert_tail(&node->n_ofile_list, of); 10468934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 10478934SJose.Borrego@Sun.COM } 10488934SJose.Borrego@Sun.COM 10498934SJose.Borrego@Sun.COM void 10508934SJose.Borrego@Sun.COM smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of) 10518934SJose.Borrego@Sun.COM { 10528934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 10538934SJose.Borrego@Sun.COM 10548934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_WRITER); 10558934SJose.Borrego@Sun.COM smb_llist_remove(&node->n_ofile_list, of); 10568934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 10578934SJose.Borrego@Sun.COM } 10588934SJose.Borrego@Sun.COM 10598934SJose.Borrego@Sun.COM void 10608934SJose.Borrego@Sun.COM smb_node_inc_open_ofiles(smb_node_t *node) 10618934SJose.Borrego@Sun.COM { 10628934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 10638934SJose.Borrego@Sun.COM 10648934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 10658934SJose.Borrego@Sun.COM node->n_open_count++; 10668934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 10678934SJose.Borrego@Sun.COM } 10688934SJose.Borrego@Sun.COM 10698934SJose.Borrego@Sun.COM void 10708934SJose.Borrego@Sun.COM smb_node_dec_open_ofiles(smb_node_t *node) 10718934SJose.Borrego@Sun.COM { 10728934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 10738934SJose.Borrego@Sun.COM 10748934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 10758934SJose.Borrego@Sun.COM node->n_open_count--; 10768934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 10778934SJose.Borrego@Sun.COM } 10788934SJose.Borrego@Sun.COM 10798934SJose.Borrego@Sun.COM uint32_t 10808934SJose.Borrego@Sun.COM smb_node_get_open_ofiles(smb_node_t *node) 10818934SJose.Borrego@Sun.COM { 10828934SJose.Borrego@Sun.COM uint32_t cnt; 10838934SJose.Borrego@Sun.COM 10848934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 10858934SJose.Borrego@Sun.COM 10868934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 10878934SJose.Borrego@Sun.COM cnt = node->n_open_count; 10888934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 10898934SJose.Borrego@Sun.COM return (cnt); 10905772Sas200622 } 10918934SJose.Borrego@Sun.COM 10928934SJose.Borrego@Sun.COM /* 10938934SJose.Borrego@Sun.COM * smb_node_alloc 10948934SJose.Borrego@Sun.COM */ 10958934SJose.Borrego@Sun.COM static smb_node_t * 10968934SJose.Borrego@Sun.COM smb_node_alloc( 10978934SJose.Borrego@Sun.COM char *od_name, 10988934SJose.Borrego@Sun.COM vnode_t *vp, 10998934SJose.Borrego@Sun.COM smb_attr_t *attr, 11008934SJose.Borrego@Sun.COM smb_llist_t *bucket, 11018934SJose.Borrego@Sun.COM uint32_t hashkey) 11028934SJose.Borrego@Sun.COM { 11038934SJose.Borrego@Sun.COM smb_node_t *node; 11048934SJose.Borrego@Sun.COM 11058934SJose.Borrego@Sun.COM node = kmem_cache_alloc(smb_node_cache, KM_SLEEP); 11068934SJose.Borrego@Sun.COM 11078934SJose.Borrego@Sun.COM if (node->n_audit_buf != NULL) 11088934SJose.Borrego@Sun.COM node->n_audit_buf->anb_index = 0; 11098934SJose.Borrego@Sun.COM 11108934SJose.Borrego@Sun.COM node->attr = *attr; 11118934SJose.Borrego@Sun.COM node->flags = NODE_FLAGS_ATTR_VALID; 11128934SJose.Borrego@Sun.COM node->n_size = node->attr.sa_vattr.va_size; 11138934SJose.Borrego@Sun.COM VN_HOLD(vp); 11148934SJose.Borrego@Sun.COM node->vp = vp; 11158934SJose.Borrego@Sun.COM node->n_refcnt = 1; 11168934SJose.Borrego@Sun.COM node->n_hash_bucket = bucket; 11178934SJose.Borrego@Sun.COM node->n_hashkey = hashkey; 11188934SJose.Borrego@Sun.COM node->n_orig_uid = 0; 11198934SJose.Borrego@Sun.COM node->readonly_creator = NULL; 11208934SJose.Borrego@Sun.COM node->waiting_event = 0; 11218934SJose.Borrego@Sun.COM node->what = 0; 11228934SJose.Borrego@Sun.COM node->n_open_count = 0; 11238934SJose.Borrego@Sun.COM node->dir_snode = NULL; 11248934SJose.Borrego@Sun.COM node->unnamed_stream_node = NULL; 11258934SJose.Borrego@Sun.COM node->delete_on_close_cred = NULL; 1126*9231SAfshin.Ardakani@Sun.COM node->n_delete_on_close_flags = 0; 11278934SJose.Borrego@Sun.COM 11288934SJose.Borrego@Sun.COM (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); 11298934SJose.Borrego@Sun.COM if (strcmp(od_name, XATTR_DIR) == 0) 11308934SJose.Borrego@Sun.COM node->flags |= NODE_XATTR_DIR; 11318934SJose.Borrego@Sun.COM 11328934SJose.Borrego@Sun.COM node->n_state = SMB_NODE_STATE_AVAILABLE; 11338934SJose.Borrego@Sun.COM node->n_magic = SMB_NODE_MAGIC; 11348934SJose.Borrego@Sun.COM return (node); 11358934SJose.Borrego@Sun.COM } 11368934SJose.Borrego@Sun.COM 11378934SJose.Borrego@Sun.COM /* 11388934SJose.Borrego@Sun.COM * smb_node_free 11398934SJose.Borrego@Sun.COM */ 11408934SJose.Borrego@Sun.COM static void 11418934SJose.Borrego@Sun.COM smb_node_free(smb_node_t *node) 11428934SJose.Borrego@Sun.COM { 11438934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 11448934SJose.Borrego@Sun.COM 11458934SJose.Borrego@Sun.COM node->n_magic = 0; 11468934SJose.Borrego@Sun.COM VERIFY(!list_link_active(&node->n_lnd)); 11478934SJose.Borrego@Sun.COM VERIFY(node->n_lock_list.ll_count == 0); 11488934SJose.Borrego@Sun.COM VERIFY(node->n_ofile_list.ll_count == 0); 11498934SJose.Borrego@Sun.COM VERIFY(node->n_oplock.ol_xthread == NULL); 11509021Samw@Sun.COM VERIFY(mutex_owner(&node->n_mutex) == NULL); 11519021Samw@Sun.COM VERIFY(!RW_LOCK_HELD(&node->n_lock)); 11528934SJose.Borrego@Sun.COM VN_RELE(node->vp); 11538934SJose.Borrego@Sun.COM kmem_cache_free(smb_node_cache, node); 11548934SJose.Borrego@Sun.COM } 11558934SJose.Borrego@Sun.COM 11568934SJose.Borrego@Sun.COM /* 11578934SJose.Borrego@Sun.COM * smb_node_constructor 11588934SJose.Borrego@Sun.COM */ 11598934SJose.Borrego@Sun.COM static int 11608934SJose.Borrego@Sun.COM smb_node_constructor(void *buf, void *un, int kmflags) 11618934SJose.Borrego@Sun.COM { 11628934SJose.Borrego@Sun.COM _NOTE(ARGUNUSED(kmflags, un)) 11638934SJose.Borrego@Sun.COM 11648934SJose.Borrego@Sun.COM smb_node_t *node = (smb_node_t *)buf; 11658934SJose.Borrego@Sun.COM 11668934SJose.Borrego@Sun.COM bzero(node, sizeof (smb_node_t)); 11678934SJose.Borrego@Sun.COM 11688934SJose.Borrego@Sun.COM smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 11698934SJose.Borrego@Sun.COM offsetof(smb_ofile_t, f_nnd)); 11708934SJose.Borrego@Sun.COM smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 11718934SJose.Borrego@Sun.COM offsetof(smb_lock_t, l_lnd)); 11728934SJose.Borrego@Sun.COM cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL); 11738934SJose.Borrego@Sun.COM rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL); 11748934SJose.Borrego@Sun.COM mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL); 11758934SJose.Borrego@Sun.COM smb_node_create_audit_buf(node, kmflags); 11768934SJose.Borrego@Sun.COM return (0); 11778934SJose.Borrego@Sun.COM } 11788934SJose.Borrego@Sun.COM 11798934SJose.Borrego@Sun.COM /* 11808934SJose.Borrego@Sun.COM * smb_node_destructor 11818934SJose.Borrego@Sun.COM */ 11828934SJose.Borrego@Sun.COM static void 11838934SJose.Borrego@Sun.COM smb_node_destructor(void *buf, void *un) 11848934SJose.Borrego@Sun.COM { 11858934SJose.Borrego@Sun.COM _NOTE(ARGUNUSED(un)) 11868934SJose.Borrego@Sun.COM 11878934SJose.Borrego@Sun.COM smb_node_t *node = (smb_node_t *)buf; 11888934SJose.Borrego@Sun.COM 11898934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(node); 11908934SJose.Borrego@Sun.COM mutex_destroy(&node->n_mutex); 11918934SJose.Borrego@Sun.COM rw_destroy(&node->n_lock); 11928934SJose.Borrego@Sun.COM cv_destroy(&node->n_oplock.ol_cv); 11938934SJose.Borrego@Sun.COM smb_llist_destructor(&node->n_lock_list); 11948934SJose.Borrego@Sun.COM smb_llist_destructor(&node->n_ofile_list); 11958934SJose.Borrego@Sun.COM } 11968934SJose.Borrego@Sun.COM 11978934SJose.Borrego@Sun.COM /* 11988934SJose.Borrego@Sun.COM * smb_node_create_audit_buf 11998934SJose.Borrego@Sun.COM */ 12008934SJose.Borrego@Sun.COM static void 12018934SJose.Borrego@Sun.COM smb_node_create_audit_buf(smb_node_t *node, int kmflags) 12028934SJose.Borrego@Sun.COM { 12038934SJose.Borrego@Sun.COM smb_audit_buf_node_t *abn; 12048934SJose.Borrego@Sun.COM 12058934SJose.Borrego@Sun.COM if (smb_audit_flags & SMB_AUDIT_NODE) { 12068934SJose.Borrego@Sun.COM abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags); 12078934SJose.Borrego@Sun.COM abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1; 12088934SJose.Borrego@Sun.COM node->n_audit_buf = abn; 12098934SJose.Borrego@Sun.COM } 12108934SJose.Borrego@Sun.COM } 12118934SJose.Borrego@Sun.COM 12128934SJose.Borrego@Sun.COM /* 12138934SJose.Borrego@Sun.COM * smb_node_destroy_audit_buf 12148934SJose.Borrego@Sun.COM */ 12158934SJose.Borrego@Sun.COM static void 12168934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(smb_node_t *node) 12178934SJose.Borrego@Sun.COM { 12188934SJose.Borrego@Sun.COM if (node->n_audit_buf != NULL) { 12198934SJose.Borrego@Sun.COM kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t)); 12208934SJose.Borrego@Sun.COM node->n_audit_buf = NULL; 12218934SJose.Borrego@Sun.COM } 12228934SJose.Borrego@Sun.COM } 12238934SJose.Borrego@Sun.COM 12248934SJose.Borrego@Sun.COM /* 12258934SJose.Borrego@Sun.COM * smb_node_audit 12268934SJose.Borrego@Sun.COM * 12278934SJose.Borrego@Sun.COM * This function saves the calling stack in the audit buffer of the node passed 12288934SJose.Borrego@Sun.COM * in. 12298934SJose.Borrego@Sun.COM */ 12308934SJose.Borrego@Sun.COM static void 12318934SJose.Borrego@Sun.COM smb_node_audit(smb_node_t *node) 12328934SJose.Borrego@Sun.COM { 12338934SJose.Borrego@Sun.COM smb_audit_buf_node_t *abn; 12348934SJose.Borrego@Sun.COM smb_audit_record_node_t *anr; 12358934SJose.Borrego@Sun.COM 12368934SJose.Borrego@Sun.COM if (node->n_audit_buf) { 12378934SJose.Borrego@Sun.COM abn = node->n_audit_buf; 12388934SJose.Borrego@Sun.COM anr = abn->anb_records; 12398934SJose.Borrego@Sun.COM anr += abn->anb_index; 12408934SJose.Borrego@Sun.COM abn->anb_index++; 12418934SJose.Borrego@Sun.COM abn->anb_index &= abn->anb_max_index; 12428934SJose.Borrego@Sun.COM anr->anr_refcnt = node->n_refcnt; 12438934SJose.Borrego@Sun.COM anr->anr_depth = getpcstack(anr->anr_stack, 12448934SJose.Borrego@Sun.COM SMB_AUDIT_STACK_DEPTH); 12458934SJose.Borrego@Sun.COM } 12468934SJose.Borrego@Sun.COM } 12478934SJose.Borrego@Sun.COM 12488934SJose.Borrego@Sun.COM static smb_llist_t * 12498934SJose.Borrego@Sun.COM smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey) 12508934SJose.Borrego@Sun.COM { 12518934SJose.Borrego@Sun.COM uint32_t hashkey; 12528934SJose.Borrego@Sun.COM 12538934SJose.Borrego@Sun.COM hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid; 12548934SJose.Borrego@Sun.COM hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 12558934SJose.Borrego@Sun.COM *phashkey = hashkey; 12568934SJose.Borrego@Sun.COM return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]); 12578934SJose.Borrego@Sun.COM } 1258