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 /* 2212065SKeyur.Desai@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 235331Samw */ 245331Samw /* 255331Samw * SMB Node State Machine 265331Samw * ---------------------- 275331Samw * 289021Samw@Sun.COM * 299021Samw@Sun.COM * +----------- Creation/Allocation 305331Samw * | 319021Samw@Sun.COM * | T0 325331Samw * | 335331Samw * v 349021Samw@Sun.COM * +----------------------------+ T1 359021Samw@Sun.COM * | SMB_NODE_STATE_AVAILABLE |--------------------+ 369021Samw@Sun.COM * +----------------------------+ | 379021Samw@Sun.COM * | ^ | 389021Samw@Sun.COM * | | v 399021Samw@Sun.COM * | | T2 +-------------------------------+ 409021Samw@Sun.COM * | |<---------| SMB_NODE_STATE_OPLOCK_GRANTED | 419021Samw@Sun.COM * | | +-------------------------------+ 429021Samw@Sun.COM * | T5 | | 439021Samw@Sun.COM * | | | T3 449021Samw@Sun.COM * | | v 459021Samw@Sun.COM * | | T4 +--------------------------------+ 469021Samw@Sun.COM * | +----------| SMB_NODE_STATE_OPLOCK_BREAKING | 479021Samw@Sun.COM * | +--------------------------------+ 489021Samw@Sun.COM * | 499021Samw@Sun.COM * v 505331Samw * +-----------------------------+ 519021Samw@Sun.COM * | SMB_NODE_STATE_DESTROYING | 529021Samw@Sun.COM * +-----------------------------+ 539021Samw@Sun.COM * | 549021Samw@Sun.COM * | 559021Samw@Sun.COM * | T6 569021Samw@Sun.COM * | 579021Samw@Sun.COM * +----------> Deletion/Free 585331Samw * 595331Samw * Transition T0 605331Samw * 615331Samw * This transition occurs in smb_node_lookup(). If the node looked for is 625331Samw * not found in the has table a new node is created. The reference count is 635331Samw * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE. 645331Samw * 655331Samw * Transition T1 665331Samw * 679021Samw@Sun.COM * This transition occurs smb_oplock_acquire() during an OPEN. 689021Samw@Sun.COM * 699021Samw@Sun.COM * Transition T2 709021Samw@Sun.COM * 719021Samw@Sun.COM * This transition occurs in smb_oplock_release(). The events triggering 729021Samw@Sun.COM * it are: 739021Samw@Sun.COM * 749021Samw@Sun.COM * - LockingAndX sent by the client that was granted the oplock. 759021Samw@Sun.COM * - Closing of the file. 769021Samw@Sun.COM * 779021Samw@Sun.COM * Transition T3 789021Samw@Sun.COM * 799021Samw@Sun.COM * This transition occurs in smb_oplock_break(). The events triggering 809021Samw@Sun.COM * it are: 819021Samw@Sun.COM * 829021Samw@Sun.COM * - Another client wants to open the file. 839021Samw@Sun.COM * - A client is trying to delete the file. 849021Samw@Sun.COM * - A client is trying to rename the file. 859021Samw@Sun.COM * - A client is trying to set/modify the file attributes. 869021Samw@Sun.COM * 879021Samw@Sun.COM * Transition T4 889021Samw@Sun.COM * 899021Samw@Sun.COM * This transition occurs in smb_oplock_release or smb_oplock_break(). The 909021Samw@Sun.COM * events triggering it are: 919021Samw@Sun.COM * 929021Samw@Sun.COM * - The client that was granting the oplock releases it (close or 939021Samw@Sun.COM * LockingAndx). 949021Samw@Sun.COM * - The time alloted to release the oplock expired. 959021Samw@Sun.COM * 969021Samw@Sun.COM * Transition T5 979021Samw@Sun.COM * 985331Samw * This transition occurs in smb_node_release(). If the reference count 995331Samw * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more 1005331Samw * reference count will be given out for that node. 1015331Samw * 1029021Samw@Sun.COM * Transition T6 1035331Samw * 1045331Samw * This transition occurs in smb_node_release(). The structure is deleted. 1055331Samw * 1065331Samw * Comments 1075331Samw * -------- 1085331Samw * 1095331Samw * The reason the smb node has 2 states is the following synchronization 1105331Samw * rule: 1115331Samw * 1125331Samw * There's a mutex embedded in the node used to protect its fields and 1135331Samw * there's a lock embedded in the bucket of the hash table the node belongs 1145331Samw * to. To increment or to decrement the reference count the mutex must be 1155331Samw * entered. To insert the node into the bucket and to remove it from the 1165331Samw * bucket the lock must be entered in RW_WRITER mode. When both (mutex and 1175331Samw * lock) have to be entered, the lock has always to be entered first then 1185331Samw * the mutex. This prevents a deadlock between smb_node_lookup() and 1195331Samw * smb_node_release() from occurring. However, in smb_node_release() when the 1205331Samw * reference count drops to zero and triggers the deletion of the node, the 1215331Samw * mutex has to be released before entering the lock of the bucket (to 1225331Samw * remove the node). This creates a window during which the node that is 1235331Samw * about to be freed could be given out by smb_node_lookup(). To close that 1245331Samw * window the node is moved to the state SMB_NODE_STATE_DESTROYING before 1255331Samw * releasing the mutex. That way, even if smb_node_lookup() finds it, the 1265331Samw * state will indicate that the node should be treated as non existent (of 1275331Samw * course the state of the node should be tested/updated under the 1285331Samw * protection of the mutex). 1295331Samw */ 13010966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h> 1315331Samw #include <smbsrv/smb_fsops.h> 1328934SJose.Borrego@Sun.COM #include <smbsrv/smb_kstat.h> 1335331Samw #include <sys/pathname.h> 1345331Samw #include <sys/sdt.h> 1355772Sas200622 #include <sys/nbmlock.h> 13611963SAfshin.Ardakani@Sun.COM #include <fs/fs_reparse.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 *); 14310001SJoyce.McIntosh@Sun.COM static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t); 1448934SJose.Borrego@Sun.COM static void smb_node_free(smb_node_t *); 1458934SJose.Borrego@Sun.COM static int smb_node_constructor(void *, void *, int); 1468934SJose.Borrego@Sun.COM static void smb_node_destructor(void *, void *); 1478934SJose.Borrego@Sun.COM static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *); 14810504SKeyur.Desai@Sun.COM 14910504SKeyur.Desai@Sun.COM static void smb_node_init_cached_data(smb_node_t *); 15010504SKeyur.Desai@Sun.COM static void smb_node_clear_cached_data(smb_node_t *); 15110504SKeyur.Desai@Sun.COM 15210504SKeyur.Desai@Sun.COM static void smb_node_init_cached_timestamps(smb_node_t *, smb_attr_t *); 15310001SJoyce.McIntosh@Sun.COM static void smb_node_clear_cached_timestamps(smb_node_t *); 15410001SJoyce.McIntosh@Sun.COM static void smb_node_get_cached_timestamps(smb_node_t *, smb_attr_t *); 15510001SJoyce.McIntosh@Sun.COM static void smb_node_set_cached_timestamps(smb_node_t *, smb_attr_t *); 1565331Samw 15710504SKeyur.Desai@Sun.COM static void smb_node_init_cached_allocsz(smb_node_t *, smb_attr_t *); 15810504SKeyur.Desai@Sun.COM static void smb_node_clear_cached_allocsz(smb_node_t *); 15910504SKeyur.Desai@Sun.COM static void smb_node_get_cached_allocsz(smb_node_t *, smb_attr_t *); 16010504SKeyur.Desai@Sun.COM static void smb_node_set_cached_allocsz(smb_node_t *, smb_attr_t *); 16111963SAfshin.Ardakani@Sun.COM static void smb_node_init_reparse(smb_node_t *, smb_attr_t *); 16211963SAfshin.Ardakani@Sun.COM static void smb_node_init_system(smb_node_t *); 16310504SKeyur.Desai@Sun.COM 1645331Samw #define VALIDATE_DIR_NODE(_dir_, _node_) \ 1655331Samw ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \ 1665331Samw ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \ 16710122SJordan.Brown@Sun.COM ASSERT((_dir_)->n_dnode != (_node_)); 1685331Samw 16910504SKeyur.Desai@Sun.COM /* round sz to DEV_BSIZE block */ 17010504SKeyur.Desai@Sun.COM #define SMB_ALLOCSZ(sz) (((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1)) 17110504SKeyur.Desai@Sun.COM 1728934SJose.Borrego@Sun.COM static kmem_cache_t *smb_node_cache = NULL; 1736139Sjb150015 static boolean_t smb_node_initialized = B_FALSE; 1746139Sjb150015 static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1]; 1756139Sjb150015 1766139Sjb150015 /* 1776139Sjb150015 * smb_node_init 1786139Sjb150015 * 1796139Sjb150015 * Initialization of the SMB node layer. 1806139Sjb150015 * 1816139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 1826139Sjb150015 * thread makes the call. 1836139Sjb150015 */ 1846139Sjb150015 int 1856139Sjb150015 smb_node_init(void) 1866139Sjb150015 { 1876139Sjb150015 int i; 1886139Sjb150015 1896139Sjb150015 if (smb_node_initialized) 1906139Sjb150015 return (0); 1918934SJose.Borrego@Sun.COM smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE, 1928934SJose.Borrego@Sun.COM sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor, 1938934SJose.Borrego@Sun.COM NULL, NULL, NULL, 0); 1946139Sjb150015 1956139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 1966139Sjb150015 smb_llist_constructor(&smb_node_hash_table[i], 1976139Sjb150015 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 1986139Sjb150015 } 1996139Sjb150015 smb_node_initialized = B_TRUE; 2006139Sjb150015 return (0); 2016139Sjb150015 } 2026139Sjb150015 2036139Sjb150015 /* 2046139Sjb150015 * smb_node_fini 2056139Sjb150015 * 2066139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 2076139Sjb150015 * thread makes the call. 2086139Sjb150015 */ 2096139Sjb150015 void 2106139Sjb150015 smb_node_fini(void) 2116139Sjb150015 { 2126139Sjb150015 int i; 2136139Sjb150015 2146139Sjb150015 if (!smb_node_initialized) 2156139Sjb150015 return; 2166139Sjb150015 2176139Sjb150015 #ifdef DEBUG 2186139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 2196139Sjb150015 smb_node_t *node; 2206139Sjb150015 2216139Sjb150015 /* 2226139Sjb150015 * The following sequence is just intended for sanity check. 2236139Sjb150015 * This will have to be modified when the code goes into 2246139Sjb150015 * production. 2256139Sjb150015 * 2266139Sjb150015 * The SMB node hash table should be emtpy at this point. If the 2276139Sjb150015 * hash table is not empty a panic will be triggered. 2286139Sjb150015 * 2296139Sjb150015 * The reason why SMB nodes are still remaining in the hash 2306139Sjb150015 * table is problably due to a mismatch between calls to 2316139Sjb150015 * smb_node_lookup() and smb_node_release(). You must track that 2326139Sjb150015 * down. 2336139Sjb150015 */ 2346139Sjb150015 node = smb_llist_head(&smb_node_hash_table[i]); 2356139Sjb150015 ASSERT(node == NULL); 2366139Sjb150015 } 2376139Sjb150015 #endif 2386139Sjb150015 2396139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 2406139Sjb150015 smb_llist_destructor(&smb_node_hash_table[i]); 2416139Sjb150015 } 2428934SJose.Borrego@Sun.COM kmem_cache_destroy(smb_node_cache); 2438934SJose.Borrego@Sun.COM smb_node_cache = NULL; 2446139Sjb150015 smb_node_initialized = B_FALSE; 2456139Sjb150015 } 2466139Sjb150015 2475331Samw /* 2485331Samw * smb_node_lookup() 2495331Samw * 2505331Samw * NOTE: This routine should only be called by the file system interface layer, 2515331Samw * and not by SMB. 2525331Samw * 2535331Samw * smb_node_lookup() is called upon successful lookup, mkdir, and create 2545331Samw * (for both non-streams and streams). In each of these cases, a held vnode is 2558670SJose.Borrego@Sun.COM * passed into this routine. If a new smb_node is created it will take its 2568670SJose.Borrego@Sun.COM * own hold on the vnode. The caller's hold therefore still belongs to, and 2578670SJose.Borrego@Sun.COM * should be released by, the caller. 2585331Samw * 2595331Samw * A reference is taken on the smb_node whether found in the hash table 2605331Samw * or newly created. 2615331Samw * 2625331Samw * If an smb_node needs to be created, a reference is also taken on the 26310122SJordan.Brown@Sun.COM * dnode (if passed in). 2645331Samw * 2655331Samw * See smb_node_release() for details on the release of these references. 2665331Samw */ 2675331Samw 2685331Samw /*ARGSUSED*/ 2695331Samw smb_node_t * 2705331Samw smb_node_lookup( 2715331Samw struct smb_request *sr, 2725331Samw struct open_param *op, 2735331Samw cred_t *cred, 2745331Samw vnode_t *vp, 2755331Samw char *od_name, 27610122SJordan.Brown@Sun.COM smb_node_t *dnode, 27710122SJordan.Brown@Sun.COM smb_node_t *unode) 2785331Samw { 2795331Samw smb_llist_t *node_hdr; 2805331Samw smb_node_t *node; 28110001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 2825331Samw uint32_t hashkey = 0; 2837348SJose.Borrego@Sun.COM fsid_t fsid; 2845331Samw int error; 2855331Samw krw_t lock_mode; 2865331Samw vnode_t *unnamed_vp = NULL; 2875331Samw 2885331Samw /* 2895331Samw * smb_vop_getattr() is called here instead of smb_fsop_getattr(), 2905331Samw * because the node may not yet exist. We also do not want to call 2915331Samw * it with the list lock held. 2925331Samw */ 2935331Samw 29410122SJordan.Brown@Sun.COM if (unode) 29510122SJordan.Brown@Sun.COM unnamed_vp = unode->vp; 2965331Samw 2975331Samw /* 2985331Samw * This getattr is performed on behalf of the server 2995331Samw * that's why kcred is used not the user's cred 3005331Samw */ 30110001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_ALL; 30210001SJoyce.McIntosh@Sun.COM error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, kcred); 3035331Samw if (error) 3045331Samw return (NULL); 3055331Samw 3067348SJose.Borrego@Sun.COM if (sr && sr->tid_tree) { 3077348SJose.Borrego@Sun.COM /* 3087348SJose.Borrego@Sun.COM * The fsid for a file is that of the tree, even 3097348SJose.Borrego@Sun.COM * if the file resides in a different mountpoint 3107348SJose.Borrego@Sun.COM * under the share. 3117348SJose.Borrego@Sun.COM */ 3127348SJose.Borrego@Sun.COM fsid = SMB_TREE_FSID(sr->tid_tree); 3135331Samw } else { 3147348SJose.Borrego@Sun.COM /* 3157348SJose.Borrego@Sun.COM * This should be getting executed only for the 3167348SJose.Borrego@Sun.COM * tree root smb_node. 3177348SJose.Borrego@Sun.COM */ 3187348SJose.Borrego@Sun.COM fsid = vp->v_vfsp->vfs_fsid; 3195331Samw } 3205331Samw 32110001SJoyce.McIntosh@Sun.COM node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey); 3225331Samw lock_mode = RW_READER; 3235331Samw 3245331Samw smb_llist_enter(node_hdr, lock_mode); 3255331Samw for (;;) { 3265331Samw node = list_head(&node_hdr->ll_list); 3275331Samw while (node) { 3285331Samw ASSERT(node->n_magic == SMB_NODE_MAGIC); 3295331Samw ASSERT(node->n_hash_bucket == node_hdr); 3305331Samw if ((node->n_hashkey == hashkey) && (node->vp == vp)) { 3318934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 3325331Samw DTRACE_PROBE1(smb_node_lookup_hit, 3335331Samw smb_node_t *, node); 3345331Samw switch (node->n_state) { 3358934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 3368934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 3375331Samw case SMB_NODE_STATE_AVAILABLE: 3385331Samw /* The node was found. */ 3395331Samw node->n_refcnt++; 34010122SJordan.Brown@Sun.COM if ((node->n_dnode == NULL) && 34110122SJordan.Brown@Sun.COM (dnode != NULL) && 34211633SJoyce.McIntosh@Sun.COM (node != dnode) && 3435331Samw (strcmp(od_name, "..") != 0) && 3445331Samw (strcmp(od_name, ".") != 0)) { 34510122SJordan.Brown@Sun.COM VALIDATE_DIR_NODE(dnode, node); 34610122SJordan.Brown@Sun.COM node->n_dnode = dnode; 34710122SJordan.Brown@Sun.COM smb_node_ref(dnode); 3485331Samw } 3495331Samw 3508934SJose.Borrego@Sun.COM smb_node_audit(node); 3518934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 3525331Samw smb_llist_exit(node_hdr); 3535331Samw return (node); 3545331Samw 3555331Samw case SMB_NODE_STATE_DESTROYING: 3565331Samw /* 3575331Samw * Although the node exists it is about 3585331Samw * to be destroyed. We act as it hasn't 3595331Samw * been found. 3605331Samw */ 3618934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 3625331Samw break; 3635331Samw default: 3645331Samw /* 3655331Samw * Although the node exists it is in an 3665331Samw * unknown state. We act as it hasn't 3675331Samw * been found. 3685331Samw */ 3695331Samw ASSERT(0); 3708934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 3715331Samw break; 3725331Samw } 3735331Samw } 3745331Samw node = smb_llist_next(node_hdr, node); 3755331Samw } 3765331Samw if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) { 3775331Samw lock_mode = RW_WRITER; 3785331Samw continue; 3795331Samw } 3805331Samw break; 3815331Samw } 38210001SJoyce.McIntosh@Sun.COM node = smb_node_alloc(od_name, vp, node_hdr, hashkey); 38311963SAfshin.Ardakani@Sun.COM smb_node_init_reparse(node, &attr); 3845331Samw 3855331Samw if (op) 3869343SAfshin.Ardakani@Sun.COM node->flags |= smb_is_executable(op->fqi.fq_last_comp); 3875331Samw 38810122SJordan.Brown@Sun.COM if (dnode) { 38910122SJordan.Brown@Sun.COM smb_node_ref(dnode); 39010122SJordan.Brown@Sun.COM node->n_dnode = dnode; 39110122SJordan.Brown@Sun.COM ASSERT(dnode->n_dnode != node); 39210122SJordan.Brown@Sun.COM ASSERT((dnode->vp->v_xattrdir) || 39310122SJordan.Brown@Sun.COM (dnode->vp->v_type == VDIR)); 3945331Samw } 3955331Samw 39610122SJordan.Brown@Sun.COM if (unode) { 39710122SJordan.Brown@Sun.COM smb_node_ref(unode); 39810122SJordan.Brown@Sun.COM node->n_unode = unode; 3995331Samw } 4005331Samw 40111963SAfshin.Ardakani@Sun.COM smb_node_init_system(node); 40211963SAfshin.Ardakani@Sun.COM 4035331Samw DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node); 4048934SJose.Borrego@Sun.COM smb_node_audit(node); 4055331Samw smb_llist_insert_head(node_hdr, node); 4065331Samw smb_llist_exit(node_hdr); 4075331Samw return (node); 4085331Samw } 4095331Samw 4105331Samw /* 4115331Samw * smb_stream_node_lookup() 4125331Samw * 4135331Samw * Note: stream_name (the name that will be stored in the "od_name" field 4145331Samw * of a stream's smb_node) is the same as the on-disk name for the stream 4155331Samw * except that it does not have SMB_STREAM_PREFIX prepended. 4165331Samw */ 4175331Samw 4185331Samw smb_node_t * 4198934SJose.Borrego@Sun.COM smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode, 42010001SJoyce.McIntosh@Sun.COM vnode_t *xattrdirvp, vnode_t *vp, char *stream_name) 4215331Samw { 4225331Samw smb_node_t *xattrdir_node; 4235331Samw smb_node_t *snode; 4245331Samw 4255331Samw xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR, 42610001SJoyce.McIntosh@Sun.COM fnode, NULL); 4275331Samw 4285331Samw if (xattrdir_node == NULL) 4295331Samw return (NULL); 4305331Samw 4315331Samw snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node, 43210001SJoyce.McIntosh@Sun.COM fnode); 4335331Samw 4345331Samw (void) smb_node_release(xattrdir_node); 4355331Samw return (snode); 4365331Samw } 4375331Samw 4385331Samw 4395331Samw /* 4405331Samw * This function should be called whenever a reference is needed on an 4415331Samw * smb_node pointer. The copy of an smb_node pointer from one non-local 4425331Samw * data structure to another requires a reference to be taken on the smb_node 4435331Samw * (unless the usage is localized). Each data structure deallocation routine 4445331Samw * will call smb_node_release() on its smb_node pointers. 4455331Samw * 4465331Samw * In general, an smb_node pointer residing in a structure should never be 4475331Samw * stale. A node pointer may be NULL, however, and care should be taken 4485331Samw * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid. 4495331Samw * Care also needs to be taken with respect to racing deallocations of a 4505331Samw * structure. 4515331Samw */ 4525331Samw void 4535331Samw smb_node_ref(smb_node_t *node) 4545331Samw { 4558934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 4565331Samw 4578934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 4588934SJose.Borrego@Sun.COM switch (node->n_state) { 4598934SJose.Borrego@Sun.COM case SMB_NODE_STATE_AVAILABLE: 4608934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 4618934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 4628934SJose.Borrego@Sun.COM node->n_refcnt++; 4638934SJose.Borrego@Sun.COM ASSERT(node->n_refcnt); 4648934SJose.Borrego@Sun.COM DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); 4658934SJose.Borrego@Sun.COM smb_node_audit(node); 4668934SJose.Borrego@Sun.COM break; 4678934SJose.Borrego@Sun.COM default: 4688934SJose.Borrego@Sun.COM SMB_PANIC(); 4698934SJose.Borrego@Sun.COM } 4708934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 4715331Samw } 4725331Samw 4735331Samw /* 4745331Samw * smb_node_lookup() takes a hold on an smb_node, whether found in the 4755331Samw * hash table or newly created. This hold is expected to be released 4765331Samw * in the following manner. 4775331Samw * 4785331Samw * smb_node_lookup() takes an address of an smb_node pointer. This should 4795331Samw * be getting passed down via a lookup (whether path name or component), mkdir, 4805331Samw * create. If the original smb_node pointer resides in a data structure, then 4815331Samw * the deallocation routine for the data structure is responsible for calling 4825331Samw * smb_node_release() on the smb_node pointer. Alternatively, 4835331Samw * smb_node_release() can be called as soon as the smb_node pointer is no longer 4845331Samw * needed. In this case, callers are responsible for setting an embedded 4855331Samw * pointer to NULL if it is known that the last reference is being released. 4865331Samw * 4875331Samw * If the passed-in address of the smb_node pointer belongs to a local variable, 4885331Samw * then the caller with the local variable should call smb_node_release() 4895331Samw * directly. 4905331Samw * 49110122SJordan.Brown@Sun.COM * smb_node_release() itself will call smb_node_release() on a node's n_dnode, 49210122SJordan.Brown@Sun.COM * as smb_node_lookup() takes a hold on dnode. 4935331Samw */ 4945331Samw void 4955331Samw smb_node_release(smb_node_t *node) 4965331Samw { 4978934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 4985331Samw 4998934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 5005331Samw ASSERT(node->n_refcnt); 5015331Samw DTRACE_PROBE1(smb_node_release, smb_node_t *, node); 5025331Samw if (--node->n_refcnt == 0) { 5035331Samw switch (node->n_state) { 5045331Samw 5055331Samw case SMB_NODE_STATE_AVAILABLE: 5065331Samw node->n_state = SMB_NODE_STATE_DESTROYING; 5078934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5085331Samw 5095331Samw smb_llist_enter(node->n_hash_bucket, RW_WRITER); 5105331Samw smb_llist_remove(node->n_hash_bucket, node); 5115331Samw smb_llist_exit(node->n_hash_bucket); 5125331Samw 5135331Samw /* 5145331Samw * Check if the file was deleted 5155331Samw */ 5165331Samw smb_node_delete_on_close(node); 5175331Samw 51810122SJordan.Brown@Sun.COM if (node->n_dnode) { 51910122SJordan.Brown@Sun.COM ASSERT(node->n_dnode->n_magic == 5205331Samw SMB_NODE_MAGIC); 52110122SJordan.Brown@Sun.COM smb_node_release(node->n_dnode); 5225331Samw } 5235331Samw 52410122SJordan.Brown@Sun.COM if (node->n_unode) { 52510122SJordan.Brown@Sun.COM ASSERT(node->n_unode->n_magic == 5265331Samw SMB_NODE_MAGIC); 52710122SJordan.Brown@Sun.COM smb_node_release(node->n_unode); 5285331Samw } 5295331Samw 5308934SJose.Borrego@Sun.COM smb_node_free(node); 5315331Samw return; 5325331Samw 5335331Samw default: 5348934SJose.Borrego@Sun.COM SMB_PANIC(); 5355331Samw } 5365331Samw } 5378934SJose.Borrego@Sun.COM smb_node_audit(node); 5388934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5395331Samw } 5405331Samw 5415331Samw static void 5425331Samw smb_node_delete_on_close(smb_node_t *node) 5435331Samw { 5445331Samw smb_node_t *d_snode; 5455331Samw int rc = 0; 5469231SAfshin.Ardakani@Sun.COM uint32_t flags = 0; 5475331Samw 54810122SJordan.Brown@Sun.COM d_snode = node->n_dnode; 5495331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 5509231SAfshin.Ardakani@Sun.COM node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 5519231SAfshin.Ardakani@Sun.COM flags = node->n_delete_on_close_flags; 5529231SAfshin.Ardakani@Sun.COM ASSERT(node->od_name != NULL); 5535331Samw 55411963SAfshin.Ardakani@Sun.COM if (smb_node_is_dir(node)) 5555331Samw rc = smb_fsop_rmdir(0, node->delete_on_close_cred, 5569231SAfshin.Ardakani@Sun.COM d_snode, node->od_name, flags); 5575331Samw else 5585331Samw rc = smb_fsop_remove(0, node->delete_on_close_cred, 5599231SAfshin.Ardakani@Sun.COM d_snode, node->od_name, flags); 560*12508Samw@Sun.COM crfree(node->delete_on_close_cred); 5615331Samw } 5625331Samw if (rc != 0) 5635331Samw cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n", 5645331Samw node->od_name, rc); 5655331Samw DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node); 5665331Samw } 5675331Samw 5685331Samw /* 5695331Samw * smb_node_rename() 5705331Samw * 5715331Samw */ 5728934SJose.Borrego@Sun.COM void 5735331Samw smb_node_rename( 5748934SJose.Borrego@Sun.COM smb_node_t *from_dnode, 5758934SJose.Borrego@Sun.COM smb_node_t *ret_node, 5768934SJose.Borrego@Sun.COM smb_node_t *to_dnode, 5775331Samw char *to_name) 5785331Samw { 5798934SJose.Borrego@Sun.COM SMB_NODE_VALID(from_dnode); 5808934SJose.Borrego@Sun.COM SMB_NODE_VALID(to_dnode); 5818934SJose.Borrego@Sun.COM SMB_NODE_VALID(ret_node); 5825331Samw 5838934SJose.Borrego@Sun.COM smb_node_ref(to_dnode); 5848934SJose.Borrego@Sun.COM mutex_enter(&ret_node->n_mutex); 5858934SJose.Borrego@Sun.COM switch (ret_node->n_state) { 5868934SJose.Borrego@Sun.COM case SMB_NODE_STATE_AVAILABLE: 5878934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 5888934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 58910122SJordan.Brown@Sun.COM ret_node->n_dnode = to_dnode; 5908934SJose.Borrego@Sun.COM mutex_exit(&ret_node->n_mutex); 59110122SJordan.Brown@Sun.COM ASSERT(to_dnode->n_dnode != ret_node); 5928934SJose.Borrego@Sun.COM ASSERT((to_dnode->vp->v_xattrdir) || 5938934SJose.Borrego@Sun.COM (to_dnode->vp->v_type == VDIR)); 5948934SJose.Borrego@Sun.COM smb_node_release(from_dnode); 5958934SJose.Borrego@Sun.COM (void) strcpy(ret_node->od_name, to_name); 5968934SJose.Borrego@Sun.COM /* 5978934SJose.Borrego@Sun.COM * XXX Need to update attributes? 5988934SJose.Borrego@Sun.COM */ 5998934SJose.Borrego@Sun.COM break; 6008934SJose.Borrego@Sun.COM default: 6018934SJose.Borrego@Sun.COM SMB_PANIC(); 6028934SJose.Borrego@Sun.COM } 6035331Samw } 6045331Samw 6055331Samw int 6066139Sjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root) 6075331Samw { 60810001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 6096139Sjb150015 int error; 6106139Sjb150015 uint32_t hashkey; 6116139Sjb150015 smb_llist_t *node_hdr; 6126139Sjb150015 smb_node_t *node; 6135331Samw 61410001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_ALL; 61510001SJoyce.McIntosh@Sun.COM error = smb_vop_getattr(vp, NULL, &attr, 0, kcred); 6166139Sjb150015 if (error) { 6176139Sjb150015 VN_RELE(vp); 6186139Sjb150015 return (error); 6196139Sjb150015 } 6206139Sjb150015 62110001SJoyce.McIntosh@Sun.COM node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &attr, &hashkey); 6225331Samw 62310001SJoyce.McIntosh@Sun.COM node = smb_node_alloc(ROOTVOL, vp, node_hdr, hashkey); 6246139Sjb150015 6256139Sjb150015 sv->si_root_smb_node = node; 6268934SJose.Borrego@Sun.COM smb_node_audit(node); 6276139Sjb150015 smb_llist_enter(node_hdr, RW_WRITER); 6286139Sjb150015 smb_llist_insert_head(node_hdr, node); 6296139Sjb150015 smb_llist_exit(node_hdr); 6306139Sjb150015 *root = node; 6316139Sjb150015 return (0); 6325331Samw } 6335331Samw 6345331Samw /* 6359231SAfshin.Ardakani@Sun.COM * When DeleteOnClose is set on an smb_node, the common open code will 6369231SAfshin.Ardakani@Sun.COM * reject subsequent open requests for the file. Observation of Windows 6379231SAfshin.Ardakani@Sun.COM * 2000 indicates that subsequent opens should be allowed (assuming 6389231SAfshin.Ardakani@Sun.COM * there would be no sharing violation) until the file is closed using 6399231SAfshin.Ardakani@Sun.COM * the fid on which the DeleteOnClose was requested. 6409231SAfshin.Ardakani@Sun.COM * 6419231SAfshin.Ardakani@Sun.COM * If there are multiple opens with delete-on-close create options, 6429231SAfshin.Ardakani@Sun.COM * whichever the first file handle is closed will trigger the node to be 6439231SAfshin.Ardakani@Sun.COM * marked as delete-on-close. The credentials of that ofile will be used 6449231SAfshin.Ardakani@Sun.COM * as the delete-on-close credentials of the node. 6459231SAfshin.Ardakani@Sun.COM */ 6465331Samw int 6479231SAfshin.Ardakani@Sun.COM smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags) 6485331Samw { 64910717Samw@Sun.COM int rc = 0; 65010001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 6515331Samw 65210717Samw@Sun.COM if (node->readonly_creator) 65310001SJoyce.McIntosh@Sun.COM return (-1); 65410001SJoyce.McIntosh@Sun.COM 65510001SJoyce.McIntosh@Sun.COM bzero(&attr, sizeof (smb_attr_t)); 65610001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_DOSATTR; 65710001SJoyce.McIntosh@Sun.COM rc = smb_fsop_getattr(NULL, kcred, node, &attr); 65810001SJoyce.McIntosh@Sun.COM if ((rc != 0) || (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) { 65910001SJoyce.McIntosh@Sun.COM return (-1); 66010001SJoyce.McIntosh@Sun.COM } 66110001SJoyce.McIntosh@Sun.COM 66210717Samw@Sun.COM mutex_enter(&node->n_mutex); 66310717Samw@Sun.COM if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 66410717Samw@Sun.COM rc = -1; 66510717Samw@Sun.COM } else { 66610717Samw@Sun.COM crhold(cr); 66710717Samw@Sun.COM node->delete_on_close_cred = cr; 66810717Samw@Sun.COM node->n_delete_on_close_flags = flags; 66910717Samw@Sun.COM node->flags |= NODE_FLAGS_DELETE_ON_CLOSE; 67010717Samw@Sun.COM rc = 0; 67110717Samw@Sun.COM } 6728934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 67310717Samw@Sun.COM return (rc); 6745331Samw } 6755331Samw 6765331Samw void 6775331Samw smb_node_reset_delete_on_close(smb_node_t *node) 6785331Samw { 6798934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 6805331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 6815331Samw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 6825331Samw crfree(node->delete_on_close_cred); 6835331Samw node->delete_on_close_cred = NULL; 6849231SAfshin.Ardakani@Sun.COM node->n_delete_on_close_flags = 0; 6855331Samw } 6868934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 6875331Samw } 6885772Sas200622 6895772Sas200622 /* 6906771Sjb150015 * smb_node_open_check 6915772Sas200622 * 6925772Sas200622 * check file sharing rules for current open request 6935772Sas200622 * against all existing opens for a file. 6945772Sas200622 * 6955772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 6965772Sas200622 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 6975772Sas200622 */ 6985772Sas200622 uint32_t 69911963SAfshin.Ardakani@Sun.COM smb_node_open_check(smb_node_t *node, uint32_t desired_access, 70011963SAfshin.Ardakani@Sun.COM uint32_t share_access) 7015772Sas200622 { 7025772Sas200622 smb_ofile_t *of; 7035772Sas200622 uint32_t status; 7045772Sas200622 7058934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 7065772Sas200622 7075772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 7085772Sas200622 of = smb_llist_head(&node->n_ofile_list); 7095772Sas200622 while (of) { 71011963SAfshin.Ardakani@Sun.COM status = smb_ofile_open_check(of, desired_access, share_access); 7116771Sjb150015 7126771Sjb150015 switch (status) { 7136771Sjb150015 case NT_STATUS_INVALID_HANDLE: 7146771Sjb150015 case NT_STATUS_SUCCESS: 7156771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 7166771Sjb150015 break; 7176771Sjb150015 default: 7186771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 7195772Sas200622 smb_llist_exit(&node->n_ofile_list); 7205772Sas200622 return (status); 7215772Sas200622 } 7225772Sas200622 } 7236771Sjb150015 7245772Sas200622 smb_llist_exit(&node->n_ofile_list); 7255772Sas200622 return (NT_STATUS_SUCCESS); 7265772Sas200622 } 7275772Sas200622 7285772Sas200622 uint32_t 7298934SJose.Borrego@Sun.COM smb_node_rename_check(smb_node_t *node) 7305772Sas200622 { 7318934SJose.Borrego@Sun.COM smb_ofile_t *of; 7328934SJose.Borrego@Sun.COM uint32_t status; 7335772Sas200622 7348934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 7355772Sas200622 7365772Sas200622 /* 7375772Sas200622 * Intra-CIFS check 7385772Sas200622 */ 7395772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 7406771Sjb150015 of = smb_llist_head(&node->n_ofile_list); 7416771Sjb150015 while (of) { 7426771Sjb150015 status = smb_ofile_rename_check(of); 7435772Sas200622 7446771Sjb150015 switch (status) { 7456771Sjb150015 case NT_STATUS_INVALID_HANDLE: 7466771Sjb150015 case NT_STATUS_SUCCESS: 7476771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 7486771Sjb150015 break; 7496771Sjb150015 default: 7506771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 7516771Sjb150015 smb_llist_exit(&node->n_ofile_list); 7526771Sjb150015 return (status); 7535772Sas200622 } 7545772Sas200622 } 7555772Sas200622 smb_llist_exit(&node->n_ofile_list); 7565772Sas200622 7575772Sas200622 /* 7585772Sas200622 * system-wide share check 7595772Sas200622 */ 7605772Sas200622 if (nbl_share_conflict(node->vp, NBL_RENAME, NULL)) 7615772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 7625772Sas200622 else 7635772Sas200622 return (NT_STATUS_SUCCESS); 7645772Sas200622 } 7655772Sas200622 7666771Sjb150015 uint32_t 7675772Sas200622 smb_node_delete_check(smb_node_t *node) 7685772Sas200622 { 7698934SJose.Borrego@Sun.COM smb_ofile_t *of; 7708934SJose.Borrego@Sun.COM uint32_t status; 7715772Sas200622 7728934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 7735772Sas200622 77411963SAfshin.Ardakani@Sun.COM if (smb_node_is_dir(node)) 7755772Sas200622 return (NT_STATUS_SUCCESS); 7765772Sas200622 77711963SAfshin.Ardakani@Sun.COM if (smb_node_is_reparse(node)) 77811963SAfshin.Ardakani@Sun.COM return (NT_STATUS_ACCESS_DENIED); 77911963SAfshin.Ardakani@Sun.COM 7805772Sas200622 /* 7815772Sas200622 * intra-CIFS check 7825772Sas200622 */ 7835772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 7846771Sjb150015 of = smb_llist_head(&node->n_ofile_list); 7856771Sjb150015 while (of) { 7866771Sjb150015 status = smb_ofile_delete_check(of); 7876771Sjb150015 7886771Sjb150015 switch (status) { 7896771Sjb150015 case NT_STATUS_INVALID_HANDLE: 7906771Sjb150015 case NT_STATUS_SUCCESS: 7916771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 7926771Sjb150015 break; 7936771Sjb150015 default: 7946771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 7955772Sas200622 smb_llist_exit(&node->n_ofile_list); 7966771Sjb150015 return (status); 7975772Sas200622 } 7985772Sas200622 } 7995772Sas200622 smb_llist_exit(&node->n_ofile_list); 8005772Sas200622 8015772Sas200622 /* 8025772Sas200622 * system-wide share check 8035772Sas200622 */ 8045772Sas200622 if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL)) 8055772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 8065772Sas200622 else 8075772Sas200622 return (NT_STATUS_SUCCESS); 8085772Sas200622 } 8095772Sas200622 8109914Samw@Sun.COM void 8119914Samw@Sun.COM smb_node_notify_change(smb_node_t *node) 8129914Samw@Sun.COM { 8139914Samw@Sun.COM SMB_NODE_VALID(node); 8149914Samw@Sun.COM 8159914Samw@Sun.COM if (node->flags & NODE_FLAGS_NOTIFY_CHANGE) { 8169914Samw@Sun.COM node->flags |= NODE_FLAGS_CHANGED; 8179914Samw@Sun.COM smb_process_node_notify_change_queue(node); 8189914Samw@Sun.COM } 81911963SAfshin.Ardakani@Sun.COM 82011963SAfshin.Ardakani@Sun.COM smb_node_notify_parents(node); 8219914Samw@Sun.COM } 8229914Samw@Sun.COM 82311963SAfshin.Ardakani@Sun.COM /* 82411963SAfshin.Ardakani@Sun.COM * smb_node_notify_parents 82511963SAfshin.Ardakani@Sun.COM * 82611963SAfshin.Ardakani@Sun.COM * Iterate up the directory tree notifying any parent 82711963SAfshin.Ardakani@Sun.COM * directories that are being watched for changes in 82811963SAfshin.Ardakani@Sun.COM * their sub directories. 82911963SAfshin.Ardakani@Sun.COM * Stop at the root node, which has a NULL parent node. 83011963SAfshin.Ardakani@Sun.COM */ 83111963SAfshin.Ardakani@Sun.COM void 83211963SAfshin.Ardakani@Sun.COM smb_node_notify_parents(smb_node_t *dnode) 83311337SWilliam.Krier@Sun.COM { 83411963SAfshin.Ardakani@Sun.COM smb_node_t *pnode = dnode; 83511963SAfshin.Ardakani@Sun.COM 83611963SAfshin.Ardakani@Sun.COM SMB_NODE_VALID(dnode); 83711337SWilliam.Krier@Sun.COM 83811963SAfshin.Ardakani@Sun.COM while ((pnode = pnode->n_dnode) != NULL) { 83911963SAfshin.Ardakani@Sun.COM SMB_NODE_VALID(pnode); 84011963SAfshin.Ardakani@Sun.COM if ((pnode->flags & NODE_FLAGS_NOTIFY_CHANGE) && 84111963SAfshin.Ardakani@Sun.COM (pnode->flags & NODE_FLAGS_WATCH_TREE)) { 84211963SAfshin.Ardakani@Sun.COM pnode->flags |= NODE_FLAGS_CHANGED; 84311963SAfshin.Ardakani@Sun.COM smb_process_node_notify_change_queue(pnode); 84411963SAfshin.Ardakani@Sun.COM } 84511963SAfshin.Ardakani@Sun.COM } 84611337SWilliam.Krier@Sun.COM } 84711337SWilliam.Krier@Sun.COM 8485772Sas200622 /* 8495772Sas200622 * smb_node_start_crit() 8505772Sas200622 * 8515772Sas200622 * Enter critical region for share reservations. 8525772Sas200622 * See comments above smb_fsop_shrlock(). 8535772Sas200622 */ 8545772Sas200622 void 8555772Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode) 8565772Sas200622 { 8578934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, mode); 8585772Sas200622 nbl_start_crit(node->vp, mode); 8595772Sas200622 } 8605772Sas200622 8615772Sas200622 /* 8625772Sas200622 * smb_node_end_crit() 8635772Sas200622 * 8645772Sas200622 * Exit critical region for share reservations. 8655772Sas200622 */ 8665772Sas200622 void 8675772Sas200622 smb_node_end_crit(smb_node_t *node) 8685772Sas200622 { 8695772Sas200622 nbl_end_crit(node->vp); 8708934SJose.Borrego@Sun.COM rw_exit(&node->n_lock); 8715772Sas200622 } 8725772Sas200622 8735772Sas200622 int 8745772Sas200622 smb_node_in_crit(smb_node_t *node) 8755772Sas200622 { 8768934SJose.Borrego@Sun.COM return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock)); 8778934SJose.Borrego@Sun.COM } 8788934SJose.Borrego@Sun.COM 8798934SJose.Borrego@Sun.COM void 8808934SJose.Borrego@Sun.COM smb_node_rdlock(smb_node_t *node) 8818934SJose.Borrego@Sun.COM { 8828934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, RW_READER); 8838934SJose.Borrego@Sun.COM } 8848934SJose.Borrego@Sun.COM 8858934SJose.Borrego@Sun.COM void 8868934SJose.Borrego@Sun.COM smb_node_wrlock(smb_node_t *node) 8878934SJose.Borrego@Sun.COM { 8888934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, RW_WRITER); 8898934SJose.Borrego@Sun.COM } 8908934SJose.Borrego@Sun.COM 8918934SJose.Borrego@Sun.COM void 8928934SJose.Borrego@Sun.COM smb_node_unlock(smb_node_t *node) 8938934SJose.Borrego@Sun.COM { 8948934SJose.Borrego@Sun.COM rw_exit(&node->n_lock); 8958934SJose.Borrego@Sun.COM } 8968934SJose.Borrego@Sun.COM 8978934SJose.Borrego@Sun.COM uint32_t 8988934SJose.Borrego@Sun.COM smb_node_get_ofile_count(smb_node_t *node) 8998934SJose.Borrego@Sun.COM { 9008934SJose.Borrego@Sun.COM uint32_t cntr; 9018934SJose.Borrego@Sun.COM 9028934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9038934SJose.Borrego@Sun.COM 9048934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_READER); 9058934SJose.Borrego@Sun.COM cntr = smb_llist_get_count(&node->n_ofile_list); 9068934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 9078934SJose.Borrego@Sun.COM return (cntr); 9088934SJose.Borrego@Sun.COM } 9098934SJose.Borrego@Sun.COM 9108934SJose.Borrego@Sun.COM void 9118934SJose.Borrego@Sun.COM smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of) 9128934SJose.Borrego@Sun.COM { 9138934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9148934SJose.Borrego@Sun.COM 9158934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_WRITER); 9168934SJose.Borrego@Sun.COM smb_llist_insert_tail(&node->n_ofile_list, of); 9178934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 9188934SJose.Borrego@Sun.COM } 9198934SJose.Borrego@Sun.COM 9208934SJose.Borrego@Sun.COM void 9218934SJose.Borrego@Sun.COM smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of) 9228934SJose.Borrego@Sun.COM { 9238934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9248934SJose.Borrego@Sun.COM 9258934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_WRITER); 9268934SJose.Borrego@Sun.COM smb_llist_remove(&node->n_ofile_list, of); 9278934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 9288934SJose.Borrego@Sun.COM } 9298934SJose.Borrego@Sun.COM 93010001SJoyce.McIntosh@Sun.COM /* 93110001SJoyce.McIntosh@Sun.COM * smb_node_inc_open_ofiles 93210001SJoyce.McIntosh@Sun.COM */ 9338934SJose.Borrego@Sun.COM void 9348934SJose.Borrego@Sun.COM smb_node_inc_open_ofiles(smb_node_t *node) 9358934SJose.Borrego@Sun.COM { 9368934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9378934SJose.Borrego@Sun.COM 9388934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 9398934SJose.Borrego@Sun.COM node->n_open_count++; 9408934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 94110001SJoyce.McIntosh@Sun.COM 94210504SKeyur.Desai@Sun.COM smb_node_init_cached_data(node); 9438934SJose.Borrego@Sun.COM } 9448934SJose.Borrego@Sun.COM 94510001SJoyce.McIntosh@Sun.COM /* 94610001SJoyce.McIntosh@Sun.COM * smb_node_dec_open_ofiles 94710001SJoyce.McIntosh@Sun.COM */ 9488934SJose.Borrego@Sun.COM void 9498934SJose.Borrego@Sun.COM smb_node_dec_open_ofiles(smb_node_t *node) 9508934SJose.Borrego@Sun.COM { 9518934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9528934SJose.Borrego@Sun.COM 9538934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 9548934SJose.Borrego@Sun.COM node->n_open_count--; 9558934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 95610001SJoyce.McIntosh@Sun.COM 95710504SKeyur.Desai@Sun.COM smb_node_clear_cached_data(node); 9588934SJose.Borrego@Sun.COM } 9598934SJose.Borrego@Sun.COM 9608934SJose.Borrego@Sun.COM uint32_t 9618934SJose.Borrego@Sun.COM smb_node_get_open_ofiles(smb_node_t *node) 9628934SJose.Borrego@Sun.COM { 9638934SJose.Borrego@Sun.COM uint32_t cnt; 9648934SJose.Borrego@Sun.COM 9658934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9668934SJose.Borrego@Sun.COM 9678934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 9688934SJose.Borrego@Sun.COM cnt = node->n_open_count; 9698934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 9708934SJose.Borrego@Sun.COM return (cnt); 9715772Sas200622 } 9728934SJose.Borrego@Sun.COM 9738934SJose.Borrego@Sun.COM /* 97411963SAfshin.Ardakani@Sun.COM * smb_node_getmntpath 97511963SAfshin.Ardakani@Sun.COM */ 97611963SAfshin.Ardakani@Sun.COM int 97711963SAfshin.Ardakani@Sun.COM smb_node_getmntpath(smb_node_t *node, char *buf, uint32_t buflen) 97811963SAfshin.Ardakani@Sun.COM { 97911963SAfshin.Ardakani@Sun.COM vnode_t *vp, *root_vp; 98011963SAfshin.Ardakani@Sun.COM vfs_t *vfsp; 98111963SAfshin.Ardakani@Sun.COM int err; 98211963SAfshin.Ardakani@Sun.COM 98311963SAfshin.Ardakani@Sun.COM ASSERT(node); 98411963SAfshin.Ardakani@Sun.COM ASSERT(node->vp); 98511963SAfshin.Ardakani@Sun.COM ASSERT(node->vp->v_vfsp); 98611963SAfshin.Ardakani@Sun.COM 98711963SAfshin.Ardakani@Sun.COM vp = node->vp; 98811963SAfshin.Ardakani@Sun.COM vfsp = vp->v_vfsp; 98911963SAfshin.Ardakani@Sun.COM 99011963SAfshin.Ardakani@Sun.COM if (VFS_ROOT(vfsp, &root_vp)) 99111963SAfshin.Ardakani@Sun.COM return (ENOENT); 99211963SAfshin.Ardakani@Sun.COM 99311963SAfshin.Ardakani@Sun.COM VN_HOLD(vp); 99411963SAfshin.Ardakani@Sun.COM 99511963SAfshin.Ardakani@Sun.COM /* NULL is passed in as we want to start at "/" */ 99611963SAfshin.Ardakani@Sun.COM err = vnodetopath(NULL, root_vp, buf, buflen, kcred); 99711963SAfshin.Ardakani@Sun.COM 99811963SAfshin.Ardakani@Sun.COM VN_RELE(vp); 99911963SAfshin.Ardakani@Sun.COM VN_RELE(root_vp); 100011963SAfshin.Ardakani@Sun.COM return (err); 100111963SAfshin.Ardakani@Sun.COM } 100211963SAfshin.Ardakani@Sun.COM 100311963SAfshin.Ardakani@Sun.COM /* 100411963SAfshin.Ardakani@Sun.COM * smb_node_getshrpath 100511963SAfshin.Ardakani@Sun.COM * 100611963SAfshin.Ardakani@Sun.COM * Determine the absolute pathname of 'node' within the share (tree). 100711963SAfshin.Ardakani@Sun.COM * For example if the node represents file "test1.txt" in directory 100811963SAfshin.Ardakani@Sun.COM * "dir1" the pathname would be: \dir1\test1.txt 100911963SAfshin.Ardakani@Sun.COM */ 101011963SAfshin.Ardakani@Sun.COM int 101111963SAfshin.Ardakani@Sun.COM smb_node_getshrpath(smb_node_t *node, smb_tree_t *tree, 101211963SAfshin.Ardakani@Sun.COM char *buf, uint32_t buflen) 101311963SAfshin.Ardakani@Sun.COM { 101411963SAfshin.Ardakani@Sun.COM int rc; 101511963SAfshin.Ardakani@Sun.COM 101612065SKeyur.Desai@Sun.COM ASSERT(node); 101712065SKeyur.Desai@Sun.COM ASSERT(tree); 101812065SKeyur.Desai@Sun.COM ASSERT(tree->t_snode); 101911963SAfshin.Ardakani@Sun.COM 102012065SKeyur.Desai@Sun.COM rc = smb_node_getpath(node, tree->t_snode->vp, buf, buflen); 102112065SKeyur.Desai@Sun.COM (void) strsubst(buf, '/', '\\'); 102212065SKeyur.Desai@Sun.COM return (rc); 102312065SKeyur.Desai@Sun.COM } 102411963SAfshin.Ardakani@Sun.COM 102512065SKeyur.Desai@Sun.COM /* 102612065SKeyur.Desai@Sun.COM * smb_node_getpath 102712065SKeyur.Desai@Sun.COM * 102812065SKeyur.Desai@Sun.COM * Determine the absolute pathname of 'node' from 'rootvp'. 102912065SKeyur.Desai@Sun.COM * 103012065SKeyur.Desai@Sun.COM * Using vnodetopath is only reliable for directory nodes (due to 103112065SKeyur.Desai@Sun.COM * its reliance on the DNLC for non-directory nodes). Thus, if node 103212065SKeyur.Desai@Sun.COM * represents a file, construct the pathname for the parent dnode 103312065SKeyur.Desai@Sun.COM * and append filename. 103412065SKeyur.Desai@Sun.COM * If node represents a named stream, construct the pathname for the 103512065SKeyur.Desai@Sun.COM * associated unnamed stream and append the stream name. 103612065SKeyur.Desai@Sun.COM * 103712065SKeyur.Desai@Sun.COM * The pathname returned in buf will be '/' separated. 103812065SKeyur.Desai@Sun.COM */ 103912065SKeyur.Desai@Sun.COM int 104012065SKeyur.Desai@Sun.COM smb_node_getpath(smb_node_t *node, vnode_t *rootvp, char *buf, uint32_t buflen) 104112065SKeyur.Desai@Sun.COM { 104212065SKeyur.Desai@Sun.COM int rc; 104312065SKeyur.Desai@Sun.COM vnode_t *vp; 104412065SKeyur.Desai@Sun.COM smb_node_t *unode, *dnode; 104512065SKeyur.Desai@Sun.COM 104612065SKeyur.Desai@Sun.COM unode = (SMB_IS_STREAM(node)) ? node->n_unode : node; 104712065SKeyur.Desai@Sun.COM dnode = (smb_node_is_dir(unode)) ? unode : unode->n_dnode; 104811963SAfshin.Ardakani@Sun.COM 104912065SKeyur.Desai@Sun.COM /* find path to directory node */ 105012065SKeyur.Desai@Sun.COM vp = dnode->vp; 105112065SKeyur.Desai@Sun.COM VN_HOLD(vp); 105212065SKeyur.Desai@Sun.COM if (rootvp) { 105312065SKeyur.Desai@Sun.COM VN_HOLD(rootvp); 105412065SKeyur.Desai@Sun.COM rc = vnodetopath(rootvp, vp, buf, buflen, kcred); 105512065SKeyur.Desai@Sun.COM VN_RELE(rootvp); 105612065SKeyur.Desai@Sun.COM } else { 105712065SKeyur.Desai@Sun.COM rc = vnodetopath(NULL, vp, buf, buflen, kcred); 105812065SKeyur.Desai@Sun.COM } 105912065SKeyur.Desai@Sun.COM VN_RELE(vp); 106011963SAfshin.Ardakani@Sun.COM 106112065SKeyur.Desai@Sun.COM if (rc != 0) 106212065SKeyur.Desai@Sun.COM return (rc); 106312065SKeyur.Desai@Sun.COM 106412065SKeyur.Desai@Sun.COM /* append filename if necessary */ 106512065SKeyur.Desai@Sun.COM if (!smb_node_is_dir(unode)) { 106612065SKeyur.Desai@Sun.COM if (buf[strlen(buf) - 1] != '/') 106712065SKeyur.Desai@Sun.COM (void) strlcat(buf, "/", buflen); 106812065SKeyur.Desai@Sun.COM (void) strlcat(buf, unode->od_name, buflen); 106911963SAfshin.Ardakani@Sun.COM } 107011963SAfshin.Ardakani@Sun.COM 107112065SKeyur.Desai@Sun.COM /* append named stream name if necessary */ 107212065SKeyur.Desai@Sun.COM if (SMB_IS_STREAM(node)) 107312065SKeyur.Desai@Sun.COM (void) strlcat(buf, node->od_name, buflen); 107412065SKeyur.Desai@Sun.COM 107511963SAfshin.Ardakani@Sun.COM return (rc); 107611963SAfshin.Ardakani@Sun.COM } 107711963SAfshin.Ardakani@Sun.COM 107811963SAfshin.Ardakani@Sun.COM /* 10798934SJose.Borrego@Sun.COM * smb_node_alloc 10808934SJose.Borrego@Sun.COM */ 10818934SJose.Borrego@Sun.COM static smb_node_t * 10828934SJose.Borrego@Sun.COM smb_node_alloc( 10838934SJose.Borrego@Sun.COM char *od_name, 10848934SJose.Borrego@Sun.COM vnode_t *vp, 10858934SJose.Borrego@Sun.COM smb_llist_t *bucket, 10868934SJose.Borrego@Sun.COM uint32_t hashkey) 10878934SJose.Borrego@Sun.COM { 10888934SJose.Borrego@Sun.COM smb_node_t *node; 108911963SAfshin.Ardakani@Sun.COM vnode_t *root_vp; 10908934SJose.Borrego@Sun.COM 10918934SJose.Borrego@Sun.COM node = kmem_cache_alloc(smb_node_cache, KM_SLEEP); 10928934SJose.Borrego@Sun.COM 10938934SJose.Borrego@Sun.COM if (node->n_audit_buf != NULL) 10948934SJose.Borrego@Sun.COM node->n_audit_buf->anb_index = 0; 10958934SJose.Borrego@Sun.COM 109610001SJoyce.McIntosh@Sun.COM node->flags = 0; 10978934SJose.Borrego@Sun.COM VN_HOLD(vp); 10988934SJose.Borrego@Sun.COM node->vp = vp; 10998934SJose.Borrego@Sun.COM node->n_refcnt = 1; 11008934SJose.Borrego@Sun.COM node->n_hash_bucket = bucket; 11018934SJose.Borrego@Sun.COM node->n_hashkey = hashkey; 11028934SJose.Borrego@Sun.COM node->readonly_creator = NULL; 11038934SJose.Borrego@Sun.COM node->waiting_event = 0; 11048934SJose.Borrego@Sun.COM node->n_open_count = 0; 110510122SJordan.Brown@Sun.COM node->n_dnode = NULL; 110610122SJordan.Brown@Sun.COM node->n_unode = NULL; 11078934SJose.Borrego@Sun.COM node->delete_on_close_cred = NULL; 11089231SAfshin.Ardakani@Sun.COM node->n_delete_on_close_flags = 0; 11098934SJose.Borrego@Sun.COM 11108934SJose.Borrego@Sun.COM (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); 11118934SJose.Borrego@Sun.COM if (strcmp(od_name, XATTR_DIR) == 0) 11128934SJose.Borrego@Sun.COM node->flags |= NODE_XATTR_DIR; 11138934SJose.Borrego@Sun.COM 111411963SAfshin.Ardakani@Sun.COM if (VFS_ROOT(vp->v_vfsp, &root_vp) == 0) { 111511963SAfshin.Ardakani@Sun.COM if (vp == root_vp) 111611963SAfshin.Ardakani@Sun.COM node->flags |= NODE_FLAGS_VFSROOT; 111711963SAfshin.Ardakani@Sun.COM VN_RELE(root_vp); 111811963SAfshin.Ardakani@Sun.COM } 111911963SAfshin.Ardakani@Sun.COM 11208934SJose.Borrego@Sun.COM node->n_state = SMB_NODE_STATE_AVAILABLE; 11218934SJose.Borrego@Sun.COM node->n_magic = SMB_NODE_MAGIC; 112211963SAfshin.Ardakani@Sun.COM 11238934SJose.Borrego@Sun.COM return (node); 11248934SJose.Borrego@Sun.COM } 11258934SJose.Borrego@Sun.COM 11268934SJose.Borrego@Sun.COM /* 11278934SJose.Borrego@Sun.COM * smb_node_free 11288934SJose.Borrego@Sun.COM */ 11298934SJose.Borrego@Sun.COM static void 11308934SJose.Borrego@Sun.COM smb_node_free(smb_node_t *node) 11318934SJose.Borrego@Sun.COM { 11328934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 11338934SJose.Borrego@Sun.COM 11348934SJose.Borrego@Sun.COM node->n_magic = 0; 11358934SJose.Borrego@Sun.COM VERIFY(!list_link_active(&node->n_lnd)); 11368934SJose.Borrego@Sun.COM VERIFY(node->n_lock_list.ll_count == 0); 11378934SJose.Borrego@Sun.COM VERIFY(node->n_ofile_list.ll_count == 0); 11388934SJose.Borrego@Sun.COM VERIFY(node->n_oplock.ol_xthread == NULL); 11399021Samw@Sun.COM VERIFY(mutex_owner(&node->n_mutex) == NULL); 11409021Samw@Sun.COM VERIFY(!RW_LOCK_HELD(&node->n_lock)); 11418934SJose.Borrego@Sun.COM VN_RELE(node->vp); 11428934SJose.Borrego@Sun.COM kmem_cache_free(smb_node_cache, node); 11438934SJose.Borrego@Sun.COM } 11448934SJose.Borrego@Sun.COM 11458934SJose.Borrego@Sun.COM /* 11468934SJose.Borrego@Sun.COM * smb_node_constructor 11478934SJose.Borrego@Sun.COM */ 11488934SJose.Borrego@Sun.COM static int 11498934SJose.Borrego@Sun.COM smb_node_constructor(void *buf, void *un, int kmflags) 11508934SJose.Borrego@Sun.COM { 11518934SJose.Borrego@Sun.COM _NOTE(ARGUNUSED(kmflags, un)) 11528934SJose.Borrego@Sun.COM 11538934SJose.Borrego@Sun.COM smb_node_t *node = (smb_node_t *)buf; 11548934SJose.Borrego@Sun.COM 11558934SJose.Borrego@Sun.COM bzero(node, sizeof (smb_node_t)); 11568934SJose.Borrego@Sun.COM 11578934SJose.Borrego@Sun.COM smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 11588934SJose.Borrego@Sun.COM offsetof(smb_ofile_t, f_nnd)); 11598934SJose.Borrego@Sun.COM smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 11608934SJose.Borrego@Sun.COM offsetof(smb_lock_t, l_lnd)); 11618934SJose.Borrego@Sun.COM cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL); 11628934SJose.Borrego@Sun.COM rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL); 11638934SJose.Borrego@Sun.COM mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL); 11648934SJose.Borrego@Sun.COM smb_node_create_audit_buf(node, kmflags); 11658934SJose.Borrego@Sun.COM return (0); 11668934SJose.Borrego@Sun.COM } 11678934SJose.Borrego@Sun.COM 11688934SJose.Borrego@Sun.COM /* 11698934SJose.Borrego@Sun.COM * smb_node_destructor 11708934SJose.Borrego@Sun.COM */ 11718934SJose.Borrego@Sun.COM static void 11728934SJose.Borrego@Sun.COM smb_node_destructor(void *buf, void *un) 11738934SJose.Borrego@Sun.COM { 11748934SJose.Borrego@Sun.COM _NOTE(ARGUNUSED(un)) 11758934SJose.Borrego@Sun.COM 11768934SJose.Borrego@Sun.COM smb_node_t *node = (smb_node_t *)buf; 11778934SJose.Borrego@Sun.COM 11788934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(node); 11798934SJose.Borrego@Sun.COM mutex_destroy(&node->n_mutex); 11808934SJose.Borrego@Sun.COM rw_destroy(&node->n_lock); 11818934SJose.Borrego@Sun.COM cv_destroy(&node->n_oplock.ol_cv); 11828934SJose.Borrego@Sun.COM smb_llist_destructor(&node->n_lock_list); 11838934SJose.Borrego@Sun.COM smb_llist_destructor(&node->n_ofile_list); 11848934SJose.Borrego@Sun.COM } 11858934SJose.Borrego@Sun.COM 11868934SJose.Borrego@Sun.COM /* 11878934SJose.Borrego@Sun.COM * smb_node_create_audit_buf 11888934SJose.Borrego@Sun.COM */ 11898934SJose.Borrego@Sun.COM static void 11908934SJose.Borrego@Sun.COM smb_node_create_audit_buf(smb_node_t *node, int kmflags) 11918934SJose.Borrego@Sun.COM { 11928934SJose.Borrego@Sun.COM smb_audit_buf_node_t *abn; 11938934SJose.Borrego@Sun.COM 11948934SJose.Borrego@Sun.COM if (smb_audit_flags & SMB_AUDIT_NODE) { 11958934SJose.Borrego@Sun.COM abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags); 11968934SJose.Borrego@Sun.COM abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1; 11978934SJose.Borrego@Sun.COM node->n_audit_buf = abn; 11988934SJose.Borrego@Sun.COM } 11998934SJose.Borrego@Sun.COM } 12008934SJose.Borrego@Sun.COM 12018934SJose.Borrego@Sun.COM /* 12028934SJose.Borrego@Sun.COM * smb_node_destroy_audit_buf 12038934SJose.Borrego@Sun.COM */ 12048934SJose.Borrego@Sun.COM static void 12058934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(smb_node_t *node) 12068934SJose.Borrego@Sun.COM { 12078934SJose.Borrego@Sun.COM if (node->n_audit_buf != NULL) { 12088934SJose.Borrego@Sun.COM kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t)); 12098934SJose.Borrego@Sun.COM node->n_audit_buf = NULL; 12108934SJose.Borrego@Sun.COM } 12118934SJose.Borrego@Sun.COM } 12128934SJose.Borrego@Sun.COM 12138934SJose.Borrego@Sun.COM /* 12148934SJose.Borrego@Sun.COM * smb_node_audit 12158934SJose.Borrego@Sun.COM * 12168934SJose.Borrego@Sun.COM * This function saves the calling stack in the audit buffer of the node passed 12178934SJose.Borrego@Sun.COM * in. 12188934SJose.Borrego@Sun.COM */ 12198934SJose.Borrego@Sun.COM static void 12208934SJose.Borrego@Sun.COM smb_node_audit(smb_node_t *node) 12218934SJose.Borrego@Sun.COM { 12228934SJose.Borrego@Sun.COM smb_audit_buf_node_t *abn; 12238934SJose.Borrego@Sun.COM smb_audit_record_node_t *anr; 12248934SJose.Borrego@Sun.COM 12258934SJose.Borrego@Sun.COM if (node->n_audit_buf) { 12268934SJose.Borrego@Sun.COM abn = node->n_audit_buf; 12278934SJose.Borrego@Sun.COM anr = abn->anb_records; 12288934SJose.Borrego@Sun.COM anr += abn->anb_index; 12298934SJose.Borrego@Sun.COM abn->anb_index++; 12308934SJose.Borrego@Sun.COM abn->anb_index &= abn->anb_max_index; 12318934SJose.Borrego@Sun.COM anr->anr_refcnt = node->n_refcnt; 12328934SJose.Borrego@Sun.COM anr->anr_depth = getpcstack(anr->anr_stack, 12338934SJose.Borrego@Sun.COM SMB_AUDIT_STACK_DEPTH); 12348934SJose.Borrego@Sun.COM } 12358934SJose.Borrego@Sun.COM } 12368934SJose.Borrego@Sun.COM 12378934SJose.Borrego@Sun.COM static smb_llist_t * 12388934SJose.Borrego@Sun.COM smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey) 12398934SJose.Borrego@Sun.COM { 12408934SJose.Borrego@Sun.COM uint32_t hashkey; 12418934SJose.Borrego@Sun.COM 12428934SJose.Borrego@Sun.COM hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid; 12438934SJose.Borrego@Sun.COM hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 12448934SJose.Borrego@Sun.COM *phashkey = hashkey; 12458934SJose.Borrego@Sun.COM return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]); 12468934SJose.Borrego@Sun.COM } 124710001SJoyce.McIntosh@Sun.COM 124810001SJoyce.McIntosh@Sun.COM boolean_t 124911963SAfshin.Ardakani@Sun.COM smb_node_is_file(smb_node_t *node) 125011963SAfshin.Ardakani@Sun.COM { 125111963SAfshin.Ardakani@Sun.COM SMB_NODE_VALID(node); 125211963SAfshin.Ardakani@Sun.COM return (node->vp->v_type == VREG); 125311963SAfshin.Ardakani@Sun.COM } 125411963SAfshin.Ardakani@Sun.COM 125511963SAfshin.Ardakani@Sun.COM boolean_t 125610001SJoyce.McIntosh@Sun.COM smb_node_is_dir(smb_node_t *node) 125710001SJoyce.McIntosh@Sun.COM { 125810001SJoyce.McIntosh@Sun.COM SMB_NODE_VALID(node); 125911963SAfshin.Ardakani@Sun.COM return ((node->vp->v_type == VDIR) || 126011963SAfshin.Ardakani@Sun.COM (node->flags & NODE_FLAGS_DFSLINK)); 126111963SAfshin.Ardakani@Sun.COM } 126211963SAfshin.Ardakani@Sun.COM 126311963SAfshin.Ardakani@Sun.COM boolean_t 126411963SAfshin.Ardakani@Sun.COM smb_node_is_symlink(smb_node_t *node) 126511963SAfshin.Ardakani@Sun.COM { 126611963SAfshin.Ardakani@Sun.COM SMB_NODE_VALID(node); 126711963SAfshin.Ardakani@Sun.COM return ((node->vp->v_type == VLNK) && 126811963SAfshin.Ardakani@Sun.COM ((node->flags & NODE_FLAGS_REPARSE) == 0)); 126910001SJoyce.McIntosh@Sun.COM } 127010001SJoyce.McIntosh@Sun.COM 127110001SJoyce.McIntosh@Sun.COM boolean_t 127211963SAfshin.Ardakani@Sun.COM smb_node_is_dfslink(smb_node_t *node) 127311963SAfshin.Ardakani@Sun.COM { 127411963SAfshin.Ardakani@Sun.COM SMB_NODE_VALID(node); 127511963SAfshin.Ardakani@Sun.COM return ((node->vp->v_type == VLNK) && 127611963SAfshin.Ardakani@Sun.COM (node->flags & NODE_FLAGS_DFSLINK)); 127711963SAfshin.Ardakani@Sun.COM } 127811963SAfshin.Ardakani@Sun.COM 127911963SAfshin.Ardakani@Sun.COM boolean_t 128011963SAfshin.Ardakani@Sun.COM smb_node_is_reparse(smb_node_t *node) 128110001SJoyce.McIntosh@Sun.COM { 128210001SJoyce.McIntosh@Sun.COM SMB_NODE_VALID(node); 128311963SAfshin.Ardakani@Sun.COM return ((node->vp->v_type == VLNK) && 128411963SAfshin.Ardakani@Sun.COM (node->flags & NODE_FLAGS_REPARSE)); 128511963SAfshin.Ardakani@Sun.COM } 128611963SAfshin.Ardakani@Sun.COM 128711963SAfshin.Ardakani@Sun.COM boolean_t 128811963SAfshin.Ardakani@Sun.COM smb_node_is_vfsroot(smb_node_t *node) 128911963SAfshin.Ardakani@Sun.COM { 129011963SAfshin.Ardakani@Sun.COM SMB_NODE_VALID(node); 129111963SAfshin.Ardakani@Sun.COM return ((node->flags & NODE_FLAGS_VFSROOT) == NODE_FLAGS_VFSROOT); 129211963SAfshin.Ardakani@Sun.COM } 129311963SAfshin.Ardakani@Sun.COM 129411963SAfshin.Ardakani@Sun.COM boolean_t 129511963SAfshin.Ardakani@Sun.COM smb_node_is_system(smb_node_t *node) 129611963SAfshin.Ardakani@Sun.COM { 129711963SAfshin.Ardakani@Sun.COM SMB_NODE_VALID(node); 129811963SAfshin.Ardakani@Sun.COM return ((node->flags & NODE_FLAGS_SYSTEM) == NODE_FLAGS_SYSTEM); 129910001SJoyce.McIntosh@Sun.COM } 130010001SJoyce.McIntosh@Sun.COM 130110001SJoyce.McIntosh@Sun.COM /* 130210001SJoyce.McIntosh@Sun.COM * smb_node_file_is_readonly 130310001SJoyce.McIntosh@Sun.COM * 130410001SJoyce.McIntosh@Sun.COM * Checks if the file (which node represents) is marked readonly 130510001SJoyce.McIntosh@Sun.COM * in the filesystem. No account is taken of any pending readonly 130610001SJoyce.McIntosh@Sun.COM * in the node, which must be handled by the callers. 130710001SJoyce.McIntosh@Sun.COM * (See SMB_OFILE_IS_READONLY and SMB_PATHFILE_IS_READONLY) 130810001SJoyce.McIntosh@Sun.COM */ 130910001SJoyce.McIntosh@Sun.COM boolean_t 131010001SJoyce.McIntosh@Sun.COM smb_node_file_is_readonly(smb_node_t *node) 131110001SJoyce.McIntosh@Sun.COM { 131210001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 131310001SJoyce.McIntosh@Sun.COM 131410001SJoyce.McIntosh@Sun.COM if (node == NULL) 131510001SJoyce.McIntosh@Sun.COM return (B_FALSE); 131610001SJoyce.McIntosh@Sun.COM 131710001SJoyce.McIntosh@Sun.COM bzero(&attr, sizeof (smb_attr_t)); 131810001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_DOSATTR; 131910001SJoyce.McIntosh@Sun.COM (void) smb_fsop_getattr(NULL, kcred, node, &attr); 132010001SJoyce.McIntosh@Sun.COM return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0); 132110001SJoyce.McIntosh@Sun.COM } 132210001SJoyce.McIntosh@Sun.COM 132310001SJoyce.McIntosh@Sun.COM /* 132410001SJoyce.McIntosh@Sun.COM * smb_node_setattr 132510001SJoyce.McIntosh@Sun.COM * 132610001SJoyce.McIntosh@Sun.COM * The sr may be NULL, for example when closing an ofile. 132710001SJoyce.McIntosh@Sun.COM * The ofile may be NULL, for example when a client request 132810001SJoyce.McIntosh@Sun.COM * specifies the file by pathname. 132910001SJoyce.McIntosh@Sun.COM * 133010504SKeyur.Desai@Sun.COM * Timestamps 133110001SJoyce.McIntosh@Sun.COM * When attributes are set on an ofile, any pending timestamps 133210001SJoyce.McIntosh@Sun.COM * from a write request on the ofile are implicitly set to "now". 133310001SJoyce.McIntosh@Sun.COM * For compatibility with windows the following timestamps are 133410001SJoyce.McIntosh@Sun.COM * also implicitly set to now: 133510001SJoyce.McIntosh@Sun.COM * - if any attribute is being explicitly set, set ctime to now 133610001SJoyce.McIntosh@Sun.COM * - if file size is being explicitly set, set atime & ctime to now 133710001SJoyce.McIntosh@Sun.COM * 133810504SKeyur.Desai@Sun.COM * Any timestamp that is being explicitly set, or has previously 133910001SJoyce.McIntosh@Sun.COM * been explicitly set on the ofile, is excluded from implicit 134010001SJoyce.McIntosh@Sun.COM * (now) setting. 134110001SJoyce.McIntosh@Sun.COM * 134210001SJoyce.McIntosh@Sun.COM * Updates the node's cached timestamp values. 134310001SJoyce.McIntosh@Sun.COM * Updates the ofile's explicit times flag. 134410001SJoyce.McIntosh@Sun.COM * 134510504SKeyur.Desai@Sun.COM * File allocation size 134610504SKeyur.Desai@Sun.COM * When the file allocation size is set it is first rounded up 134710504SKeyur.Desai@Sun.COM * to block size. If the file size is smaller than the allocation 134810504SKeyur.Desai@Sun.COM * size the file is truncated by setting the filesize to allocsz. 134910504SKeyur.Desai@Sun.COM * If there are open ofiles, the allocsz is cached on the node. 135010504SKeyur.Desai@Sun.COM * 135110504SKeyur.Desai@Sun.COM * Updates the node's cached allocsz value. 135210504SKeyur.Desai@Sun.COM * 135310001SJoyce.McIntosh@Sun.COM * Returns: errno 135410001SJoyce.McIntosh@Sun.COM */ 135510001SJoyce.McIntosh@Sun.COM int 135610001SJoyce.McIntosh@Sun.COM smb_node_setattr(smb_request_t *sr, smb_node_t *node, 135710001SJoyce.McIntosh@Sun.COM cred_t *cr, smb_ofile_t *of, smb_attr_t *attr) 135810001SJoyce.McIntosh@Sun.COM { 135910001SJoyce.McIntosh@Sun.COM int rc; 136010504SKeyur.Desai@Sun.COM uint32_t pending_times = 0; 136110504SKeyur.Desai@Sun.COM uint32_t explicit_times = 0; 136210001SJoyce.McIntosh@Sun.COM timestruc_t now; 136310504SKeyur.Desai@Sun.COM smb_attr_t tmp_attr; 136410001SJoyce.McIntosh@Sun.COM 136510001SJoyce.McIntosh@Sun.COM ASSERT(attr); 136610001SJoyce.McIntosh@Sun.COM SMB_NODE_VALID(node); 136710001SJoyce.McIntosh@Sun.COM 136810504SKeyur.Desai@Sun.COM /* set attributes specified in attr */ 136910504SKeyur.Desai@Sun.COM if (attr->sa_mask != 0) { 137010504SKeyur.Desai@Sun.COM /* if allocation size is < file size, truncate the file */ 137110504SKeyur.Desai@Sun.COM if (attr->sa_mask & SMB_AT_ALLOCSZ) { 137210504SKeyur.Desai@Sun.COM attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz); 137310001SJoyce.McIntosh@Sun.COM 137410504SKeyur.Desai@Sun.COM bzero(&tmp_attr, sizeof (smb_attr_t)); 137510504SKeyur.Desai@Sun.COM tmp_attr.sa_mask = SMB_AT_SIZE; 137610504SKeyur.Desai@Sun.COM (void) smb_fsop_getattr(NULL, kcred, node, &tmp_attr); 137710001SJoyce.McIntosh@Sun.COM 137810504SKeyur.Desai@Sun.COM if (tmp_attr.sa_vattr.va_size > attr->sa_allocsz) { 137910504SKeyur.Desai@Sun.COM attr->sa_vattr.va_size = attr->sa_allocsz; 138010504SKeyur.Desai@Sun.COM attr->sa_mask |= SMB_AT_SIZE; 138110504SKeyur.Desai@Sun.COM } 138210001SJoyce.McIntosh@Sun.COM } 138310504SKeyur.Desai@Sun.COM 138410504SKeyur.Desai@Sun.COM rc = smb_fsop_setattr(sr, cr, node, attr); 138510504SKeyur.Desai@Sun.COM if (rc != 0) 138610504SKeyur.Desai@Sun.COM return (rc); 138710504SKeyur.Desai@Sun.COM 138810504SKeyur.Desai@Sun.COM smb_node_set_cached_allocsz(node, attr); 138910504SKeyur.Desai@Sun.COM smb_node_set_cached_timestamps(node, attr); 139010504SKeyur.Desai@Sun.COM if (of) { 139110504SKeyur.Desai@Sun.COM smb_ofile_set_explicit_times(of, 139210504SKeyur.Desai@Sun.COM (attr->sa_mask & SMB_AT_TIMES)); 139310001SJoyce.McIntosh@Sun.COM } 139410001SJoyce.McIntosh@Sun.COM } 139510001SJoyce.McIntosh@Sun.COM 139610504SKeyur.Desai@Sun.COM /* 139710504SKeyur.Desai@Sun.COM * Determine which timestamps to implicitly set to "now". 139810504SKeyur.Desai@Sun.COM * Don't overwrite timestamps already explicitly set. 139910504SKeyur.Desai@Sun.COM */ 140010504SKeyur.Desai@Sun.COM bzero(&tmp_attr, sizeof (smb_attr_t)); 140110504SKeyur.Desai@Sun.COM gethrestime(&now); 140210504SKeyur.Desai@Sun.COM tmp_attr.sa_vattr.va_atime = now; 140310504SKeyur.Desai@Sun.COM tmp_attr.sa_vattr.va_mtime = now; 140410504SKeyur.Desai@Sun.COM tmp_attr.sa_vattr.va_ctime = now; 140510001SJoyce.McIntosh@Sun.COM 140610504SKeyur.Desai@Sun.COM /* pending write timestamps */ 140710504SKeyur.Desai@Sun.COM if (of) { 140810504SKeyur.Desai@Sun.COM if (smb_ofile_write_time_pending(of)) { 140910504SKeyur.Desai@Sun.COM pending_times |= 141010504SKeyur.Desai@Sun.COM (SMB_AT_MTIME | SMB_AT_CTIME | SMB_AT_ATIME); 141110504SKeyur.Desai@Sun.COM } 141210504SKeyur.Desai@Sun.COM explicit_times |= (smb_ofile_explicit_times(of)); 141310504SKeyur.Desai@Sun.COM } 141410504SKeyur.Desai@Sun.COM explicit_times |= (attr->sa_mask & SMB_AT_TIMES); 141510504SKeyur.Desai@Sun.COM pending_times &= ~explicit_times; 141610001SJoyce.McIntosh@Sun.COM 141710504SKeyur.Desai@Sun.COM if (pending_times) { 141810504SKeyur.Desai@Sun.COM tmp_attr.sa_mask = pending_times; 141910504SKeyur.Desai@Sun.COM (void) smb_fsop_setattr(NULL, kcred, node, &tmp_attr); 142010504SKeyur.Desai@Sun.COM } 142110001SJoyce.McIntosh@Sun.COM 142210504SKeyur.Desai@Sun.COM /* additional timestamps to update in cache */ 142310504SKeyur.Desai@Sun.COM if (attr->sa_mask) 142410504SKeyur.Desai@Sun.COM tmp_attr.sa_mask |= SMB_AT_CTIME; 142510504SKeyur.Desai@Sun.COM if (attr->sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ)) 142610504SKeyur.Desai@Sun.COM tmp_attr.sa_mask |= SMB_AT_MTIME; 142710504SKeyur.Desai@Sun.COM tmp_attr.sa_mask &= ~explicit_times; 142810504SKeyur.Desai@Sun.COM 142910504SKeyur.Desai@Sun.COM if (tmp_attr.sa_mask) 143010504SKeyur.Desai@Sun.COM smb_node_set_cached_timestamps(node, &tmp_attr); 143110001SJoyce.McIntosh@Sun.COM 143211963SAfshin.Ardakani@Sun.COM if (tmp_attr.sa_mask & SMB_AT_MTIME || explicit_times & SMB_AT_MTIME) { 143311963SAfshin.Ardakani@Sun.COM if (node->n_dnode != NULL) 143411963SAfshin.Ardakani@Sun.COM smb_node_notify_change(node->n_dnode); 143511963SAfshin.Ardakani@Sun.COM } 143611337SWilliam.Krier@Sun.COM 143710001SJoyce.McIntosh@Sun.COM return (0); 143810001SJoyce.McIntosh@Sun.COM } 143910001SJoyce.McIntosh@Sun.COM 144010001SJoyce.McIntosh@Sun.COM /* 144110001SJoyce.McIntosh@Sun.COM * smb_node_getattr 144210001SJoyce.McIntosh@Sun.COM * 144310001SJoyce.McIntosh@Sun.COM * Get attributes from the file system and apply any smb-specific 144410001SJoyce.McIntosh@Sun.COM * overrides for size, dos attributes and timestamps 144510001SJoyce.McIntosh@Sun.COM * 144610001SJoyce.McIntosh@Sun.COM * node->readonly_creator reflects whether a readonly set is pending 144710001SJoyce.McIntosh@Sun.COM * from a readonly create. The readonly attribute should be visible to 144810001SJoyce.McIntosh@Sun.COM * all clients even though the readonly creator fid is immune to the 144910001SJoyce.McIntosh@Sun.COM * readonly bit until close. 145010001SJoyce.McIntosh@Sun.COM * 145110001SJoyce.McIntosh@Sun.COM * Returns: errno 145210001SJoyce.McIntosh@Sun.COM */ 145310001SJoyce.McIntosh@Sun.COM int 145410001SJoyce.McIntosh@Sun.COM smb_node_getattr(smb_request_t *sr, smb_node_t *node, smb_attr_t *attr) 145510001SJoyce.McIntosh@Sun.COM { 145610001SJoyce.McIntosh@Sun.COM int rc; 145710001SJoyce.McIntosh@Sun.COM 145810001SJoyce.McIntosh@Sun.COM SMB_NODE_VALID(node); 145910001SJoyce.McIntosh@Sun.COM 146010001SJoyce.McIntosh@Sun.COM bzero(attr, sizeof (smb_attr_t)); 146110001SJoyce.McIntosh@Sun.COM attr->sa_mask = SMB_AT_ALL; 146210001SJoyce.McIntosh@Sun.COM rc = smb_fsop_getattr(sr, kcred, node, attr); 146310001SJoyce.McIntosh@Sun.COM if (rc != 0) 146410001SJoyce.McIntosh@Sun.COM return (rc); 146510001SJoyce.McIntosh@Sun.COM 146610001SJoyce.McIntosh@Sun.COM mutex_enter(&node->n_mutex); 146710001SJoyce.McIntosh@Sun.COM 146811963SAfshin.Ardakani@Sun.COM if (smb_node_is_dir(node)) { 146910001SJoyce.McIntosh@Sun.COM attr->sa_vattr.va_size = 0; 147010504SKeyur.Desai@Sun.COM attr->sa_allocsz = 0; 147110966SJordan.Brown@Sun.COM attr->sa_vattr.va_nlink = 1; 147210504SKeyur.Desai@Sun.COM } 147310001SJoyce.McIntosh@Sun.COM 147410001SJoyce.McIntosh@Sun.COM if (node->readonly_creator) 147510001SJoyce.McIntosh@Sun.COM attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 147610001SJoyce.McIntosh@Sun.COM if (attr->sa_dosattr == 0) 147710001SJoyce.McIntosh@Sun.COM attr->sa_dosattr = FILE_ATTRIBUTE_NORMAL; 147810001SJoyce.McIntosh@Sun.COM 147910504SKeyur.Desai@Sun.COM 148010001SJoyce.McIntosh@Sun.COM mutex_exit(&node->n_mutex); 148110001SJoyce.McIntosh@Sun.COM 148210504SKeyur.Desai@Sun.COM smb_node_get_cached_allocsz(node, attr); 148310001SJoyce.McIntosh@Sun.COM smb_node_get_cached_timestamps(node, attr); 148410504SKeyur.Desai@Sun.COM 148510001SJoyce.McIntosh@Sun.COM return (0); 148610001SJoyce.McIntosh@Sun.COM } 148710001SJoyce.McIntosh@Sun.COM 148810001SJoyce.McIntosh@Sun.COM /* 148910504SKeyur.Desai@Sun.COM * smb_node_init_cached_data 149010504SKeyur.Desai@Sun.COM */ 149110504SKeyur.Desai@Sun.COM static void 149210504SKeyur.Desai@Sun.COM smb_node_init_cached_data(smb_node_t *node) 149310504SKeyur.Desai@Sun.COM { 149410504SKeyur.Desai@Sun.COM smb_attr_t attr; 149510504SKeyur.Desai@Sun.COM 149610504SKeyur.Desai@Sun.COM bzero(&attr, sizeof (smb_attr_t)); 149710504SKeyur.Desai@Sun.COM attr.sa_mask = SMB_AT_ALL; 149810504SKeyur.Desai@Sun.COM (void) smb_fsop_getattr(NULL, kcred, node, &attr); 149910504SKeyur.Desai@Sun.COM 150010504SKeyur.Desai@Sun.COM smb_node_init_cached_allocsz(node, &attr); 150110504SKeyur.Desai@Sun.COM smb_node_init_cached_timestamps(node, &attr); 150210504SKeyur.Desai@Sun.COM } 150310504SKeyur.Desai@Sun.COM 150410504SKeyur.Desai@Sun.COM /* 150510504SKeyur.Desai@Sun.COM * smb_node_clear_cached_data 150610504SKeyur.Desai@Sun.COM */ 150710504SKeyur.Desai@Sun.COM static void 150810504SKeyur.Desai@Sun.COM smb_node_clear_cached_data(smb_node_t *node) 150910504SKeyur.Desai@Sun.COM { 151010504SKeyur.Desai@Sun.COM smb_node_clear_cached_allocsz(node); 151110504SKeyur.Desai@Sun.COM smb_node_clear_cached_timestamps(node); 151210504SKeyur.Desai@Sun.COM } 151310504SKeyur.Desai@Sun.COM 151410504SKeyur.Desai@Sun.COM /* 151510504SKeyur.Desai@Sun.COM * File allocation size (allocsz) caching 151610504SKeyur.Desai@Sun.COM * 151710504SKeyur.Desai@Sun.COM * When there are open ofiles on the node, the file allocsz is cached. 151810504SKeyur.Desai@Sun.COM * The cached value (n_allocsz) is initialized when the first ofile is 151910504SKeyur.Desai@Sun.COM * opened and cleared when the last is closed. Allocsz calculated from 152010504SKeyur.Desai@Sun.COM * the filesize (rounded up to block size). 152110504SKeyur.Desai@Sun.COM * When the allocation size is queried, if the cached allocsz is less 152210504SKeyur.Desai@Sun.COM * than the filesize, it is recalculated from the filesize. 152310504SKeyur.Desai@Sun.COM */ 152410504SKeyur.Desai@Sun.COM 152510504SKeyur.Desai@Sun.COM /* 152610504SKeyur.Desai@Sun.COM * smb_node_init_cached_allocsz 152710504SKeyur.Desai@Sun.COM * 152810504SKeyur.Desai@Sun.COM * If there are open ofiles, cache the allocsz in the node. 152910504SKeyur.Desai@Sun.COM * Calculate the allocsz from the filesizes. 153010504SKeyur.Desai@Sun.COM * block size). 153110504SKeyur.Desai@Sun.COM */ 153210504SKeyur.Desai@Sun.COM static void 153310504SKeyur.Desai@Sun.COM smb_node_init_cached_allocsz(smb_node_t *node, smb_attr_t *attr) 153410504SKeyur.Desai@Sun.COM { 153510504SKeyur.Desai@Sun.COM mutex_enter(&node->n_mutex); 153610504SKeyur.Desai@Sun.COM if (node->n_open_count == 1) 153710504SKeyur.Desai@Sun.COM node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size); 153810504SKeyur.Desai@Sun.COM mutex_exit(&node->n_mutex); 153910504SKeyur.Desai@Sun.COM } 154010504SKeyur.Desai@Sun.COM 154110504SKeyur.Desai@Sun.COM /* 154210504SKeyur.Desai@Sun.COM * smb_node_clear_cached_allocsz 154310504SKeyur.Desai@Sun.COM */ 154410504SKeyur.Desai@Sun.COM static void 154510504SKeyur.Desai@Sun.COM smb_node_clear_cached_allocsz(smb_node_t *node) 154610504SKeyur.Desai@Sun.COM { 154710504SKeyur.Desai@Sun.COM mutex_enter(&node->n_mutex); 154810504SKeyur.Desai@Sun.COM if (node->n_open_count == 0) 154910504SKeyur.Desai@Sun.COM node->n_allocsz = 0; 155010504SKeyur.Desai@Sun.COM mutex_exit(&node->n_mutex); 155110504SKeyur.Desai@Sun.COM } 155210504SKeyur.Desai@Sun.COM 155310504SKeyur.Desai@Sun.COM /* 155410504SKeyur.Desai@Sun.COM * smb_node_get_cached_allocsz 155510504SKeyur.Desai@Sun.COM * 155610504SKeyur.Desai@Sun.COM * If there is no cached allocsz (no open files), calculate 155710504SKeyur.Desai@Sun.COM * allocsz from the filesize. 155810504SKeyur.Desai@Sun.COM * If the allocsz is cached but is smaller than the filesize 155910504SKeyur.Desai@Sun.COM * recalculate the cached allocsz from the filesize. 156010504SKeyur.Desai@Sun.COM * 156110504SKeyur.Desai@Sun.COM * Return allocs in attr->sa_allocsz. 156210504SKeyur.Desai@Sun.COM */ 156310504SKeyur.Desai@Sun.COM static void 156410504SKeyur.Desai@Sun.COM smb_node_get_cached_allocsz(smb_node_t *node, smb_attr_t *attr) 156510504SKeyur.Desai@Sun.COM { 156611963SAfshin.Ardakani@Sun.COM if (smb_node_is_dir(node)) 156710504SKeyur.Desai@Sun.COM return; 156810504SKeyur.Desai@Sun.COM 156910504SKeyur.Desai@Sun.COM mutex_enter(&node->n_mutex); 157010504SKeyur.Desai@Sun.COM if (node->n_open_count == 0) { 157110504SKeyur.Desai@Sun.COM attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size); 157210504SKeyur.Desai@Sun.COM } else { 157310504SKeyur.Desai@Sun.COM if (node->n_allocsz < attr->sa_vattr.va_size) 157410504SKeyur.Desai@Sun.COM node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size); 157510504SKeyur.Desai@Sun.COM attr->sa_allocsz = node->n_allocsz; 157610504SKeyur.Desai@Sun.COM } 157710504SKeyur.Desai@Sun.COM mutex_exit(&node->n_mutex); 157810504SKeyur.Desai@Sun.COM } 157910504SKeyur.Desai@Sun.COM 158010504SKeyur.Desai@Sun.COM /* 158110504SKeyur.Desai@Sun.COM * smb_node_set_cached_allocsz 158210504SKeyur.Desai@Sun.COM * 158310504SKeyur.Desai@Sun.COM * attr->sa_allocsz has already been rounded to block size by 158410504SKeyur.Desai@Sun.COM * the caller. 158510504SKeyur.Desai@Sun.COM */ 158610504SKeyur.Desai@Sun.COM static void 158710504SKeyur.Desai@Sun.COM smb_node_set_cached_allocsz(smb_node_t *node, smb_attr_t *attr) 158810504SKeyur.Desai@Sun.COM { 158910504SKeyur.Desai@Sun.COM mutex_enter(&node->n_mutex); 159010504SKeyur.Desai@Sun.COM if (attr->sa_mask & SMB_AT_ALLOCSZ) { 159110504SKeyur.Desai@Sun.COM if (node->n_open_count > 0) 159210504SKeyur.Desai@Sun.COM node->n_allocsz = attr->sa_allocsz; 159310504SKeyur.Desai@Sun.COM } 159410504SKeyur.Desai@Sun.COM mutex_exit(&node->n_mutex); 159510504SKeyur.Desai@Sun.COM } 159610504SKeyur.Desai@Sun.COM 159710504SKeyur.Desai@Sun.COM 159810504SKeyur.Desai@Sun.COM /* 159910001SJoyce.McIntosh@Sun.COM * Timestamp caching 160010001SJoyce.McIntosh@Sun.COM * 160110001SJoyce.McIntosh@Sun.COM * Solaris file systems handle timestamps different from NTFS. For 160210001SJoyce.McIntosh@Sun.COM * example when file data is written NTFS doesn't update the timestamps 160310001SJoyce.McIntosh@Sun.COM * until the file is closed, and then only if they haven't been explicity 160410001SJoyce.McIntosh@Sun.COM * set via a set attribute request. In order to provide a more similar 160510001SJoyce.McIntosh@Sun.COM * view of an open file's timestamps, we cache the timestamps in the 160610001SJoyce.McIntosh@Sun.COM * node and manipulate them in a manner more consistent with windows. 160710001SJoyce.McIntosh@Sun.COM * (See handling of explicit times and pending timestamps from a write 160810001SJoyce.McIntosh@Sun.COM * request in smb_node_getattr and smb_node_setattr above.) 160910001SJoyce.McIntosh@Sun.COM * Timestamps remain cached while there are open ofiles for the node. 161010001SJoyce.McIntosh@Sun.COM * This includes open ofiles for named streams. 161110001SJoyce.McIntosh@Sun.COM * n_open_ofiles cannot be used as this doesn't include ofiles opened 161210001SJoyce.McIntosh@Sun.COM * for the node's named streams. Thus n_timestamps contains a count 161310001SJoyce.McIntosh@Sun.COM * of open ofiles (t_open_ofiles), including named streams' ofiles, 161410001SJoyce.McIntosh@Sun.COM * to be used to control timestamp caching. 161510001SJoyce.McIntosh@Sun.COM * 161610001SJoyce.McIntosh@Sun.COM * If a node represents a named stream the associated unnamed streams 161710001SJoyce.McIntosh@Sun.COM * cached timestamps are used instead. 161810001SJoyce.McIntosh@Sun.COM */ 161910001SJoyce.McIntosh@Sun.COM 162010001SJoyce.McIntosh@Sun.COM /* 162110001SJoyce.McIntosh@Sun.COM * smb_node_init_cached_timestamps 162210001SJoyce.McIntosh@Sun.COM * 162310001SJoyce.McIntosh@Sun.COM * Increment count of open ofiles which are using the cached timestamps. 162410001SJoyce.McIntosh@Sun.COM * If this is the first open ofile, init the cached timestamps from the 162510001SJoyce.McIntosh@Sun.COM * file system values. 162610001SJoyce.McIntosh@Sun.COM */ 162710001SJoyce.McIntosh@Sun.COM static void 162810504SKeyur.Desai@Sun.COM smb_node_init_cached_timestamps(smb_node_t *node, smb_attr_t *attr) 162910001SJoyce.McIntosh@Sun.COM { 163010001SJoyce.McIntosh@Sun.COM smb_node_t *unode; 163110001SJoyce.McIntosh@Sun.COM 163210001SJoyce.McIntosh@Sun.COM if ((unode = SMB_IS_STREAM(node)) != NULL) 163310001SJoyce.McIntosh@Sun.COM node = unode; 163410001SJoyce.McIntosh@Sun.COM 163510001SJoyce.McIntosh@Sun.COM mutex_enter(&node->n_mutex); 163610001SJoyce.McIntosh@Sun.COM ++(node->n_timestamps.t_open_ofiles); 163710001SJoyce.McIntosh@Sun.COM if (node->n_timestamps.t_open_ofiles == 1) { 163810504SKeyur.Desai@Sun.COM node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime; 163910504SKeyur.Desai@Sun.COM node->n_timestamps.t_atime = attr->sa_vattr.va_atime; 164010504SKeyur.Desai@Sun.COM node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime; 164110504SKeyur.Desai@Sun.COM node->n_timestamps.t_crtime = attr->sa_crtime; 164210001SJoyce.McIntosh@Sun.COM node->n_timestamps.t_cached = B_TRUE; 164310001SJoyce.McIntosh@Sun.COM } 164410001SJoyce.McIntosh@Sun.COM mutex_exit(&node->n_mutex); 164510001SJoyce.McIntosh@Sun.COM } 164610001SJoyce.McIntosh@Sun.COM 164710001SJoyce.McIntosh@Sun.COM /* 164810001SJoyce.McIntosh@Sun.COM * smb_node_clear_cached_timestamps 164910001SJoyce.McIntosh@Sun.COM * 165010001SJoyce.McIntosh@Sun.COM * Decrement count of open ofiles using the cached timestamps. 165110001SJoyce.McIntosh@Sun.COM * If the decremented count is zero, clear the cached timestamps. 165210001SJoyce.McIntosh@Sun.COM */ 165310001SJoyce.McIntosh@Sun.COM static void 165410001SJoyce.McIntosh@Sun.COM smb_node_clear_cached_timestamps(smb_node_t *node) 165510001SJoyce.McIntosh@Sun.COM { 165610001SJoyce.McIntosh@Sun.COM smb_node_t *unode; 165710001SJoyce.McIntosh@Sun.COM 165810001SJoyce.McIntosh@Sun.COM if ((unode = SMB_IS_STREAM(node)) != NULL) 165910001SJoyce.McIntosh@Sun.COM node = unode; 166010001SJoyce.McIntosh@Sun.COM 166110001SJoyce.McIntosh@Sun.COM mutex_enter(&node->n_mutex); 166210001SJoyce.McIntosh@Sun.COM ASSERT(node->n_timestamps.t_open_ofiles > 0); 166310001SJoyce.McIntosh@Sun.COM --(node->n_timestamps.t_open_ofiles); 166410001SJoyce.McIntosh@Sun.COM if (node->n_timestamps.t_open_ofiles == 0) 166510001SJoyce.McIntosh@Sun.COM bzero(&node->n_timestamps, sizeof (smb_times_t)); 166610001SJoyce.McIntosh@Sun.COM mutex_exit(&node->n_mutex); 166710001SJoyce.McIntosh@Sun.COM } 166810001SJoyce.McIntosh@Sun.COM 166910001SJoyce.McIntosh@Sun.COM /* 167010001SJoyce.McIntosh@Sun.COM * smb_node_get_cached_timestamps 167110001SJoyce.McIntosh@Sun.COM * 167210001SJoyce.McIntosh@Sun.COM * Overwrite timestamps in attr with those cached in node. 167310001SJoyce.McIntosh@Sun.COM */ 167410001SJoyce.McIntosh@Sun.COM static void 167510001SJoyce.McIntosh@Sun.COM smb_node_get_cached_timestamps(smb_node_t *node, smb_attr_t *attr) 167610001SJoyce.McIntosh@Sun.COM { 167710001SJoyce.McIntosh@Sun.COM smb_node_t *unode; 167810001SJoyce.McIntosh@Sun.COM 167910001SJoyce.McIntosh@Sun.COM if ((unode = SMB_IS_STREAM(node)) != NULL) 168010001SJoyce.McIntosh@Sun.COM node = unode; 168110001SJoyce.McIntosh@Sun.COM 168210001SJoyce.McIntosh@Sun.COM mutex_enter(&node->n_mutex); 168310001SJoyce.McIntosh@Sun.COM if (node->n_timestamps.t_cached) { 168410001SJoyce.McIntosh@Sun.COM attr->sa_vattr.va_mtime = node->n_timestamps.t_mtime; 168510001SJoyce.McIntosh@Sun.COM attr->sa_vattr.va_atime = node->n_timestamps.t_atime; 168610001SJoyce.McIntosh@Sun.COM attr->sa_vattr.va_ctime = node->n_timestamps.t_ctime; 168710001SJoyce.McIntosh@Sun.COM attr->sa_crtime = node->n_timestamps.t_crtime; 168810001SJoyce.McIntosh@Sun.COM } 168910001SJoyce.McIntosh@Sun.COM mutex_exit(&node->n_mutex); 169010001SJoyce.McIntosh@Sun.COM } 169110001SJoyce.McIntosh@Sun.COM 169210001SJoyce.McIntosh@Sun.COM /* 169310001SJoyce.McIntosh@Sun.COM * smb_node_set_cached_timestamps 169410001SJoyce.McIntosh@Sun.COM * 169510001SJoyce.McIntosh@Sun.COM * Update the node's cached timestamps with values from attr. 169610001SJoyce.McIntosh@Sun.COM */ 169710001SJoyce.McIntosh@Sun.COM static void 169810001SJoyce.McIntosh@Sun.COM smb_node_set_cached_timestamps(smb_node_t *node, smb_attr_t *attr) 169910001SJoyce.McIntosh@Sun.COM { 170010001SJoyce.McIntosh@Sun.COM smb_node_t *unode; 170110001SJoyce.McIntosh@Sun.COM 170210001SJoyce.McIntosh@Sun.COM if ((unode = SMB_IS_STREAM(node)) != NULL) 170310001SJoyce.McIntosh@Sun.COM node = unode; 170410001SJoyce.McIntosh@Sun.COM 170510001SJoyce.McIntosh@Sun.COM mutex_enter(&node->n_mutex); 170610001SJoyce.McIntosh@Sun.COM if (node->n_timestamps.t_cached) { 170710001SJoyce.McIntosh@Sun.COM if (attr->sa_mask & SMB_AT_MTIME) 170810001SJoyce.McIntosh@Sun.COM node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime; 170910001SJoyce.McIntosh@Sun.COM if (attr->sa_mask & SMB_AT_ATIME) 171010001SJoyce.McIntosh@Sun.COM node->n_timestamps.t_atime = attr->sa_vattr.va_atime; 171110001SJoyce.McIntosh@Sun.COM if (attr->sa_mask & SMB_AT_CTIME) 171210001SJoyce.McIntosh@Sun.COM node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime; 171310001SJoyce.McIntosh@Sun.COM if (attr->sa_mask & SMB_AT_CRTIME) 171410001SJoyce.McIntosh@Sun.COM node->n_timestamps.t_crtime = attr->sa_crtime; 171510001SJoyce.McIntosh@Sun.COM } 171610001SJoyce.McIntosh@Sun.COM mutex_exit(&node->n_mutex); 171710001SJoyce.McIntosh@Sun.COM } 171811963SAfshin.Ardakani@Sun.COM 171911963SAfshin.Ardakani@Sun.COM /* 172011963SAfshin.Ardakani@Sun.COM * Check to see if the node represents a reparse point. 172111963SAfshin.Ardakani@Sun.COM * If yes, whether the reparse point contains a DFS link. 172211963SAfshin.Ardakani@Sun.COM */ 172311963SAfshin.Ardakani@Sun.COM static void 172411963SAfshin.Ardakani@Sun.COM smb_node_init_reparse(smb_node_t *node, smb_attr_t *attr) 172511963SAfshin.Ardakani@Sun.COM { 172611963SAfshin.Ardakani@Sun.COM nvlist_t *nvl; 172711963SAfshin.Ardakani@Sun.COM nvpair_t *rec; 172811963SAfshin.Ardakani@Sun.COM char *rec_type; 172911963SAfshin.Ardakani@Sun.COM 173011963SAfshin.Ardakani@Sun.COM if ((attr->sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0) 173111963SAfshin.Ardakani@Sun.COM return; 173211963SAfshin.Ardakani@Sun.COM 173311963SAfshin.Ardakani@Sun.COM if ((nvl = reparse_init()) == NULL) 173411963SAfshin.Ardakani@Sun.COM return; 173511963SAfshin.Ardakani@Sun.COM 173611963SAfshin.Ardakani@Sun.COM if (reparse_vnode_parse(node->vp, nvl) != 0) { 173711963SAfshin.Ardakani@Sun.COM reparse_free(nvl); 173811963SAfshin.Ardakani@Sun.COM return; 173911963SAfshin.Ardakani@Sun.COM } 174011963SAfshin.Ardakani@Sun.COM 174111963SAfshin.Ardakani@Sun.COM node->flags |= NODE_FLAGS_REPARSE; 174211963SAfshin.Ardakani@Sun.COM 174311963SAfshin.Ardakani@Sun.COM rec = nvlist_next_nvpair(nvl, NULL); 174411963SAfshin.Ardakani@Sun.COM while (rec != NULL) { 174511963SAfshin.Ardakani@Sun.COM rec_type = nvpair_name(rec); 174611963SAfshin.Ardakani@Sun.COM if ((rec_type != NULL) && 174711963SAfshin.Ardakani@Sun.COM (strcasecmp(rec_type, DFS_REPARSE_SVCTYPE) == 0)) { 174811963SAfshin.Ardakani@Sun.COM node->flags |= NODE_FLAGS_DFSLINK; 174911963SAfshin.Ardakani@Sun.COM break; 175011963SAfshin.Ardakani@Sun.COM } 175111963SAfshin.Ardakani@Sun.COM rec = nvlist_next_nvpair(nvl, rec); 175211963SAfshin.Ardakani@Sun.COM } 175311963SAfshin.Ardakani@Sun.COM 175411963SAfshin.Ardakani@Sun.COM reparse_free(nvl); 175511963SAfshin.Ardakani@Sun.COM } 175611963SAfshin.Ardakani@Sun.COM 175711963SAfshin.Ardakani@Sun.COM /* 175811963SAfshin.Ardakani@Sun.COM * smb_node_init_system 175911963SAfshin.Ardakani@Sun.COM * 176011963SAfshin.Ardakani@Sun.COM * If the node represents a special system file set NODE_FLAG_SYSTEM. 176111963SAfshin.Ardakani@Sun.COM * System files: 176211963SAfshin.Ardakani@Sun.COM * - any node whose parent dnode has NODE_FLAG_SYSTEM set 176311963SAfshin.Ardakani@Sun.COM * - any node whose associated unnamed stream node (unode) has 176411963SAfshin.Ardakani@Sun.COM * NODE_FLAG_SYSTEM set 176511963SAfshin.Ardakani@Sun.COM * - .$EXTEND at root of share (quota management) 176611963SAfshin.Ardakani@Sun.COM */ 176711963SAfshin.Ardakani@Sun.COM static void 176811963SAfshin.Ardakani@Sun.COM smb_node_init_system(smb_node_t *node) 176911963SAfshin.Ardakani@Sun.COM { 177011963SAfshin.Ardakani@Sun.COM smb_node_t *dnode = node->n_dnode; 177111963SAfshin.Ardakani@Sun.COM smb_node_t *unode = node->n_unode; 177211963SAfshin.Ardakani@Sun.COM 177311963SAfshin.Ardakani@Sun.COM if ((dnode) && (dnode->flags & NODE_FLAGS_SYSTEM)) { 177411963SAfshin.Ardakani@Sun.COM node->flags |= NODE_FLAGS_SYSTEM; 177511963SAfshin.Ardakani@Sun.COM return; 177611963SAfshin.Ardakani@Sun.COM } 177711963SAfshin.Ardakani@Sun.COM 177811963SAfshin.Ardakani@Sun.COM if ((unode) && (unode->flags & NODE_FLAGS_SYSTEM)) { 177911963SAfshin.Ardakani@Sun.COM node->flags |= NODE_FLAGS_SYSTEM; 178011963SAfshin.Ardakani@Sun.COM return; 178111963SAfshin.Ardakani@Sun.COM } 178211963SAfshin.Ardakani@Sun.COM 178311963SAfshin.Ardakani@Sun.COM if ((dnode) && (smb_node_is_vfsroot(node->n_dnode) && 178411963SAfshin.Ardakani@Sun.COM (strcasecmp(node->od_name, ".$EXTEND") == 0))) { 178511963SAfshin.Ardakani@Sun.COM node->flags |= NODE_FLAGS_SYSTEM; 178611963SAfshin.Ardakani@Sun.COM } 178711963SAfshin.Ardakani@Sun.COM } 1788