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 /* 22*11633SJoyce.McIntosh@Sun.COM * Copyright 2010 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 */ 13110966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.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 *); 13911337SWilliam.Krier@Sun.COM static void smb_node_notify_parent(smb_node_t *); 1408934SJose.Borrego@Sun.COM static void smb_node_delete_on_close(smb_node_t *); 1418934SJose.Borrego@Sun.COM static void smb_node_create_audit_buf(smb_node_t *, int); 1428934SJose.Borrego@Sun.COM static void smb_node_destroy_audit_buf(smb_node_t *); 1438934SJose.Borrego@Sun.COM static void smb_node_audit(smb_node_t *); 14410001SJoyce.McIntosh@Sun.COM static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t); 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 *); 14910504SKeyur.Desai@Sun.COM 15010504SKeyur.Desai@Sun.COM static void smb_node_init_cached_data(smb_node_t *); 15110504SKeyur.Desai@Sun.COM static void smb_node_clear_cached_data(smb_node_t *); 15210504SKeyur.Desai@Sun.COM 15310504SKeyur.Desai@Sun.COM static void smb_node_init_cached_timestamps(smb_node_t *, smb_attr_t *); 15410001SJoyce.McIntosh@Sun.COM static void smb_node_clear_cached_timestamps(smb_node_t *); 15510001SJoyce.McIntosh@Sun.COM static void smb_node_get_cached_timestamps(smb_node_t *, smb_attr_t *); 15610001SJoyce.McIntosh@Sun.COM static void smb_node_set_cached_timestamps(smb_node_t *, smb_attr_t *); 1575331Samw 15810504SKeyur.Desai@Sun.COM static void smb_node_init_cached_allocsz(smb_node_t *, smb_attr_t *); 15910504SKeyur.Desai@Sun.COM static void smb_node_clear_cached_allocsz(smb_node_t *); 16010504SKeyur.Desai@Sun.COM static void smb_node_get_cached_allocsz(smb_node_t *, smb_attr_t *); 16110504SKeyur.Desai@Sun.COM static void smb_node_set_cached_allocsz(smb_node_t *, smb_attr_t *); 16210504SKeyur.Desai@Sun.COM 1635331Samw #define VALIDATE_DIR_NODE(_dir_, _node_) \ 1645331Samw ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \ 1655331Samw ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \ 16610122SJordan.Brown@Sun.COM ASSERT((_dir_)->n_dnode != (_node_)); 1675331Samw 16810504SKeyur.Desai@Sun.COM /* round sz to DEV_BSIZE block */ 16910504SKeyur.Desai@Sun.COM #define SMB_ALLOCSZ(sz) (((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1)) 17010504SKeyur.Desai@Sun.COM 1718934SJose.Borrego@Sun.COM static kmem_cache_t *smb_node_cache = NULL; 1726139Sjb150015 static boolean_t smb_node_initialized = B_FALSE; 1736139Sjb150015 static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1]; 1746139Sjb150015 1756139Sjb150015 /* 1766139Sjb150015 * smb_node_init 1776139Sjb150015 * 1786139Sjb150015 * Initialization of the SMB node layer. 1796139Sjb150015 * 1806139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 1816139Sjb150015 * thread makes the call. 1826139Sjb150015 */ 1836139Sjb150015 int 1846139Sjb150015 smb_node_init(void) 1856139Sjb150015 { 1866139Sjb150015 int i; 1876139Sjb150015 1886139Sjb150015 if (smb_node_initialized) 1896139Sjb150015 return (0); 1908934SJose.Borrego@Sun.COM smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE, 1918934SJose.Borrego@Sun.COM sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor, 1928934SJose.Borrego@Sun.COM NULL, NULL, NULL, 0); 1936139Sjb150015 1946139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 1956139Sjb150015 smb_llist_constructor(&smb_node_hash_table[i], 1966139Sjb150015 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 1976139Sjb150015 } 1986139Sjb150015 smb_node_initialized = B_TRUE; 1996139Sjb150015 return (0); 2006139Sjb150015 } 2016139Sjb150015 2026139Sjb150015 /* 2036139Sjb150015 * smb_node_fini 2046139Sjb150015 * 2056139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 2066139Sjb150015 * thread makes the call. 2076139Sjb150015 */ 2086139Sjb150015 void 2096139Sjb150015 smb_node_fini(void) 2106139Sjb150015 { 2116139Sjb150015 int i; 2126139Sjb150015 2136139Sjb150015 if (!smb_node_initialized) 2146139Sjb150015 return; 2156139Sjb150015 2166139Sjb150015 #ifdef DEBUG 2176139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 2186139Sjb150015 smb_node_t *node; 2196139Sjb150015 2206139Sjb150015 /* 2216139Sjb150015 * The following sequence is just intended for sanity check. 2226139Sjb150015 * This will have to be modified when the code goes into 2236139Sjb150015 * production. 2246139Sjb150015 * 2256139Sjb150015 * The SMB node hash table should be emtpy at this point. If the 2266139Sjb150015 * hash table is not empty a panic will be triggered. 2276139Sjb150015 * 2286139Sjb150015 * The reason why SMB nodes are still remaining in the hash 2296139Sjb150015 * table is problably due to a mismatch between calls to 2306139Sjb150015 * smb_node_lookup() and smb_node_release(). You must track that 2316139Sjb150015 * down. 2326139Sjb150015 */ 2336139Sjb150015 node = smb_llist_head(&smb_node_hash_table[i]); 2346139Sjb150015 ASSERT(node == NULL); 2356139Sjb150015 } 2366139Sjb150015 #endif 2376139Sjb150015 2386139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 2396139Sjb150015 smb_llist_destructor(&smb_node_hash_table[i]); 2406139Sjb150015 } 2418934SJose.Borrego@Sun.COM kmem_cache_destroy(smb_node_cache); 2428934SJose.Borrego@Sun.COM smb_node_cache = NULL; 2436139Sjb150015 smb_node_initialized = B_FALSE; 2446139Sjb150015 } 2456139Sjb150015 2465331Samw /* 2475331Samw * smb_node_lookup() 2485331Samw * 2495331Samw * NOTE: This routine should only be called by the file system interface layer, 2505331Samw * and not by SMB. 2515331Samw * 2525331Samw * smb_node_lookup() is called upon successful lookup, mkdir, and create 2535331Samw * (for both non-streams and streams). In each of these cases, a held vnode is 2548670SJose.Borrego@Sun.COM * passed into this routine. If a new smb_node is created it will take its 2558670SJose.Borrego@Sun.COM * own hold on the vnode. The caller's hold therefore still belongs to, and 2568670SJose.Borrego@Sun.COM * should be released by, the caller. 2575331Samw * 2585331Samw * A reference is taken on the smb_node whether found in the hash table 2595331Samw * or newly created. 2605331Samw * 2615331Samw * If an smb_node needs to be created, a reference is also taken on the 26210122SJordan.Brown@Sun.COM * dnode (if passed in). 2635331Samw * 2645331Samw * See smb_node_release() for details on the release of these references. 2655331Samw */ 2665331Samw 2675331Samw /*ARGSUSED*/ 2685331Samw smb_node_t * 2695331Samw smb_node_lookup( 2705331Samw struct smb_request *sr, 2715331Samw struct open_param *op, 2725331Samw cred_t *cred, 2735331Samw vnode_t *vp, 2745331Samw char *od_name, 27510122SJordan.Brown@Sun.COM smb_node_t *dnode, 27610122SJordan.Brown@Sun.COM smb_node_t *unode) 2775331Samw { 2785331Samw smb_llist_t *node_hdr; 2795331Samw smb_node_t *node; 28010001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 2815331Samw uint32_t hashkey = 0; 2827348SJose.Borrego@Sun.COM fsid_t fsid; 2835331Samw int error; 2845331Samw krw_t lock_mode; 2855331Samw vnode_t *unnamed_vp = NULL; 2865331Samw 2875331Samw /* 2885331Samw * smb_vop_getattr() is called here instead of smb_fsop_getattr(), 2895331Samw * because the node may not yet exist. We also do not want to call 2905331Samw * it with the list lock held. 2915331Samw */ 2925331Samw 29310122SJordan.Brown@Sun.COM if (unode) 29410122SJordan.Brown@Sun.COM unnamed_vp = unode->vp; 2955331Samw 2965331Samw /* 2975331Samw * This getattr is performed on behalf of the server 2985331Samw * that's why kcred is used not the user's cred 2995331Samw */ 30010001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_ALL; 30110001SJoyce.McIntosh@Sun.COM error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, kcred); 3025331Samw if (error) 3035331Samw return (NULL); 3045331Samw 3057348SJose.Borrego@Sun.COM if (sr && sr->tid_tree) { 3067348SJose.Borrego@Sun.COM /* 3077348SJose.Borrego@Sun.COM * The fsid for a file is that of the tree, even 3087348SJose.Borrego@Sun.COM * if the file resides in a different mountpoint 3097348SJose.Borrego@Sun.COM * under the share. 3107348SJose.Borrego@Sun.COM */ 3117348SJose.Borrego@Sun.COM fsid = SMB_TREE_FSID(sr->tid_tree); 3125331Samw } else { 3137348SJose.Borrego@Sun.COM /* 3147348SJose.Borrego@Sun.COM * This should be getting executed only for the 3157348SJose.Borrego@Sun.COM * tree root smb_node. 3167348SJose.Borrego@Sun.COM */ 3177348SJose.Borrego@Sun.COM fsid = vp->v_vfsp->vfs_fsid; 3185331Samw } 3195331Samw 32010001SJoyce.McIntosh@Sun.COM node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey); 3215331Samw lock_mode = RW_READER; 3225331Samw 3235331Samw smb_llist_enter(node_hdr, lock_mode); 3245331Samw for (;;) { 3255331Samw node = list_head(&node_hdr->ll_list); 3265331Samw while (node) { 3275331Samw ASSERT(node->n_magic == SMB_NODE_MAGIC); 3285331Samw ASSERT(node->n_hash_bucket == node_hdr); 3295331Samw if ((node->n_hashkey == hashkey) && (node->vp == vp)) { 3308934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 3315331Samw DTRACE_PROBE1(smb_node_lookup_hit, 3325331Samw smb_node_t *, node); 3335331Samw switch (node->n_state) { 3348934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 3358934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 3365331Samw case SMB_NODE_STATE_AVAILABLE: 3375331Samw /* The node was found. */ 3385331Samw node->n_refcnt++; 33910122SJordan.Brown@Sun.COM if ((node->n_dnode == NULL) && 34010122SJordan.Brown@Sun.COM (dnode != NULL) && 341*11633SJoyce.McIntosh@Sun.COM (node != dnode) && 3425331Samw (strcmp(od_name, "..") != 0) && 3435331Samw (strcmp(od_name, ".") != 0)) { 34410122SJordan.Brown@Sun.COM VALIDATE_DIR_NODE(dnode, node); 34510122SJordan.Brown@Sun.COM node->n_dnode = dnode; 34610122SJordan.Brown@Sun.COM smb_node_ref(dnode); 3475331Samw } 3485331Samw 3498934SJose.Borrego@Sun.COM smb_node_audit(node); 3508934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 3515331Samw smb_llist_exit(node_hdr); 3525331Samw return (node); 3535331Samw 3545331Samw case SMB_NODE_STATE_DESTROYING: 3555331Samw /* 3565331Samw * Although the node exists it is about 3575331Samw * to be destroyed. We act as it hasn't 3585331Samw * been found. 3595331Samw */ 3608934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 3615331Samw break; 3625331Samw default: 3635331Samw /* 3645331Samw * Although the node exists it is in an 3655331Samw * unknown state. We act as it hasn't 3665331Samw * been found. 3675331Samw */ 3685331Samw ASSERT(0); 3698934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 3705331Samw break; 3715331Samw } 3725331Samw } 3735331Samw node = smb_llist_next(node_hdr, node); 3745331Samw } 3755331Samw if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) { 3765331Samw lock_mode = RW_WRITER; 3775331Samw continue; 3785331Samw } 3795331Samw break; 3805331Samw } 38110001SJoyce.McIntosh@Sun.COM node = smb_node_alloc(od_name, vp, node_hdr, hashkey); 3828934SJose.Borrego@Sun.COM node->n_orig_uid = crgetuid(sr->user_cr); 3835331Samw 3845331Samw if (op) 3859343SAfshin.Ardakani@Sun.COM node->flags |= smb_is_executable(op->fqi.fq_last_comp); 3865331Samw 38710122SJordan.Brown@Sun.COM if (dnode) { 38810122SJordan.Brown@Sun.COM smb_node_ref(dnode); 38910122SJordan.Brown@Sun.COM node->n_dnode = dnode; 39010122SJordan.Brown@Sun.COM ASSERT(dnode->n_dnode != node); 39110122SJordan.Brown@Sun.COM ASSERT((dnode->vp->v_xattrdir) || 39210122SJordan.Brown@Sun.COM (dnode->vp->v_type == VDIR)); 3935331Samw } 3945331Samw 39510122SJordan.Brown@Sun.COM if (unode) { 39610122SJordan.Brown@Sun.COM smb_node_ref(unode); 39710122SJordan.Brown@Sun.COM node->n_unode = unode; 3985331Samw } 3995331Samw 4005331Samw DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node); 4018934SJose.Borrego@Sun.COM smb_node_audit(node); 4025331Samw smb_llist_insert_head(node_hdr, node); 4035331Samw smb_llist_exit(node_hdr); 4045331Samw return (node); 4055331Samw } 4065331Samw 4075331Samw /* 4085331Samw * smb_stream_node_lookup() 4095331Samw * 4105331Samw * Note: stream_name (the name that will be stored in the "od_name" field 4115331Samw * of a stream's smb_node) is the same as the on-disk name for the stream 4125331Samw * except that it does not have SMB_STREAM_PREFIX prepended. 4135331Samw */ 4145331Samw 4155331Samw smb_node_t * 4168934SJose.Borrego@Sun.COM smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode, 41710001SJoyce.McIntosh@Sun.COM vnode_t *xattrdirvp, vnode_t *vp, char *stream_name) 4185331Samw { 4195331Samw smb_node_t *xattrdir_node; 4205331Samw smb_node_t *snode; 4215331Samw 4225331Samw xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR, 42310001SJoyce.McIntosh@Sun.COM fnode, NULL); 4245331Samw 4255331Samw if (xattrdir_node == NULL) 4265331Samw return (NULL); 4275331Samw 4285331Samw snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node, 42910001SJoyce.McIntosh@Sun.COM fnode); 4305331Samw 4315331Samw (void) smb_node_release(xattrdir_node); 4325331Samw return (snode); 4335331Samw } 4345331Samw 4355331Samw 4365331Samw /* 4375331Samw * This function should be called whenever a reference is needed on an 4385331Samw * smb_node pointer. The copy of an smb_node pointer from one non-local 4395331Samw * data structure to another requires a reference to be taken on the smb_node 4405331Samw * (unless the usage is localized). Each data structure deallocation routine 4415331Samw * will call smb_node_release() on its smb_node pointers. 4425331Samw * 4435331Samw * In general, an smb_node pointer residing in a structure should never be 4445331Samw * stale. A node pointer may be NULL, however, and care should be taken 4455331Samw * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid. 4465331Samw * Care also needs to be taken with respect to racing deallocations of a 4475331Samw * structure. 4485331Samw */ 4495331Samw void 4505331Samw smb_node_ref(smb_node_t *node) 4515331Samw { 4528934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 4535331Samw 4548934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 4558934SJose.Borrego@Sun.COM switch (node->n_state) { 4568934SJose.Borrego@Sun.COM case SMB_NODE_STATE_AVAILABLE: 4578934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 4588934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 4598934SJose.Borrego@Sun.COM node->n_refcnt++; 4608934SJose.Borrego@Sun.COM ASSERT(node->n_refcnt); 4618934SJose.Borrego@Sun.COM DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); 4628934SJose.Borrego@Sun.COM smb_node_audit(node); 4638934SJose.Borrego@Sun.COM break; 4648934SJose.Borrego@Sun.COM default: 4658934SJose.Borrego@Sun.COM SMB_PANIC(); 4668934SJose.Borrego@Sun.COM } 4678934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 4685331Samw } 4695331Samw 4705331Samw /* 4715331Samw * smb_node_lookup() takes a hold on an smb_node, whether found in the 4725331Samw * hash table or newly created. This hold is expected to be released 4735331Samw * in the following manner. 4745331Samw * 4755331Samw * smb_node_lookup() takes an address of an smb_node pointer. This should 4765331Samw * be getting passed down via a lookup (whether path name or component), mkdir, 4775331Samw * create. If the original smb_node pointer resides in a data structure, then 4785331Samw * the deallocation routine for the data structure is responsible for calling 4795331Samw * smb_node_release() on the smb_node pointer. Alternatively, 4805331Samw * smb_node_release() can be called as soon as the smb_node pointer is no longer 4815331Samw * needed. In this case, callers are responsible for setting an embedded 4825331Samw * pointer to NULL if it is known that the last reference is being released. 4835331Samw * 4845331Samw * If the passed-in address of the smb_node pointer belongs to a local variable, 4855331Samw * then the caller with the local variable should call smb_node_release() 4865331Samw * directly. 4875331Samw * 48810122SJordan.Brown@Sun.COM * smb_node_release() itself will call smb_node_release() on a node's n_dnode, 48910122SJordan.Brown@Sun.COM * as smb_node_lookup() takes a hold on dnode. 4905331Samw */ 4915331Samw void 4925331Samw smb_node_release(smb_node_t *node) 4935331Samw { 4948934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 4955331Samw 4968934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 4975331Samw ASSERT(node->n_refcnt); 4985331Samw DTRACE_PROBE1(smb_node_release, smb_node_t *, node); 4995331Samw if (--node->n_refcnt == 0) { 5005331Samw switch (node->n_state) { 5015331Samw 5025331Samw case SMB_NODE_STATE_AVAILABLE: 5035331Samw node->n_state = SMB_NODE_STATE_DESTROYING; 5048934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5055331Samw 5065331Samw smb_llist_enter(node->n_hash_bucket, RW_WRITER); 5075331Samw smb_llist_remove(node->n_hash_bucket, node); 5085331Samw smb_llist_exit(node->n_hash_bucket); 5095331Samw 5105331Samw /* 5115331Samw * Check if the file was deleted 5125331Samw */ 5135331Samw smb_node_delete_on_close(node); 5145331Samw 51510122SJordan.Brown@Sun.COM if (node->n_dnode) { 51610122SJordan.Brown@Sun.COM ASSERT(node->n_dnode->n_magic == 5175331Samw SMB_NODE_MAGIC); 51810122SJordan.Brown@Sun.COM smb_node_release(node->n_dnode); 5195331Samw } 5205331Samw 52110122SJordan.Brown@Sun.COM if (node->n_unode) { 52210122SJordan.Brown@Sun.COM ASSERT(node->n_unode->n_magic == 5235331Samw SMB_NODE_MAGIC); 52410122SJordan.Brown@Sun.COM smb_node_release(node->n_unode); 5255331Samw } 5265331Samw 5278934SJose.Borrego@Sun.COM smb_node_free(node); 5285331Samw return; 5295331Samw 5305331Samw default: 5318934SJose.Borrego@Sun.COM SMB_PANIC(); 5325331Samw } 5335331Samw } 5348934SJose.Borrego@Sun.COM smb_node_audit(node); 5358934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5365331Samw } 5375331Samw 5385331Samw static void 5395331Samw smb_node_delete_on_close(smb_node_t *node) 5405331Samw { 5415331Samw smb_node_t *d_snode; 5425331Samw int rc = 0; 5439231SAfshin.Ardakani@Sun.COM uint32_t flags = 0; 5445331Samw 54510122SJordan.Brown@Sun.COM d_snode = node->n_dnode; 5465331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 5479231SAfshin.Ardakani@Sun.COM node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 5489231SAfshin.Ardakani@Sun.COM flags = node->n_delete_on_close_flags; 5499231SAfshin.Ardakani@Sun.COM ASSERT(node->od_name != NULL); 5505331Samw 55110001SJoyce.McIntosh@Sun.COM if (node->vp->v_type == VDIR) 5525331Samw rc = smb_fsop_rmdir(0, node->delete_on_close_cred, 5539231SAfshin.Ardakani@Sun.COM d_snode, node->od_name, flags); 5545331Samw else 5555331Samw rc = smb_fsop_remove(0, node->delete_on_close_cred, 5569231SAfshin.Ardakani@Sun.COM d_snode, node->od_name, flags); 5575331Samw smb_cred_rele(node->delete_on_close_cred); 5585331Samw } 5595331Samw if (rc != 0) 5605331Samw cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n", 5615331Samw node->od_name, rc); 5625331Samw DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node); 5635331Samw } 5645331Samw 5655331Samw /* 5665331Samw * smb_node_rename() 5675331Samw * 5685331Samw */ 5698934SJose.Borrego@Sun.COM void 5705331Samw smb_node_rename( 5718934SJose.Borrego@Sun.COM smb_node_t *from_dnode, 5728934SJose.Borrego@Sun.COM smb_node_t *ret_node, 5738934SJose.Borrego@Sun.COM smb_node_t *to_dnode, 5745331Samw char *to_name) 5755331Samw { 5768934SJose.Borrego@Sun.COM SMB_NODE_VALID(from_dnode); 5778934SJose.Borrego@Sun.COM SMB_NODE_VALID(to_dnode); 5788934SJose.Borrego@Sun.COM SMB_NODE_VALID(ret_node); 5795331Samw 5808934SJose.Borrego@Sun.COM smb_node_ref(to_dnode); 5818934SJose.Borrego@Sun.COM mutex_enter(&ret_node->n_mutex); 5828934SJose.Borrego@Sun.COM switch (ret_node->n_state) { 5838934SJose.Borrego@Sun.COM case SMB_NODE_STATE_AVAILABLE: 5848934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_GRANTED: 5858934SJose.Borrego@Sun.COM case SMB_NODE_STATE_OPLOCK_BREAKING: 58610122SJordan.Brown@Sun.COM ret_node->n_dnode = to_dnode; 5878934SJose.Borrego@Sun.COM mutex_exit(&ret_node->n_mutex); 58810122SJordan.Brown@Sun.COM ASSERT(to_dnode->n_dnode != ret_node); 5898934SJose.Borrego@Sun.COM ASSERT((to_dnode->vp->v_xattrdir) || 5908934SJose.Borrego@Sun.COM (to_dnode->vp->v_type == VDIR)); 5918934SJose.Borrego@Sun.COM smb_node_release(from_dnode); 5928934SJose.Borrego@Sun.COM (void) strcpy(ret_node->od_name, to_name); 5938934SJose.Borrego@Sun.COM /* 5948934SJose.Borrego@Sun.COM * XXX Need to update attributes? 5958934SJose.Borrego@Sun.COM */ 5968934SJose.Borrego@Sun.COM break; 5978934SJose.Borrego@Sun.COM default: 5988934SJose.Borrego@Sun.COM SMB_PANIC(); 5998934SJose.Borrego@Sun.COM } 6005331Samw } 6015331Samw 6025331Samw int 6036139Sjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root) 6045331Samw { 60510001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 6066139Sjb150015 int error; 6076139Sjb150015 uint32_t hashkey; 6086139Sjb150015 smb_llist_t *node_hdr; 6096139Sjb150015 smb_node_t *node; 6105331Samw 61110001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_ALL; 61210001SJoyce.McIntosh@Sun.COM error = smb_vop_getattr(vp, NULL, &attr, 0, kcred); 6136139Sjb150015 if (error) { 6146139Sjb150015 VN_RELE(vp); 6156139Sjb150015 return (error); 6166139Sjb150015 } 6176139Sjb150015 61810001SJoyce.McIntosh@Sun.COM node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &attr, &hashkey); 6195331Samw 62010001SJoyce.McIntosh@Sun.COM node = smb_node_alloc(ROOTVOL, vp, node_hdr, hashkey); 6216139Sjb150015 6226139Sjb150015 sv->si_root_smb_node = node; 6238934SJose.Borrego@Sun.COM smb_node_audit(node); 6246139Sjb150015 smb_llist_enter(node_hdr, RW_WRITER); 6256139Sjb150015 smb_llist_insert_head(node_hdr, node); 6266139Sjb150015 smb_llist_exit(node_hdr); 6276139Sjb150015 *root = node; 6286139Sjb150015 return (0); 6295331Samw } 6305331Samw 6315331Samw /* 6329231SAfshin.Ardakani@Sun.COM * When DeleteOnClose is set on an smb_node, the common open code will 6339231SAfshin.Ardakani@Sun.COM * reject subsequent open requests for the file. Observation of Windows 6349231SAfshin.Ardakani@Sun.COM * 2000 indicates that subsequent opens should be allowed (assuming 6359231SAfshin.Ardakani@Sun.COM * there would be no sharing violation) until the file is closed using 6369231SAfshin.Ardakani@Sun.COM * the fid on which the DeleteOnClose was requested. 6379231SAfshin.Ardakani@Sun.COM * 6389231SAfshin.Ardakani@Sun.COM * If there are multiple opens with delete-on-close create options, 6399231SAfshin.Ardakani@Sun.COM * whichever the first file handle is closed will trigger the node to be 6409231SAfshin.Ardakani@Sun.COM * marked as delete-on-close. The credentials of that ofile will be used 6419231SAfshin.Ardakani@Sun.COM * as the delete-on-close credentials of the node. 6429231SAfshin.Ardakani@Sun.COM */ 6435331Samw int 6449231SAfshin.Ardakani@Sun.COM smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags) 6455331Samw { 64610717Samw@Sun.COM int rc = 0; 64710001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 6485331Samw 64910717Samw@Sun.COM if (node->readonly_creator) 65010001SJoyce.McIntosh@Sun.COM return (-1); 65110001SJoyce.McIntosh@Sun.COM 65210001SJoyce.McIntosh@Sun.COM bzero(&attr, sizeof (smb_attr_t)); 65310001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_DOSATTR; 65410001SJoyce.McIntosh@Sun.COM rc = smb_fsop_getattr(NULL, kcred, node, &attr); 65510001SJoyce.McIntosh@Sun.COM if ((rc != 0) || (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) { 65610001SJoyce.McIntosh@Sun.COM return (-1); 65710001SJoyce.McIntosh@Sun.COM } 65810001SJoyce.McIntosh@Sun.COM 65910717Samw@Sun.COM mutex_enter(&node->n_mutex); 66010717Samw@Sun.COM if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 66110717Samw@Sun.COM rc = -1; 66210717Samw@Sun.COM } else { 66310717Samw@Sun.COM crhold(cr); 66410717Samw@Sun.COM node->delete_on_close_cred = cr; 66510717Samw@Sun.COM node->n_delete_on_close_flags = flags; 66610717Samw@Sun.COM node->flags |= NODE_FLAGS_DELETE_ON_CLOSE; 66710717Samw@Sun.COM rc = 0; 66810717Samw@Sun.COM } 6698934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 67010717Samw@Sun.COM return (rc); 6715331Samw } 6725331Samw 6735331Samw void 6745331Samw smb_node_reset_delete_on_close(smb_node_t *node) 6755331Samw { 6768934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 6775331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 6785331Samw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 6795331Samw crfree(node->delete_on_close_cred); 6805331Samw node->delete_on_close_cred = NULL; 6819231SAfshin.Ardakani@Sun.COM node->n_delete_on_close_flags = 0; 6825331Samw } 6838934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 6845331Samw } 6855772Sas200622 6865772Sas200622 /* 6876771Sjb150015 * smb_node_open_check 6885772Sas200622 * 6895772Sas200622 * check file sharing rules for current open request 6905772Sas200622 * against all existing opens for a file. 6915772Sas200622 * 6925772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 6935772Sas200622 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 6945772Sas200622 */ 6955772Sas200622 uint32_t 6968934SJose.Borrego@Sun.COM smb_node_open_check( 6978934SJose.Borrego@Sun.COM smb_node_t *node, 6988934SJose.Borrego@Sun.COM cred_t *cr, 6998934SJose.Borrego@Sun.COM uint32_t desired_access, 7008934SJose.Borrego@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) { 7106771Sjb150015 status = smb_ofile_open_check(of, cr, desired_access, 7116771Sjb150015 share_access); 7126771Sjb150015 7136771Sjb150015 switch (status) { 7146771Sjb150015 case NT_STATUS_INVALID_HANDLE: 7156771Sjb150015 case NT_STATUS_SUCCESS: 7166771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 7176771Sjb150015 break; 7186771Sjb150015 default: 7196771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 7205772Sas200622 smb_llist_exit(&node->n_ofile_list); 7215772Sas200622 return (status); 7225772Sas200622 } 7235772Sas200622 } 7246771Sjb150015 7255772Sas200622 smb_llist_exit(&node->n_ofile_list); 7265772Sas200622 return (NT_STATUS_SUCCESS); 7275772Sas200622 } 7285772Sas200622 7295772Sas200622 uint32_t 7308934SJose.Borrego@Sun.COM smb_node_rename_check(smb_node_t *node) 7315772Sas200622 { 7328934SJose.Borrego@Sun.COM smb_ofile_t *of; 7338934SJose.Borrego@Sun.COM uint32_t status; 7345772Sas200622 7358934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 7365772Sas200622 7375772Sas200622 /* 7385772Sas200622 * Intra-CIFS check 7395772Sas200622 */ 7405772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 7416771Sjb150015 of = smb_llist_head(&node->n_ofile_list); 7426771Sjb150015 while (of) { 7436771Sjb150015 status = smb_ofile_rename_check(of); 7445772Sas200622 7456771Sjb150015 switch (status) { 7466771Sjb150015 case NT_STATUS_INVALID_HANDLE: 7476771Sjb150015 case NT_STATUS_SUCCESS: 7486771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 7496771Sjb150015 break; 7506771Sjb150015 default: 7516771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 7526771Sjb150015 smb_llist_exit(&node->n_ofile_list); 7536771Sjb150015 return (status); 7545772Sas200622 } 7555772Sas200622 } 7565772Sas200622 smb_llist_exit(&node->n_ofile_list); 7575772Sas200622 7585772Sas200622 /* 7595772Sas200622 * system-wide share check 7605772Sas200622 */ 7615772Sas200622 if (nbl_share_conflict(node->vp, NBL_RENAME, NULL)) 7625772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 7635772Sas200622 else 7645772Sas200622 return (NT_STATUS_SUCCESS); 7655772Sas200622 } 7665772Sas200622 7676771Sjb150015 uint32_t 7685772Sas200622 smb_node_delete_check(smb_node_t *node) 7695772Sas200622 { 7708934SJose.Borrego@Sun.COM smb_ofile_t *of; 7718934SJose.Borrego@Sun.COM uint32_t status; 7725772Sas200622 7738934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 7745772Sas200622 77510001SJoyce.McIntosh@Sun.COM if (node->vp->v_type == VDIR) 7765772Sas200622 return (NT_STATUS_SUCCESS); 7775772Sas200622 7785772Sas200622 /* 7795772Sas200622 * intra-CIFS check 7805772Sas200622 */ 7815772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 7826771Sjb150015 of = smb_llist_head(&node->n_ofile_list); 7836771Sjb150015 while (of) { 7846771Sjb150015 status = smb_ofile_delete_check(of); 7856771Sjb150015 7866771Sjb150015 switch (status) { 7876771Sjb150015 case NT_STATUS_INVALID_HANDLE: 7886771Sjb150015 case NT_STATUS_SUCCESS: 7896771Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 7906771Sjb150015 break; 7916771Sjb150015 default: 7926771Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 7935772Sas200622 smb_llist_exit(&node->n_ofile_list); 7946771Sjb150015 return (status); 7955772Sas200622 } 7965772Sas200622 } 7975772Sas200622 smb_llist_exit(&node->n_ofile_list); 7985772Sas200622 7995772Sas200622 /* 8005772Sas200622 * system-wide share check 8015772Sas200622 */ 8025772Sas200622 if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL)) 8035772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 8045772Sas200622 else 8055772Sas200622 return (NT_STATUS_SUCCESS); 8065772Sas200622 } 8075772Sas200622 8089914Samw@Sun.COM void 8099914Samw@Sun.COM smb_node_notify_change(smb_node_t *node) 8109914Samw@Sun.COM { 8119914Samw@Sun.COM SMB_NODE_VALID(node); 8129914Samw@Sun.COM 8139914Samw@Sun.COM if (node->flags & NODE_FLAGS_NOTIFY_CHANGE) { 8149914Samw@Sun.COM node->flags |= NODE_FLAGS_CHANGED; 8159914Samw@Sun.COM smb_process_node_notify_change_queue(node); 8169914Samw@Sun.COM } 8179914Samw@Sun.COM } 8189914Samw@Sun.COM 81911337SWilliam.Krier@Sun.COM static void 82011337SWilliam.Krier@Sun.COM smb_node_notify_parent(smb_node_t *node) 82111337SWilliam.Krier@Sun.COM { 82211337SWilliam.Krier@Sun.COM SMB_NODE_VALID(node); 82311337SWilliam.Krier@Sun.COM 82411337SWilliam.Krier@Sun.COM if (node->n_dnode != NULL) 82511337SWilliam.Krier@Sun.COM smb_node_notify_change(node->n_dnode); 82611337SWilliam.Krier@Sun.COM } 82711337SWilliam.Krier@Sun.COM 8285772Sas200622 /* 8295772Sas200622 * smb_node_start_crit() 8305772Sas200622 * 8315772Sas200622 * Enter critical region for share reservations. 8325772Sas200622 * See comments above smb_fsop_shrlock(). 8335772Sas200622 */ 8345772Sas200622 8355772Sas200622 void 8365772Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode) 8375772Sas200622 { 8388934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, mode); 8395772Sas200622 nbl_start_crit(node->vp, mode); 8405772Sas200622 } 8415772Sas200622 8425772Sas200622 /* 8435772Sas200622 * smb_node_end_crit() 8445772Sas200622 * 8455772Sas200622 * Exit critical region for share reservations. 8465772Sas200622 */ 8475772Sas200622 8485772Sas200622 void 8495772Sas200622 smb_node_end_crit(smb_node_t *node) 8505772Sas200622 { 8515772Sas200622 nbl_end_crit(node->vp); 8528934SJose.Borrego@Sun.COM rw_exit(&node->n_lock); 8535772Sas200622 } 8545772Sas200622 8555772Sas200622 int 8565772Sas200622 smb_node_in_crit(smb_node_t *node) 8575772Sas200622 { 8588934SJose.Borrego@Sun.COM return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock)); 8598934SJose.Borrego@Sun.COM } 8608934SJose.Borrego@Sun.COM 8618934SJose.Borrego@Sun.COM void 8628934SJose.Borrego@Sun.COM smb_node_rdlock(smb_node_t *node) 8638934SJose.Borrego@Sun.COM { 8648934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, RW_READER); 8658934SJose.Borrego@Sun.COM } 8668934SJose.Borrego@Sun.COM 8678934SJose.Borrego@Sun.COM void 8688934SJose.Borrego@Sun.COM smb_node_wrlock(smb_node_t *node) 8698934SJose.Borrego@Sun.COM { 8708934SJose.Borrego@Sun.COM rw_enter(&node->n_lock, RW_WRITER); 8718934SJose.Borrego@Sun.COM } 8728934SJose.Borrego@Sun.COM 8738934SJose.Borrego@Sun.COM void 8748934SJose.Borrego@Sun.COM smb_node_unlock(smb_node_t *node) 8758934SJose.Borrego@Sun.COM { 8768934SJose.Borrego@Sun.COM rw_exit(&node->n_lock); 8778934SJose.Borrego@Sun.COM } 8788934SJose.Borrego@Sun.COM 8798934SJose.Borrego@Sun.COM uint32_t 8808934SJose.Borrego@Sun.COM smb_node_get_ofile_count(smb_node_t *node) 8818934SJose.Borrego@Sun.COM { 8828934SJose.Borrego@Sun.COM uint32_t cntr; 8838934SJose.Borrego@Sun.COM 8848934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 8858934SJose.Borrego@Sun.COM 8868934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_READER); 8878934SJose.Borrego@Sun.COM cntr = smb_llist_get_count(&node->n_ofile_list); 8888934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 8898934SJose.Borrego@Sun.COM return (cntr); 8908934SJose.Borrego@Sun.COM } 8918934SJose.Borrego@Sun.COM 8928934SJose.Borrego@Sun.COM void 8938934SJose.Borrego@Sun.COM smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of) 8948934SJose.Borrego@Sun.COM { 8958934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 8968934SJose.Borrego@Sun.COM 8978934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_WRITER); 8988934SJose.Borrego@Sun.COM smb_llist_insert_tail(&node->n_ofile_list, of); 8998934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 9008934SJose.Borrego@Sun.COM } 9018934SJose.Borrego@Sun.COM 9028934SJose.Borrego@Sun.COM void 9038934SJose.Borrego@Sun.COM smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of) 9048934SJose.Borrego@Sun.COM { 9058934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9068934SJose.Borrego@Sun.COM 9078934SJose.Borrego@Sun.COM smb_llist_enter(&node->n_ofile_list, RW_WRITER); 9088934SJose.Borrego@Sun.COM smb_llist_remove(&node->n_ofile_list, of); 9098934SJose.Borrego@Sun.COM smb_llist_exit(&node->n_ofile_list); 9108934SJose.Borrego@Sun.COM } 9118934SJose.Borrego@Sun.COM 91210001SJoyce.McIntosh@Sun.COM /* 91310001SJoyce.McIntosh@Sun.COM * smb_node_inc_open_ofiles 91410001SJoyce.McIntosh@Sun.COM */ 9158934SJose.Borrego@Sun.COM void 9168934SJose.Borrego@Sun.COM smb_node_inc_open_ofiles(smb_node_t *node) 9178934SJose.Borrego@Sun.COM { 9188934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9198934SJose.Borrego@Sun.COM 9208934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 9218934SJose.Borrego@Sun.COM node->n_open_count++; 9228934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 92310001SJoyce.McIntosh@Sun.COM 92410504SKeyur.Desai@Sun.COM smb_node_init_cached_data(node); 9258934SJose.Borrego@Sun.COM } 9268934SJose.Borrego@Sun.COM 92710001SJoyce.McIntosh@Sun.COM /* 92810001SJoyce.McIntosh@Sun.COM * smb_node_dec_open_ofiles 92910001SJoyce.McIntosh@Sun.COM */ 9308934SJose.Borrego@Sun.COM void 9318934SJose.Borrego@Sun.COM smb_node_dec_open_ofiles(smb_node_t *node) 9328934SJose.Borrego@Sun.COM { 9338934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9348934SJose.Borrego@Sun.COM 9358934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 9368934SJose.Borrego@Sun.COM node->n_open_count--; 9378934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 93810001SJoyce.McIntosh@Sun.COM 93910504SKeyur.Desai@Sun.COM smb_node_clear_cached_data(node); 9408934SJose.Borrego@Sun.COM } 9418934SJose.Borrego@Sun.COM 9428934SJose.Borrego@Sun.COM uint32_t 9438934SJose.Borrego@Sun.COM smb_node_get_open_ofiles(smb_node_t *node) 9448934SJose.Borrego@Sun.COM { 9458934SJose.Borrego@Sun.COM uint32_t cnt; 9468934SJose.Borrego@Sun.COM 9478934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 9488934SJose.Borrego@Sun.COM 9498934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 9508934SJose.Borrego@Sun.COM cnt = node->n_open_count; 9518934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 9528934SJose.Borrego@Sun.COM return (cnt); 9535772Sas200622 } 9548934SJose.Borrego@Sun.COM 9558934SJose.Borrego@Sun.COM /* 9568934SJose.Borrego@Sun.COM * smb_node_alloc 9578934SJose.Borrego@Sun.COM */ 9588934SJose.Borrego@Sun.COM static smb_node_t * 9598934SJose.Borrego@Sun.COM smb_node_alloc( 9608934SJose.Borrego@Sun.COM char *od_name, 9618934SJose.Borrego@Sun.COM vnode_t *vp, 9628934SJose.Borrego@Sun.COM smb_llist_t *bucket, 9638934SJose.Borrego@Sun.COM uint32_t hashkey) 9648934SJose.Borrego@Sun.COM { 9658934SJose.Borrego@Sun.COM smb_node_t *node; 9668934SJose.Borrego@Sun.COM 9678934SJose.Borrego@Sun.COM node = kmem_cache_alloc(smb_node_cache, KM_SLEEP); 9688934SJose.Borrego@Sun.COM 9698934SJose.Borrego@Sun.COM if (node->n_audit_buf != NULL) 9708934SJose.Borrego@Sun.COM node->n_audit_buf->anb_index = 0; 9718934SJose.Borrego@Sun.COM 97210001SJoyce.McIntosh@Sun.COM node->flags = 0; 9738934SJose.Borrego@Sun.COM VN_HOLD(vp); 9748934SJose.Borrego@Sun.COM node->vp = vp; 9758934SJose.Borrego@Sun.COM node->n_refcnt = 1; 9768934SJose.Borrego@Sun.COM node->n_hash_bucket = bucket; 9778934SJose.Borrego@Sun.COM node->n_hashkey = hashkey; 9788934SJose.Borrego@Sun.COM node->n_orig_uid = 0; 9798934SJose.Borrego@Sun.COM node->readonly_creator = NULL; 9808934SJose.Borrego@Sun.COM node->waiting_event = 0; 9818934SJose.Borrego@Sun.COM node->n_open_count = 0; 98210122SJordan.Brown@Sun.COM node->n_dnode = NULL; 98310122SJordan.Brown@Sun.COM node->n_unode = NULL; 9848934SJose.Borrego@Sun.COM node->delete_on_close_cred = NULL; 9859231SAfshin.Ardakani@Sun.COM node->n_delete_on_close_flags = 0; 9868934SJose.Borrego@Sun.COM 9878934SJose.Borrego@Sun.COM (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); 9888934SJose.Borrego@Sun.COM if (strcmp(od_name, XATTR_DIR) == 0) 9898934SJose.Borrego@Sun.COM node->flags |= NODE_XATTR_DIR; 9908934SJose.Borrego@Sun.COM 9918934SJose.Borrego@Sun.COM node->n_state = SMB_NODE_STATE_AVAILABLE; 9928934SJose.Borrego@Sun.COM node->n_magic = SMB_NODE_MAGIC; 9938934SJose.Borrego@Sun.COM return (node); 9948934SJose.Borrego@Sun.COM } 9958934SJose.Borrego@Sun.COM 9968934SJose.Borrego@Sun.COM /* 9978934SJose.Borrego@Sun.COM * smb_node_free 9988934SJose.Borrego@Sun.COM */ 9998934SJose.Borrego@Sun.COM static void 10008934SJose.Borrego@Sun.COM smb_node_free(smb_node_t *node) 10018934SJose.Borrego@Sun.COM { 10028934SJose.Borrego@Sun.COM SMB_NODE_VALID(node); 10038934SJose.Borrego@Sun.COM 10048934SJose.Borrego@Sun.COM node->n_magic = 0; 10058934SJose.Borrego@Sun.COM VERIFY(!list_link_active(&node->n_lnd)); 10068934SJose.Borrego@Sun.COM VERIFY(node->n_lock_list.ll_count == 0); 10078934SJose.Borrego@Sun.COM VERIFY(node->n_ofile_list.ll_count == 0); 10088934SJose.Borrego@Sun.COM VERIFY(node->n_oplock.ol_xthread == NULL); 10099021Samw@Sun.COM VERIFY(mutex_owner(&node->n_mutex) == NULL); 10109021Samw@Sun.COM VERIFY(!RW_LOCK_HELD(&node->n_lock)); 10118934SJose.Borrego@Sun.COM VN_RELE(node->vp); 10128934SJose.Borrego@Sun.COM kmem_cache_free(smb_node_cache, node); 10138934SJose.Borrego@Sun.COM } 10148934SJose.Borrego@Sun.COM 10158934SJose.Borrego@Sun.COM /* 10168934SJose.Borrego@Sun.COM * smb_node_constructor 10178934SJose.Borrego@Sun.COM */ 10188934SJose.Borrego@Sun.COM static int 10198934SJose.Borrego@Sun.COM smb_node_constructor(void *buf, void *un, int kmflags) 10208934SJose.Borrego@Sun.COM { 10218934SJose.Borrego@Sun.COM _NOTE(ARGUNUSED(kmflags, un)) 10228934SJose.Borrego@Sun.COM 10238934SJose.Borrego@Sun.COM smb_node_t *node = (smb_node_t *)buf; 10248934SJose.Borrego@Sun.COM 10258934SJose.Borrego@Sun.COM bzero(node, sizeof (smb_node_t)); 10268934SJose.Borrego@Sun.COM 10278934SJose.Borrego@Sun.COM smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 10288934SJose.Borrego@Sun.COM offsetof(smb_ofile_t, f_nnd)); 10298934SJose.Borrego@Sun.COM smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 10308934SJose.Borrego@Sun.COM offsetof(smb_lock_t, l_lnd)); 10318934SJose.Borrego@Sun.COM cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL); 10328934SJose.Borrego@Sun.COM rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL); 10338934SJose.Borrego@Sun.COM mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL); 10348934SJose.Borrego@Sun.COM smb_node_create_audit_buf(node, kmflags); 10358934SJose.Borrego@Sun.COM return (0); 10368934SJose.Borrego@Sun.COM } 10378934SJose.Borrego@Sun.COM 10388934SJose.Borrego@Sun.COM /* 10398934SJose.Borrego@Sun.COM * smb_node_destructor 10408934SJose.Borrego@Sun.COM */ 10418934SJose.Borrego@Sun.COM static void 10428934SJose.Borrego@Sun.COM smb_node_destructor(void *buf, void *un) 10438934SJose.Borrego@Sun.COM { 10448934SJose.Borrego@Sun.COM _NOTE(ARGUNUSED(un)) 10458934SJose.Borrego@Sun.COM 10468934SJose.Borrego@Sun.COM smb_node_t *node = (smb_node_t *)buf; 10478934SJose.Borrego@Sun.COM 10488934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(node); 10498934SJose.Borrego@Sun.COM mutex_destroy(&node->n_mutex); 10508934SJose.Borrego@Sun.COM rw_destroy(&node->n_lock); 10518934SJose.Borrego@Sun.COM cv_destroy(&node->n_oplock.ol_cv); 10528934SJose.Borrego@Sun.COM smb_llist_destructor(&node->n_lock_list); 10538934SJose.Borrego@Sun.COM smb_llist_destructor(&node->n_ofile_list); 10548934SJose.Borrego@Sun.COM } 10558934SJose.Borrego@Sun.COM 10568934SJose.Borrego@Sun.COM /* 10578934SJose.Borrego@Sun.COM * smb_node_create_audit_buf 10588934SJose.Borrego@Sun.COM */ 10598934SJose.Borrego@Sun.COM static void 10608934SJose.Borrego@Sun.COM smb_node_create_audit_buf(smb_node_t *node, int kmflags) 10618934SJose.Borrego@Sun.COM { 10628934SJose.Borrego@Sun.COM smb_audit_buf_node_t *abn; 10638934SJose.Borrego@Sun.COM 10648934SJose.Borrego@Sun.COM if (smb_audit_flags & SMB_AUDIT_NODE) { 10658934SJose.Borrego@Sun.COM abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags); 10668934SJose.Borrego@Sun.COM abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1; 10678934SJose.Borrego@Sun.COM node->n_audit_buf = abn; 10688934SJose.Borrego@Sun.COM } 10698934SJose.Borrego@Sun.COM } 10708934SJose.Borrego@Sun.COM 10718934SJose.Borrego@Sun.COM /* 10728934SJose.Borrego@Sun.COM * smb_node_destroy_audit_buf 10738934SJose.Borrego@Sun.COM */ 10748934SJose.Borrego@Sun.COM static void 10758934SJose.Borrego@Sun.COM smb_node_destroy_audit_buf(smb_node_t *node) 10768934SJose.Borrego@Sun.COM { 10778934SJose.Borrego@Sun.COM if (node->n_audit_buf != NULL) { 10788934SJose.Borrego@Sun.COM kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t)); 10798934SJose.Borrego@Sun.COM node->n_audit_buf = NULL; 10808934SJose.Borrego@Sun.COM } 10818934SJose.Borrego@Sun.COM } 10828934SJose.Borrego@Sun.COM 10838934SJose.Borrego@Sun.COM /* 10848934SJose.Borrego@Sun.COM * smb_node_audit 10858934SJose.Borrego@Sun.COM * 10868934SJose.Borrego@Sun.COM * This function saves the calling stack in the audit buffer of the node passed 10878934SJose.Borrego@Sun.COM * in. 10888934SJose.Borrego@Sun.COM */ 10898934SJose.Borrego@Sun.COM static void 10908934SJose.Borrego@Sun.COM smb_node_audit(smb_node_t *node) 10918934SJose.Borrego@Sun.COM { 10928934SJose.Borrego@Sun.COM smb_audit_buf_node_t *abn; 10938934SJose.Borrego@Sun.COM smb_audit_record_node_t *anr; 10948934SJose.Borrego@Sun.COM 10958934SJose.Borrego@Sun.COM if (node->n_audit_buf) { 10968934SJose.Borrego@Sun.COM abn = node->n_audit_buf; 10978934SJose.Borrego@Sun.COM anr = abn->anb_records; 10988934SJose.Borrego@Sun.COM anr += abn->anb_index; 10998934SJose.Borrego@Sun.COM abn->anb_index++; 11008934SJose.Borrego@Sun.COM abn->anb_index &= abn->anb_max_index; 11018934SJose.Borrego@Sun.COM anr->anr_refcnt = node->n_refcnt; 11028934SJose.Borrego@Sun.COM anr->anr_depth = getpcstack(anr->anr_stack, 11038934SJose.Borrego@Sun.COM SMB_AUDIT_STACK_DEPTH); 11048934SJose.Borrego@Sun.COM } 11058934SJose.Borrego@Sun.COM } 11068934SJose.Borrego@Sun.COM 11078934SJose.Borrego@Sun.COM static smb_llist_t * 11088934SJose.Borrego@Sun.COM smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey) 11098934SJose.Borrego@Sun.COM { 11108934SJose.Borrego@Sun.COM uint32_t hashkey; 11118934SJose.Borrego@Sun.COM 11128934SJose.Borrego@Sun.COM hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid; 11138934SJose.Borrego@Sun.COM hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 11148934SJose.Borrego@Sun.COM *phashkey = hashkey; 11158934SJose.Borrego@Sun.COM return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]); 11168934SJose.Borrego@Sun.COM } 111710001SJoyce.McIntosh@Sun.COM 111810001SJoyce.McIntosh@Sun.COM boolean_t 111910001SJoyce.McIntosh@Sun.COM smb_node_is_dir(smb_node_t *node) 112010001SJoyce.McIntosh@Sun.COM { 112110001SJoyce.McIntosh@Sun.COM SMB_NODE_VALID(node); 112210001SJoyce.McIntosh@Sun.COM return (node->vp->v_type == VDIR); 112310001SJoyce.McIntosh@Sun.COM } 112410001SJoyce.McIntosh@Sun.COM 112510001SJoyce.McIntosh@Sun.COM boolean_t 112610001SJoyce.McIntosh@Sun.COM smb_node_is_link(smb_node_t *node) 112710001SJoyce.McIntosh@Sun.COM { 112810001SJoyce.McIntosh@Sun.COM SMB_NODE_VALID(node); 112910001SJoyce.McIntosh@Sun.COM return (node->vp->v_type == VLNK); 113010001SJoyce.McIntosh@Sun.COM } 113110001SJoyce.McIntosh@Sun.COM 113210001SJoyce.McIntosh@Sun.COM /* 113310001SJoyce.McIntosh@Sun.COM * smb_node_file_is_readonly 113410001SJoyce.McIntosh@Sun.COM * 113510001SJoyce.McIntosh@Sun.COM * Checks if the file (which node represents) is marked readonly 113610001SJoyce.McIntosh@Sun.COM * in the filesystem. No account is taken of any pending readonly 113710001SJoyce.McIntosh@Sun.COM * in the node, which must be handled by the callers. 113810001SJoyce.McIntosh@Sun.COM * (See SMB_OFILE_IS_READONLY and SMB_PATHFILE_IS_READONLY) 113910001SJoyce.McIntosh@Sun.COM */ 114010001SJoyce.McIntosh@Sun.COM boolean_t 114110001SJoyce.McIntosh@Sun.COM smb_node_file_is_readonly(smb_node_t *node) 114210001SJoyce.McIntosh@Sun.COM { 114310001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 114410001SJoyce.McIntosh@Sun.COM 114510001SJoyce.McIntosh@Sun.COM if (node == NULL) 114610001SJoyce.McIntosh@Sun.COM return (B_FALSE); 114710001SJoyce.McIntosh@Sun.COM 114810001SJoyce.McIntosh@Sun.COM bzero(&attr, sizeof (smb_attr_t)); 114910001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_DOSATTR; 115010001SJoyce.McIntosh@Sun.COM (void) smb_fsop_getattr(NULL, kcred, node, &attr); 115110001SJoyce.McIntosh@Sun.COM return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0); 115210001SJoyce.McIntosh@Sun.COM } 115310001SJoyce.McIntosh@Sun.COM 115410001SJoyce.McIntosh@Sun.COM /* 115510001SJoyce.McIntosh@Sun.COM * smb_node_setattr 115610001SJoyce.McIntosh@Sun.COM * 115710001SJoyce.McIntosh@Sun.COM * The sr may be NULL, for example when closing an ofile. 115810001SJoyce.McIntosh@Sun.COM * The ofile may be NULL, for example when a client request 115910001SJoyce.McIntosh@Sun.COM * specifies the file by pathname. 116010001SJoyce.McIntosh@Sun.COM * 116110504SKeyur.Desai@Sun.COM * Timestamps 116210001SJoyce.McIntosh@Sun.COM * When attributes are set on an ofile, any pending timestamps 116310001SJoyce.McIntosh@Sun.COM * from a write request on the ofile are implicitly set to "now". 116410001SJoyce.McIntosh@Sun.COM * For compatibility with windows the following timestamps are 116510001SJoyce.McIntosh@Sun.COM * also implicitly set to now: 116610001SJoyce.McIntosh@Sun.COM * - if any attribute is being explicitly set, set ctime to now 116710001SJoyce.McIntosh@Sun.COM * - if file size is being explicitly set, set atime & ctime to now 116810001SJoyce.McIntosh@Sun.COM * 116910504SKeyur.Desai@Sun.COM * Any timestamp that is being explicitly set, or has previously 117010001SJoyce.McIntosh@Sun.COM * been explicitly set on the ofile, is excluded from implicit 117110001SJoyce.McIntosh@Sun.COM * (now) setting. 117210001SJoyce.McIntosh@Sun.COM * 117310001SJoyce.McIntosh@Sun.COM * Updates the node's cached timestamp values. 117410001SJoyce.McIntosh@Sun.COM * Updates the ofile's explicit times flag. 117510001SJoyce.McIntosh@Sun.COM * 117610504SKeyur.Desai@Sun.COM * File allocation size 117710504SKeyur.Desai@Sun.COM * When the file allocation size is set it is first rounded up 117810504SKeyur.Desai@Sun.COM * to block size. If the file size is smaller than the allocation 117910504SKeyur.Desai@Sun.COM * size the file is truncated by setting the filesize to allocsz. 118010504SKeyur.Desai@Sun.COM * If there are open ofiles, the allocsz is cached on the node. 118110504SKeyur.Desai@Sun.COM * 118210504SKeyur.Desai@Sun.COM * Updates the node's cached allocsz value. 118310504SKeyur.Desai@Sun.COM * 118410001SJoyce.McIntosh@Sun.COM * Returns: errno 118510001SJoyce.McIntosh@Sun.COM */ 118610001SJoyce.McIntosh@Sun.COM int 118710001SJoyce.McIntosh@Sun.COM smb_node_setattr(smb_request_t *sr, smb_node_t *node, 118810001SJoyce.McIntosh@Sun.COM cred_t *cr, smb_ofile_t *of, smb_attr_t *attr) 118910001SJoyce.McIntosh@Sun.COM { 119010001SJoyce.McIntosh@Sun.COM int rc; 119110504SKeyur.Desai@Sun.COM uint32_t pending_times = 0; 119210504SKeyur.Desai@Sun.COM uint32_t explicit_times = 0; 119310001SJoyce.McIntosh@Sun.COM timestruc_t now; 119410504SKeyur.Desai@Sun.COM smb_attr_t tmp_attr; 119510001SJoyce.McIntosh@Sun.COM 119610001SJoyce.McIntosh@Sun.COM ASSERT(attr); 119710001SJoyce.McIntosh@Sun.COM SMB_NODE_VALID(node); 119810001SJoyce.McIntosh@Sun.COM 119910504SKeyur.Desai@Sun.COM /* set attributes specified in attr */ 120010504SKeyur.Desai@Sun.COM if (attr->sa_mask != 0) { 120110504SKeyur.Desai@Sun.COM /* if allocation size is < file size, truncate the file */ 120210504SKeyur.Desai@Sun.COM if (attr->sa_mask & SMB_AT_ALLOCSZ) { 120310504SKeyur.Desai@Sun.COM attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz); 120410001SJoyce.McIntosh@Sun.COM 120510504SKeyur.Desai@Sun.COM bzero(&tmp_attr, sizeof (smb_attr_t)); 120610504SKeyur.Desai@Sun.COM tmp_attr.sa_mask = SMB_AT_SIZE; 120710504SKeyur.Desai@Sun.COM (void) smb_fsop_getattr(NULL, kcred, node, &tmp_attr); 120810001SJoyce.McIntosh@Sun.COM 120910504SKeyur.Desai@Sun.COM if (tmp_attr.sa_vattr.va_size > attr->sa_allocsz) { 121010504SKeyur.Desai@Sun.COM attr->sa_vattr.va_size = attr->sa_allocsz; 121110504SKeyur.Desai@Sun.COM attr->sa_mask |= SMB_AT_SIZE; 121210504SKeyur.Desai@Sun.COM } 121310001SJoyce.McIntosh@Sun.COM } 121410504SKeyur.Desai@Sun.COM 121510504SKeyur.Desai@Sun.COM rc = smb_fsop_setattr(sr, cr, node, attr); 121610504SKeyur.Desai@Sun.COM if (rc != 0) 121710504SKeyur.Desai@Sun.COM return (rc); 121810504SKeyur.Desai@Sun.COM 121910504SKeyur.Desai@Sun.COM smb_node_set_cached_allocsz(node, attr); 122010504SKeyur.Desai@Sun.COM smb_node_set_cached_timestamps(node, attr); 122110504SKeyur.Desai@Sun.COM if (of) { 122210504SKeyur.Desai@Sun.COM smb_ofile_set_explicit_times(of, 122310504SKeyur.Desai@Sun.COM (attr->sa_mask & SMB_AT_TIMES)); 122410001SJoyce.McIntosh@Sun.COM } 122510001SJoyce.McIntosh@Sun.COM } 122610001SJoyce.McIntosh@Sun.COM 122710504SKeyur.Desai@Sun.COM /* 122810504SKeyur.Desai@Sun.COM * Determine which timestamps to implicitly set to "now". 122910504SKeyur.Desai@Sun.COM * Don't overwrite timestamps already explicitly set. 123010504SKeyur.Desai@Sun.COM */ 123110504SKeyur.Desai@Sun.COM bzero(&tmp_attr, sizeof (smb_attr_t)); 123210504SKeyur.Desai@Sun.COM gethrestime(&now); 123310504SKeyur.Desai@Sun.COM tmp_attr.sa_vattr.va_atime = now; 123410504SKeyur.Desai@Sun.COM tmp_attr.sa_vattr.va_mtime = now; 123510504SKeyur.Desai@Sun.COM tmp_attr.sa_vattr.va_ctime = now; 123610001SJoyce.McIntosh@Sun.COM 123710504SKeyur.Desai@Sun.COM /* pending write timestamps */ 123810504SKeyur.Desai@Sun.COM if (of) { 123910504SKeyur.Desai@Sun.COM if (smb_ofile_write_time_pending(of)) { 124010504SKeyur.Desai@Sun.COM pending_times |= 124110504SKeyur.Desai@Sun.COM (SMB_AT_MTIME | SMB_AT_CTIME | SMB_AT_ATIME); 124210504SKeyur.Desai@Sun.COM } 124310504SKeyur.Desai@Sun.COM explicit_times |= (smb_ofile_explicit_times(of)); 124410504SKeyur.Desai@Sun.COM } 124510504SKeyur.Desai@Sun.COM explicit_times |= (attr->sa_mask & SMB_AT_TIMES); 124610504SKeyur.Desai@Sun.COM pending_times &= ~explicit_times; 124710001SJoyce.McIntosh@Sun.COM 124810504SKeyur.Desai@Sun.COM if (pending_times) { 124910504SKeyur.Desai@Sun.COM tmp_attr.sa_mask = pending_times; 125010504SKeyur.Desai@Sun.COM (void) smb_fsop_setattr(NULL, kcred, node, &tmp_attr); 125110504SKeyur.Desai@Sun.COM } 125210001SJoyce.McIntosh@Sun.COM 125310504SKeyur.Desai@Sun.COM /* additional timestamps to update in cache */ 125410504SKeyur.Desai@Sun.COM if (attr->sa_mask) 125510504SKeyur.Desai@Sun.COM tmp_attr.sa_mask |= SMB_AT_CTIME; 125610504SKeyur.Desai@Sun.COM if (attr->sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ)) 125710504SKeyur.Desai@Sun.COM tmp_attr.sa_mask |= SMB_AT_MTIME; 125810504SKeyur.Desai@Sun.COM tmp_attr.sa_mask &= ~explicit_times; 125910504SKeyur.Desai@Sun.COM 126010504SKeyur.Desai@Sun.COM if (tmp_attr.sa_mask) 126110504SKeyur.Desai@Sun.COM smb_node_set_cached_timestamps(node, &tmp_attr); 126210001SJoyce.McIntosh@Sun.COM 126311337SWilliam.Krier@Sun.COM if (tmp_attr.sa_mask & SMB_AT_MTIME || explicit_times & SMB_AT_MTIME) 126411337SWilliam.Krier@Sun.COM smb_node_notify_parent(node); 126511337SWilliam.Krier@Sun.COM 126610001SJoyce.McIntosh@Sun.COM return (0); 126710001SJoyce.McIntosh@Sun.COM } 126810001SJoyce.McIntosh@Sun.COM 126910001SJoyce.McIntosh@Sun.COM /* 127010001SJoyce.McIntosh@Sun.COM * smb_node_getattr 127110001SJoyce.McIntosh@Sun.COM * 127210001SJoyce.McIntosh@Sun.COM * Get attributes from the file system and apply any smb-specific 127310001SJoyce.McIntosh@Sun.COM * overrides for size, dos attributes and timestamps 127410001SJoyce.McIntosh@Sun.COM * 127510001SJoyce.McIntosh@Sun.COM * node->readonly_creator reflects whether a readonly set is pending 127610001SJoyce.McIntosh@Sun.COM * from a readonly create. The readonly attribute should be visible to 127710001SJoyce.McIntosh@Sun.COM * all clients even though the readonly creator fid is immune to the 127810001SJoyce.McIntosh@Sun.COM * readonly bit until close. 127910001SJoyce.McIntosh@Sun.COM * 128010001SJoyce.McIntosh@Sun.COM * Returns: errno 128110001SJoyce.McIntosh@Sun.COM */ 128210001SJoyce.McIntosh@Sun.COM int 128310001SJoyce.McIntosh@Sun.COM smb_node_getattr(smb_request_t *sr, smb_node_t *node, smb_attr_t *attr) 128410001SJoyce.McIntosh@Sun.COM { 128510001SJoyce.McIntosh@Sun.COM int rc; 128610001SJoyce.McIntosh@Sun.COM 128710001SJoyce.McIntosh@Sun.COM SMB_NODE_VALID(node); 128810001SJoyce.McIntosh@Sun.COM 128910001SJoyce.McIntosh@Sun.COM bzero(attr, sizeof (smb_attr_t)); 129010001SJoyce.McIntosh@Sun.COM attr->sa_mask = SMB_AT_ALL; 129110001SJoyce.McIntosh@Sun.COM rc = smb_fsop_getattr(sr, kcred, node, attr); 129210001SJoyce.McIntosh@Sun.COM if (rc != 0) 129310001SJoyce.McIntosh@Sun.COM return (rc); 129410001SJoyce.McIntosh@Sun.COM 129510001SJoyce.McIntosh@Sun.COM mutex_enter(&node->n_mutex); 129610001SJoyce.McIntosh@Sun.COM 129710504SKeyur.Desai@Sun.COM if (node->vp->v_type == VDIR) { 129810001SJoyce.McIntosh@Sun.COM attr->sa_vattr.va_size = 0; 129910504SKeyur.Desai@Sun.COM attr->sa_allocsz = 0; 130010966SJordan.Brown@Sun.COM attr->sa_vattr.va_nlink = 1; 130110504SKeyur.Desai@Sun.COM } 130210001SJoyce.McIntosh@Sun.COM 130310001SJoyce.McIntosh@Sun.COM if (node->readonly_creator) 130410001SJoyce.McIntosh@Sun.COM attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 130510001SJoyce.McIntosh@Sun.COM if (attr->sa_dosattr == 0) 130610001SJoyce.McIntosh@Sun.COM attr->sa_dosattr = FILE_ATTRIBUTE_NORMAL; 130710001SJoyce.McIntosh@Sun.COM 130810504SKeyur.Desai@Sun.COM 130910001SJoyce.McIntosh@Sun.COM mutex_exit(&node->n_mutex); 131010001SJoyce.McIntosh@Sun.COM 131110504SKeyur.Desai@Sun.COM smb_node_get_cached_allocsz(node, attr); 131210001SJoyce.McIntosh@Sun.COM smb_node_get_cached_timestamps(node, attr); 131310504SKeyur.Desai@Sun.COM 131410001SJoyce.McIntosh@Sun.COM return (0); 131510001SJoyce.McIntosh@Sun.COM } 131610001SJoyce.McIntosh@Sun.COM 131710001SJoyce.McIntosh@Sun.COM /* 131810504SKeyur.Desai@Sun.COM * smb_node_init_cached_data 131910504SKeyur.Desai@Sun.COM */ 132010504SKeyur.Desai@Sun.COM static void 132110504SKeyur.Desai@Sun.COM smb_node_init_cached_data(smb_node_t *node) 132210504SKeyur.Desai@Sun.COM { 132310504SKeyur.Desai@Sun.COM smb_attr_t attr; 132410504SKeyur.Desai@Sun.COM 132510504SKeyur.Desai@Sun.COM bzero(&attr, sizeof (smb_attr_t)); 132610504SKeyur.Desai@Sun.COM attr.sa_mask = SMB_AT_ALL; 132710504SKeyur.Desai@Sun.COM (void) smb_fsop_getattr(NULL, kcred, node, &attr); 132810504SKeyur.Desai@Sun.COM 132910504SKeyur.Desai@Sun.COM smb_node_init_cached_allocsz(node, &attr); 133010504SKeyur.Desai@Sun.COM smb_node_init_cached_timestamps(node, &attr); 133110504SKeyur.Desai@Sun.COM } 133210504SKeyur.Desai@Sun.COM 133310504SKeyur.Desai@Sun.COM /* 133410504SKeyur.Desai@Sun.COM * smb_node_clear_cached_data 133510504SKeyur.Desai@Sun.COM */ 133610504SKeyur.Desai@Sun.COM static void 133710504SKeyur.Desai@Sun.COM smb_node_clear_cached_data(smb_node_t *node) 133810504SKeyur.Desai@Sun.COM { 133910504SKeyur.Desai@Sun.COM smb_node_clear_cached_allocsz(node); 134010504SKeyur.Desai@Sun.COM smb_node_clear_cached_timestamps(node); 134110504SKeyur.Desai@Sun.COM } 134210504SKeyur.Desai@Sun.COM 134310504SKeyur.Desai@Sun.COM /* 134410504SKeyur.Desai@Sun.COM * File allocation size (allocsz) caching 134510504SKeyur.Desai@Sun.COM * 134610504SKeyur.Desai@Sun.COM * When there are open ofiles on the node, the file allocsz is cached. 134710504SKeyur.Desai@Sun.COM * The cached value (n_allocsz) is initialized when the first ofile is 134810504SKeyur.Desai@Sun.COM * opened and cleared when the last is closed. Allocsz calculated from 134910504SKeyur.Desai@Sun.COM * the filesize (rounded up to block size). 135010504SKeyur.Desai@Sun.COM * When the allocation size is queried, if the cached allocsz is less 135110504SKeyur.Desai@Sun.COM * than the filesize, it is recalculated from the filesize. 135210504SKeyur.Desai@Sun.COM */ 135310504SKeyur.Desai@Sun.COM 135410504SKeyur.Desai@Sun.COM /* 135510504SKeyur.Desai@Sun.COM * smb_node_init_cached_allocsz 135610504SKeyur.Desai@Sun.COM * 135710504SKeyur.Desai@Sun.COM * If there are open ofiles, cache the allocsz in the node. 135810504SKeyur.Desai@Sun.COM * Calculate the allocsz from the filesizes. 135910504SKeyur.Desai@Sun.COM * block size). 136010504SKeyur.Desai@Sun.COM */ 136110504SKeyur.Desai@Sun.COM static void 136210504SKeyur.Desai@Sun.COM smb_node_init_cached_allocsz(smb_node_t *node, smb_attr_t *attr) 136310504SKeyur.Desai@Sun.COM { 136410504SKeyur.Desai@Sun.COM mutex_enter(&node->n_mutex); 136510504SKeyur.Desai@Sun.COM if (node->n_open_count == 1) 136610504SKeyur.Desai@Sun.COM node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size); 136710504SKeyur.Desai@Sun.COM mutex_exit(&node->n_mutex); 136810504SKeyur.Desai@Sun.COM } 136910504SKeyur.Desai@Sun.COM 137010504SKeyur.Desai@Sun.COM /* 137110504SKeyur.Desai@Sun.COM * smb_node_clear_cached_allocsz 137210504SKeyur.Desai@Sun.COM */ 137310504SKeyur.Desai@Sun.COM static void 137410504SKeyur.Desai@Sun.COM smb_node_clear_cached_allocsz(smb_node_t *node) 137510504SKeyur.Desai@Sun.COM { 137610504SKeyur.Desai@Sun.COM mutex_enter(&node->n_mutex); 137710504SKeyur.Desai@Sun.COM if (node->n_open_count == 0) 137810504SKeyur.Desai@Sun.COM node->n_allocsz = 0; 137910504SKeyur.Desai@Sun.COM mutex_exit(&node->n_mutex); 138010504SKeyur.Desai@Sun.COM } 138110504SKeyur.Desai@Sun.COM 138210504SKeyur.Desai@Sun.COM /* 138310504SKeyur.Desai@Sun.COM * smb_node_get_cached_allocsz 138410504SKeyur.Desai@Sun.COM * 138510504SKeyur.Desai@Sun.COM * If there is no cached allocsz (no open files), calculate 138610504SKeyur.Desai@Sun.COM * allocsz from the filesize. 138710504SKeyur.Desai@Sun.COM * If the allocsz is cached but is smaller than the filesize 138810504SKeyur.Desai@Sun.COM * recalculate the cached allocsz from the filesize. 138910504SKeyur.Desai@Sun.COM * 139010504SKeyur.Desai@Sun.COM * Return allocs in attr->sa_allocsz. 139110504SKeyur.Desai@Sun.COM */ 139210504SKeyur.Desai@Sun.COM static void 139310504SKeyur.Desai@Sun.COM smb_node_get_cached_allocsz(smb_node_t *node, smb_attr_t *attr) 139410504SKeyur.Desai@Sun.COM { 139510504SKeyur.Desai@Sun.COM if (node->vp->v_type == VDIR) 139610504SKeyur.Desai@Sun.COM return; 139710504SKeyur.Desai@Sun.COM 139810504SKeyur.Desai@Sun.COM mutex_enter(&node->n_mutex); 139910504SKeyur.Desai@Sun.COM if (node->n_open_count == 0) { 140010504SKeyur.Desai@Sun.COM attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size); 140110504SKeyur.Desai@Sun.COM } else { 140210504SKeyur.Desai@Sun.COM if (node->n_allocsz < attr->sa_vattr.va_size) 140310504SKeyur.Desai@Sun.COM node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size); 140410504SKeyur.Desai@Sun.COM attr->sa_allocsz = node->n_allocsz; 140510504SKeyur.Desai@Sun.COM } 140610504SKeyur.Desai@Sun.COM mutex_exit(&node->n_mutex); 140710504SKeyur.Desai@Sun.COM } 140810504SKeyur.Desai@Sun.COM 140910504SKeyur.Desai@Sun.COM /* 141010504SKeyur.Desai@Sun.COM * smb_node_set_cached_allocsz 141110504SKeyur.Desai@Sun.COM * 141210504SKeyur.Desai@Sun.COM * attr->sa_allocsz has already been rounded to block size by 141310504SKeyur.Desai@Sun.COM * the caller. 141410504SKeyur.Desai@Sun.COM */ 141510504SKeyur.Desai@Sun.COM static void 141610504SKeyur.Desai@Sun.COM smb_node_set_cached_allocsz(smb_node_t *node, smb_attr_t *attr) 141710504SKeyur.Desai@Sun.COM { 141810504SKeyur.Desai@Sun.COM mutex_enter(&node->n_mutex); 141910504SKeyur.Desai@Sun.COM if (attr->sa_mask & SMB_AT_ALLOCSZ) { 142010504SKeyur.Desai@Sun.COM if (node->n_open_count > 0) 142110504SKeyur.Desai@Sun.COM node->n_allocsz = attr->sa_allocsz; 142210504SKeyur.Desai@Sun.COM } 142310504SKeyur.Desai@Sun.COM mutex_exit(&node->n_mutex); 142410504SKeyur.Desai@Sun.COM } 142510504SKeyur.Desai@Sun.COM 142610504SKeyur.Desai@Sun.COM 142710504SKeyur.Desai@Sun.COM /* 142810001SJoyce.McIntosh@Sun.COM * Timestamp caching 142910001SJoyce.McIntosh@Sun.COM * 143010001SJoyce.McIntosh@Sun.COM * Solaris file systems handle timestamps different from NTFS. For 143110001SJoyce.McIntosh@Sun.COM * example when file data is written NTFS doesn't update the timestamps 143210001SJoyce.McIntosh@Sun.COM * until the file is closed, and then only if they haven't been explicity 143310001SJoyce.McIntosh@Sun.COM * set via a set attribute request. In order to provide a more similar 143410001SJoyce.McIntosh@Sun.COM * view of an open file's timestamps, we cache the timestamps in the 143510001SJoyce.McIntosh@Sun.COM * node and manipulate them in a manner more consistent with windows. 143610001SJoyce.McIntosh@Sun.COM * (See handling of explicit times and pending timestamps from a write 143710001SJoyce.McIntosh@Sun.COM * request in smb_node_getattr and smb_node_setattr above.) 143810001SJoyce.McIntosh@Sun.COM * Timestamps remain cached while there are open ofiles for the node. 143910001SJoyce.McIntosh@Sun.COM * This includes open ofiles for named streams. 144010001SJoyce.McIntosh@Sun.COM * n_open_ofiles cannot be used as this doesn't include ofiles opened 144110001SJoyce.McIntosh@Sun.COM * for the node's named streams. Thus n_timestamps contains a count 144210001SJoyce.McIntosh@Sun.COM * of open ofiles (t_open_ofiles), including named streams' ofiles, 144310001SJoyce.McIntosh@Sun.COM * to be used to control timestamp caching. 144410001SJoyce.McIntosh@Sun.COM * 144510001SJoyce.McIntosh@Sun.COM * If a node represents a named stream the associated unnamed streams 144610001SJoyce.McIntosh@Sun.COM * cached timestamps are used instead. 144710001SJoyce.McIntosh@Sun.COM */ 144810001SJoyce.McIntosh@Sun.COM 144910001SJoyce.McIntosh@Sun.COM /* 145010001SJoyce.McIntosh@Sun.COM * smb_node_init_cached_timestamps 145110001SJoyce.McIntosh@Sun.COM * 145210001SJoyce.McIntosh@Sun.COM * Increment count of open ofiles which are using the cached timestamps. 145310001SJoyce.McIntosh@Sun.COM * If this is the first open ofile, init the cached timestamps from the 145410001SJoyce.McIntosh@Sun.COM * file system values. 145510001SJoyce.McIntosh@Sun.COM */ 145610001SJoyce.McIntosh@Sun.COM static void 145710504SKeyur.Desai@Sun.COM smb_node_init_cached_timestamps(smb_node_t *node, smb_attr_t *attr) 145810001SJoyce.McIntosh@Sun.COM { 145910001SJoyce.McIntosh@Sun.COM smb_node_t *unode; 146010001SJoyce.McIntosh@Sun.COM 146110001SJoyce.McIntosh@Sun.COM if ((unode = SMB_IS_STREAM(node)) != NULL) 146210001SJoyce.McIntosh@Sun.COM node = unode; 146310001SJoyce.McIntosh@Sun.COM 146410001SJoyce.McIntosh@Sun.COM mutex_enter(&node->n_mutex); 146510001SJoyce.McIntosh@Sun.COM ++(node->n_timestamps.t_open_ofiles); 146610001SJoyce.McIntosh@Sun.COM if (node->n_timestamps.t_open_ofiles == 1) { 146710504SKeyur.Desai@Sun.COM node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime; 146810504SKeyur.Desai@Sun.COM node->n_timestamps.t_atime = attr->sa_vattr.va_atime; 146910504SKeyur.Desai@Sun.COM node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime; 147010504SKeyur.Desai@Sun.COM node->n_timestamps.t_crtime = attr->sa_crtime; 147110001SJoyce.McIntosh@Sun.COM node->n_timestamps.t_cached = B_TRUE; 147210001SJoyce.McIntosh@Sun.COM } 147310001SJoyce.McIntosh@Sun.COM mutex_exit(&node->n_mutex); 147410001SJoyce.McIntosh@Sun.COM } 147510001SJoyce.McIntosh@Sun.COM 147610001SJoyce.McIntosh@Sun.COM /* 147710001SJoyce.McIntosh@Sun.COM * smb_node_clear_cached_timestamps 147810001SJoyce.McIntosh@Sun.COM * 147910001SJoyce.McIntosh@Sun.COM * Decrement count of open ofiles using the cached timestamps. 148010001SJoyce.McIntosh@Sun.COM * If the decremented count is zero, clear the cached timestamps. 148110001SJoyce.McIntosh@Sun.COM */ 148210001SJoyce.McIntosh@Sun.COM static void 148310001SJoyce.McIntosh@Sun.COM smb_node_clear_cached_timestamps(smb_node_t *node) 148410001SJoyce.McIntosh@Sun.COM { 148510001SJoyce.McIntosh@Sun.COM smb_node_t *unode; 148610001SJoyce.McIntosh@Sun.COM 148710001SJoyce.McIntosh@Sun.COM if ((unode = SMB_IS_STREAM(node)) != NULL) 148810001SJoyce.McIntosh@Sun.COM node = unode; 148910001SJoyce.McIntosh@Sun.COM 149010001SJoyce.McIntosh@Sun.COM mutex_enter(&node->n_mutex); 149110001SJoyce.McIntosh@Sun.COM ASSERT(node->n_timestamps.t_open_ofiles > 0); 149210001SJoyce.McIntosh@Sun.COM --(node->n_timestamps.t_open_ofiles); 149310001SJoyce.McIntosh@Sun.COM if (node->n_timestamps.t_open_ofiles == 0) 149410001SJoyce.McIntosh@Sun.COM bzero(&node->n_timestamps, sizeof (smb_times_t)); 149510001SJoyce.McIntosh@Sun.COM mutex_exit(&node->n_mutex); 149610001SJoyce.McIntosh@Sun.COM } 149710001SJoyce.McIntosh@Sun.COM 149810001SJoyce.McIntosh@Sun.COM /* 149910001SJoyce.McIntosh@Sun.COM * smb_node_get_cached_timestamps 150010001SJoyce.McIntosh@Sun.COM * 150110001SJoyce.McIntosh@Sun.COM * Overwrite timestamps in attr with those cached in node. 150210001SJoyce.McIntosh@Sun.COM */ 150310001SJoyce.McIntosh@Sun.COM static void 150410001SJoyce.McIntosh@Sun.COM smb_node_get_cached_timestamps(smb_node_t *node, smb_attr_t *attr) 150510001SJoyce.McIntosh@Sun.COM { 150610001SJoyce.McIntosh@Sun.COM smb_node_t *unode; 150710001SJoyce.McIntosh@Sun.COM 150810001SJoyce.McIntosh@Sun.COM if ((unode = SMB_IS_STREAM(node)) != NULL) 150910001SJoyce.McIntosh@Sun.COM node = unode; 151010001SJoyce.McIntosh@Sun.COM 151110001SJoyce.McIntosh@Sun.COM mutex_enter(&node->n_mutex); 151210001SJoyce.McIntosh@Sun.COM if (node->n_timestamps.t_cached) { 151310001SJoyce.McIntosh@Sun.COM attr->sa_vattr.va_mtime = node->n_timestamps.t_mtime; 151410001SJoyce.McIntosh@Sun.COM attr->sa_vattr.va_atime = node->n_timestamps.t_atime; 151510001SJoyce.McIntosh@Sun.COM attr->sa_vattr.va_ctime = node->n_timestamps.t_ctime; 151610001SJoyce.McIntosh@Sun.COM attr->sa_crtime = node->n_timestamps.t_crtime; 151710001SJoyce.McIntosh@Sun.COM } 151810001SJoyce.McIntosh@Sun.COM mutex_exit(&node->n_mutex); 151910001SJoyce.McIntosh@Sun.COM } 152010001SJoyce.McIntosh@Sun.COM 152110001SJoyce.McIntosh@Sun.COM /* 152210001SJoyce.McIntosh@Sun.COM * smb_node_set_cached_timestamps 152310001SJoyce.McIntosh@Sun.COM * 152410001SJoyce.McIntosh@Sun.COM * Update the node's cached timestamps with values from attr. 152510001SJoyce.McIntosh@Sun.COM */ 152610001SJoyce.McIntosh@Sun.COM static void 152710001SJoyce.McIntosh@Sun.COM smb_node_set_cached_timestamps(smb_node_t *node, smb_attr_t *attr) 152810001SJoyce.McIntosh@Sun.COM { 152910001SJoyce.McIntosh@Sun.COM smb_node_t *unode; 153010001SJoyce.McIntosh@Sun.COM 153110001SJoyce.McIntosh@Sun.COM if ((unode = SMB_IS_STREAM(node)) != NULL) 153210001SJoyce.McIntosh@Sun.COM node = unode; 153310001SJoyce.McIntosh@Sun.COM 153410001SJoyce.McIntosh@Sun.COM mutex_enter(&node->n_mutex); 153510001SJoyce.McIntosh@Sun.COM if (node->n_timestamps.t_cached) { 153610001SJoyce.McIntosh@Sun.COM if (attr->sa_mask & SMB_AT_MTIME) 153710001SJoyce.McIntosh@Sun.COM node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime; 153810001SJoyce.McIntosh@Sun.COM if (attr->sa_mask & SMB_AT_ATIME) 153910001SJoyce.McIntosh@Sun.COM node->n_timestamps.t_atime = attr->sa_vattr.va_atime; 154010001SJoyce.McIntosh@Sun.COM if (attr->sa_mask & SMB_AT_CTIME) 154110001SJoyce.McIntosh@Sun.COM node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime; 154210001SJoyce.McIntosh@Sun.COM if (attr->sa_mask & SMB_AT_CRTIME) 154310001SJoyce.McIntosh@Sun.COM node->n_timestamps.t_crtime = attr->sa_crtime; 154410001SJoyce.McIntosh@Sun.COM } 154510001SJoyce.McIntosh@Sun.COM mutex_exit(&node->n_mutex); 154610001SJoyce.McIntosh@Sun.COM } 1547