1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22c5866007SKeyur Desai * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 236d1c73b5SDan Vatca * Copyright 2016 Syneto S.R.L. All rights reserved. 2448bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved. 25811599a4SMatt Barden * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 26da6c28aaSamw */ 27da6c28aaSamw 28da6c28aaSamw /* 29da6c28aaSamw * General Structures Layout 30da6c28aaSamw * ------------------------- 31da6c28aaSamw * 32da6c28aaSamw * This is a simplified diagram showing the relationship between most of the 33da6c28aaSamw * main structures. 34da6c28aaSamw * 35da6c28aaSamw * +-------------------+ 36da6c28aaSamw * | SMB_INFO | 37da6c28aaSamw * +-------------------+ 38da6c28aaSamw * | 39da6c28aaSamw * | 40da6c28aaSamw * v 41da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 42da6c28aaSamw * | SESSION |<----->| SESSION |......| SESSION | 43da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 443b13a1efSThomas Keiser * | | 453b13a1efSThomas Keiser * | | 463b13a1efSThomas Keiser * | v 473b13a1efSThomas Keiser * | +-------------------+ +-------------------+ +-------------------+ 483b13a1efSThomas Keiser * | | USER |<--->| USER |...| USER | 493b13a1efSThomas Keiser * | +-------------------+ +-------------------+ +-------------------+ 50da6c28aaSamw * | 51da6c28aaSamw * | 52da6c28aaSamw * v 53da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 54da6c28aaSamw * | TREE |<----->| TREE |......| TREE | 55da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 56da6c28aaSamw * | | 57da6c28aaSamw * | | 58da6c28aaSamw * | v 59da6c28aaSamw * | +-------+ +-------+ +-------+ 60da6c28aaSamw * | | OFILE |<----->| OFILE |......| OFILE | 61da6c28aaSamw * | +-------+ +-------+ +-------+ 62da6c28aaSamw * | 63da6c28aaSamw * | 64da6c28aaSamw * v 65da6c28aaSamw * +-------+ +------+ +------+ 66da6c28aaSamw * | ODIR |<----->| ODIR |......| ODIR | 67da6c28aaSamw * +-------+ +------+ +------+ 68da6c28aaSamw * 69da6c28aaSamw * 70da6c28aaSamw * Ofile State Machine 71da6c28aaSamw * ------------------ 72da6c28aaSamw * 73da6c28aaSamw * +-------------------------+ T0 74811599a4SMatt Barden * | SMB_OFILE_STATE_OPEN |<--+-------- Creation/Allocation 75811599a4SMatt Barden * +-------------------------+ | 76811599a4SMatt Barden * | | | T5 77811599a4SMatt Barden * | | +---------------------------+ 78811599a4SMatt Barden * | | | SMB_OFILE_STATE_RECONNECT | 79811599a4SMatt Barden * | | +---------------------------+ 80811599a4SMatt Barden * | | ^ 81811599a4SMatt Barden * | v | 82811599a4SMatt Barden * | +---------------+ | 83811599a4SMatt Barden * | | STATE_SAVE_DH | | 84811599a4SMatt Barden * | | STATE_SAVING | | 85811599a4SMatt Barden * | +---------------+ | 86811599a4SMatt Barden * | | | T4 87811599a4SMatt Barden * | T1 | T3 +--------------------------+ 88811599a4SMatt Barden * | +------>| SMB_OFILE_STATE_ORPHANED | 89811599a4SMatt Barden * v +--------------------------+ 90811599a4SMatt Barden * +-------------------------+ | | 91811599a4SMatt Barden * | SMB_OFILE_STATE_CLOSING |<--+ T6 | T7 92811599a4SMatt Barden * +-------------------------+ | 93811599a4SMatt Barden * | ^ v 94811599a4SMatt Barden * | T2 | T8 +-------------------------+ 95811599a4SMatt Barden * | +-------| SMB_OFILE_STATE_EXPIRED | 96811599a4SMatt Barden * v +-------------------------+ 97da6c28aaSamw * +-------------------------+ 98da6c28aaSamw * | SMB_OFILE_STATE_CLOSED |----------> Deletion/Free 99811599a4SMatt Barden * +-------------------------+ T9 100da6c28aaSamw * 101da6c28aaSamw * SMB_OFILE_STATE_OPEN 102da6c28aaSamw * 103da6c28aaSamw * While in this state: 104da6c28aaSamw * - The ofile is queued in the list of ofiles of its tree. 105da6c28aaSamw * - References will be given out if the ofile is looked up. 106da6c28aaSamw * 107811599a4SMatt Barden * SMB_OFILE_STATE_SAVE_DH 108811599a4SMatt Barden * 109811599a4SMatt Barden * Similar to state _CLOSING, but instead of deleting the ofile, 110811599a4SMatt Barden * it leaves the ofile in state _ORPHANED (for later reclaim). 111811599a4SMatt Barden * Will move to _SAVING after last ref, then _ORPHANED. 112811599a4SMatt Barden * 113811599a4SMatt Barden * While in this state: 114811599a4SMatt Barden * - The ofile has been marked for preservation during a 115811599a4SMatt Barden * walk of the tree ofile list to close multiple files. 116811599a4SMatt Barden * - References will not be given out if the ofile is looked up, 117811599a4SMatt Barden * except for oplock break processing. 118811599a4SMatt Barden * - Still affects Sharing Violation rules 119811599a4SMatt Barden * 120811599a4SMatt Barden * SMB_OFILE_STATE_SAVING 121811599a4SMatt Barden * 122811599a4SMatt Barden * Transient state used to keep oplock break processing out 123811599a4SMatt Barden * while the ofile moves to state _ORPHANED. 124811599a4SMatt Barden * 125811599a4SMatt Barden * While in this state: 126811599a4SMatt Barden * - References will not be given out if the ofile is looked up, 127811599a4SMatt Barden * except for oplock break processing. 128811599a4SMatt Barden * - Still affects Sharing Violation rules 129811599a4SMatt Barden * 130da6c28aaSamw * SMB_OFILE_STATE_CLOSING 131da6c28aaSamw * 132811599a4SMatt Barden * Close has been requested. Stay in this state until the last 133811599a4SMatt Barden * ref. is gone, then move to state _CLOSED 134811599a4SMatt Barden * 135da6c28aaSamw * While in this state: 136da6c28aaSamw * - The ofile is queued in the list of ofiles of its tree. 137da6c28aaSamw * - References will not be given out if the ofile is looked up. 138da6c28aaSamw * - The file is closed and the locks held are being released. 139da6c28aaSamw * - The resources associated with the ofile remain. 140da6c28aaSamw * 141da6c28aaSamw * SMB_OFILE_STATE_CLOSED 142da6c28aaSamw * 143da6c28aaSamw * While in this state: 144da6c28aaSamw * - The ofile is queued in the list of ofiles of its tree. 145da6c28aaSamw * - References will not be given out if the ofile is looked up. 146da6c28aaSamw * - The resources associated with the ofile remain. 147da6c28aaSamw * 148811599a4SMatt Barden * SMB_OFILE_STATE_ORPHANED 149811599a4SMatt Barden * 150811599a4SMatt Barden * While in this state: 151811599a4SMatt Barden * - The ofile is queued in the list of ofiles of its tree. 152811599a4SMatt Barden * - Can be reclaimed by the original owner 153811599a4SMatt Barden * - References will not be given out if the ofile is looked up. 154811599a4SMatt Barden * - All the tree, user, and session "up" pointers are NULL! 155811599a4SMatt Barden * - Will eventually be "expired" if not reclaimed 156811599a4SMatt Barden * - Can be closed if its oplock is broken 157811599a4SMatt Barden * - Still affects Sharing Violation rules 158811599a4SMatt Barden * 159811599a4SMatt Barden * SMB_OFILE_STATE_EXPIRED 160811599a4SMatt Barden * 161811599a4SMatt Barden * While in this state: 162811599a4SMatt Barden * - The ofile is queued in the list of ofiles of its tree. 163811599a4SMatt Barden * - References will not be given out if the ofile is looked up. 164811599a4SMatt Barden * - The ofile has not been reclaimed and will soon be closed, 165811599a4SMatt Barden * due to, for example, the durable handle timer expiring, or its 166811599a4SMatt Barden * oplock being broken. 167811599a4SMatt Barden * - Cannot be reclaimed at this point 168811599a4SMatt Barden * 169811599a4SMatt Barden * SMB_OFILE_STATE_RECONNECT 170811599a4SMatt Barden * 171811599a4SMatt Barden * Transient state used to keep oplock break processing out 172811599a4SMatt Barden * while the ofile moves from state _ORPHANED to _OPEN. 173811599a4SMatt Barden * 174811599a4SMatt Barden * While in this state: 175811599a4SMatt Barden * - The ofile is being reclaimed; do not touch it. 176811599a4SMatt Barden * - References will not be given out if the ofile is looked up. 177811599a4SMatt Barden * - Still affects Sharing Violation rules 178811599a4SMatt Barden * - see smb2_dh_reconnect() for which members need to be avoided 179811599a4SMatt Barden * 180da6c28aaSamw * Transition T0 181da6c28aaSamw * 182da6c28aaSamw * This transition occurs in smb_ofile_open(). A new ofile is created and 183da6c28aaSamw * added to the list of ofiles of a tree. 184da6c28aaSamw * 185da6c28aaSamw * Transition T1 186da6c28aaSamw * 187811599a4SMatt Barden * This transition occurs in smb_ofile_close(). Note that this only happens 188811599a4SMatt Barden * when we determine that an ofile should be closed in spite of its durable 189811599a4SMatt Barden * handle properties. 190da6c28aaSamw * 191da6c28aaSamw * Transition T2 192da6c28aaSamw * 193da6c28aaSamw * This transition occurs in smb_ofile_release(). The resources associated 194da6c28aaSamw * with the ofile are freed as well as the ofile structure. For the 195da6c28aaSamw * transition to occur, the ofile must be in the SMB_OFILE_STATE_CLOSED 196da6c28aaSamw * state and the reference count be zero. 197da6c28aaSamw * 198811599a4SMatt Barden * Transition T3 199811599a4SMatt Barden * 200811599a4SMatt Barden * This transition occurs in smb_ofile_orphan_dh(). It happens during an 201811599a4SMatt Barden * smb2 logoff, or during a session disconnect when certain conditions are 202811599a4SMatt Barden * met. The ofile and structures above it will be kept around until the ofile 203811599a4SMatt Barden * either gets reclaimed, expires after f_timeout_offset nanoseconds, or its 204811599a4SMatt Barden * oplock is broken. 205811599a4SMatt Barden * 206811599a4SMatt Barden * Transition T4 207811599a4SMatt Barden * 208811599a4SMatt Barden * This transition occurs in smb2_dh_reconnect(). An smb2 create request 209811599a4SMatt Barden * with a DURABLE_HANDLE_RECONNECT(_V2) create context has been 210811599a4SMatt Barden * recieved from the original owner. If leases are supported or it's 211811599a4SMatt Barden * RECONNECT_V2, reconnect is subject to additional conditions. The ofile 212811599a4SMatt Barden * will be unwired from the old, disconnected session, tree, and user, 213811599a4SMatt Barden * and wired up to its new context. 214811599a4SMatt Barden * 215811599a4SMatt Barden * Transition T5 216811599a4SMatt Barden * 217811599a4SMatt Barden * This transition occurs in smb2_dh_reconnect(). The ofile has been 218811599a4SMatt Barden * successfully reclaimed. 219811599a4SMatt Barden * 220811599a4SMatt Barden * Transition T6 221811599a4SMatt Barden * 222811599a4SMatt Barden * This transition occurs in smb_ofile_close(). The ofile has been orphaned 223811599a4SMatt Barden * while some thread was blocked, and that thread closes the ofile. Can only 224811599a4SMatt Barden * happen when the ofile is orphaned due to an SMB2 LOGOFF request. 225811599a4SMatt Barden * 226811599a4SMatt Barden * Transition T7 227811599a4SMatt Barden * 228811599a4SMatt Barden * This transition occurs in smb_session_durable_timers() and 22994047d49SGordon Ross * smb_oplock_send_brk(). The ofile will soon be closed. 230811599a4SMatt Barden * In the former case, f_timeout_offset nanoseconds have passed since 231811599a4SMatt Barden * the ofile was orphaned. In the latter, an oplock break occured 232811599a4SMatt Barden * on the ofile while it was orphaned. 233811599a4SMatt Barden * 234811599a4SMatt Barden * Transition T8 235811599a4SMatt Barden * 236811599a4SMatt Barden * This transition occurs in smb_ofile_close(). 237811599a4SMatt Barden * 238811599a4SMatt Barden * Transition T9 239811599a4SMatt Barden * 240811599a4SMatt Barden * This transition occurs in smb_ofile_delete(). 241811599a4SMatt Barden * 242da6c28aaSamw * Comments 243da6c28aaSamw * -------- 244da6c28aaSamw * 245da6c28aaSamw * The state machine of the ofile structures is controlled by 3 elements: 246da6c28aaSamw * - The list of ofiles of the tree it belongs to. 247da6c28aaSamw * - The mutex embedded in the structure itself. 248da6c28aaSamw * - The reference count. 249da6c28aaSamw * 250da6c28aaSamw * There's a mutex embedded in the ofile structure used to protect its fields 251da6c28aaSamw * and there's a lock embedded in the list of ofiles of a tree. To 252da6c28aaSamw * increment or to decrement the reference count the mutex must be entered. 253da6c28aaSamw * To insert the ofile into the list of ofiles of the tree and to remove 254da6c28aaSamw * the ofile from it, the lock must be entered in RW_WRITER mode. 255da6c28aaSamw * 256da6c28aaSamw * Rules of access to a ofile structure: 257da6c28aaSamw * 258da6c28aaSamw * 1) In order to avoid deadlocks, when both (mutex and lock of the ofile 259811599a4SMatt Barden * list) have to be entered, the lock must be entered first. Additionally, 260811599a4SMatt Barden * f_mutex must not be held when removing the ofile from sv_persistid_ht. 261da6c28aaSamw * 262da6c28aaSamw * 2) All actions applied to an ofile require a reference count. 263da6c28aaSamw * 264da6c28aaSamw * 3) There are 2 ways of getting a reference count. One is when the ofile 265da6c28aaSamw * is opened. The other one when the ofile is looked up. This translates 266da6c28aaSamw * into 2 functions: smb_ofile_open() and smb_ofile_lookup_by_fid(). 267da6c28aaSamw * 268da6c28aaSamw * It should be noted that the reference count of an ofile registers the 269da6c28aaSamw * number of references to the ofile in other structures (such as an smb 270da6c28aaSamw * request). The reference count is not incremented in these 2 instances: 271da6c28aaSamw * 27248bbca81SDaniel Hoffman * 1) The ofile is open. An ofile is anchored by its state. If there's 273da6c28aaSamw * no activity involving an ofile currently open, the reference count 274da6c28aaSamw * of that ofile is zero. 275da6c28aaSamw * 276da6c28aaSamw * 2) The ofile is queued in the list of ofiles of its tree. The fact of 277da6c28aaSamw * being queued in that list is NOT registered by incrementing the 278da6c28aaSamw * reference count. 279da6c28aaSamw */ 280811599a4SMatt Barden #include <smbsrv/smb2_kproto.h> 281da6c28aaSamw #include <smbsrv/smb_fsops.h> 282811599a4SMatt Barden #include <sys/time.h> 283*8d94f651SGordon Ross #include <sys/random.h> 284da6c28aaSamw 2851fcced4cSJordan Brown static boolean_t smb_ofile_is_open_locked(smb_ofile_t *); 286811599a4SMatt Barden static void smb_ofile_delete(void *arg); 287811599a4SMatt Barden static void smb_ofile_save_dh(void *arg); 288811599a4SMatt Barden 2891fcced4cSJordan Brown static int smb_ofile_netinfo_encode(smb_ofile_t *, uint8_t *, size_t, 2901fcced4cSJordan Brown uint32_t *); 2911fcced4cSJordan Brown static int smb_ofile_netinfo_init(smb_ofile_t *, smb_netfileinfo_t *); 2921fcced4cSJordan Brown static void smb_ofile_netinfo_fini(smb_netfileinfo_t *); 293da6c28aaSamw 294da6c28aaSamw /* 295*8d94f651SGordon Ross * The uniq_fid is a CIFS-server-wide unique identifier for an ofile 296*8d94f651SGordon Ross * which is used to uniquely identify open instances for the 297*8d94f651SGordon Ross * VFS share reservation and POSIX locks. 298*8d94f651SGordon Ross */ 299*8d94f651SGordon Ross static volatile uint32_t smb_fids = 0; 300*8d94f651SGordon Ross #define SMB_UNIQ_FID() atomic_inc_32_nv(&smb_fids) 301*8d94f651SGordon Ross 302*8d94f651SGordon Ross /* 30394047d49SGordon Ross * smb_ofile_alloc 30494047d49SGordon Ross * Allocate an ofile and fill in it's "up" pointers, but 30594047d49SGordon Ross * do NOT link it into the tree's list of ofiles or the 30694047d49SGordon Ross * node's list of ofiles. An ofile in this state is a 30794047d49SGordon Ross * "proposed" open passed to the oplock break code. 30894047d49SGordon Ross * 30994047d49SGordon Ross * If we don't get as far as smb_ofile_open with this OF, 31094047d49SGordon Ross * call smb_ofile_free() to free this object. 311*8d94f651SGordon Ross * 312*8d94f651SGordon Ross * Note: The following sr members may be null during 313*8d94f651SGordon Ross * persistent handle import: session, uid_usr, tid_tree 314da6c28aaSamw */ 315da6c28aaSamw smb_ofile_t * 31694047d49SGordon Ross smb_ofile_alloc( 3173b13a1efSThomas Keiser smb_request_t *sr, 31894047d49SGordon Ross smb_arg_open_t *op, 31994047d49SGordon Ross smb_node_t *node, /* optional (may be NULL) */ 320da6c28aaSamw uint16_t ftype, 321*8d94f651SGordon Ross uint16_t tree_fid) 322da6c28aaSamw { 323*8d94f651SGordon Ross smb_user_t *user = sr->uid_user; /* optional */ 324*8d94f651SGordon Ross smb_tree_t *tree = sr->tid_tree; /* optional */ 325da6c28aaSamw smb_ofile_t *of; 326da6c28aaSamw 3278622ec45SGordon Ross of = kmem_cache_alloc(smb_cache_ofile, KM_SLEEP); 328da6c28aaSamw bzero(of, sizeof (smb_ofile_t)); 329da6c28aaSamw of->f_magic = SMB_OFILE_MAGIC; 330bfe5e737SGordon Ross 331bfe5e737SGordon Ross mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL); 332bfe5e737SGordon Ross list_create(&of->f_notify.nc_waiters, sizeof (smb_request_t), 333bfe5e737SGordon Ross offsetof(smb_request_t, sr_waiters)); 334*8d94f651SGordon Ross mutex_init(&of->dh_nvlock, NULL, MUTEX_DEFAULT, NULL); 335bfe5e737SGordon Ross 33694047d49SGordon Ross of->f_state = SMB_OFILE_STATE_ALLOC; 337da6c28aaSamw of->f_refcnt = 1; 338811599a4SMatt Barden of->f_ftype = ftype; 33994047d49SGordon Ross of->f_fid = tree_fid; 340811599a4SMatt Barden /* of->f_persistid see smb2_create */ 341*8d94f651SGordon Ross of->f_uniqid = SMB_UNIQ_FID(); 34268b2bbf2SGordon Ross of->f_opened_by_pid = sr->smb_pid; 343c8ec8eeaSjose borrego of->f_granted_access = op->desired_access; 344c8ec8eeaSjose borrego of->f_share_access = op->share_access; 345c8ec8eeaSjose borrego of->f_create_options = op->create_options; 346*8d94f651SGordon Ross if (user != NULL) { 347*8d94f651SGordon Ross if ((op->create_options & FILE_OPEN_FOR_BACKUP_INTENT) != 0) 348*8d94f651SGordon Ross of->f_cr = smb_user_getprivcred(user); 349*8d94f651SGordon Ross else 350*8d94f651SGordon Ross of->f_cr = user->u_cred; 351da6c28aaSamw crhold(of->f_cr); 352*8d94f651SGordon Ross } 353*8d94f651SGordon Ross of->f_server = sr->sr_server; 354*8d94f651SGordon Ross of->f_session = sr->session; /* may be NULL */ 355*8d94f651SGordon Ross 3566f58980aSGordon Ross (void) memset(of->f_lock_seq, -1, SMB_OFILE_LSEQ_MAX); 357bfe5e737SGordon Ross 35894047d49SGordon Ross of->f_mode = smb_fsop_amask_to_omode(of->f_granted_access); 35994047d49SGordon Ross if ((of->f_granted_access & FILE_DATA_ALL) == FILE_EXECUTE) 36094047d49SGordon Ross of->f_flags |= SMB_OFLAGS_EXECONLY; 36194047d49SGordon Ross 36294047d49SGordon Ross /* 36394047d49SGordon Ross * In case a lease is requested, copy the lease keys now so 36494047d49SGordon Ross * any oplock breaks during open don't break those on our 36594047d49SGordon Ross * other handles that might have the same lease. 36694047d49SGordon Ross */ 36794047d49SGordon Ross bcopy(op->lease_key, of->TargetOplockKey, SMB_LEASE_KEY_SZ); 36894047d49SGordon Ross bcopy(op->parent_lease_key, of->ParentOplockKey, SMB_LEASE_KEY_SZ); 36994047d49SGordon Ross 3703b13a1efSThomas Keiser /* 371811599a4SMatt Barden * grab a ref for of->f_user and of->f_tree 37294047d49SGordon Ross * We know the user and tree must be "live" because 37394047d49SGordon Ross * this SR holds references to them. The node ref. is 37494047d49SGordon Ross * held by our caller, until smb_ofile_open puts this 37594047d49SGordon Ross * ofile on the node ofile list with smb_node_add_ofile. 3763b13a1efSThomas Keiser */ 377*8d94f651SGordon Ross if (user != NULL) { 378*8d94f651SGordon Ross smb_user_hold_internal(user); 379*8d94f651SGordon Ross of->f_user = user; 380*8d94f651SGordon Ross } 381*8d94f651SGordon Ross if (tree != NULL) { 382811599a4SMatt Barden smb_tree_hold_internal(tree); 383da6c28aaSamw of->f_tree = tree; 384*8d94f651SGordon Ross } 385*8d94f651SGordon Ross of->f_node = node; /* may be NULL */ 3865fd03bc0SGordon Ross 38794047d49SGordon Ross return (of); 38894047d49SGordon Ross } 38994047d49SGordon Ross 39094047d49SGordon Ross /* 39194047d49SGordon Ross * smb_ofile_open 39294047d49SGordon Ross * 39394047d49SGordon Ross * Complete an open on an ofile that was previously allocated by 39494047d49SGordon Ross * smb_ofile_alloc, by putting it on the tree ofile list and 39594047d49SGordon Ross * (if it's a file) the node ofile list. 39694047d49SGordon Ross */ 39794047d49SGordon Ross void 39894047d49SGordon Ross smb_ofile_open( 39994047d49SGordon Ross smb_request_t *sr, 40094047d49SGordon Ross smb_arg_open_t *op, 40194047d49SGordon Ross smb_ofile_t *of) 40294047d49SGordon Ross { 40394047d49SGordon Ross smb_tree_t *tree = sr->tid_tree; 40494047d49SGordon Ross smb_node_t *node = of->f_node; 40594047d49SGordon Ross 40694047d49SGordon Ross ASSERT(of->f_state == SMB_OFILE_STATE_ALLOC); 40794047d49SGordon Ross of->f_state = SMB_OFILE_STATE_OPEN; 40894047d49SGordon Ross 40994047d49SGordon Ross switch (of->f_ftype) { 41094047d49SGordon Ross case SMB_FTYPE_BYTE_PIPE: 41194047d49SGordon Ross case SMB_FTYPE_MESG_PIPE: 41268b2bbf2SGordon Ross /* See smb_opipe_open. */ 41368b2bbf2SGordon Ross of->f_pipe = op->pipe; 414148c5f43SAlan Wright smb_server_inc_pipes(of->f_server); 41594047d49SGordon Ross break; 41694047d49SGordon Ross case SMB_FTYPE_DISK: 41794047d49SGordon Ross case SMB_FTYPE_PRINTER: 41894047d49SGordon Ross /* Regular file, not a pipe */ 41994047d49SGordon Ross ASSERT(node != NULL); 4208c10a865Sas200622 4212c2961f8Sjose borrego smb_node_inc_open_ofiles(node); 422fc724630SAlan Wright smb_node_add_ofile(node, of); 4238b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_ref(node); 424148c5f43SAlan Wright smb_server_inc_files(of->f_server); 42594047d49SGordon Ross break; 42694047d49SGordon Ross default: 42794047d49SGordon Ross ASSERT(0); 428da6c28aaSamw } 429da6c28aaSamw smb_llist_enter(&tree->t_ofile_list, RW_WRITER); 430da6c28aaSamw smb_llist_insert_tail(&tree->t_ofile_list, of); 431da6c28aaSamw smb_llist_exit(&tree->t_ofile_list); 4321fcced4cSJordan Brown atomic_inc_32(&tree->t_open_files); 433da6c28aaSamw atomic_inc_32(&of->f_session->s_file_cnt); 4343b13a1efSThomas Keiser 435da6c28aaSamw } 436da6c28aaSamw 437da6c28aaSamw /* 438da6c28aaSamw * smb_ofile_close 439811599a4SMatt Barden * 440811599a4SMatt Barden * Incoming states: (where from) 441811599a4SMatt Barden * SMB_OFILE_STATE_OPEN protocol close, smb_ofile_drop 442811599a4SMatt Barden * SMB_OFILE_STATE_EXPIRED called via smb2_dh_expire 443811599a4SMatt Barden * SMB_OFILE_STATE_ORPHANED smb2_dh_shutdown 444da6c28aaSamw */ 445c8ec8eeaSjose borrego void 4465fd03bc0SGordon Ross smb_ofile_close(smb_ofile_t *of, int32_t mtime_sec) 447da6c28aaSamw { 448a90cf9f2SGordon Ross smb_attr_t *pa; 4495fd03bc0SGordon Ross timestruc_t now; 450da6c28aaSamw 4515fd03bc0SGordon Ross SMB_OFILE_VALID(of); 4525fd03bc0SGordon Ross 453da6c28aaSamw mutex_enter(&of->f_mutex); 454da6c28aaSamw ASSERT(of->f_refcnt); 455811599a4SMatt Barden 456811599a4SMatt Barden switch (of->f_state) { 457811599a4SMatt Barden case SMB_OFILE_STATE_OPEN: 458811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 459811599a4SMatt Barden case SMB_OFILE_STATE_EXPIRED: 460811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_CLOSING; 461811599a4SMatt Barden mutex_exit(&of->f_mutex); 462811599a4SMatt Barden break; 463811599a4SMatt Barden default: 46468b2bbf2SGordon Ross mutex_exit(&of->f_mutex); 46568b2bbf2SGordon Ross return; 46668b2bbf2SGordon Ross } 467da6c28aaSamw 468*8d94f651SGordon Ross /* 469*8d94f651SGordon Ross * Only one thread here (the one that that set f_state closing) 470*8d94f651SGordon Ross */ 471a90cf9f2SGordon Ross switch (of->f_ftype) { 472a90cf9f2SGordon Ross case SMB_FTYPE_BYTE_PIPE: 473a90cf9f2SGordon Ross case SMB_FTYPE_MESG_PIPE: 4743db3f65cSamw smb_opipe_close(of); 475148c5f43SAlan Wright smb_server_dec_pipes(of->f_server); 476a90cf9f2SGordon Ross break; 4775fd03bc0SGordon Ross 478a90cf9f2SGordon Ross case SMB_FTYPE_DISK: 479*8d94f651SGordon Ross if (of->dh_persist) 480*8d94f651SGordon Ross smb2_dh_close_persistent(of); 481811599a4SMatt Barden if (of->f_persistid != 0) 482811599a4SMatt Barden smb_ofile_del_persistid(of); 48394047d49SGordon Ross if (of->f_lease != NULL) 48494047d49SGordon Ross smb2_lease_ofile_close(of); 48594047d49SGordon Ross smb_oplock_break_CLOSE(of->f_node, of); 486811599a4SMatt Barden /* FALLTHROUGH */ 48794047d49SGordon Ross 488811599a4SMatt Barden case SMB_FTYPE_PRINTER: /* or FTYPE_DISK */ 4895fd03bc0SGordon Ross /* 4905fd03bc0SGordon Ross * In here we make changes to of->f_pending_attr 4915fd03bc0SGordon Ross * while not holding of->f_mutex. This is OK 4925fd03bc0SGordon Ross * because we've changed f_state to CLOSING, 4935fd03bc0SGordon Ross * so no more threads will take this path. 4945fd03bc0SGordon Ross */ 495a90cf9f2SGordon Ross pa = &of->f_pending_attr; 4965fd03bc0SGordon Ross if (mtime_sec != 0) { 4975fd03bc0SGordon Ross pa->sa_vattr.va_mtime.tv_sec = mtime_sec; 4985fd03bc0SGordon Ross pa->sa_mask |= SMB_AT_MTIME; 4995fd03bc0SGordon Ross } 5005fd03bc0SGordon Ross 5015fd03bc0SGordon Ross /* 5025fd03bc0SGordon Ross * If we have ever modified data via this handle 5035fd03bc0SGordon Ross * (write or truncate) and if the mtime was not 5045fd03bc0SGordon Ross * set via this handle, update the mtime again 5055fd03bc0SGordon Ross * during the close. Windows expects this. 5065fd03bc0SGordon Ross * [ MS-FSA 2.1.5.4 "Update Timestamps" ] 5075fd03bc0SGordon Ross */ 5085fd03bc0SGordon Ross if (of->f_written && 5095fd03bc0SGordon Ross (pa->sa_mask & SMB_AT_MTIME) == 0) { 5105fd03bc0SGordon Ross pa->sa_mask |= SMB_AT_MTIME; 5115fd03bc0SGordon Ross gethrestime(&now); 5125fd03bc0SGordon Ross pa->sa_vattr.va_mtime = now; 5135fd03bc0SGordon Ross } 514da6c28aaSamw 5158b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE) { 516811599a4SMatt Barden /* We delete using the on-disk name. */ 517811599a4SMatt Barden uint32_t flags = SMB_CASE_SENSITIVE; 5188b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_node_set_delete_on_close(of->f_node, 5198b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States of->f_cr, flags); 5208b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 521dc20a302Sas200622 smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid); 5226537f381Sas200622 smb_node_destroy_lock_by_ofile(of->f_node, of); 523dc20a302Sas200622 5245fd03bc0SGordon Ross if (smb_node_is_file(of->f_node)) { 5258c10a865Sas200622 (void) smb_fsop_close(of->f_node, of->f_mode, 5268c10a865Sas200622 of->f_cr); 527a90cf9f2SGordon Ross } else { 528a90cf9f2SGordon Ross /* 529a90cf9f2SGordon Ross * If there was an odir, close it. 530a90cf9f2SGordon Ross */ 531a90cf9f2SGordon Ross if (of->f_odir != NULL) 532a90cf9f2SGordon Ross smb_odir_close(of->f_odir); 533bfe5e737SGordon Ross /* 534bfe5e737SGordon Ross * Cancel any notify change requests that 535bfe5e737SGordon Ross * might be watching this open file (dir), 536bfe5e737SGordon Ross * and unsubscribe it from node events. 537bfe5e737SGordon Ross * 538bfe5e737SGordon Ross * Can't hold f_mutex when calling smb_notify_ofile. 539bfe5e737SGordon Ross * Don't really need it when unsubscribing, but 540bfe5e737SGordon Ross * harmless, and consistent with subscribing. 541bfe5e737SGordon Ross */ 542bfe5e737SGordon Ross if (of->f_notify.nc_subscribed) 543bfe5e737SGordon Ross smb_notify_ofile(of, 544bfe5e737SGordon Ross FILE_ACTION_HANDLE_CLOSED, NULL); 545bfe5e737SGordon Ross mutex_enter(&of->f_mutex); 546bfe5e737SGordon Ross if (of->f_notify.nc_subscribed) { 547bfe5e737SGordon Ross of->f_notify.nc_subscribed = B_FALSE; 548bfe5e737SGordon Ross smb_node_fcn_unsubscribe(of->f_node); 549bfe5e737SGordon Ross of->f_notify.nc_filter = 0; 550bfe5e737SGordon Ross } 551bfe5e737SGordon Ross mutex_exit(&of->f_mutex); 5525fd03bc0SGordon Ross } 5535fd03bc0SGordon Ross if (smb_node_dec_open_ofiles(of->f_node) == 0) { 5545fd03bc0SGordon Ross /* 5555cb2894aSGordon Ross * Last close. If we're not deleting 5565cb2894aSGordon Ross * the file, apply any pending attrs. 5575cb2894aSGordon Ross * Leave allocsz zero when no open files, 5585cb2894aSGordon Ross * just to avoid confusion, because it's 5595cb2894aSGordon Ross * only updated when there are opens. 56094047d49SGordon Ross * XXX: Just do this on _every_ close. 5615fd03bc0SGordon Ross */ 56249d83597SMatt Barden mutex_enter(&of->f_node->n_mutex); 56349d83597SMatt Barden if (of->f_node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 56449d83597SMatt Barden smb_node_delete_on_close(of->f_node); 56549d83597SMatt Barden pa->sa_mask = 0; 56649d83597SMatt Barden } 5675cb2894aSGordon Ross of->f_node->n_allocsz = 0; 56849d83597SMatt Barden mutex_exit(&of->f_node->n_mutex); 5695fd03bc0SGordon Ross } 5705fd03bc0SGordon Ross if (pa->sa_mask != 0) { 5715fd03bc0SGordon Ross /* 5725fd03bc0SGordon Ross * Commit any pending attributes from 5735fd03bc0SGordon Ross * the ofile we're closing. Note that 5745fd03bc0SGordon Ross * we pass NULL as the ofile to setattr 5755fd03bc0SGordon Ross * so it will write to the file system 5765fd03bc0SGordon Ross * and not keep anything on the ofile. 5775fd03bc0SGordon Ross */ 5785fd03bc0SGordon Ross (void) smb_node_setattr(NULL, of->f_node, 5795fd03bc0SGordon Ross of->f_cr, NULL, pa); 5805fd03bc0SGordon Ross } 581dc20a302Sas200622 582148c5f43SAlan Wright smb_server_dec_files(of->f_server); 583a90cf9f2SGordon Ross break; 584da6c28aaSamw } 585811599a4SMatt Barden 586811599a4SMatt Barden /* 587811599a4SMatt Barden * Keep f_state == SMB_OFILE_STATE_CLOSING 588811599a4SMatt Barden * until the last ref. is dropped, in 589811599a4SMatt Barden * smb_ofile_release() 590811599a4SMatt Barden */ 591811599a4SMatt Barden } 592811599a4SMatt Barden 593811599a4SMatt Barden /* 594811599a4SMatt Barden * "Destructor" function for smb_ofile_close_all, and 595811599a4SMatt Barden * smb_ofile_close_all_by_pid, called after the llist lock 596811599a4SMatt Barden * for tree list has been exited. Our job is to either 597811599a4SMatt Barden * close this ofile, or (if durable) set state _SAVE_DH. 598811599a4SMatt Barden * 599811599a4SMatt Barden * The next interesting thing happens when the last ref. 600811599a4SMatt Barden * on this ofile calls smb_ofile_release(), where we 601811599a4SMatt Barden * eihter delete the ofile, or (if durable) leave it 602811599a4SMatt Barden * in the persistid hash table for possible reclaim. 603811599a4SMatt Barden * 604811599a4SMatt Barden * This is run via smb_llist_post (after smb_llist_exit) 605811599a4SMatt Barden * because smb_ofile_close can block, and we'd rather not 606811599a4SMatt Barden * block while holding the ofile list as reader. 607811599a4SMatt Barden */ 608811599a4SMatt Barden static void 609811599a4SMatt Barden smb_ofile_drop(void *arg) 610811599a4SMatt Barden { 611811599a4SMatt Barden smb_ofile_t *of = arg; 612811599a4SMatt Barden 613811599a4SMatt Barden SMB_OFILE_VALID(of); 614da6c28aaSamw 615da6c28aaSamw mutex_enter(&of->f_mutex); 616811599a4SMatt Barden switch (of->f_state) { 617811599a4SMatt Barden case SMB_OFILE_STATE_OPEN: 618811599a4SMatt Barden /* DH checks under mutex. */ 619811599a4SMatt Barden if (of->f_ftype == SMB_FTYPE_DISK && 620811599a4SMatt Barden of->dh_vers != SMB2_NOT_DURABLE && 621811599a4SMatt Barden smb_dh_should_save(of)) { 622811599a4SMatt Barden /* 623811599a4SMatt Barden * Tell smb_ofile_release() to 624811599a4SMatt Barden * make this an _ORPHANED DH. 625811599a4SMatt Barden */ 626811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_SAVE_DH; 627da6c28aaSamw mutex_exit(&of->f_mutex); 628811599a4SMatt Barden break; 629811599a4SMatt Barden } 630811599a4SMatt Barden /* OK close it. */ 631811599a4SMatt Barden mutex_exit(&of->f_mutex); 632811599a4SMatt Barden smb_ofile_close(of, 0); 633811599a4SMatt Barden break; 634811599a4SMatt Barden 635811599a4SMatt Barden default: 636811599a4SMatt Barden /* Something else closed it already. */ 637811599a4SMatt Barden mutex_exit(&of->f_mutex); 638811599a4SMatt Barden break; 639811599a4SMatt Barden } 640811599a4SMatt Barden 641811599a4SMatt Barden /* 642811599a4SMatt Barden * Release the ref acquired during the traversal loop. 643811599a4SMatt Barden * Note that on the last ref, this ofile will be 644811599a4SMatt Barden * removed from the tree list etc. 645811599a4SMatt Barden * See: smb_llist_post, smb_ofile_delete 646811599a4SMatt Barden */ 647811599a4SMatt Barden smb_ofile_release(of); 648da6c28aaSamw } 649da6c28aaSamw 650da6c28aaSamw /* 651da6c28aaSamw * smb_ofile_close_all 652da6c28aaSamw * 653da6c28aaSamw * 654da6c28aaSamw */ 655da6c28aaSamw void 656da6c28aaSamw smb_ofile_close_all( 657811599a4SMatt Barden smb_tree_t *tree, 658811599a4SMatt Barden uint32_t pid) 659da6c28aaSamw { 660da6c28aaSamw smb_ofile_t *of; 661811599a4SMatt Barden smb_llist_t *ll; 662da6c28aaSamw 663da6c28aaSamw ASSERT(tree); 664da6c28aaSamw ASSERT(tree->t_magic == SMB_TREE_MAGIC); 665da6c28aaSamw 666811599a4SMatt Barden ll = &tree->t_ofile_list; 667811599a4SMatt Barden 668811599a4SMatt Barden smb_llist_enter(ll, RW_READER); 669811599a4SMatt Barden for (of = smb_llist_head(ll); 670811599a4SMatt Barden of != NULL; 671811599a4SMatt Barden of = smb_llist_next(ll, of)) { 672da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 673da6c28aaSamw ASSERT(of->f_tree == tree); 674811599a4SMatt Barden if (pid != 0 && of->f_opened_by_pid != pid) 675811599a4SMatt Barden continue; 676811599a4SMatt Barden if (smb_ofile_hold(of)) { 677811599a4SMatt Barden smb_llist_post(ll, of, smb_ofile_drop); 678da6c28aaSamw } 679da6c28aaSamw } 680da6c28aaSamw 681da6c28aaSamw /* 682811599a4SMatt Barden * Drop the lock and process the llist dtor queue. 683811599a4SMatt Barden * Calls smb_ofile_drop on ofiles that were open. 684da6c28aaSamw */ 685811599a4SMatt Barden smb_llist_exit(ll); 686da6c28aaSamw } 687da6c28aaSamw 688da6c28aaSamw /* 6891fcced4cSJordan Brown * If the enumeration request is for ofile data, handle it here. 6901fcced4cSJordan Brown * Otherwise, return. 6911fcced4cSJordan Brown * 6921fcced4cSJordan Brown * This function should be called with a hold on the ofile. 6931fcced4cSJordan Brown */ 6941fcced4cSJordan Brown int 6951fcced4cSJordan Brown smb_ofile_enum(smb_ofile_t *of, smb_svcenum_t *svcenum) 6961fcced4cSJordan Brown { 6971fcced4cSJordan Brown uint8_t *pb; 6981fcced4cSJordan Brown uint_t nbytes; 6991fcced4cSJordan Brown int rc; 7001fcced4cSJordan Brown 7011fcced4cSJordan Brown ASSERT(of); 7021fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 7031fcced4cSJordan Brown ASSERT(of->f_refcnt); 7041fcced4cSJordan Brown 7051fcced4cSJordan Brown if (svcenum->se_type != SMB_SVCENUM_TYPE_FILE) 7061fcced4cSJordan Brown return (0); 7071fcced4cSJordan Brown 7081fcced4cSJordan Brown if (svcenum->se_nskip > 0) { 7091fcced4cSJordan Brown svcenum->se_nskip--; 7101fcced4cSJordan Brown return (0); 7111fcced4cSJordan Brown } 7121fcced4cSJordan Brown 7131fcced4cSJordan Brown if (svcenum->se_nitems >= svcenum->se_nlimit) { 7141fcced4cSJordan Brown svcenum->se_nitems = svcenum->se_nlimit; 7151fcced4cSJordan Brown return (0); 7161fcced4cSJordan Brown } 7171fcced4cSJordan Brown 7181fcced4cSJordan Brown pb = &svcenum->se_buf[svcenum->se_bused]; 7191fcced4cSJordan Brown 7201fcced4cSJordan Brown rc = smb_ofile_netinfo_encode(of, pb, svcenum->se_bavail, 7211fcced4cSJordan Brown &nbytes); 7221fcced4cSJordan Brown if (rc == 0) { 7231fcced4cSJordan Brown svcenum->se_bavail -= nbytes; 7241fcced4cSJordan Brown svcenum->se_bused += nbytes; 7251fcced4cSJordan Brown svcenum->se_nitems++; 7261fcced4cSJordan Brown } 7271fcced4cSJordan Brown 7281fcced4cSJordan Brown return (rc); 7291fcced4cSJordan Brown } 7301fcced4cSJordan Brown 7311fcced4cSJordan Brown /* 732811599a4SMatt Barden * Take a reference on an open file, in any of the states: 733811599a4SMatt Barden * RECONNECT, SAVE_DH, OPEN, ORPHANED. 734811599a4SMatt Barden * Return TRUE if ref taken. Used for oplock breaks. 735811599a4SMatt Barden * 736811599a4SMatt Barden * Note: When the oplock break code calls this, it holds the 737811599a4SMatt Barden * node ofile list lock and node oplock mutex. When we see 738811599a4SMatt Barden * an ofile in states RECONNECT or SAVING, we know the ofile 739811599a4SMatt Barden * is gaining or losing it's tree, and that happens quickly, 740811599a4SMatt Barden * so we just wait for that work to finish. However, the 741811599a4SMatt Barden * waiting for state transitions here means we have to be 742811599a4SMatt Barden * careful not to re-enter the node list lock or otherwise 743811599a4SMatt Barden * block on things that could cause a deadlock. Waiting 744811599a4SMatt Barden * just on of->f_mutex here is OK. 745811599a4SMatt Barden */ 746811599a4SMatt Barden boolean_t 747811599a4SMatt Barden smb_ofile_hold_olbrk(smb_ofile_t *of) 748811599a4SMatt Barden { 749811599a4SMatt Barden boolean_t ret = B_FALSE; 750811599a4SMatt Barden 751811599a4SMatt Barden ASSERT(of); 752811599a4SMatt Barden ASSERT(of->f_magic == SMB_OFILE_MAGIC); 753811599a4SMatt Barden 754811599a4SMatt Barden mutex_enter(&of->f_mutex); 755811599a4SMatt Barden 756811599a4SMatt Barden again: 757811599a4SMatt Barden switch (of->f_state) { 758811599a4SMatt Barden case SMB_OFILE_STATE_RECONNECT: 759811599a4SMatt Barden case SMB_OFILE_STATE_SAVING: 760811599a4SMatt Barden cv_wait(&of->f_cv, &of->f_mutex); 761811599a4SMatt Barden goto again; 762811599a4SMatt Barden 763811599a4SMatt Barden case SMB_OFILE_STATE_OPEN: 764811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 765811599a4SMatt Barden case SMB_OFILE_STATE_SAVE_DH: 766811599a4SMatt Barden of->f_refcnt++; 767811599a4SMatt Barden ret = B_TRUE; 768811599a4SMatt Barden break; 769811599a4SMatt Barden 770811599a4SMatt Barden default: 771811599a4SMatt Barden break; 772811599a4SMatt Barden } 773811599a4SMatt Barden mutex_exit(&of->f_mutex); 774811599a4SMatt Barden 775811599a4SMatt Barden return (ret); 776811599a4SMatt Barden } 777811599a4SMatt Barden 778811599a4SMatt Barden /* 7791fcced4cSJordan Brown * Take a reference on an open file. 7801fcced4cSJordan Brown */ 7811fcced4cSJordan Brown boolean_t 7821fcced4cSJordan Brown smb_ofile_hold(smb_ofile_t *of) 7831fcced4cSJordan Brown { 7841fcced4cSJordan Brown ASSERT(of); 7851fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 7861fcced4cSJordan Brown 7871fcced4cSJordan Brown mutex_enter(&of->f_mutex); 7881fcced4cSJordan Brown 78968b2bbf2SGordon Ross if (of->f_state != SMB_OFILE_STATE_OPEN) { 7901fcced4cSJordan Brown mutex_exit(&of->f_mutex); 7911fcced4cSJordan Brown return (B_FALSE); 7921fcced4cSJordan Brown } 79368b2bbf2SGordon Ross of->f_refcnt++; 79468b2bbf2SGordon Ross 79568b2bbf2SGordon Ross mutex_exit(&of->f_mutex); 79668b2bbf2SGordon Ross return (B_TRUE); 79768b2bbf2SGordon Ross } 7981fcced4cSJordan Brown 7991fcced4cSJordan Brown /* 8009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Release a reference on a file. If the reference count falls to 8019fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * zero and the file has been closed, post the object for deletion. 8029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Object deletion is deferred to avoid modifying a list while an 8039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * iteration may be in progress. 804811599a4SMatt Barden * 805811599a4SMatt Barden * We're careful to avoid dropping f_session etc. until the last 806811599a4SMatt Barden * reference goes away. The oplock break code depends on that 807811599a4SMatt Barden * not changing while it holds a ref. on an ofile. 808da6c28aaSamw */ 809da6c28aaSamw void 81024d2db37Sjose borrego smb_ofile_release(smb_ofile_t *of) 811da6c28aaSamw { 812811599a4SMatt Barden smb_tree_t *tree = of->f_tree; 813811599a4SMatt Barden boolean_t delete = B_FALSE; 814811599a4SMatt Barden 8159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OFILE_VALID(of); 816da6c28aaSamw 817da6c28aaSamw mutex_enter(&of->f_mutex); 818811599a4SMatt Barden ASSERT(of->f_refcnt > 0); 819da6c28aaSamw of->f_refcnt--; 820811599a4SMatt Barden 821da6c28aaSamw switch (of->f_state) { 822da6c28aaSamw case SMB_OFILE_STATE_OPEN: 823811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 824811599a4SMatt Barden case SMB_OFILE_STATE_EXPIRED: 825da6c28aaSamw break; 826da6c28aaSamw 827811599a4SMatt Barden case SMB_OFILE_STATE_SAVE_DH: 828811599a4SMatt Barden ASSERT(tree != NULL); 829811599a4SMatt Barden if (of->f_refcnt == 0) { 830811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_SAVING; 831811599a4SMatt Barden smb_llist_post(&tree->t_ofile_list, of, 832811599a4SMatt Barden smb_ofile_save_dh); 833811599a4SMatt Barden } 834811599a4SMatt Barden break; 835811599a4SMatt Barden 836811599a4SMatt Barden case SMB_OFILE_STATE_CLOSING: 837811599a4SMatt Barden /* Note, tree == NULL on _ORPHANED */ 838811599a4SMatt Barden if (of->f_refcnt == 0) { 839811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_CLOSED; 840811599a4SMatt Barden if (tree == NULL) { 841811599a4SMatt Barden /* Skip smb_llist_post */ 842811599a4SMatt Barden delete = B_TRUE; 843811599a4SMatt Barden break; 844811599a4SMatt Barden } 845811599a4SMatt Barden smb_llist_post(&tree->t_ofile_list, of, 846811599a4SMatt Barden smb_ofile_delete); 847811599a4SMatt Barden } 848da6c28aaSamw break; 849da6c28aaSamw 850da6c28aaSamw default: 851da6c28aaSamw ASSERT(0); 852da6c28aaSamw break; 853da6c28aaSamw } 854da6c28aaSamw mutex_exit(&of->f_mutex); 855811599a4SMatt Barden 856811599a4SMatt Barden /* 857811599a4SMatt Barden * When we drop the last ref. on an expired DH, it's no longer 858811599a4SMatt Barden * in any tree, so skip the smb_llist_post and just call 859811599a4SMatt Barden * smb_ofile_delete directly. 860811599a4SMatt Barden */ 861811599a4SMatt Barden if (delete) { 862811599a4SMatt Barden smb_ofile_delete(of); 863811599a4SMatt Barden } 864da6c28aaSamw } 865da6c28aaSamw 866da6c28aaSamw /* 867da6c28aaSamw * smb_ofile_lookup_by_fid 868da6c28aaSamw * 869da6c28aaSamw * Find the open file whose fid matches the one specified in the request. 870da6c28aaSamw * If we can't find the fid or the shares (trees) don't match, we have a 871da6c28aaSamw * bad fid. 872da6c28aaSamw */ 873da6c28aaSamw smb_ofile_t * 874da6c28aaSamw smb_ofile_lookup_by_fid( 8753b13a1efSThomas Keiser smb_request_t *sr, 876da6c28aaSamw uint16_t fid) 877da6c28aaSamw { 8783b13a1efSThomas Keiser smb_tree_t *tree = sr->tid_tree; 879da6c28aaSamw smb_llist_t *of_list; 880da6c28aaSamw smb_ofile_t *of; 881da6c28aaSamw 882da6c28aaSamw ASSERT(tree->t_magic == SMB_TREE_MAGIC); 883da6c28aaSamw 884da6c28aaSamw of_list = &tree->t_ofile_list; 885da6c28aaSamw 886da6c28aaSamw smb_llist_enter(of_list, RW_READER); 887da6c28aaSamw of = smb_llist_head(of_list); 888da6c28aaSamw while (of) { 889da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 890da6c28aaSamw ASSERT(of->f_tree == tree); 8913b13a1efSThomas Keiser if (of->f_fid == fid) 8923b13a1efSThomas Keiser break; 8933b13a1efSThomas Keiser of = smb_llist_next(of_list, of); 8943b13a1efSThomas Keiser } 8953b13a1efSThomas Keiser if (of == NULL) 8963b13a1efSThomas Keiser goto out; 8973b13a1efSThomas Keiser 8983b13a1efSThomas Keiser /* 8993b13a1efSThomas Keiser * Only allow use of a given FID with the same UID that 9003b13a1efSThomas Keiser * was used to open it. MS-CIFS 3.3.5.14 9013b13a1efSThomas Keiser */ 9023b13a1efSThomas Keiser if (of->f_user != sr->uid_user) { 9033b13a1efSThomas Keiser of = NULL; 9043b13a1efSThomas Keiser goto out; 9053b13a1efSThomas Keiser } 9063b13a1efSThomas Keiser 907811599a4SMatt Barden /* inline smb_ofile_hold() */ 908da6c28aaSamw mutex_enter(&of->f_mutex); 909da6c28aaSamw if (of->f_state != SMB_OFILE_STATE_OPEN) { 910da6c28aaSamw mutex_exit(&of->f_mutex); 9113b13a1efSThomas Keiser of = NULL; 9123b13a1efSThomas Keiser goto out; 913da6c28aaSamw } 914da6c28aaSamw of->f_refcnt++; 915da6c28aaSamw mutex_exit(&of->f_mutex); 9163b13a1efSThomas Keiser 9173b13a1efSThomas Keiser out: 918da6c28aaSamw smb_llist_exit(of_list); 919da6c28aaSamw return (of); 920da6c28aaSamw } 921da6c28aaSamw 922da6c28aaSamw /* 9231fcced4cSJordan Brown * smb_ofile_lookup_by_uniqid 9241fcced4cSJordan Brown * 9251fcced4cSJordan Brown * Find the open file whose uniqid matches the one specified in the request. 9261fcced4cSJordan Brown */ 9271fcced4cSJordan Brown smb_ofile_t * 9281fcced4cSJordan Brown smb_ofile_lookup_by_uniqid(smb_tree_t *tree, uint32_t uniqid) 9291fcced4cSJordan Brown { 9301fcced4cSJordan Brown smb_llist_t *of_list; 9311fcced4cSJordan Brown smb_ofile_t *of; 9321fcced4cSJordan Brown 9331fcced4cSJordan Brown ASSERT(tree->t_magic == SMB_TREE_MAGIC); 9341fcced4cSJordan Brown 9351fcced4cSJordan Brown of_list = &tree->t_ofile_list; 9361fcced4cSJordan Brown smb_llist_enter(of_list, RW_READER); 9371fcced4cSJordan Brown of = smb_llist_head(of_list); 9381fcced4cSJordan Brown 9391fcced4cSJordan Brown while (of) { 9401fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 9411fcced4cSJordan Brown ASSERT(of->f_tree == tree); 9421fcced4cSJordan Brown 9431fcced4cSJordan Brown if (of->f_uniqid == uniqid) { 9441fcced4cSJordan Brown if (smb_ofile_hold(of)) { 9451fcced4cSJordan Brown smb_llist_exit(of_list); 9461fcced4cSJordan Brown return (of); 9471fcced4cSJordan Brown } 9481fcced4cSJordan Brown } 9491fcced4cSJordan Brown 9501fcced4cSJordan Brown of = smb_llist_next(of_list, of); 9511fcced4cSJordan Brown } 9521fcced4cSJordan Brown 9531fcced4cSJordan Brown smb_llist_exit(of_list); 9541fcced4cSJordan Brown return (NULL); 9551fcced4cSJordan Brown } 9561fcced4cSJordan Brown 957811599a4SMatt Barden static smb_ofile_t * 958811599a4SMatt Barden smb_ofile_hold_cb(smb_ofile_t *of) 959811599a4SMatt Barden { 960811599a4SMatt Barden smb_ofile_t *ret = of; 961811599a4SMatt Barden 962811599a4SMatt Barden mutex_enter(&of->f_mutex); 963811599a4SMatt Barden if (of->f_state == SMB_OFILE_STATE_ORPHANED) 964811599a4SMatt Barden /* inline smb_ofile_hold() */ 965811599a4SMatt Barden of->f_refcnt++; 966811599a4SMatt Barden else 967811599a4SMatt Barden ret = NULL; 968811599a4SMatt Barden 969811599a4SMatt Barden mutex_exit(&of->f_mutex); 970811599a4SMatt Barden return (ret); 971811599a4SMatt Barden } 972811599a4SMatt Barden 973811599a4SMatt Barden /* 974811599a4SMatt Barden * Lookup an ofile by persistent ID, and return ONLY if in state ORPHANED 975811599a4SMatt Barden * This is used by SMB2 create "reclaim". 976811599a4SMatt Barden */ 977811599a4SMatt Barden smb_ofile_t * 978811599a4SMatt Barden smb_ofile_lookup_by_persistid(smb_request_t *sr, uint64_t persistid) 979811599a4SMatt Barden { 980811599a4SMatt Barden smb_hash_t *hash; 981811599a4SMatt Barden smb_bucket_t *bucket; 982811599a4SMatt Barden smb_llist_t *ll; 983811599a4SMatt Barden smb_ofile_t *of; 984811599a4SMatt Barden uint_t idx; 985811599a4SMatt Barden 986*8d94f651SGordon Ross if (persistid == 0) 987*8d94f651SGordon Ross return (NULL); 988*8d94f651SGordon Ross 989811599a4SMatt Barden hash = sr->sr_server->sv_persistid_ht; 990811599a4SMatt Barden idx = smb_hash_uint64(hash, persistid); 991811599a4SMatt Barden bucket = &hash->buckets[idx]; 992811599a4SMatt Barden ll = &bucket->b_list; 993811599a4SMatt Barden 994811599a4SMatt Barden smb_llist_enter(ll, RW_READER); 995811599a4SMatt Barden of = smb_llist_head(ll); 996811599a4SMatt Barden while (of != NULL) { 997811599a4SMatt Barden if (of->f_persistid == persistid) 998811599a4SMatt Barden break; 999811599a4SMatt Barden of = smb_llist_next(ll, of); 1000811599a4SMatt Barden } 1001811599a4SMatt Barden if (of != NULL) 1002811599a4SMatt Barden of = smb_ofile_hold_cb(of); 1003811599a4SMatt Barden smb_llist_exit(ll); 1004811599a4SMatt Barden 1005811599a4SMatt Barden return (of); 1006811599a4SMatt Barden } 1007811599a4SMatt Barden 1008811599a4SMatt Barden /* 1009*8d94f651SGordon Ross * Create a (unique) durable/persistent ID for a new ofile, 1010*8d94f651SGordon Ross * and add this ofile to the persistid hash table. This ID 1011*8d94f651SGordon Ross * is referred to as the persistent ID in the protocol spec, 1012*8d94f651SGordon Ross * so that's what we call it too, though the persistence may 1013*8d94f651SGordon Ross * vary. "Durable" handles are persistent across reconnects 1014*8d94f651SGordon Ross * but not server reboots. Persistent handles are persistent 1015*8d94f651SGordon Ross * across server reboots too. 1016*8d94f651SGordon Ross * 1017*8d94f651SGordon Ross * Note that persistent IDs need to be unique for the lifetime of 1018*8d94f651SGordon Ross * any given ofile. For normal (non-persistent) ofiles we can just 1019*8d94f651SGordon Ross * use a persistent ID derived from the ofile memory address, as 1020*8d94f651SGordon Ross * these don't ever live beyond the current OS boot lifetime. 1021*8d94f651SGordon Ross * 1022*8d94f651SGordon Ross * Persistent handles are re-imported after server restart, and 1023*8d94f651SGordon Ross * generally have a different memory address after import than 1024*8d94f651SGordon Ross * they had in the previous OS boot lifetime, so for these we 1025*8d94f651SGordon Ross * use a randomly assigned value that won't conflict with any 1026*8d94f651SGordon Ross * non-persistent (durable) handles. Ensuring that a randomly 1027*8d94f651SGordon Ross * generated ID is unique requires a search of the ofiles in one 1028*8d94f651SGordon Ross * hash bucket, which we'd rather avoid for non-persistent opens. 1029*8d94f651SGordon Ross * 1030*8d94f651SGordon Ross * The solution used here is to divide the persistent ID space 1031*8d94f651SGordon Ross * in half (odd and even values) where durable opens use an ID 1032*8d94f651SGordon Ross * derived from the ofile address (which is always even), and 1033*8d94f651SGordon Ross * persistent opens use an ID generated randomly (always odd). 1034*8d94f651SGordon Ross * 1035*8d94f651SGordon Ross * smb_ofile_set_persistid_dh() sets a durable handle ID and 1036*8d94f651SGordon Ross * smb_ofile_set_persistid_ph() sets a persistent handle ID. 1037811599a4SMatt Barden */ 1038811599a4SMatt Barden void 1039*8d94f651SGordon Ross smb_ofile_set_persistid_dh(smb_ofile_t *of) 1040811599a4SMatt Barden { 1041811599a4SMatt Barden smb_hash_t *hash = of->f_server->sv_persistid_ht; 1042811599a4SMatt Barden smb_bucket_t *bucket; 1043811599a4SMatt Barden smb_llist_t *ll; 1044*8d94f651SGordon Ross uint64_t persistid; 1045811599a4SMatt Barden uint_t idx; 1046811599a4SMatt Barden 1047*8d94f651SGordon Ross persistid = (uintptr_t)of; 1048*8d94f651SGordon Ross /* Avoid showing object addresses */ 1049*8d94f651SGordon Ross persistid ^= ((uintptr_t)&smb_cache_ofile); 1050*8d94f651SGordon Ross /* make sure it's even */ 1051*8d94f651SGordon Ross persistid &= ~((uint64_t)1); 1052811599a4SMatt Barden 1053*8d94f651SGordon Ross idx = smb_hash_uint64(hash, persistid); 1054811599a4SMatt Barden bucket = &hash->buckets[idx]; 1055811599a4SMatt Barden ll = &bucket->b_list; 1056811599a4SMatt Barden smb_llist_enter(ll, RW_WRITER); 1057*8d94f651SGordon Ross if (of->f_persistid == 0) { 1058*8d94f651SGordon Ross of->f_persistid = persistid; 1059811599a4SMatt Barden smb_llist_insert_tail(ll, of); 1060*8d94f651SGordon Ross } 1061811599a4SMatt Barden smb_llist_exit(ll); 1062811599a4SMatt Barden } 1063811599a4SMatt Barden 1064811599a4SMatt Barden void 1065*8d94f651SGordon Ross smb_ofile_set_persistid_ph(smb_ofile_t *of) 1066*8d94f651SGordon Ross { 1067*8d94f651SGordon Ross uint64_t persistid; 1068*8d94f651SGordon Ross int rc; 1069*8d94f651SGordon Ross 1070*8d94f651SGordon Ross top: 1071*8d94f651SGordon Ross (void) random_get_pseudo_bytes((uint8_t *)&persistid, 1072*8d94f651SGordon Ross sizeof (persistid)); 1073*8d94f651SGordon Ross if (persistid == 0) { 1074*8d94f651SGordon Ross cmn_err(CE_NOTE, "random gave all zeros!"); 1075*8d94f651SGordon Ross goto top; 1076*8d94f651SGordon Ross } 1077*8d94f651SGordon Ross /* make sure it's odd */ 1078*8d94f651SGordon Ross persistid |= (uint64_t)1; 1079*8d94f651SGordon Ross 1080*8d94f651SGordon Ross /* 1081*8d94f651SGordon Ross * Try inserting with this persistent ID. 1082*8d94f651SGordon Ross */ 1083*8d94f651SGordon Ross rc = smb_ofile_insert_persistid(of, persistid); 1084*8d94f651SGordon Ross if (rc == EEXIST) 1085*8d94f651SGordon Ross goto top; 1086*8d94f651SGordon Ross if (rc != 0) { 1087*8d94f651SGordon Ross cmn_err(CE_NOTE, "set persistid rc=%d", rc); 1088*8d94f651SGordon Ross } 1089*8d94f651SGordon Ross } 1090*8d94f651SGordon Ross 1091*8d94f651SGordon Ross /* 1092*8d94f651SGordon Ross * Insert an ofile into the persistid hash table. 1093*8d94f651SGordon Ross * If the persistent ID is in use, error. 1094*8d94f651SGordon Ross */ 1095*8d94f651SGordon Ross int 1096*8d94f651SGordon Ross smb_ofile_insert_persistid(smb_ofile_t *new_of, uint64_t persistid) 1097*8d94f651SGordon Ross { 1098*8d94f651SGordon Ross smb_hash_t *hash = new_of->f_server->sv_persistid_ht; 1099*8d94f651SGordon Ross smb_bucket_t *bucket; 1100*8d94f651SGordon Ross smb_llist_t *ll; 1101*8d94f651SGordon Ross smb_ofile_t *of; 1102*8d94f651SGordon Ross uint_t idx; 1103*8d94f651SGordon Ross 1104*8d94f651SGordon Ross ASSERT(persistid != 0); 1105*8d94f651SGordon Ross 1106*8d94f651SGordon Ross /* 1107*8d94f651SGordon Ross * Look to see if this key alreay exists. 1108*8d94f651SGordon Ross */ 1109*8d94f651SGordon Ross idx = smb_hash_uint64(hash, persistid); 1110*8d94f651SGordon Ross bucket = &hash->buckets[idx]; 1111*8d94f651SGordon Ross ll = &bucket->b_list; 1112*8d94f651SGordon Ross 1113*8d94f651SGordon Ross smb_llist_enter(ll, RW_WRITER); 1114*8d94f651SGordon Ross of = smb_llist_head(ll); 1115*8d94f651SGordon Ross while (of != NULL) { 1116*8d94f651SGordon Ross if (of->f_persistid == persistid) { 1117*8d94f651SGordon Ross /* already in use */ 1118*8d94f651SGordon Ross smb_llist_exit(ll); 1119*8d94f651SGordon Ross return (EEXIST); 1120*8d94f651SGordon Ross } 1121*8d94f651SGordon Ross of = smb_llist_next(ll, of); 1122*8d94f651SGordon Ross } 1123*8d94f651SGordon Ross 1124*8d94f651SGordon Ross /* Not found, so OK to insert. */ 1125*8d94f651SGordon Ross if (new_of->f_persistid == 0) { 1126*8d94f651SGordon Ross new_of->f_persistid = persistid; 1127*8d94f651SGordon Ross smb_llist_insert_tail(ll, new_of); 1128*8d94f651SGordon Ross } 1129*8d94f651SGordon Ross smb_llist_exit(ll); 1130*8d94f651SGordon Ross 1131*8d94f651SGordon Ross return (0); 1132*8d94f651SGordon Ross } 1133*8d94f651SGordon Ross 1134*8d94f651SGordon Ross void 1135811599a4SMatt Barden smb_ofile_del_persistid(smb_ofile_t *of) 1136811599a4SMatt Barden { 1137811599a4SMatt Barden smb_hash_t *hash = of->f_server->sv_persistid_ht; 1138811599a4SMatt Barden smb_bucket_t *bucket; 1139811599a4SMatt Barden smb_llist_t *ll; 1140811599a4SMatt Barden uint_t idx; 1141811599a4SMatt Barden 1142811599a4SMatt Barden idx = smb_hash_uint64(hash, of->f_persistid); 1143811599a4SMatt Barden bucket = &hash->buckets[idx]; 1144811599a4SMatt Barden ll = &bucket->b_list; 1145811599a4SMatt Barden smb_llist_enter(ll, RW_WRITER); 1146*8d94f651SGordon Ross if (of->f_persistid != 0) { 1147811599a4SMatt Barden smb_llist_remove(ll, of); 1148*8d94f651SGordon Ross of->f_persistid = 0; 1149*8d94f651SGordon Ross } 1150811599a4SMatt Barden smb_llist_exit(ll); 1151811599a4SMatt Barden } 1152811599a4SMatt Barden 11531fcced4cSJordan Brown /* 11541fcced4cSJordan Brown * Disallow NetFileClose on certain ofiles to avoid side-effects. 11551fcced4cSJordan Brown * Closing a tree root is not allowed: use NetSessionDel or NetShareDel. 11561fcced4cSJordan Brown * Closing SRVSVC connections is not allowed because this NetFileClose 11571fcced4cSJordan Brown * request may depend on this ofile. 11581fcced4cSJordan Brown */ 11591fcced4cSJordan Brown boolean_t 11601fcced4cSJordan Brown smb_ofile_disallow_fclose(smb_ofile_t *of) 11611fcced4cSJordan Brown { 11621fcced4cSJordan Brown ASSERT(of); 11631fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 11641fcced4cSJordan Brown ASSERT(of->f_refcnt); 11651fcced4cSJordan Brown 11661fcced4cSJordan Brown switch (of->f_ftype) { 11671fcced4cSJordan Brown case SMB_FTYPE_DISK: 11681fcced4cSJordan Brown ASSERT(of->f_tree); 11691fcced4cSJordan Brown return (of->f_node == of->f_tree->t_snode); 11701fcced4cSJordan Brown 11711fcced4cSJordan Brown case SMB_FTYPE_MESG_PIPE: 11721fcced4cSJordan Brown ASSERT(of->f_pipe); 1173bbf6f00cSJordan Brown if (smb_strcasecmp(of->f_pipe->p_name, "SRVSVC", 0) == 0) 11741fcced4cSJordan Brown return (B_TRUE); 11751fcced4cSJordan Brown break; 11761fcced4cSJordan Brown default: 11771fcced4cSJordan Brown break; 11781fcced4cSJordan Brown } 11791fcced4cSJordan Brown 11801fcced4cSJordan Brown return (B_FALSE); 11811fcced4cSJordan Brown } 11821fcced4cSJordan Brown 11831fcced4cSJordan Brown /* 1184da6c28aaSamw * smb_ofile_set_flags 1185da6c28aaSamw * 1186da6c28aaSamw * Return value: 1187da6c28aaSamw * 1188da6c28aaSamw * Current flags value 1189da6c28aaSamw * 1190da6c28aaSamw */ 1191da6c28aaSamw void 1192da6c28aaSamw smb_ofile_set_flags( 1193da6c28aaSamw smb_ofile_t *of, 1194da6c28aaSamw uint32_t flags) 1195da6c28aaSamw { 1196da6c28aaSamw ASSERT(of); 1197da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 1198da6c28aaSamw ASSERT(of->f_refcnt); 1199da6c28aaSamw 1200da6c28aaSamw mutex_enter(&of->f_mutex); 1201da6c28aaSamw of->f_flags |= flags; 1202da6c28aaSamw mutex_exit(&of->f_mutex); 1203da6c28aaSamw } 1204f96bd5c8SAlan Wright 1205da6c28aaSamw /* 1206da6c28aaSamw * smb_ofile_seek 1207da6c28aaSamw * 1208da6c28aaSamw * Return value: 1209da6c28aaSamw * 1210da6c28aaSamw * 0 Success 1211da6c28aaSamw * EINVAL Unknown mode 1212da6c28aaSamw * EOVERFLOW offset too big 1213da6c28aaSamw * 1214da6c28aaSamw */ 1215da6c28aaSamw int 1216da6c28aaSamw smb_ofile_seek( 1217da6c28aaSamw smb_ofile_t *of, 1218da6c28aaSamw ushort_t mode, 1219da6c28aaSamw int32_t off, 1220da6c28aaSamw uint32_t *retoff) 1221da6c28aaSamw { 122255bf511dSas200622 u_offset_t newoff = 0; 1223da6c28aaSamw int rc = 0; 1224037cac00Sjoyce mcintosh smb_attr_t attr; 1225da6c28aaSamw 1226da6c28aaSamw ASSERT(of); 1227da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 1228da6c28aaSamw ASSERT(of->f_refcnt); 1229da6c28aaSamw 1230da6c28aaSamw mutex_enter(&of->f_mutex); 1231da6c28aaSamw switch (mode) { 1232da6c28aaSamw case SMB_SEEK_SET: 1233da6c28aaSamw if (off < 0) 1234da6c28aaSamw newoff = 0; 1235da6c28aaSamw else 123655bf511dSas200622 newoff = (u_offset_t)off; 1237da6c28aaSamw break; 1238da6c28aaSamw 1239da6c28aaSamw case SMB_SEEK_CUR: 1240da6c28aaSamw if (off < 0 && (-off) > of->f_seek_pos) 1241da6c28aaSamw newoff = 0; 1242da6c28aaSamw else 124355bf511dSas200622 newoff = of->f_seek_pos + (u_offset_t)off; 1244da6c28aaSamw break; 1245da6c28aaSamw 1246da6c28aaSamw case SMB_SEEK_END: 1247037cac00Sjoyce mcintosh bzero(&attr, sizeof (smb_attr_t)); 1248037cac00Sjoyce mcintosh attr.sa_mask |= SMB_AT_SIZE; 12498622ec45SGordon Ross rc = smb_fsop_getattr(NULL, zone_kcred(), of->f_node, &attr); 1250037cac00Sjoyce mcintosh if (rc != 0) { 1251037cac00Sjoyce mcintosh mutex_exit(&of->f_mutex); 1252037cac00Sjoyce mcintosh return (rc); 1253037cac00Sjoyce mcintosh } 1254037cac00Sjoyce mcintosh if (off < 0 && (-off) > attr.sa_vattr.va_size) 1255da6c28aaSamw newoff = 0; 1256da6c28aaSamw else 1257037cac00Sjoyce mcintosh newoff = attr.sa_vattr.va_size + (u_offset_t)off; 1258da6c28aaSamw break; 1259da6c28aaSamw 1260da6c28aaSamw default: 1261da6c28aaSamw mutex_exit(&of->f_mutex); 1262da6c28aaSamw return (EINVAL); 1263da6c28aaSamw } 1264da6c28aaSamw 126555bf511dSas200622 /* 126655bf511dSas200622 * See comments at the beginning of smb_seek.c. 126755bf511dSas200622 * If the offset is greater than UINT_MAX, we will return an error. 126855bf511dSas200622 */ 126955bf511dSas200622 127055bf511dSas200622 if (newoff > UINT_MAX) { 1271da6c28aaSamw rc = EOVERFLOW; 1272da6c28aaSamw } else { 1273da6c28aaSamw of->f_seek_pos = newoff; 1274da6c28aaSamw *retoff = (uint32_t)newoff; 1275da6c28aaSamw } 1276da6c28aaSamw mutex_exit(&of->f_mutex); 1277da6c28aaSamw return (rc); 1278da6c28aaSamw } 1279da6c28aaSamw 1280da6c28aaSamw /* 12816d1c73b5SDan Vatca * smb_ofile_flush 12826d1c73b5SDan Vatca * 12836d1c73b5SDan Vatca * If writes on this file are not synchronous, flush it using the NFSv3 12846d1c73b5SDan Vatca * commit interface. 12856d1c73b5SDan Vatca * 12866d1c73b5SDan Vatca * XXX - todo: Flush named pipe should drain writes. 12876d1c73b5SDan Vatca */ 12886d1c73b5SDan Vatca void 12896d1c73b5SDan Vatca smb_ofile_flush(struct smb_request *sr, struct smb_ofile *of) 12906d1c73b5SDan Vatca { 12916d1c73b5SDan Vatca switch (of->f_ftype) { 12926d1c73b5SDan Vatca case SMB_FTYPE_DISK: 12936d1c73b5SDan Vatca if ((of->f_node->flags & NODE_FLAGS_WRITE_THROUGH) == 0) 12946d1c73b5SDan Vatca (void) smb_fsop_commit(sr, of->f_cr, of->f_node); 12956d1c73b5SDan Vatca break; 12966d1c73b5SDan Vatca default: 12976d1c73b5SDan Vatca break; 12986d1c73b5SDan Vatca } 12996d1c73b5SDan Vatca } 13006d1c73b5SDan Vatca 13016d1c73b5SDan Vatca /* 1302da6c28aaSamw * smb_ofile_is_open 1303da6c28aaSamw */ 1304da6c28aaSamw boolean_t 13052c2961f8Sjose borrego smb_ofile_is_open(smb_ofile_t *of) 1306da6c28aaSamw { 13071fcced4cSJordan Brown boolean_t rc; 1308da6c28aaSamw 13092c2961f8Sjose borrego SMB_OFILE_VALID(of); 1310da6c28aaSamw 1311da6c28aaSamw mutex_enter(&of->f_mutex); 13121fcced4cSJordan Brown rc = smb_ofile_is_open_locked(of); 1313da6c28aaSamw mutex_exit(&of->f_mutex); 1314da6c28aaSamw return (rc); 1315da6c28aaSamw } 1316da6c28aaSamw 1317da6c28aaSamw /* *************************** Static Functions ***************************** */ 1318da6c28aaSamw 1319da6c28aaSamw /* 13201fcced4cSJordan Brown * Determine whether or not an ofile is open. 13211fcced4cSJordan Brown * This function must be called with the mutex held. 13221fcced4cSJordan Brown */ 13231fcced4cSJordan Brown static boolean_t 13241fcced4cSJordan Brown smb_ofile_is_open_locked(smb_ofile_t *of) 13251fcced4cSJordan Brown { 1326811599a4SMatt Barden ASSERT(MUTEX_HELD(&of->f_mutex)); 1327811599a4SMatt Barden 13281fcced4cSJordan Brown switch (of->f_state) { 13291fcced4cSJordan Brown case SMB_OFILE_STATE_OPEN: 1330811599a4SMatt Barden case SMB_OFILE_STATE_SAVE_DH: 1331811599a4SMatt Barden case SMB_OFILE_STATE_SAVING: 1332811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 1333811599a4SMatt Barden case SMB_OFILE_STATE_RECONNECT: 13341fcced4cSJordan Brown return (B_TRUE); 13351fcced4cSJordan Brown 13361fcced4cSJordan Brown case SMB_OFILE_STATE_CLOSING: 13371fcced4cSJordan Brown case SMB_OFILE_STATE_CLOSED: 1338811599a4SMatt Barden case SMB_OFILE_STATE_EXPIRED: 13391fcced4cSJordan Brown return (B_FALSE); 13401fcced4cSJordan Brown 13411fcced4cSJordan Brown default: 13421fcced4cSJordan Brown ASSERT(0); 13431fcced4cSJordan Brown return (B_FALSE); 13441fcced4cSJordan Brown } 13451fcced4cSJordan Brown } 13461fcced4cSJordan Brown 13471fcced4cSJordan Brown /* 1348811599a4SMatt Barden * smb_ofile_save_dh 1349811599a4SMatt Barden * 1350811599a4SMatt Barden * Called via smb_llist_post (after smb_llist_exit) when the last ref. 1351811599a4SMatt Barden * on this ofile has gone, and this ofile is a "durable handle" (DH) 1352811599a4SMatt Barden * that has state we've decided to save. 1353811599a4SMatt Barden * 1354811599a4SMatt Barden * This does parts of what smb_ofile_delete would do, including: 1355811599a4SMatt Barden * remove the ofile from the tree ofile list and related. 1356811599a4SMatt Barden * 1357811599a4SMatt Barden * We leave the ofile in state ORPHANED, ready for reconnect 1358811599a4SMatt Barden * or expiration via smb2_dh_expire (see smb_ofile_delete). 1359da6c28aaSamw */ 1360811599a4SMatt Barden static void 1361811599a4SMatt Barden smb_ofile_save_dh(void *arg) 1362da6c28aaSamw { 1363811599a4SMatt Barden smb_ofile_t *of = (smb_ofile_t *)arg; 1364811599a4SMatt Barden smb_tree_t *tree = of->f_tree; 1365da6c28aaSamw 1366811599a4SMatt Barden SMB_OFILE_VALID(of); 1367811599a4SMatt Barden ASSERT(of->f_refcnt == 0); 1368811599a4SMatt Barden ASSERT(of->f_ftype == SMB_FTYPE_DISK); 1369811599a4SMatt Barden ASSERT(of->f_state == SMB_OFILE_STATE_SAVING); 1370da6c28aaSamw 1371811599a4SMatt Barden atomic_dec_32(&of->f_session->s_file_cnt); 1372811599a4SMatt Barden atomic_dec_32(&of->f_tree->t_open_files); 1373811599a4SMatt Barden smb_llist_enter(&tree->t_ofile_list, RW_WRITER); 1374811599a4SMatt Barden smb_llist_remove(&tree->t_ofile_list, of); 1375811599a4SMatt Barden smb_llist_exit(&tree->t_ofile_list); 1376811599a4SMatt Barden 1377da6c28aaSamw /* 1378811599a4SMatt Barden * This ofile is no longer on t_ofile_list, however... 1379811599a4SMatt Barden * 1380811599a4SMatt Barden * This is called via smb_llist_post, which means it may run 1381811599a4SMatt Barden * BEFORE smb_ofile_release drops f_mutex (if another thread 1382811599a4SMatt Barden * flushes the delete queue before we do). Synchronize. 1383da6c28aaSamw */ 1384811599a4SMatt Barden mutex_enter(&of->f_mutex); 1385811599a4SMatt Barden DTRACE_PROBE1(ofile__exit, smb_ofile_t, of); 1386da6c28aaSamw mutex_exit(&of->f_mutex); 1387811599a4SMatt Barden 1388811599a4SMatt Barden /* 1389811599a4SMatt Barden * Keep f_notify state, lease, and 1390811599a4SMatt Barden * keep on node ofile list. 1391811599a4SMatt Barden * Keep of->f_cr until reclaim. 1392811599a4SMatt Barden */ 1393811599a4SMatt Barden 1394811599a4SMatt Barden ASSERT(of->f_fid != 0); 1395811599a4SMatt Barden smb_idpool_free(&tree->t_fid_pool, of->f_fid); 1396811599a4SMatt Barden of->f_fid = 0; 1397811599a4SMatt Barden smb_tree_release(of->f_tree); 1398811599a4SMatt Barden of->f_tree = NULL; 1399811599a4SMatt Barden smb_user_release(of->f_user); 1400811599a4SMatt Barden of->f_user = NULL; 1401811599a4SMatt Barden of->f_session = NULL; 1402811599a4SMatt Barden 1403811599a4SMatt Barden /* 1404811599a4SMatt Barden * Make it "orphaned" so it can now be reclaimed. 1405811599a4SMatt Barden * Note that smb_ofile_hold_olbrk() may have blocked 1406811599a4SMatt Barden * for state SMB_OFILE_STATE_SAVING, so wake it. 1407811599a4SMatt Barden */ 1408811599a4SMatt Barden mutex_enter(&of->f_mutex); 1409811599a4SMatt Barden of->dh_expire_time = gethrtime() + of->dh_timeout_offset; 1410811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_ORPHANED; 1411811599a4SMatt Barden cv_broadcast(&of->f_cv); 1412da6c28aaSamw mutex_exit(&of->f_mutex); 1413da6c28aaSamw } 1414da6c28aaSamw 1415da6c28aaSamw /* 14169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Delete an ofile. 1417da6c28aaSamw * 141894047d49SGordon Ross * Approximately the inverse of smb_ofile_alloc() 1419811599a4SMatt Barden * Called via smb_llist_post (after smb_llist_exit) 1420811599a4SMatt Barden * when the last ref. on this ofile has gone. 1421811599a4SMatt Barden * 1422811599a4SMatt Barden * Normally,this removes the ofile from the tree list and 1423811599a4SMatt Barden * then frees resources held on the ofile. However, when 1424811599a4SMatt Barden * we're expiring an orphaned durable handle, the linkage 1425811599a4SMatt Barden * into the tree lists etc. have already been destroyed. 1426811599a4SMatt Barden * This case is distinguished by of->f_tree == NULL. 1427da6c28aaSamw */ 1428811599a4SMatt Barden static void 14299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_delete(void *arg) 1430da6c28aaSamw { 14319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_t *of = (smb_ofile_t *)arg; 1432811599a4SMatt Barden smb_tree_t *tree = of->f_tree; 14339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 14349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OFILE_VALID(of); 1435da6c28aaSamw ASSERT(of->f_refcnt == 0); 1436da6c28aaSamw ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED); 1437da6c28aaSamw 1438811599a4SMatt Barden if (tree != NULL) { 1439811599a4SMatt Barden ASSERT(of->f_user != NULL); 1440811599a4SMatt Barden ASSERT(of->f_session != NULL); 1441811599a4SMatt Barden atomic_dec_32(&of->f_session->s_file_cnt); 1442811599a4SMatt Barden atomic_dec_32(&of->f_tree->t_open_files); 14439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_enter(&tree->t_ofile_list, RW_WRITER); 14449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_remove(&tree->t_ofile_list, of); 14459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_exit(&tree->t_ofile_list); 1446811599a4SMatt Barden } 14479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1448bfe5e737SGordon Ross /* 1449bfe5e737SGordon Ross * Remove this ofile from the node's n_ofile_list so it 1450bfe5e737SGordon Ross * can't be found by list walkers like notify or oplock. 1451bfe5e737SGordon Ross * Keep the node ref. until later in this function so 1452bfe5e737SGordon Ross * of->f_node remains valid while we destroy the ofile. 1453bfe5e737SGordon Ross */ 1454bfe5e737SGordon Ross if (of->f_ftype == SMB_FTYPE_DISK || 1455bfe5e737SGordon Ross of->f_ftype == SMB_FTYPE_PRINTER) { 1456bfe5e737SGordon Ross ASSERT(of->f_node != NULL); 1457bfe5e737SGordon Ross /* 1458bfe5e737SGordon Ross * Note smb_ofile_close did smb_node_dec_open_ofiles() 1459bfe5e737SGordon Ross */ 1460bfe5e737SGordon Ross smb_node_rem_ofile(of->f_node, of); 1461bfe5e737SGordon Ross } 1462bfe5e737SGordon Ross 1463811599a4SMatt Barden /* 1464811599a4SMatt Barden * This ofile is no longer on any lists, however... 1465811599a4SMatt Barden * 1466811599a4SMatt Barden * This is called via smb_llist_post, which means it may run 1467811599a4SMatt Barden * BEFORE smb_ofile_release drops f_mutex (if another thread 1468811599a4SMatt Barden * flushes the delete queue before we do). Synchronize. 1469811599a4SMatt Barden */ 14709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&of->f_mutex); 147194047d49SGordon Ross of->f_state = SMB_OFILE_STATE_ALLOC; 147294047d49SGordon Ross DTRACE_PROBE1(ofile__exit, smb_ofile_t, of); 14739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&of->f_mutex); 1474da6c28aaSamw 1475a90cf9f2SGordon Ross switch (of->f_ftype) { 1476a90cf9f2SGordon Ross case SMB_FTYPE_BYTE_PIPE: 1477a90cf9f2SGordon Ross case SMB_FTYPE_MESG_PIPE: 14789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_dealloc(of->f_pipe); 14793db3f65cSamw of->f_pipe = NULL; 1480a90cf9f2SGordon Ross break; 1481a90cf9f2SGordon Ross case SMB_FTYPE_DISK: 1482bfe5e737SGordon Ross ASSERT(of->f_notify.nc_subscribed == B_FALSE); 1483bfe5e737SGordon Ross MBC_FLUSH(&of->f_notify.nc_buffer); 1484a90cf9f2SGordon Ross if (of->f_odir != NULL) 1485a90cf9f2SGordon Ross smb_odir_release(of->f_odir); 148694047d49SGordon Ross if (of->f_lease != NULL) { 148794047d49SGordon Ross smb2_lease_rele(of->f_lease); 148894047d49SGordon Ross of->f_lease = NULL; 148994047d49SGordon Ross } 1490bfe5e737SGordon Ross /* FALLTHROUGH */ 1491bfe5e737SGordon Ross case SMB_FTYPE_PRINTER: 1492bfe5e737SGordon Ross /* 1493bfe5e737SGordon Ross * Did smb_node_rem_ofile above. 1494bfe5e737SGordon Ross */ 1495bfe5e737SGordon Ross ASSERT(of->f_node != NULL); 1496da6c28aaSamw smb_node_release(of->f_node); 1497a90cf9f2SGordon Ross break; 1498a90cf9f2SGordon Ross default: 1499a90cf9f2SGordon Ross ASSERT(!"f_ftype"); 1500a90cf9f2SGordon Ross break; 1501da6c28aaSamw } 1502da6c28aaSamw 150394047d49SGordon Ross smb_ofile_free(of); 150494047d49SGordon Ross } 150594047d49SGordon Ross 150694047d49SGordon Ross void 150794047d49SGordon Ross smb_ofile_free(smb_ofile_t *of) 150894047d49SGordon Ross { 150994047d49SGordon Ross smb_tree_t *tree = of->f_tree; 151094047d49SGordon Ross 151194047d49SGordon Ross ASSERT(of->f_state == SMB_OFILE_STATE_ALLOC); 151294047d49SGordon Ross 1513811599a4SMatt Barden if (tree != NULL) { 1514811599a4SMatt Barden if (of->f_fid != 0) 1515811599a4SMatt Barden smb_idpool_free(&tree->t_fid_pool, of->f_fid); 1516811599a4SMatt Barden smb_tree_release(of->f_tree); 1517811599a4SMatt Barden smb_user_release(of->f_user); 1518811599a4SMatt Barden } 1519811599a4SMatt Barden 1520811599a4SMatt Barden if (of->f_cr != NULL) 1521811599a4SMatt Barden crfree(of->f_cr); 1522811599a4SMatt Barden 1523da6c28aaSamw of->f_magic = (uint32_t)~SMB_OFILE_MAGIC; 1524bfe5e737SGordon Ross list_destroy(&of->f_notify.nc_waiters); 1525*8d94f651SGordon Ross mutex_destroy(&of->dh_nvlock); 1526da6c28aaSamw mutex_destroy(&of->f_mutex); 15278622ec45SGordon Ross kmem_cache_free(smb_cache_ofile, of); 1528da6c28aaSamw } 1529da6c28aaSamw 1530da6c28aaSamw /* 1531da6c28aaSamw * smb_ofile_access 1532da6c28aaSamw * 1533da6c28aaSamw * This function will check to see if the access requested is granted. 1534da6c28aaSamw * Returns NT status codes. 1535da6c28aaSamw */ 1536da6c28aaSamw uint32_t 1537da6c28aaSamw smb_ofile_access(smb_ofile_t *of, cred_t *cr, uint32_t access) 1538da6c28aaSamw { 1539da6c28aaSamw 15408622ec45SGordon Ross if ((of == NULL) || (cr == zone_kcred())) 1541da6c28aaSamw return (NT_STATUS_SUCCESS); 1542da6c28aaSamw 1543da6c28aaSamw /* 1544da6c28aaSamw * If the request is for something 1545da6c28aaSamw * I don't grant it is an error 1546da6c28aaSamw */ 1547da6c28aaSamw if (~(of->f_granted_access) & access) { 1548da6c28aaSamw if (!(of->f_granted_access & ACCESS_SYSTEM_SECURITY) && 1549da6c28aaSamw (access & ACCESS_SYSTEM_SECURITY)) { 1550da6c28aaSamw return (NT_STATUS_PRIVILEGE_NOT_HELD); 1551da6c28aaSamw } 1552da6c28aaSamw return (NT_STATUS_ACCESS_DENIED); 1553da6c28aaSamw } 1554da6c28aaSamw 1555da6c28aaSamw return (NT_STATUS_SUCCESS); 1556da6c28aaSamw } 15573ad684d6Sjb150015 1558cb174861Sjoyce mcintosh /* 1559cb174861Sjoyce mcintosh * smb_ofile_share_check 1560cb174861Sjoyce mcintosh * 1561cb174861Sjoyce mcintosh * Check if ofile was opened with share access NONE (0). 1562cb174861Sjoyce mcintosh * Returns: B_TRUE - share access non-zero 1563cb174861Sjoyce mcintosh * B_FALSE - share access NONE 1564cb174861Sjoyce mcintosh */ 1565cb174861Sjoyce mcintosh boolean_t 1566cb174861Sjoyce mcintosh smb_ofile_share_check(smb_ofile_t *of) 1567cb174861Sjoyce mcintosh { 1568cb174861Sjoyce mcintosh return (!SMB_DENY_ALL(of->f_share_access)); 1569cb174861Sjoyce mcintosh } 15703ad684d6Sjb150015 15713ad684d6Sjb150015 /* 15723ad684d6Sjb150015 * check file sharing rules for current open request 15733ad684d6Sjb150015 * against existing open instances of the same file 15743ad684d6Sjb150015 * 15753ad684d6Sjb150015 * Returns NT_STATUS_SHARING_VIOLATION if there is any 15763ad684d6Sjb150015 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 15773ad684d6Sjb150015 */ 15783ad684d6Sjb150015 uint32_t 15799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_open_check(smb_ofile_t *of, uint32_t desired_access, 15803ad684d6Sjb150015 uint32_t share_access) 15813ad684d6Sjb150015 { 1582811599a4SMatt Barden uint32_t ret; 1583811599a4SMatt Barden 15843ad684d6Sjb150015 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 15853ad684d6Sjb150015 15863ad684d6Sjb150015 mutex_enter(&of->f_mutex); 15873ad684d6Sjb150015 1588811599a4SMatt Barden if (!smb_ofile_is_open_locked(of)) { 1589811599a4SMatt Barden ret = NT_STATUS_INVALID_HANDLE; 1590811599a4SMatt Barden goto out; 15913ad684d6Sjb150015 } 15923ad684d6Sjb150015 15933ad684d6Sjb150015 /* if it's just meta data */ 15943ad684d6Sjb150015 if ((of->f_granted_access & FILE_DATA_ALL) == 0) { 1595811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1596811599a4SMatt Barden goto out; 15973ad684d6Sjb150015 } 15983ad684d6Sjb150015 15993ad684d6Sjb150015 /* 16003ad684d6Sjb150015 * Check requested share access against the 16013ad684d6Sjb150015 * open granted (desired) access 16023ad684d6Sjb150015 */ 16033ad684d6Sjb150015 if (SMB_DENY_DELETE(share_access) && (of->f_granted_access & DELETE)) { 1604811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1605811599a4SMatt Barden goto out; 16063ad684d6Sjb150015 } 16073ad684d6Sjb150015 16083ad684d6Sjb150015 if (SMB_DENY_READ(share_access) && 16093ad684d6Sjb150015 (of->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE))) { 1610811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1611811599a4SMatt Barden goto out; 16123ad684d6Sjb150015 } 16133ad684d6Sjb150015 16143ad684d6Sjb150015 if (SMB_DENY_WRITE(share_access) && 16153ad684d6Sjb150015 (of->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) { 1616811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1617811599a4SMatt Barden goto out; 16183ad684d6Sjb150015 } 16193ad684d6Sjb150015 16203ad684d6Sjb150015 /* check requested desired access against the open share access */ 16213ad684d6Sjb150015 if (SMB_DENY_DELETE(of->f_share_access) && (desired_access & DELETE)) { 1622811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1623811599a4SMatt Barden goto out; 16243ad684d6Sjb150015 } 16253ad684d6Sjb150015 16263ad684d6Sjb150015 if (SMB_DENY_READ(of->f_share_access) && 16273ad684d6Sjb150015 (desired_access & (FILE_READ_DATA | FILE_EXECUTE))) { 1628811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1629811599a4SMatt Barden goto out; 16303ad684d6Sjb150015 } 16313ad684d6Sjb150015 16323ad684d6Sjb150015 if (SMB_DENY_WRITE(of->f_share_access) && 16333ad684d6Sjb150015 (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) { 1634811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1635811599a4SMatt Barden goto out; 16363ad684d6Sjb150015 } 16373ad684d6Sjb150015 1638811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1639811599a4SMatt Barden out: 16403ad684d6Sjb150015 mutex_exit(&of->f_mutex); 1641811599a4SMatt Barden return (ret); 16423ad684d6Sjb150015 } 16433ad684d6Sjb150015 16443ad684d6Sjb150015 /* 16453ad684d6Sjb150015 * smb_ofile_rename_check 16463ad684d6Sjb150015 * 1647575d359dSGordon Ross * This does the work described in MS-FSA 2.1.5.1.2.2 (Algorithm 1648575d359dSGordon Ross * to Check Sharing Access to an Existing Stream or Directory), 1649575d359dSGordon Ross * where the "open in-progress" has DesiredAccess = DELETE and 1650575d359dSGordon Ross * SharingMode = SHARE_READ | SHARE_WRITE | SHARE_DELETE. 16513ad684d6Sjb150015 */ 16523ad684d6Sjb150015 16533ad684d6Sjb150015 uint32_t 16543ad684d6Sjb150015 smb_ofile_rename_check(smb_ofile_t *of) 16553ad684d6Sjb150015 { 1656811599a4SMatt Barden uint32_t ret; 1657811599a4SMatt Barden 16583ad684d6Sjb150015 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 16593ad684d6Sjb150015 16603ad684d6Sjb150015 mutex_enter(&of->f_mutex); 16613ad684d6Sjb150015 1662811599a4SMatt Barden if (!smb_ofile_is_open_locked(of)) { 1663811599a4SMatt Barden ret = NT_STATUS_INVALID_HANDLE; 1664811599a4SMatt Barden goto out; 16653ad684d6Sjb150015 } 16663ad684d6Sjb150015 1667575d359dSGordon Ross if ((of->f_granted_access & FILE_DATA_ALL) == 0) { 1668811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1669811599a4SMatt Barden goto out; 16703ad684d6Sjb150015 } 16713ad684d6Sjb150015 16723ad684d6Sjb150015 if ((of->f_share_access & FILE_SHARE_DELETE) == 0) { 1673811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1674811599a4SMatt Barden goto out; 16753ad684d6Sjb150015 } 16763ad684d6Sjb150015 1677811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1678811599a4SMatt Barden out: 16793ad684d6Sjb150015 mutex_exit(&of->f_mutex); 1680811599a4SMatt Barden return (ret); 16813ad684d6Sjb150015 } 16823ad684d6Sjb150015 16833ad684d6Sjb150015 /* 16843ad684d6Sjb150015 * smb_ofile_delete_check 16853ad684d6Sjb150015 * 16863ad684d6Sjb150015 * An open file can be deleted only if opened for 16873ad684d6Sjb150015 * accessing meta data. Share modes aren't important 16883ad684d6Sjb150015 * in this case. 16893ad684d6Sjb150015 * 16903ad684d6Sjb150015 * NOTE: there is another mechanism for deleting an 16913ad684d6Sjb150015 * open file that NT clients usually use. 16923ad684d6Sjb150015 * That's setting "Delete on close" flag for an open 16933ad684d6Sjb150015 * file. In this way the file will be deleted after 16943ad684d6Sjb150015 * last close. This flag can be set by SmbTrans2SetFileInfo 16953ad684d6Sjb150015 * with FILE_DISPOSITION_INFO information level. 16963ad684d6Sjb150015 * For setting this flag, the file should be opened by 16973ad684d6Sjb150015 * DELETE access in the FID that is passed in the Trans2 16983ad684d6Sjb150015 * request. 16993ad684d6Sjb150015 */ 17003ad684d6Sjb150015 17013ad684d6Sjb150015 uint32_t 17023ad684d6Sjb150015 smb_ofile_delete_check(smb_ofile_t *of) 17033ad684d6Sjb150015 { 1704811599a4SMatt Barden uint32_t ret; 1705811599a4SMatt Barden 17063ad684d6Sjb150015 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 17073ad684d6Sjb150015 17083ad684d6Sjb150015 mutex_enter(&of->f_mutex); 17093ad684d6Sjb150015 1710811599a4SMatt Barden if (!smb_ofile_is_open_locked(of)) { 1711811599a4SMatt Barden ret = NT_STATUS_INVALID_HANDLE; 1712811599a4SMatt Barden goto out; 17133ad684d6Sjb150015 } 17143ad684d6Sjb150015 17153ad684d6Sjb150015 if (of->f_granted_access & 17163ad684d6Sjb150015 (FILE_READ_DATA | FILE_WRITE_DATA | 17173ad684d6Sjb150015 FILE_APPEND_DATA | FILE_EXECUTE | DELETE)) { 1718811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1719811599a4SMatt Barden goto out; 17203ad684d6Sjb150015 } 17213ad684d6Sjb150015 1722811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1723811599a4SMatt Barden out: 17243ad684d6Sjb150015 mutex_exit(&of->f_mutex); 1725811599a4SMatt Barden return (ret); 17263ad684d6Sjb150015 } 1727b89a8333Snatalie li - Sun Microsystems - Irvine United States 1728b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t * 1729b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ofile_getcred(smb_ofile_t *of) 1730b89a8333Snatalie li - Sun Microsystems - Irvine United States { 1731b89a8333Snatalie li - Sun Microsystems - Irvine United States return (of->f_cr); 1732b89a8333Snatalie li - Sun Microsystems - Irvine United States } 17338b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 17348b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /* 17358b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * smb_ofile_set_delete_on_close 17368b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 17378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * Set the DeleteOnClose flag on the smb file. When the file is closed, 17388b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * the flag will be transferred to the smb node, which will commit the 17398b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * delete operation and inhibit subsequent open requests. 17408b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 17418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * When DeleteOnClose is set on an smb_node, the common open code will 17428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * reject subsequent open requests for the file. Observation of Windows 17438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 2000 indicates that subsequent opens should be allowed (assuming 17448b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * there would be no sharing violation) until the file is closed using 17458b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * the fid on which the DeleteOnClose was requested. 17468b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States */ 17478b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States void 174894047d49SGordon Ross smb_ofile_set_delete_on_close(smb_request_t *sr, smb_ofile_t *of) 17498b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States { 175094047d49SGordon Ross uint32_t status; 175194047d49SGordon Ross 175294047d49SGordon Ross /* 175394047d49SGordon Ross * Break any oplock handle caching. 175494047d49SGordon Ross */ 175594047d49SGordon Ross status = smb_oplock_break_SETINFO(of->f_node, of, 175694047d49SGordon Ross FileDispositionInformation); 175794047d49SGordon Ross if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 175894047d49SGordon Ross if (sr->session->dialect >= SMB_VERS_2_BASE) 175994047d49SGordon Ross (void) smb2sr_go_async(sr); 176094047d49SGordon Ross (void) smb_oplock_wait_break(of->f_node, 0); 176194047d49SGordon Ross } 176294047d49SGordon Ross 17638b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&of->f_mutex); 17648b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States of->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE; 17658b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&of->f_mutex); 17668b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 17671fcced4cSJordan Brown 17681fcced4cSJordan Brown /* 17691fcced4cSJordan Brown * Encode open file information into a buffer; needed in user space to 17701fcced4cSJordan Brown * support RPC requests. 17711fcced4cSJordan Brown */ 17721fcced4cSJordan Brown static int 17731fcced4cSJordan Brown smb_ofile_netinfo_encode(smb_ofile_t *of, uint8_t *buf, size_t buflen, 17741fcced4cSJordan Brown uint32_t *nbytes) 17751fcced4cSJordan Brown { 17761fcced4cSJordan Brown smb_netfileinfo_t fi; 17771fcced4cSJordan Brown int rc; 17781fcced4cSJordan Brown 17791fcced4cSJordan Brown rc = smb_ofile_netinfo_init(of, &fi); 17801fcced4cSJordan Brown if (rc == 0) { 17811fcced4cSJordan Brown rc = smb_netfileinfo_encode(&fi, buf, buflen, nbytes); 17821fcced4cSJordan Brown smb_ofile_netinfo_fini(&fi); 17831fcced4cSJordan Brown } 17841fcced4cSJordan Brown 17851fcced4cSJordan Brown return (rc); 17861fcced4cSJordan Brown } 17871fcced4cSJordan Brown 17881fcced4cSJordan Brown static int 17891fcced4cSJordan Brown smb_ofile_netinfo_init(smb_ofile_t *of, smb_netfileinfo_t *fi) 17901fcced4cSJordan Brown { 17911fcced4cSJordan Brown smb_user_t *user; 17921fcced4cSJordan Brown smb_tree_t *tree; 17931fcced4cSJordan Brown smb_node_t *node; 17941fcced4cSJordan Brown char *path; 17951fcced4cSJordan Brown char *buf; 17961fcced4cSJordan Brown int rc; 17971fcced4cSJordan Brown 17981fcced4cSJordan Brown ASSERT(of); 17991fcced4cSJordan Brown user = of->f_user; 18001fcced4cSJordan Brown tree = of->f_tree; 18011fcced4cSJordan Brown ASSERT(user); 18021fcced4cSJordan Brown ASSERT(tree); 18031fcced4cSJordan Brown 18041fcced4cSJordan Brown buf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 18051fcced4cSJordan Brown 18061fcced4cSJordan Brown switch (of->f_ftype) { 18071fcced4cSJordan Brown case SMB_FTYPE_DISK: 18081fcced4cSJordan Brown node = of->f_node; 18091fcced4cSJordan Brown ASSERT(node); 18101fcced4cSJordan Brown 18111fcced4cSJordan Brown fi->fi_permissions = of->f_granted_access; 1812148c5f43SAlan Wright fi->fi_numlocks = smb_lock_get_lock_count(node, of); 18131fcced4cSJordan Brown 18141fcced4cSJordan Brown path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 18151fcced4cSJordan Brown 18161fcced4cSJordan Brown if (node != tree->t_snode) { 1817148c5f43SAlan Wright rc = smb_node_getshrpath(node, tree, path, MAXPATHLEN); 1818148c5f43SAlan Wright if (rc != 0) 18191fcced4cSJordan Brown (void) strlcpy(path, node->od_name, MAXPATHLEN); 18201fcced4cSJordan Brown } 18211fcced4cSJordan Brown 18221fcced4cSJordan Brown (void) snprintf(buf, MAXPATHLEN, "%s:%s", tree->t_sharename, 18231fcced4cSJordan Brown path); 18241fcced4cSJordan Brown kmem_free(path, MAXPATHLEN); 18251fcced4cSJordan Brown break; 18261fcced4cSJordan Brown 18271fcced4cSJordan Brown case SMB_FTYPE_MESG_PIPE: 18281fcced4cSJordan Brown ASSERT(of->f_pipe); 18291fcced4cSJordan Brown 18301fcced4cSJordan Brown fi->fi_permissions = FILE_READ_DATA | FILE_WRITE_DATA | 18311fcced4cSJordan Brown FILE_EXECUTE; 18321fcced4cSJordan Brown fi->fi_numlocks = 0; 18331fcced4cSJordan Brown (void) snprintf(buf, MAXPATHLEN, "\\PIPE\\%s", 18341fcced4cSJordan Brown of->f_pipe->p_name); 18351fcced4cSJordan Brown break; 18361fcced4cSJordan Brown 18371fcced4cSJordan Brown default: 18381fcced4cSJordan Brown kmem_free(buf, MAXPATHLEN); 18391fcced4cSJordan Brown return (-1); 18401fcced4cSJordan Brown } 18411fcced4cSJordan Brown 18421fcced4cSJordan Brown fi->fi_fid = of->f_fid; 18431fcced4cSJordan Brown fi->fi_uniqid = of->f_uniqid; 18441fcced4cSJordan Brown fi->fi_pathlen = strlen(buf) + 1; 18459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States fi->fi_path = smb_mem_strdup(buf); 18461fcced4cSJordan Brown kmem_free(buf, MAXPATHLEN); 18471fcced4cSJordan Brown 18481fcced4cSJordan Brown fi->fi_namelen = user->u_domain_len + user->u_name_len + 2; 18491fcced4cSJordan Brown fi->fi_username = kmem_alloc(fi->fi_namelen, KM_SLEEP); 18501fcced4cSJordan Brown (void) snprintf(fi->fi_username, fi->fi_namelen, "%s\\%s", 18511fcced4cSJordan Brown user->u_domain, user->u_name); 18521fcced4cSJordan Brown return (0); 18531fcced4cSJordan Brown } 18541fcced4cSJordan Brown 18551fcced4cSJordan Brown static void 18561fcced4cSJordan Brown smb_ofile_netinfo_fini(smb_netfileinfo_t *fi) 18571fcced4cSJordan Brown { 18581fcced4cSJordan Brown if (fi == NULL) 18591fcced4cSJordan Brown return; 18601fcced4cSJordan Brown 18611fcced4cSJordan Brown if (fi->fi_path) 18629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(fi->fi_path); 18631fcced4cSJordan Brown if (fi->fi_username) 18641fcced4cSJordan Brown kmem_free(fi->fi_username, fi->fi_namelen); 18651fcced4cSJordan Brown 18661fcced4cSJordan Brown bzero(fi, sizeof (smb_netfileinfo_t)); 18671fcced4cSJordan Brown } 18689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 18699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 18709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * A query of user and group quotas may span multiple requests. 18719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * f_quota_resume is used to determine where the query should 18729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * be resumed, in a subsequent request. f_quota_resume contains 18739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * the SID of the last quota entry returned to the client. 18749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 18759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void 18769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_set_quota_resume(smb_ofile_t *ofile, char *resume) 18779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 18789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(ofile); 18799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&ofile->f_mutex); 18809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (resume == NULL) 18819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States bzero(ofile->f_quota_resume, SMB_SID_STRSZ); 18829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States else 18839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) strlcpy(ofile->f_quota_resume, resume, SMB_SID_STRSZ); 18849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&ofile->f_mutex); 18859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 18869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 18879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void 18889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_get_quota_resume(smb_ofile_t *ofile, char *buf, int bufsize) 18899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 18909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(ofile); 18919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&ofile->f_mutex); 18929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) strlcpy(buf, ofile->f_quota_resume, bufsize); 18939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&ofile->f_mutex); 18949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 1895