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. 23525641e8SGordon Ross * Copyright 2011-2020 Tintri by DDN, Inc. All rights reserved. 246d1c73b5SDan Vatca * Copyright 2016 Syneto S.R.L. All rights reserved. 2548bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved. 26*f8e30ca2SGordon Ross * Copyright 2022 RackTop Systems, Inc. 27da6c28aaSamw */ 28da6c28aaSamw 29da6c28aaSamw /* 30da6c28aaSamw * General Structures Layout 31da6c28aaSamw * ------------------------- 32da6c28aaSamw * 33da6c28aaSamw * This is a simplified diagram showing the relationship between most of the 34da6c28aaSamw * main structures. 35da6c28aaSamw * 36da6c28aaSamw * +-------------------+ 37da6c28aaSamw * | SMB_INFO | 38da6c28aaSamw * +-------------------+ 39da6c28aaSamw * | 40da6c28aaSamw * | 41da6c28aaSamw * v 42da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 43da6c28aaSamw * | SESSION |<----->| SESSION |......| SESSION | 44da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 453b13a1efSThomas Keiser * | | 463b13a1efSThomas Keiser * | | 473b13a1efSThomas Keiser * | v 483b13a1efSThomas Keiser * | +-------------------+ +-------------------+ +-------------------+ 493b13a1efSThomas Keiser * | | USER |<--->| USER |...| USER | 503b13a1efSThomas Keiser * | +-------------------+ +-------------------+ +-------------------+ 51da6c28aaSamw * | 52da6c28aaSamw * | 53da6c28aaSamw * v 54da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 55da6c28aaSamw * | TREE |<----->| TREE |......| TREE | 56da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 57da6c28aaSamw * | | 58da6c28aaSamw * | | 59da6c28aaSamw * | v 60da6c28aaSamw * | +-------+ +-------+ +-------+ 61da6c28aaSamw * | | OFILE |<----->| OFILE |......| OFILE | 62da6c28aaSamw * | +-------+ +-------+ +-------+ 63da6c28aaSamw * | 64da6c28aaSamw * | 65da6c28aaSamw * v 66da6c28aaSamw * +-------+ +------+ +------+ 67da6c28aaSamw * | ODIR |<----->| ODIR |......| ODIR | 68da6c28aaSamw * +-------+ +------+ +------+ 69da6c28aaSamw * 70da6c28aaSamw * 71da6c28aaSamw * Ofile State Machine 72da6c28aaSamw * ------------------ 73da6c28aaSamw * 74da6c28aaSamw * +-------------------------+ T0 75811599a4SMatt Barden * | SMB_OFILE_STATE_OPEN |<--+-------- Creation/Allocation 76811599a4SMatt Barden * +-------------------------+ | 77811599a4SMatt Barden * | | | T5 78811599a4SMatt Barden * | | +---------------------------+ 79811599a4SMatt Barden * | | | SMB_OFILE_STATE_RECONNECT | 80811599a4SMatt Barden * | | +---------------------------+ 81811599a4SMatt Barden * | | ^ 82811599a4SMatt Barden * | v | 83811599a4SMatt Barden * | +---------------+ | 84811599a4SMatt Barden * | | STATE_SAVE_DH | | 85811599a4SMatt Barden * | | STATE_SAVING | | 86811599a4SMatt Barden * | +---------------+ | 87811599a4SMatt Barden * | | | T4 88811599a4SMatt Barden * | T1 | T3 +--------------------------+ 89811599a4SMatt Barden * | +------>| SMB_OFILE_STATE_ORPHANED | 90811599a4SMatt Barden * v +--------------------------+ 91811599a4SMatt Barden * +-------------------------+ | | 92811599a4SMatt Barden * | SMB_OFILE_STATE_CLOSING |<--+ T6 | T7 93811599a4SMatt Barden * +-------------------------+ | 94811599a4SMatt Barden * | ^ v 95811599a4SMatt Barden * | T2 | T8 +-------------------------+ 96811599a4SMatt Barden * | +-------| SMB_OFILE_STATE_EXPIRED | 97811599a4SMatt Barden * v +-------------------------+ 98da6c28aaSamw * +-------------------------+ 99da6c28aaSamw * | SMB_OFILE_STATE_CLOSED |----------> Deletion/Free 100811599a4SMatt Barden * +-------------------------+ T9 101da6c28aaSamw * 102da6c28aaSamw * SMB_OFILE_STATE_OPEN 103da6c28aaSamw * 104da6c28aaSamw * While in this state: 105da6c28aaSamw * - The ofile is queued in the list of ofiles of its tree. 106da6c28aaSamw * - References will be given out if the ofile is looked up. 107da6c28aaSamw * 108811599a4SMatt Barden * SMB_OFILE_STATE_SAVE_DH 109811599a4SMatt Barden * 110811599a4SMatt Barden * Similar to state _CLOSING, but instead of deleting the ofile, 111811599a4SMatt Barden * it leaves the ofile in state _ORPHANED (for later reclaim). 112811599a4SMatt Barden * Will move to _SAVING after last ref, then _ORPHANED. 113811599a4SMatt Barden * 114811599a4SMatt Barden * While in this state: 115811599a4SMatt Barden * - The ofile has been marked for preservation during a 116811599a4SMatt Barden * walk of the tree ofile list to close multiple files. 117811599a4SMatt Barden * - References will not be given out if the ofile is looked up, 118811599a4SMatt Barden * except for oplock break processing. 119811599a4SMatt Barden * - Still affects Sharing Violation rules 120811599a4SMatt Barden * 121811599a4SMatt Barden * SMB_OFILE_STATE_SAVING 122811599a4SMatt Barden * 123811599a4SMatt Barden * Transient state used to keep oplock break processing out 124811599a4SMatt Barden * while the ofile moves to state _ORPHANED. 125811599a4SMatt Barden * 126811599a4SMatt Barden * While in this state: 127811599a4SMatt Barden * - References will not be given out if the ofile is looked up, 128811599a4SMatt Barden * except for oplock break processing. 129811599a4SMatt Barden * - Still affects Sharing Violation rules 130811599a4SMatt Barden * 131da6c28aaSamw * SMB_OFILE_STATE_CLOSING 132da6c28aaSamw * 133811599a4SMatt Barden * Close has been requested. Stay in this state until the last 134811599a4SMatt Barden * ref. is gone, then move to state _CLOSED 135811599a4SMatt Barden * 136da6c28aaSamw * While in this state: 137da6c28aaSamw * - The ofile is queued in the list of ofiles of its tree. 138da6c28aaSamw * - References will not be given out if the ofile is looked up. 139da6c28aaSamw * - The file is closed and the locks held are being released. 140da6c28aaSamw * - The resources associated with the ofile remain. 141da6c28aaSamw * 142da6c28aaSamw * SMB_OFILE_STATE_CLOSED 143da6c28aaSamw * 144da6c28aaSamw * While in this state: 145da6c28aaSamw * - The ofile is queued in the list of ofiles of its tree. 146da6c28aaSamw * - References will not be given out if the ofile is looked up. 147da6c28aaSamw * - The resources associated with the ofile remain. 148da6c28aaSamw * 149811599a4SMatt Barden * SMB_OFILE_STATE_ORPHANED 150811599a4SMatt Barden * 151811599a4SMatt Barden * While in this state: 152811599a4SMatt Barden * - The ofile is queued in the list of ofiles of its tree. 153811599a4SMatt Barden * - Can be reclaimed by the original owner 154811599a4SMatt Barden * - References will not be given out if the ofile is looked up. 155811599a4SMatt Barden * - All the tree, user, and session "up" pointers are NULL! 156811599a4SMatt Barden * - Will eventually be "expired" if not reclaimed 157811599a4SMatt Barden * - Can be closed if its oplock is broken 158811599a4SMatt Barden * - Still affects Sharing Violation rules 159811599a4SMatt Barden * 160811599a4SMatt Barden * SMB_OFILE_STATE_EXPIRED 161811599a4SMatt Barden * 162811599a4SMatt Barden * While in this state: 163811599a4SMatt Barden * - The ofile is queued in the list of ofiles of its tree. 164811599a4SMatt Barden * - References will not be given out if the ofile is looked up. 165811599a4SMatt Barden * - The ofile has not been reclaimed and will soon be closed, 166811599a4SMatt Barden * due to, for example, the durable handle timer expiring, or its 167811599a4SMatt Barden * oplock being broken. 168811599a4SMatt Barden * - Cannot be reclaimed at this point 169811599a4SMatt Barden * 170811599a4SMatt Barden * SMB_OFILE_STATE_RECONNECT 171811599a4SMatt Barden * 172811599a4SMatt Barden * Transient state used to keep oplock break processing out 173811599a4SMatt Barden * while the ofile moves from state _ORPHANED to _OPEN. 174811599a4SMatt Barden * 175811599a4SMatt Barden * While in this state: 176811599a4SMatt Barden * - The ofile is being reclaimed; do not touch it. 177811599a4SMatt Barden * - References will not be given out if the ofile is looked up. 178811599a4SMatt Barden * - Still affects Sharing Violation rules 179811599a4SMatt Barden * - see smb2_dh_reconnect() for which members need to be avoided 180811599a4SMatt Barden * 181da6c28aaSamw * Transition T0 182da6c28aaSamw * 183da6c28aaSamw * This transition occurs in smb_ofile_open(). A new ofile is created and 184da6c28aaSamw * added to the list of ofiles of a tree. 185da6c28aaSamw * 186da6c28aaSamw * Transition T1 187da6c28aaSamw * 188811599a4SMatt Barden * This transition occurs in smb_ofile_close(). Note that this only happens 189811599a4SMatt Barden * when we determine that an ofile should be closed in spite of its durable 190811599a4SMatt Barden * handle properties. 191da6c28aaSamw * 192da6c28aaSamw * Transition T2 193da6c28aaSamw * 194da6c28aaSamw * This transition occurs in smb_ofile_release(). The resources associated 195da6c28aaSamw * with the ofile are freed as well as the ofile structure. For the 196da6c28aaSamw * transition to occur, the ofile must be in the SMB_OFILE_STATE_CLOSED 197da6c28aaSamw * state and the reference count be zero. 198da6c28aaSamw * 199811599a4SMatt Barden * Transition T3 200811599a4SMatt Barden * 201811599a4SMatt Barden * This transition occurs in smb_ofile_orphan_dh(). It happens during an 202811599a4SMatt Barden * smb2 logoff, or during a session disconnect when certain conditions are 203811599a4SMatt Barden * met. The ofile and structures above it will be kept around until the ofile 204811599a4SMatt Barden * either gets reclaimed, expires after f_timeout_offset nanoseconds, or its 205811599a4SMatt Barden * oplock is broken. 206811599a4SMatt Barden * 207811599a4SMatt Barden * Transition T4 208811599a4SMatt Barden * 209811599a4SMatt Barden * This transition occurs in smb2_dh_reconnect(). An smb2 create request 210811599a4SMatt Barden * with a DURABLE_HANDLE_RECONNECT(_V2) create context has been 211811599a4SMatt Barden * recieved from the original owner. If leases are supported or it's 212811599a4SMatt Barden * RECONNECT_V2, reconnect is subject to additional conditions. The ofile 213811599a4SMatt Barden * will be unwired from the old, disconnected session, tree, and user, 214811599a4SMatt Barden * and wired up to its new context. 215811599a4SMatt Barden * 216811599a4SMatt Barden * Transition T5 217811599a4SMatt Barden * 218811599a4SMatt Barden * This transition occurs in smb2_dh_reconnect(). The ofile has been 219811599a4SMatt Barden * successfully reclaimed. 220811599a4SMatt Barden * 221811599a4SMatt Barden * Transition T6 222811599a4SMatt Barden * 223811599a4SMatt Barden * This transition occurs in smb_ofile_close(). The ofile has been orphaned 224811599a4SMatt Barden * while some thread was blocked, and that thread closes the ofile. Can only 225811599a4SMatt Barden * happen when the ofile is orphaned due to an SMB2 LOGOFF request. 226811599a4SMatt Barden * 227811599a4SMatt Barden * Transition T7 228811599a4SMatt Barden * 229811599a4SMatt Barden * This transition occurs in smb_session_durable_timers() and 23094047d49SGordon Ross * smb_oplock_send_brk(). The ofile will soon be closed. 231811599a4SMatt Barden * In the former case, f_timeout_offset nanoseconds have passed since 232811599a4SMatt Barden * the ofile was orphaned. In the latter, an oplock break occured 233811599a4SMatt Barden * on the ofile while it was orphaned. 234811599a4SMatt Barden * 235811599a4SMatt Barden * Transition T8 236811599a4SMatt Barden * 237811599a4SMatt Barden * This transition occurs in smb_ofile_close(). 238811599a4SMatt Barden * 239811599a4SMatt Barden * Transition T9 240811599a4SMatt Barden * 241811599a4SMatt Barden * This transition occurs in smb_ofile_delete(). 242811599a4SMatt Barden * 243da6c28aaSamw * Comments 244da6c28aaSamw * -------- 245da6c28aaSamw * 246da6c28aaSamw * The state machine of the ofile structures is controlled by 3 elements: 247da6c28aaSamw * - The list of ofiles of the tree it belongs to. 248da6c28aaSamw * - The mutex embedded in the structure itself. 249da6c28aaSamw * - The reference count. 250da6c28aaSamw * 251da6c28aaSamw * There's a mutex embedded in the ofile structure used to protect its fields 252da6c28aaSamw * and there's a lock embedded in the list of ofiles of a tree. To 253da6c28aaSamw * increment or to decrement the reference count the mutex must be entered. 254da6c28aaSamw * To insert the ofile into the list of ofiles of the tree and to remove 255da6c28aaSamw * the ofile from it, the lock must be entered in RW_WRITER mode. 256da6c28aaSamw * 257da6c28aaSamw * Rules of access to a ofile structure: 258da6c28aaSamw * 259da6c28aaSamw * 1) In order to avoid deadlocks, when both (mutex and lock of the ofile 260811599a4SMatt Barden * list) have to be entered, the lock must be entered first. Additionally, 261811599a4SMatt Barden * f_mutex must not be held when removing the ofile from sv_persistid_ht. 262da6c28aaSamw * 263da6c28aaSamw * 2) All actions applied to an ofile require a reference count. 264da6c28aaSamw * 265da6c28aaSamw * 3) There are 2 ways of getting a reference count. One is when the ofile 266da6c28aaSamw * is opened. The other one when the ofile is looked up. This translates 267da6c28aaSamw * into 2 functions: smb_ofile_open() and smb_ofile_lookup_by_fid(). 268da6c28aaSamw * 269da6c28aaSamw * It should be noted that the reference count of an ofile registers the 270da6c28aaSamw * number of references to the ofile in other structures (such as an smb 271da6c28aaSamw * request). The reference count is not incremented in these 2 instances: 272da6c28aaSamw * 27348bbca81SDaniel Hoffman * 1) The ofile is open. An ofile is anchored by its state. If there's 274da6c28aaSamw * no activity involving an ofile currently open, the reference count 275da6c28aaSamw * of that ofile is zero. 276da6c28aaSamw * 277da6c28aaSamw * 2) The ofile is queued in the list of ofiles of its tree. The fact of 278da6c28aaSamw * being queued in that list is NOT registered by incrementing the 279da6c28aaSamw * reference count. 280da6c28aaSamw */ 281811599a4SMatt Barden #include <smbsrv/smb2_kproto.h> 282da6c28aaSamw #include <smbsrv/smb_fsops.h> 283811599a4SMatt Barden #include <sys/time.h> 2848d94f651SGordon Ross #include <sys/random.h> 285da6c28aaSamw 2861fcced4cSJordan Brown static boolean_t smb_ofile_is_open_locked(smb_ofile_t *); 287811599a4SMatt Barden static void smb_ofile_delete(void *arg); 288811599a4SMatt Barden static void smb_ofile_save_dh(void *arg); 289811599a4SMatt Barden 2901fcced4cSJordan Brown static int smb_ofile_netinfo_encode(smb_ofile_t *, uint8_t *, size_t, 2911fcced4cSJordan Brown uint32_t *); 2921fcced4cSJordan Brown static int smb_ofile_netinfo_init(smb_ofile_t *, smb_netfileinfo_t *); 2931fcced4cSJordan Brown static void smb_ofile_netinfo_fini(smb_netfileinfo_t *); 294da6c28aaSamw 295da6c28aaSamw /* 2968d94f651SGordon Ross * The uniq_fid is a CIFS-server-wide unique identifier for an ofile 2978d94f651SGordon Ross * which is used to uniquely identify open instances for the 2988d94f651SGordon Ross * VFS share reservation and POSIX locks. 2998d94f651SGordon Ross */ 3008d94f651SGordon Ross static volatile uint32_t smb_fids = 0; 3018d94f651SGordon Ross #define SMB_UNIQ_FID() atomic_inc_32_nv(&smb_fids) 3028d94f651SGordon Ross 3038d94f651SGordon Ross /* 30494047d49SGordon Ross * smb_ofile_alloc 30594047d49SGordon Ross * Allocate an ofile and fill in it's "up" pointers, but 30694047d49SGordon Ross * do NOT link it into the tree's list of ofiles or the 30794047d49SGordon Ross * node's list of ofiles. An ofile in this state is a 30894047d49SGordon Ross * "proposed" open passed to the oplock break code. 30994047d49SGordon Ross * 31094047d49SGordon Ross * If we don't get as far as smb_ofile_open with this OF, 31194047d49SGordon Ross * call smb_ofile_free() to free this object. 3128d94f651SGordon Ross * 3138d94f651SGordon Ross * Note: The following sr members may be null during 3148d94f651SGordon Ross * persistent handle import: session, uid_usr, tid_tree 315da6c28aaSamw */ 316da6c28aaSamw smb_ofile_t * 31794047d49SGordon Ross smb_ofile_alloc( 3183b13a1efSThomas Keiser smb_request_t *sr, 31994047d49SGordon Ross smb_arg_open_t *op, 32094047d49SGordon Ross smb_node_t *node, /* optional (may be NULL) */ 321da6c28aaSamw uint16_t ftype, 3228d94f651SGordon Ross uint16_t tree_fid) 323da6c28aaSamw { 3248d94f651SGordon Ross smb_user_t *user = sr->uid_user; /* optional */ 3258d94f651SGordon Ross smb_tree_t *tree = sr->tid_tree; /* optional */ 326da6c28aaSamw smb_ofile_t *of; 327da6c28aaSamw 3288622ec45SGordon Ross of = kmem_cache_alloc(smb_cache_ofile, KM_SLEEP); 329da6c28aaSamw bzero(of, sizeof (smb_ofile_t)); 330da6c28aaSamw of->f_magic = SMB_OFILE_MAGIC; 331bfe5e737SGordon Ross 332bfe5e737SGordon Ross mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL); 333bfe5e737SGordon Ross list_create(&of->f_notify.nc_waiters, sizeof (smb_request_t), 334bfe5e737SGordon Ross offsetof(smb_request_t, sr_waiters)); 3358d94f651SGordon Ross mutex_init(&of->dh_nvlock, NULL, MUTEX_DEFAULT, NULL); 336bfe5e737SGordon Ross 33794047d49SGordon Ross of->f_state = SMB_OFILE_STATE_ALLOC; 338da6c28aaSamw of->f_refcnt = 1; 339811599a4SMatt Barden of->f_ftype = ftype; 34094047d49SGordon Ross of->f_fid = tree_fid; 341811599a4SMatt Barden /* of->f_persistid see smb2_create */ 3428d94f651SGordon Ross of->f_uniqid = SMB_UNIQ_FID(); 34368b2bbf2SGordon Ross of->f_opened_by_pid = sr->smb_pid; 344c8ec8eeaSjose borrego of->f_granted_access = op->desired_access; 345c8ec8eeaSjose borrego of->f_share_access = op->share_access; 346c8ec8eeaSjose borrego of->f_create_options = op->create_options; 3478d94f651SGordon Ross if (user != NULL) { 3488d94f651SGordon Ross if ((op->create_options & FILE_OPEN_FOR_BACKUP_INTENT) != 0) 3498d94f651SGordon Ross of->f_cr = smb_user_getprivcred(user); 3508d94f651SGordon Ross else 3518d94f651SGordon Ross of->f_cr = user->u_cred; 352da6c28aaSamw crhold(of->f_cr); 3538d94f651SGordon Ross } 3548d94f651SGordon Ross of->f_server = sr->sr_server; 3558d94f651SGordon Ross of->f_session = sr->session; /* may be NULL */ 3568d94f651SGordon Ross 3576f58980aSGordon Ross (void) memset(of->f_lock_seq, -1, SMB_OFILE_LSEQ_MAX); 358bfe5e737SGordon Ross 35994047d49SGordon Ross of->f_mode = smb_fsop_amask_to_omode(of->f_granted_access); 36094047d49SGordon Ross if ((of->f_granted_access & FILE_DATA_ALL) == FILE_EXECUTE) 36194047d49SGordon Ross of->f_flags |= SMB_OFLAGS_EXECONLY; 36294047d49SGordon Ross 36394047d49SGordon Ross /* 36494047d49SGordon Ross * In case a lease is requested, copy the lease keys now so 36594047d49SGordon Ross * any oplock breaks during open don't break those on our 36694047d49SGordon Ross * other handles that might have the same lease. 36794047d49SGordon Ross */ 36894047d49SGordon Ross bcopy(op->lease_key, of->TargetOplockKey, SMB_LEASE_KEY_SZ); 36994047d49SGordon Ross bcopy(op->parent_lease_key, of->ParentOplockKey, SMB_LEASE_KEY_SZ); 37094047d49SGordon Ross 3713b13a1efSThomas Keiser /* 372811599a4SMatt Barden * grab a ref for of->f_user and of->f_tree 37394047d49SGordon Ross * We know the user and tree must be "live" because 37494047d49SGordon Ross * this SR holds references to them. The node ref. is 37594047d49SGordon Ross * held by our caller, until smb_ofile_open puts this 37694047d49SGordon Ross * ofile on the node ofile list with smb_node_add_ofile. 3773b13a1efSThomas Keiser */ 3788d94f651SGordon Ross if (user != NULL) { 3798d94f651SGordon Ross smb_user_hold_internal(user); 3808d94f651SGordon Ross of->f_user = user; 3818d94f651SGordon Ross } 3828d94f651SGordon Ross if (tree != NULL) { 383811599a4SMatt Barden smb_tree_hold_internal(tree); 384da6c28aaSamw of->f_tree = tree; 3858d94f651SGordon Ross } 3868d94f651SGordon Ross of->f_node = node; /* may be NULL */ 3875fd03bc0SGordon Ross 38894047d49SGordon Ross return (of); 38994047d49SGordon Ross } 39094047d49SGordon Ross 39194047d49SGordon Ross /* 39294047d49SGordon Ross * smb_ofile_open 39394047d49SGordon Ross * 39494047d49SGordon Ross * Complete an open on an ofile that was previously allocated by 39594047d49SGordon Ross * smb_ofile_alloc, by putting it on the tree ofile list and 39694047d49SGordon Ross * (if it's a file) the node ofile list. 39794047d49SGordon Ross */ 39894047d49SGordon Ross void 39994047d49SGordon Ross smb_ofile_open( 40094047d49SGordon Ross smb_request_t *sr, 40194047d49SGordon Ross smb_arg_open_t *op, 40294047d49SGordon Ross smb_ofile_t *of) 40394047d49SGordon Ross { 40494047d49SGordon Ross smb_tree_t *tree = sr->tid_tree; 40594047d49SGordon Ross smb_node_t *node = of->f_node; 40694047d49SGordon Ross 40794047d49SGordon Ross ASSERT(of->f_state == SMB_OFILE_STATE_ALLOC); 408088ae41eSGordon Ross ASSERT(of->f_fid != 0); 409088ae41eSGordon Ross 41094047d49SGordon Ross of->f_state = SMB_OFILE_STATE_OPEN; 41194047d49SGordon Ross 41294047d49SGordon Ross switch (of->f_ftype) { 41394047d49SGordon Ross case SMB_FTYPE_BYTE_PIPE: 41494047d49SGordon Ross case SMB_FTYPE_MESG_PIPE: 41568b2bbf2SGordon Ross /* See smb_opipe_open. */ 41668b2bbf2SGordon Ross of->f_pipe = op->pipe; 417148c5f43SAlan Wright smb_server_inc_pipes(of->f_server); 41894047d49SGordon Ross break; 41994047d49SGordon Ross case SMB_FTYPE_DISK: 42094047d49SGordon Ross case SMB_FTYPE_PRINTER: 42194047d49SGordon Ross /* Regular file, not a pipe */ 42294047d49SGordon Ross ASSERT(node != NULL); 4238c10a865Sas200622 4242c2961f8Sjose borrego smb_node_inc_open_ofiles(node); 425fc724630SAlan Wright smb_node_add_ofile(node, of); 4268b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_ref(node); 427148c5f43SAlan Wright smb_server_inc_files(of->f_server); 42894047d49SGordon Ross break; 42994047d49SGordon Ross default: 43094047d49SGordon Ross ASSERT(0); 431da6c28aaSamw } 432da6c28aaSamw smb_llist_enter(&tree->t_ofile_list, RW_WRITER); 433da6c28aaSamw smb_llist_insert_tail(&tree->t_ofile_list, of); 434da6c28aaSamw smb_llist_exit(&tree->t_ofile_list); 4351fcced4cSJordan Brown atomic_inc_32(&tree->t_open_files); 436da6c28aaSamw atomic_inc_32(&of->f_session->s_file_cnt); 4373b13a1efSThomas Keiser 438da6c28aaSamw } 439da6c28aaSamw 440da6c28aaSamw /* 441da6c28aaSamw * smb_ofile_close 442811599a4SMatt Barden * 443811599a4SMatt Barden * Incoming states: (where from) 444811599a4SMatt Barden * SMB_OFILE_STATE_OPEN protocol close, smb_ofile_drop 445811599a4SMatt Barden * SMB_OFILE_STATE_EXPIRED called via smb2_dh_expire 446811599a4SMatt Barden * SMB_OFILE_STATE_ORPHANED smb2_dh_shutdown 447da6c28aaSamw */ 448c8ec8eeaSjose borrego void 4495fd03bc0SGordon Ross smb_ofile_close(smb_ofile_t *of, int32_t mtime_sec) 450da6c28aaSamw { 451a90cf9f2SGordon Ross smb_attr_t *pa; 452da6c28aaSamw 4535fd03bc0SGordon Ross SMB_OFILE_VALID(of); 4545fd03bc0SGordon Ross 4551f0845f1SGordon Ross if (of->f_ftype == SMB_FTYPE_DISK) { 4561f0845f1SGordon Ross smb_node_t *node = of->f_node; 4571f0845f1SGordon Ross 4581f0845f1SGordon Ross smb_llist_enter(&node->n_ofile_list, RW_READER); 4591f0845f1SGordon Ross mutex_enter(&node->n_oplock.ol_mutex); 4601f0845f1SGordon Ross 4616f8336c5SGordon Ross if (of->f_oplock_closing == B_FALSE) { 4626f8336c5SGordon Ross of->f_oplock_closing = B_TRUE; 4636f8336c5SGordon Ross 4641f0845f1SGordon Ross if (of->f_lease != NULL) 4651f0845f1SGordon Ross smb2_lease_ofile_close(of); 4661f0845f1SGordon Ross smb_oplock_break_CLOSE(node, of); 4676f8336c5SGordon Ross } 4681f0845f1SGordon Ross 4691f0845f1SGordon Ross mutex_exit(&node->n_oplock.ol_mutex); 4701f0845f1SGordon Ross smb_llist_exit(&node->n_ofile_list); 4711f0845f1SGordon Ross } 4721f0845f1SGordon Ross 473da6c28aaSamw mutex_enter(&of->f_mutex); 474da6c28aaSamw ASSERT(of->f_refcnt); 475811599a4SMatt Barden 476811599a4SMatt Barden switch (of->f_state) { 477811599a4SMatt Barden case SMB_OFILE_STATE_OPEN: 478811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 479811599a4SMatt Barden case SMB_OFILE_STATE_EXPIRED: 480811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_CLOSING; 481811599a4SMatt Barden mutex_exit(&of->f_mutex); 482811599a4SMatt Barden break; 483811599a4SMatt Barden default: 48468b2bbf2SGordon Ross mutex_exit(&of->f_mutex); 48568b2bbf2SGordon Ross return; 48668b2bbf2SGordon Ross } 487da6c28aaSamw 4888d94f651SGordon Ross /* 4898d94f651SGordon Ross * Only one thread here (the one that that set f_state closing) 4908d94f651SGordon Ross */ 491a90cf9f2SGordon Ross switch (of->f_ftype) { 492a90cf9f2SGordon Ross case SMB_FTYPE_BYTE_PIPE: 493a90cf9f2SGordon Ross case SMB_FTYPE_MESG_PIPE: 4943db3f65cSamw smb_opipe_close(of); 495148c5f43SAlan Wright smb_server_dec_pipes(of->f_server); 496a90cf9f2SGordon Ross break; 4975fd03bc0SGordon Ross 498a90cf9f2SGordon Ross case SMB_FTYPE_DISK: 4998d94f651SGordon Ross if (of->dh_persist) 5008d94f651SGordon Ross smb2_dh_close_persistent(of); 501811599a4SMatt Barden if (of->f_persistid != 0) 502811599a4SMatt Barden smb_ofile_del_persistid(of); 503811599a4SMatt Barden /* FALLTHROUGH */ 50494047d49SGordon Ross 505811599a4SMatt Barden case SMB_FTYPE_PRINTER: /* or FTYPE_DISK */ 5065fd03bc0SGordon Ross /* 5075fd03bc0SGordon Ross * In here we make changes to of->f_pending_attr 5085fd03bc0SGordon Ross * while not holding of->f_mutex. This is OK 5095fd03bc0SGordon Ross * because we've changed f_state to CLOSING, 5105fd03bc0SGordon Ross * so no more threads will take this path. 5115fd03bc0SGordon Ross */ 512a90cf9f2SGordon Ross pa = &of->f_pending_attr; 5135fd03bc0SGordon Ross if (mtime_sec != 0) { 5145fd03bc0SGordon Ross pa->sa_vattr.va_mtime.tv_sec = mtime_sec; 5155fd03bc0SGordon Ross pa->sa_mask |= SMB_AT_MTIME; 5165fd03bc0SGordon Ross } 5175fd03bc0SGordon Ross 5188b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE) { 519811599a4SMatt Barden /* We delete using the on-disk name. */ 520811599a4SMatt Barden uint32_t flags = SMB_CASE_SENSITIVE; 5218b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States (void) smb_node_set_delete_on_close(of->f_node, 5228b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States of->f_cr, flags); 5238b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 524dc20a302Sas200622 smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid); 5256537f381Sas200622 smb_node_destroy_lock_by_ofile(of->f_node, of); 526dc20a302Sas200622 5275fd03bc0SGordon Ross if (smb_node_is_file(of->f_node)) { 5288c10a865Sas200622 (void) smb_fsop_close(of->f_node, of->f_mode, 5298c10a865Sas200622 of->f_cr); 530a90cf9f2SGordon Ross } else { 531a90cf9f2SGordon Ross /* 532a90cf9f2SGordon Ross * If there was an odir, close it. 533a90cf9f2SGordon Ross */ 534a90cf9f2SGordon Ross if (of->f_odir != NULL) 535a90cf9f2SGordon Ross smb_odir_close(of->f_odir); 536bfe5e737SGordon Ross /* 537bfe5e737SGordon Ross * Cancel any notify change requests that 538bfe5e737SGordon Ross * might be watching this open file (dir), 539bfe5e737SGordon Ross * and unsubscribe it from node events. 540bfe5e737SGordon Ross * 541bfe5e737SGordon Ross * Can't hold f_mutex when calling smb_notify_ofile. 542bfe5e737SGordon Ross * Don't really need it when unsubscribing, but 543bfe5e737SGordon Ross * harmless, and consistent with subscribing. 544bfe5e737SGordon Ross */ 545bfe5e737SGordon Ross if (of->f_notify.nc_subscribed) 546bfe5e737SGordon Ross smb_notify_ofile(of, 547bfe5e737SGordon Ross FILE_ACTION_HANDLE_CLOSED, NULL); 548bfe5e737SGordon Ross mutex_enter(&of->f_mutex); 549bfe5e737SGordon Ross if (of->f_notify.nc_subscribed) { 550bfe5e737SGordon Ross of->f_notify.nc_subscribed = B_FALSE; 551bfe5e737SGordon Ross smb_node_fcn_unsubscribe(of->f_node); 552bfe5e737SGordon Ross of->f_notify.nc_filter = 0; 553bfe5e737SGordon Ross } 554bfe5e737SGordon Ross mutex_exit(&of->f_mutex); 5555fd03bc0SGordon Ross } 5565fd03bc0SGordon Ross if (smb_node_dec_open_ofiles(of->f_node) == 0) { 5575fd03bc0SGordon Ross /* 5585cb2894aSGordon Ross * Last close. If we're not deleting 5595cb2894aSGordon Ross * the file, apply any pending attrs. 5605cb2894aSGordon Ross * Leave allocsz zero when no open files, 5615cb2894aSGordon Ross * just to avoid confusion, because it's 5625cb2894aSGordon Ross * only updated when there are opens. 56394047d49SGordon Ross * XXX: Just do this on _every_ close. 5645fd03bc0SGordon Ross */ 56549d83597SMatt Barden mutex_enter(&of->f_node->n_mutex); 56649d83597SMatt Barden if (of->f_node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 56749d83597SMatt Barden smb_node_delete_on_close(of->f_node); 56849d83597SMatt Barden pa->sa_mask = 0; 56949d83597SMatt Barden } 5705cb2894aSGordon Ross of->f_node->n_allocsz = 0; 57149d83597SMatt Barden mutex_exit(&of->f_node->n_mutex); 5725fd03bc0SGordon Ross } 5735fd03bc0SGordon Ross if (pa->sa_mask != 0) { 5745fd03bc0SGordon Ross /* 5755fd03bc0SGordon Ross * Commit any pending attributes from 5765fd03bc0SGordon Ross * the ofile we're closing. Note that 5775fd03bc0SGordon Ross * we pass NULL as the ofile to setattr 5785fd03bc0SGordon Ross * so it will write to the file system 5795fd03bc0SGordon Ross * and not keep anything on the ofile. 5805fd03bc0SGordon Ross */ 5815fd03bc0SGordon Ross (void) smb_node_setattr(NULL, of->f_node, 5825fd03bc0SGordon Ross of->f_cr, NULL, pa); 5835fd03bc0SGordon Ross } 584*f8e30ca2SGordon Ross /* 585*f8e30ca2SGordon Ross * Don't want the performance cost of generating 586*f8e30ca2SGordon Ross * change notify events on every write. Instead: 587*f8e30ca2SGordon Ross * Keep track of the fact that we have written 588*f8e30ca2SGordon Ross * data via this handle, and do change notify 589*f8e30ca2SGordon Ross * work on the first write, and during close. 590*f8e30ca2SGordon Ross */ 591*f8e30ca2SGordon Ross if (of->f_written) { 592*f8e30ca2SGordon Ross smb_node_notify_modified(of->f_node); 593*f8e30ca2SGordon Ross } 594dc20a302Sas200622 595148c5f43SAlan Wright smb_server_dec_files(of->f_server); 596a90cf9f2SGordon Ross break; 597da6c28aaSamw } 598811599a4SMatt Barden 599811599a4SMatt Barden /* 600811599a4SMatt Barden * Keep f_state == SMB_OFILE_STATE_CLOSING 601811599a4SMatt Barden * until the last ref. is dropped, in 602811599a4SMatt Barden * smb_ofile_release() 603811599a4SMatt Barden */ 604811599a4SMatt Barden } 605811599a4SMatt Barden 606811599a4SMatt Barden /* 607811599a4SMatt Barden * "Destructor" function for smb_ofile_close_all, and 608811599a4SMatt Barden * smb_ofile_close_all_by_pid, called after the llist lock 609811599a4SMatt Barden * for tree list has been exited. Our job is to either 610811599a4SMatt Barden * close this ofile, or (if durable) set state _SAVE_DH. 611811599a4SMatt Barden * 612811599a4SMatt Barden * The next interesting thing happens when the last ref. 613811599a4SMatt Barden * on this ofile calls smb_ofile_release(), where we 614811599a4SMatt Barden * eihter delete the ofile, or (if durable) leave it 615811599a4SMatt Barden * in the persistid hash table for possible reclaim. 616811599a4SMatt Barden * 617811599a4SMatt Barden * This is run via smb_llist_post (after smb_llist_exit) 618811599a4SMatt Barden * because smb_ofile_close can block, and we'd rather not 619811599a4SMatt Barden * block while holding the ofile list as reader. 620811599a4SMatt Barden */ 621811599a4SMatt Barden static void 622811599a4SMatt Barden smb_ofile_drop(void *arg) 623811599a4SMatt Barden { 624811599a4SMatt Barden smb_ofile_t *of = arg; 625811599a4SMatt Barden 626811599a4SMatt Barden SMB_OFILE_VALID(of); 627da6c28aaSamw 628da6c28aaSamw mutex_enter(&of->f_mutex); 629811599a4SMatt Barden switch (of->f_state) { 630811599a4SMatt Barden case SMB_OFILE_STATE_OPEN: 631811599a4SMatt Barden /* DH checks under mutex. */ 632811599a4SMatt Barden if (of->f_ftype == SMB_FTYPE_DISK && 633811599a4SMatt Barden of->dh_vers != SMB2_NOT_DURABLE && 634811599a4SMatt Barden smb_dh_should_save(of)) { 635811599a4SMatt Barden /* 636811599a4SMatt Barden * Tell smb_ofile_release() to 637811599a4SMatt Barden * make this an _ORPHANED DH. 638811599a4SMatt Barden */ 639811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_SAVE_DH; 640da6c28aaSamw mutex_exit(&of->f_mutex); 641811599a4SMatt Barden break; 642811599a4SMatt Barden } 643811599a4SMatt Barden /* OK close it. */ 644811599a4SMatt Barden mutex_exit(&of->f_mutex); 645811599a4SMatt Barden smb_ofile_close(of, 0); 646811599a4SMatt Barden break; 647811599a4SMatt Barden 648811599a4SMatt Barden default: 649811599a4SMatt Barden /* Something else closed it already. */ 650811599a4SMatt Barden mutex_exit(&of->f_mutex); 651811599a4SMatt Barden break; 652811599a4SMatt Barden } 653811599a4SMatt Barden 654811599a4SMatt Barden /* 655811599a4SMatt Barden * Release the ref acquired during the traversal loop. 656811599a4SMatt Barden * Note that on the last ref, this ofile will be 657811599a4SMatt Barden * removed from the tree list etc. 658811599a4SMatt Barden * See: smb_llist_post, smb_ofile_delete 659811599a4SMatt Barden */ 660811599a4SMatt Barden smb_ofile_release(of); 661da6c28aaSamw } 662da6c28aaSamw 663da6c28aaSamw /* 664da6c28aaSamw * smb_ofile_close_all 665da6c28aaSamw * 666da6c28aaSamw * 667da6c28aaSamw */ 668da6c28aaSamw void 669da6c28aaSamw smb_ofile_close_all( 670811599a4SMatt Barden smb_tree_t *tree, 671811599a4SMatt Barden uint32_t pid) 672da6c28aaSamw { 673da6c28aaSamw smb_ofile_t *of; 674811599a4SMatt Barden smb_llist_t *ll; 675da6c28aaSamw 676da6c28aaSamw ASSERT(tree); 677da6c28aaSamw ASSERT(tree->t_magic == SMB_TREE_MAGIC); 678da6c28aaSamw 679811599a4SMatt Barden ll = &tree->t_ofile_list; 680811599a4SMatt Barden 681811599a4SMatt Barden smb_llist_enter(ll, RW_READER); 682811599a4SMatt Barden for (of = smb_llist_head(ll); 683811599a4SMatt Barden of != NULL; 684811599a4SMatt Barden of = smb_llist_next(ll, of)) { 685da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 686da6c28aaSamw ASSERT(of->f_tree == tree); 687811599a4SMatt Barden if (pid != 0 && of->f_opened_by_pid != pid) 688811599a4SMatt Barden continue; 689811599a4SMatt Barden if (smb_ofile_hold(of)) { 690811599a4SMatt Barden smb_llist_post(ll, of, smb_ofile_drop); 691da6c28aaSamw } 692da6c28aaSamw } 693da6c28aaSamw 694da6c28aaSamw /* 695811599a4SMatt Barden * Drop the lock and process the llist dtor queue. 696811599a4SMatt Barden * Calls smb_ofile_drop on ofiles that were open. 697da6c28aaSamw */ 698811599a4SMatt Barden smb_llist_exit(ll); 699da6c28aaSamw } 700da6c28aaSamw 701da6c28aaSamw /* 7021fcced4cSJordan Brown * If the enumeration request is for ofile data, handle it here. 7031fcced4cSJordan Brown * Otherwise, return. 7041fcced4cSJordan Brown * 7051fcced4cSJordan Brown * This function should be called with a hold on the ofile. 7061fcced4cSJordan Brown */ 7071fcced4cSJordan Brown int 7081fcced4cSJordan Brown smb_ofile_enum(smb_ofile_t *of, smb_svcenum_t *svcenum) 7091fcced4cSJordan Brown { 7101fcced4cSJordan Brown uint8_t *pb; 7111fcced4cSJordan Brown uint_t nbytes; 7121fcced4cSJordan Brown int rc; 7131fcced4cSJordan Brown 7141fcced4cSJordan Brown ASSERT(of); 7151fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 7161fcced4cSJordan Brown ASSERT(of->f_refcnt); 7171fcced4cSJordan Brown 7181fcced4cSJordan Brown if (svcenum->se_type != SMB_SVCENUM_TYPE_FILE) 7191fcced4cSJordan Brown return (0); 7201fcced4cSJordan Brown 7211fcced4cSJordan Brown if (svcenum->se_nskip > 0) { 7221fcced4cSJordan Brown svcenum->se_nskip--; 7231fcced4cSJordan Brown return (0); 7241fcced4cSJordan Brown } 7251fcced4cSJordan Brown 7261fcced4cSJordan Brown if (svcenum->se_nitems >= svcenum->se_nlimit) { 7271fcced4cSJordan Brown svcenum->se_nitems = svcenum->se_nlimit; 7281fcced4cSJordan Brown return (0); 7291fcced4cSJordan Brown } 7301fcced4cSJordan Brown 7311fcced4cSJordan Brown pb = &svcenum->se_buf[svcenum->se_bused]; 7321fcced4cSJordan Brown 7331fcced4cSJordan Brown rc = smb_ofile_netinfo_encode(of, pb, svcenum->se_bavail, 7341fcced4cSJordan Brown &nbytes); 7351fcced4cSJordan Brown if (rc == 0) { 7361fcced4cSJordan Brown svcenum->se_bavail -= nbytes; 7371fcced4cSJordan Brown svcenum->se_bused += nbytes; 7381fcced4cSJordan Brown svcenum->se_nitems++; 7391fcced4cSJordan Brown } 7401fcced4cSJordan Brown 7411fcced4cSJordan Brown return (rc); 7421fcced4cSJordan Brown } 7431fcced4cSJordan Brown 7441fcced4cSJordan Brown /* 745811599a4SMatt Barden * Take a reference on an open file, in any of the states: 746811599a4SMatt Barden * RECONNECT, SAVE_DH, OPEN, ORPHANED. 747811599a4SMatt Barden * Return TRUE if ref taken. Used for oplock breaks. 748811599a4SMatt Barden * 749811599a4SMatt Barden * Note: When the oplock break code calls this, it holds the 750811599a4SMatt Barden * node ofile list lock and node oplock mutex. When we see 751811599a4SMatt Barden * an ofile in states RECONNECT or SAVING, we know the ofile 752811599a4SMatt Barden * is gaining or losing it's tree, and that happens quickly, 753811599a4SMatt Barden * so we just wait for that work to finish. However, the 754811599a4SMatt Barden * waiting for state transitions here means we have to be 755811599a4SMatt Barden * careful not to re-enter the node list lock or otherwise 756811599a4SMatt Barden * block on things that could cause a deadlock. Waiting 757811599a4SMatt Barden * just on of->f_mutex here is OK. 758811599a4SMatt Barden */ 759811599a4SMatt Barden boolean_t 760811599a4SMatt Barden smb_ofile_hold_olbrk(smb_ofile_t *of) 761811599a4SMatt Barden { 762811599a4SMatt Barden boolean_t ret = B_FALSE; 763811599a4SMatt Barden 764811599a4SMatt Barden ASSERT(of); 765811599a4SMatt Barden ASSERT(of->f_magic == SMB_OFILE_MAGIC); 766811599a4SMatt Barden 767811599a4SMatt Barden mutex_enter(&of->f_mutex); 768811599a4SMatt Barden 769811599a4SMatt Barden again: 770811599a4SMatt Barden switch (of->f_state) { 771811599a4SMatt Barden case SMB_OFILE_STATE_RECONNECT: 772811599a4SMatt Barden case SMB_OFILE_STATE_SAVING: 773811599a4SMatt Barden cv_wait(&of->f_cv, &of->f_mutex); 774811599a4SMatt Barden goto again; 775811599a4SMatt Barden 776811599a4SMatt Barden case SMB_OFILE_STATE_OPEN: 777811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 778811599a4SMatt Barden case SMB_OFILE_STATE_SAVE_DH: 779811599a4SMatt Barden of->f_refcnt++; 780811599a4SMatt Barden ret = B_TRUE; 781811599a4SMatt Barden break; 782811599a4SMatt Barden 783811599a4SMatt Barden default: 784811599a4SMatt Barden break; 785811599a4SMatt Barden } 786811599a4SMatt Barden mutex_exit(&of->f_mutex); 787811599a4SMatt Barden 788811599a4SMatt Barden return (ret); 789811599a4SMatt Barden } 790811599a4SMatt Barden 791811599a4SMatt Barden /* 7921fcced4cSJordan Brown * Take a reference on an open file. 7931fcced4cSJordan Brown */ 7941fcced4cSJordan Brown boolean_t 7951fcced4cSJordan Brown smb_ofile_hold(smb_ofile_t *of) 7961fcced4cSJordan Brown { 7971fcced4cSJordan Brown ASSERT(of); 7981fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 7991fcced4cSJordan Brown 8001fcced4cSJordan Brown mutex_enter(&of->f_mutex); 8011fcced4cSJordan Brown 80268b2bbf2SGordon Ross if (of->f_state != SMB_OFILE_STATE_OPEN) { 8031fcced4cSJordan Brown mutex_exit(&of->f_mutex); 8041fcced4cSJordan Brown return (B_FALSE); 8051fcced4cSJordan Brown } 80668b2bbf2SGordon Ross of->f_refcnt++; 80768b2bbf2SGordon Ross 80868b2bbf2SGordon Ross mutex_exit(&of->f_mutex); 80968b2bbf2SGordon Ross return (B_TRUE); 81068b2bbf2SGordon Ross } 8111fcced4cSJordan Brown 8121fcced4cSJordan Brown /* 813525641e8SGordon Ross * Void arg variant of smb_ofile_release for use with smb_llist_post. 814525641e8SGordon Ross * This is needed because smb_ofile_release may need to enter the 815525641e8SGordon Ross * smb_llist as writer when it drops the last reference, so when 816525641e8SGordon Ross * we're in the llist as reader, use smb_llist_post with this 817525641e8SGordon Ross * function to arrange for the release call at llist_exit. 818525641e8SGordon Ross */ 819525641e8SGordon Ross void 820525641e8SGordon Ross smb_ofile_release_LL(void *arg) 821525641e8SGordon Ross { 822525641e8SGordon Ross smb_ofile_t *of = arg; 823525641e8SGordon Ross 824525641e8SGordon Ross SMB_OFILE_VALID(of); 825525641e8SGordon Ross smb_ofile_release(of); 826525641e8SGordon Ross } 827525641e8SGordon Ross 828525641e8SGordon Ross /* 8299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Release a reference on a file. If the reference count falls to 8309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * zero and the file has been closed, post the object for deletion. 8319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Object deletion is deferred to avoid modifying a list while an 8329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * iteration may be in progress. 833811599a4SMatt Barden * 834811599a4SMatt Barden * We're careful to avoid dropping f_session etc. until the last 835811599a4SMatt Barden * reference goes away. The oplock break code depends on that 836811599a4SMatt Barden * not changing while it holds a ref. on an ofile. 837da6c28aaSamw */ 838da6c28aaSamw void 83924d2db37Sjose borrego smb_ofile_release(smb_ofile_t *of) 840da6c28aaSamw { 841811599a4SMatt Barden smb_tree_t *tree = of->f_tree; 842811599a4SMatt Barden boolean_t delete = B_FALSE; 843811599a4SMatt Barden 8449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OFILE_VALID(of); 845da6c28aaSamw 846da6c28aaSamw mutex_enter(&of->f_mutex); 847811599a4SMatt Barden ASSERT(of->f_refcnt > 0); 848da6c28aaSamw of->f_refcnt--; 849811599a4SMatt Barden 850da6c28aaSamw switch (of->f_state) { 851da6c28aaSamw case SMB_OFILE_STATE_OPEN: 852811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 853811599a4SMatt Barden case SMB_OFILE_STATE_EXPIRED: 854da6c28aaSamw break; 855da6c28aaSamw 856811599a4SMatt Barden case SMB_OFILE_STATE_SAVE_DH: 857811599a4SMatt Barden ASSERT(tree != NULL); 858811599a4SMatt Barden if (of->f_refcnt == 0) { 859811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_SAVING; 860811599a4SMatt Barden smb_llist_post(&tree->t_ofile_list, of, 861811599a4SMatt Barden smb_ofile_save_dh); 862811599a4SMatt Barden } 863811599a4SMatt Barden break; 864811599a4SMatt Barden 865811599a4SMatt Barden case SMB_OFILE_STATE_CLOSING: 866811599a4SMatt Barden /* Note, tree == NULL on _ORPHANED */ 867811599a4SMatt Barden if (of->f_refcnt == 0) { 868811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_CLOSED; 869811599a4SMatt Barden if (tree == NULL) { 870811599a4SMatt Barden /* Skip smb_llist_post */ 871811599a4SMatt Barden delete = B_TRUE; 872811599a4SMatt Barden break; 873811599a4SMatt Barden } 874811599a4SMatt Barden smb_llist_post(&tree->t_ofile_list, of, 875811599a4SMatt Barden smb_ofile_delete); 876811599a4SMatt Barden } 877da6c28aaSamw break; 878da6c28aaSamw 879da6c28aaSamw default: 880da6c28aaSamw ASSERT(0); 881da6c28aaSamw break; 882da6c28aaSamw } 883da6c28aaSamw mutex_exit(&of->f_mutex); 884811599a4SMatt Barden 885811599a4SMatt Barden /* 886811599a4SMatt Barden * When we drop the last ref. on an expired DH, it's no longer 887811599a4SMatt Barden * in any tree, so skip the smb_llist_post and just call 888811599a4SMatt Barden * smb_ofile_delete directly. 889811599a4SMatt Barden */ 890811599a4SMatt Barden if (delete) { 891811599a4SMatt Barden smb_ofile_delete(of); 892811599a4SMatt Barden } 893da6c28aaSamw } 894da6c28aaSamw 895da6c28aaSamw /* 896da6c28aaSamw * smb_ofile_lookup_by_fid 897da6c28aaSamw * 898da6c28aaSamw * Find the open file whose fid matches the one specified in the request. 899da6c28aaSamw * If we can't find the fid or the shares (trees) don't match, we have a 900da6c28aaSamw * bad fid. 901da6c28aaSamw */ 902da6c28aaSamw smb_ofile_t * 903da6c28aaSamw smb_ofile_lookup_by_fid( 9043b13a1efSThomas Keiser smb_request_t *sr, 905da6c28aaSamw uint16_t fid) 906da6c28aaSamw { 9073b13a1efSThomas Keiser smb_tree_t *tree = sr->tid_tree; 908da6c28aaSamw smb_llist_t *of_list; 909da6c28aaSamw smb_ofile_t *of; 910da6c28aaSamw 911da6c28aaSamw ASSERT(tree->t_magic == SMB_TREE_MAGIC); 912da6c28aaSamw 913da6c28aaSamw of_list = &tree->t_ofile_list; 914da6c28aaSamw 915da6c28aaSamw smb_llist_enter(of_list, RW_READER); 916da6c28aaSamw of = smb_llist_head(of_list); 917da6c28aaSamw while (of) { 918da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 919da6c28aaSamw ASSERT(of->f_tree == tree); 9203b13a1efSThomas Keiser if (of->f_fid == fid) 9213b13a1efSThomas Keiser break; 9223b13a1efSThomas Keiser of = smb_llist_next(of_list, of); 9233b13a1efSThomas Keiser } 9243b13a1efSThomas Keiser if (of == NULL) 9253b13a1efSThomas Keiser goto out; 9263b13a1efSThomas Keiser 9273b13a1efSThomas Keiser /* 9283b13a1efSThomas Keiser * Only allow use of a given FID with the same UID that 9293b13a1efSThomas Keiser * was used to open it. MS-CIFS 3.3.5.14 9303b13a1efSThomas Keiser */ 9313b13a1efSThomas Keiser if (of->f_user != sr->uid_user) { 9323b13a1efSThomas Keiser of = NULL; 9333b13a1efSThomas Keiser goto out; 9343b13a1efSThomas Keiser } 9353b13a1efSThomas Keiser 936811599a4SMatt Barden /* inline smb_ofile_hold() */ 937da6c28aaSamw mutex_enter(&of->f_mutex); 938da6c28aaSamw if (of->f_state != SMB_OFILE_STATE_OPEN) { 939da6c28aaSamw mutex_exit(&of->f_mutex); 9403b13a1efSThomas Keiser of = NULL; 9413b13a1efSThomas Keiser goto out; 942da6c28aaSamw } 943da6c28aaSamw of->f_refcnt++; 944da6c28aaSamw mutex_exit(&of->f_mutex); 9453b13a1efSThomas Keiser 9463b13a1efSThomas Keiser out: 947da6c28aaSamw smb_llist_exit(of_list); 948da6c28aaSamw return (of); 949da6c28aaSamw } 950da6c28aaSamw 951da6c28aaSamw /* 9521fcced4cSJordan Brown * smb_ofile_lookup_by_uniqid 9531fcced4cSJordan Brown * 9541fcced4cSJordan Brown * Find the open file whose uniqid matches the one specified in the request. 9551fcced4cSJordan Brown */ 9561fcced4cSJordan Brown smb_ofile_t * 9571fcced4cSJordan Brown smb_ofile_lookup_by_uniqid(smb_tree_t *tree, uint32_t uniqid) 9581fcced4cSJordan Brown { 9591fcced4cSJordan Brown smb_llist_t *of_list; 9601fcced4cSJordan Brown smb_ofile_t *of; 9611fcced4cSJordan Brown 9621fcced4cSJordan Brown ASSERT(tree->t_magic == SMB_TREE_MAGIC); 9631fcced4cSJordan Brown 9641fcced4cSJordan Brown of_list = &tree->t_ofile_list; 9651fcced4cSJordan Brown smb_llist_enter(of_list, RW_READER); 9661fcced4cSJordan Brown of = smb_llist_head(of_list); 9671fcced4cSJordan Brown 9681fcced4cSJordan Brown while (of) { 9691fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 9701fcced4cSJordan Brown ASSERT(of->f_tree == tree); 9711fcced4cSJordan Brown 9721fcced4cSJordan Brown if (of->f_uniqid == uniqid) { 9731fcced4cSJordan Brown if (smb_ofile_hold(of)) { 9741fcced4cSJordan Brown smb_llist_exit(of_list); 9751fcced4cSJordan Brown return (of); 9761fcced4cSJordan Brown } 9771fcced4cSJordan Brown } 9781fcced4cSJordan Brown 9791fcced4cSJordan Brown of = smb_llist_next(of_list, of); 9801fcced4cSJordan Brown } 9811fcced4cSJordan Brown 9821fcced4cSJordan Brown smb_llist_exit(of_list); 9831fcced4cSJordan Brown return (NULL); 9841fcced4cSJordan Brown } 9851fcced4cSJordan Brown 986817fa55fSGordon Ross /* 987817fa55fSGordon Ross * Durable ID (or persistent ID) 988817fa55fSGordon Ross */ 989817fa55fSGordon Ross 990811599a4SMatt Barden static smb_ofile_t * 991811599a4SMatt Barden smb_ofile_hold_cb(smb_ofile_t *of) 992811599a4SMatt Barden { 993811599a4SMatt Barden smb_ofile_t *ret = of; 994811599a4SMatt Barden 995811599a4SMatt Barden mutex_enter(&of->f_mutex); 996811599a4SMatt Barden if (of->f_state == SMB_OFILE_STATE_ORPHANED) 997811599a4SMatt Barden /* inline smb_ofile_hold() */ 998811599a4SMatt Barden of->f_refcnt++; 999811599a4SMatt Barden else 1000811599a4SMatt Barden ret = NULL; 1001811599a4SMatt Barden 1002811599a4SMatt Barden mutex_exit(&of->f_mutex); 1003811599a4SMatt Barden return (ret); 1004811599a4SMatt Barden } 1005811599a4SMatt Barden 1006811599a4SMatt Barden /* 1007811599a4SMatt Barden * Lookup an ofile by persistent ID, and return ONLY if in state ORPHANED 1008811599a4SMatt Barden * This is used by SMB2 create "reclaim". 1009811599a4SMatt Barden */ 1010811599a4SMatt Barden smb_ofile_t * 1011811599a4SMatt Barden smb_ofile_lookup_by_persistid(smb_request_t *sr, uint64_t persistid) 1012811599a4SMatt Barden { 1013811599a4SMatt Barden smb_hash_t *hash; 1014811599a4SMatt Barden smb_bucket_t *bucket; 1015811599a4SMatt Barden smb_llist_t *ll; 1016811599a4SMatt Barden smb_ofile_t *of; 1017811599a4SMatt Barden uint_t idx; 1018811599a4SMatt Barden 10198d94f651SGordon Ross if (persistid == 0) 10208d94f651SGordon Ross return (NULL); 10218d94f651SGordon Ross 1022811599a4SMatt Barden hash = sr->sr_server->sv_persistid_ht; 1023811599a4SMatt Barden idx = smb_hash_uint64(hash, persistid); 1024811599a4SMatt Barden bucket = &hash->buckets[idx]; 1025811599a4SMatt Barden ll = &bucket->b_list; 1026811599a4SMatt Barden 1027811599a4SMatt Barden smb_llist_enter(ll, RW_READER); 1028811599a4SMatt Barden of = smb_llist_head(ll); 1029811599a4SMatt Barden while (of != NULL) { 1030811599a4SMatt Barden if (of->f_persistid == persistid) 1031811599a4SMatt Barden break; 1032811599a4SMatt Barden of = smb_llist_next(ll, of); 1033811599a4SMatt Barden } 1034811599a4SMatt Barden if (of != NULL) 1035811599a4SMatt Barden of = smb_ofile_hold_cb(of); 1036811599a4SMatt Barden smb_llist_exit(ll); 1037811599a4SMatt Barden 1038811599a4SMatt Barden return (of); 1039811599a4SMatt Barden } 1040811599a4SMatt Barden 1041811599a4SMatt Barden /* 10428d94f651SGordon Ross * Create a (unique) durable/persistent ID for a new ofile, 10438d94f651SGordon Ross * and add this ofile to the persistid hash table. This ID 10448d94f651SGordon Ross * is referred to as the persistent ID in the protocol spec, 10458d94f651SGordon Ross * so that's what we call it too, though the persistence may 10468d94f651SGordon Ross * vary. "Durable" handles are persistent across reconnects 10478d94f651SGordon Ross * but not server reboots. Persistent handles are persistent 10488d94f651SGordon Ross * across server reboots too. 10498d94f651SGordon Ross * 10508d94f651SGordon Ross * Note that persistent IDs need to be unique for the lifetime of 10518d94f651SGordon Ross * any given ofile. For normal (non-persistent) ofiles we can just 10528d94f651SGordon Ross * use a persistent ID derived from the ofile memory address, as 10538d94f651SGordon Ross * these don't ever live beyond the current OS boot lifetime. 10548d94f651SGordon Ross * 10558d94f651SGordon Ross * Persistent handles are re-imported after server restart, and 10568d94f651SGordon Ross * generally have a different memory address after import than 10578d94f651SGordon Ross * they had in the previous OS boot lifetime, so for these we 10588d94f651SGordon Ross * use a randomly assigned value that won't conflict with any 10598d94f651SGordon Ross * non-persistent (durable) handles. Ensuring that a randomly 10608d94f651SGordon Ross * generated ID is unique requires a search of the ofiles in one 10618d94f651SGordon Ross * hash bucket, which we'd rather avoid for non-persistent opens. 10628d94f651SGordon Ross * 10638d94f651SGordon Ross * The solution used here is to divide the persistent ID space 10648d94f651SGordon Ross * in half (odd and even values) where durable opens use an ID 10658d94f651SGordon Ross * derived from the ofile address (which is always even), and 10668d94f651SGordon Ross * persistent opens use an ID generated randomly (always odd). 10678d94f651SGordon Ross * 10688d94f651SGordon Ross * smb_ofile_set_persistid_dh() sets a durable handle ID and 10698d94f651SGordon Ross * smb_ofile_set_persistid_ph() sets a persistent handle ID. 1070811599a4SMatt Barden */ 1071811599a4SMatt Barden void 10728d94f651SGordon Ross smb_ofile_set_persistid_dh(smb_ofile_t *of) 1073811599a4SMatt Barden { 1074811599a4SMatt Barden smb_hash_t *hash = of->f_server->sv_persistid_ht; 1075811599a4SMatt Barden smb_bucket_t *bucket; 1076811599a4SMatt Barden smb_llist_t *ll; 10778d94f651SGordon Ross uint64_t persistid; 1078811599a4SMatt Barden uint_t idx; 1079811599a4SMatt Barden 10808d94f651SGordon Ross persistid = (uintptr_t)of; 10818d94f651SGordon Ross /* Avoid showing object addresses */ 10828d94f651SGordon Ross persistid ^= ((uintptr_t)&smb_cache_ofile); 10838d94f651SGordon Ross /* make sure it's even */ 10848d94f651SGordon Ross persistid &= ~((uint64_t)1); 1085811599a4SMatt Barden 10868d94f651SGordon Ross idx = smb_hash_uint64(hash, persistid); 1087811599a4SMatt Barden bucket = &hash->buckets[idx]; 1088811599a4SMatt Barden ll = &bucket->b_list; 1089811599a4SMatt Barden smb_llist_enter(ll, RW_WRITER); 10908d94f651SGordon Ross if (of->f_persistid == 0) { 10918d94f651SGordon Ross of->f_persistid = persistid; 1092811599a4SMatt Barden smb_llist_insert_tail(ll, of); 10938d94f651SGordon Ross } 1094811599a4SMatt Barden smb_llist_exit(ll); 1095811599a4SMatt Barden } 1096811599a4SMatt Barden 1097811599a4SMatt Barden void 10988d94f651SGordon Ross smb_ofile_set_persistid_ph(smb_ofile_t *of) 10998d94f651SGordon Ross { 11008d94f651SGordon Ross uint64_t persistid; 11018d94f651SGordon Ross int rc; 11028d94f651SGordon Ross 11038d94f651SGordon Ross top: 11048d94f651SGordon Ross (void) random_get_pseudo_bytes((uint8_t *)&persistid, 11058d94f651SGordon Ross sizeof (persistid)); 11068d94f651SGordon Ross if (persistid == 0) { 11078d94f651SGordon Ross cmn_err(CE_NOTE, "random gave all zeros!"); 11088d94f651SGordon Ross goto top; 11098d94f651SGordon Ross } 11108d94f651SGordon Ross /* make sure it's odd */ 11118d94f651SGordon Ross persistid |= (uint64_t)1; 11128d94f651SGordon Ross 11138d94f651SGordon Ross /* 11148d94f651SGordon Ross * Try inserting with this persistent ID. 11158d94f651SGordon Ross */ 11168d94f651SGordon Ross rc = smb_ofile_insert_persistid(of, persistid); 11178d94f651SGordon Ross if (rc == EEXIST) 11188d94f651SGordon Ross goto top; 11198d94f651SGordon Ross if (rc != 0) { 11208d94f651SGordon Ross cmn_err(CE_NOTE, "set persistid rc=%d", rc); 11218d94f651SGordon Ross } 11228d94f651SGordon Ross } 11238d94f651SGordon Ross 11248d94f651SGordon Ross /* 11258d94f651SGordon Ross * Insert an ofile into the persistid hash table. 11268d94f651SGordon Ross * If the persistent ID is in use, error. 11278d94f651SGordon Ross */ 11288d94f651SGordon Ross int 11298d94f651SGordon Ross smb_ofile_insert_persistid(smb_ofile_t *new_of, uint64_t persistid) 11308d94f651SGordon Ross { 11318d94f651SGordon Ross smb_hash_t *hash = new_of->f_server->sv_persistid_ht; 11328d94f651SGordon Ross smb_bucket_t *bucket; 11338d94f651SGordon Ross smb_llist_t *ll; 11348d94f651SGordon Ross smb_ofile_t *of; 11358d94f651SGordon Ross uint_t idx; 11368d94f651SGordon Ross 11378d94f651SGordon Ross ASSERT(persistid != 0); 11388d94f651SGordon Ross 11398d94f651SGordon Ross /* 11408d94f651SGordon Ross * Look to see if this key alreay exists. 11418d94f651SGordon Ross */ 11428d94f651SGordon Ross idx = smb_hash_uint64(hash, persistid); 11438d94f651SGordon Ross bucket = &hash->buckets[idx]; 11448d94f651SGordon Ross ll = &bucket->b_list; 11458d94f651SGordon Ross 11468d94f651SGordon Ross smb_llist_enter(ll, RW_WRITER); 11478d94f651SGordon Ross of = smb_llist_head(ll); 11488d94f651SGordon Ross while (of != NULL) { 11498d94f651SGordon Ross if (of->f_persistid == persistid) { 11508d94f651SGordon Ross /* already in use */ 11518d94f651SGordon Ross smb_llist_exit(ll); 11528d94f651SGordon Ross return (EEXIST); 11538d94f651SGordon Ross } 11548d94f651SGordon Ross of = smb_llist_next(ll, of); 11558d94f651SGordon Ross } 11568d94f651SGordon Ross 11578d94f651SGordon Ross /* Not found, so OK to insert. */ 11588d94f651SGordon Ross if (new_of->f_persistid == 0) { 11598d94f651SGordon Ross new_of->f_persistid = persistid; 11608d94f651SGordon Ross smb_llist_insert_tail(ll, new_of); 11618d94f651SGordon Ross } 11628d94f651SGordon Ross smb_llist_exit(ll); 11638d94f651SGordon Ross 11648d94f651SGordon Ross return (0); 11658d94f651SGordon Ross } 11668d94f651SGordon Ross 11678d94f651SGordon Ross void 1168811599a4SMatt Barden smb_ofile_del_persistid(smb_ofile_t *of) 1169811599a4SMatt Barden { 1170811599a4SMatt Barden smb_hash_t *hash = of->f_server->sv_persistid_ht; 1171811599a4SMatt Barden smb_bucket_t *bucket; 1172811599a4SMatt Barden smb_llist_t *ll; 1173811599a4SMatt Barden uint_t idx; 1174811599a4SMatt Barden 1175811599a4SMatt Barden idx = smb_hash_uint64(hash, of->f_persistid); 1176811599a4SMatt Barden bucket = &hash->buckets[idx]; 1177811599a4SMatt Barden ll = &bucket->b_list; 1178811599a4SMatt Barden smb_llist_enter(ll, RW_WRITER); 11798d94f651SGordon Ross if (of->f_persistid != 0) { 1180811599a4SMatt Barden smb_llist_remove(ll, of); 11818d94f651SGordon Ross of->f_persistid = 0; 11828d94f651SGordon Ross } 1183811599a4SMatt Barden smb_llist_exit(ll); 1184811599a4SMatt Barden } 1185811599a4SMatt Barden 11861fcced4cSJordan Brown /* 11871fcced4cSJordan Brown * Disallow NetFileClose on certain ofiles to avoid side-effects. 11881fcced4cSJordan Brown * Closing a tree root is not allowed: use NetSessionDel or NetShareDel. 11891fcced4cSJordan Brown * Closing SRVSVC connections is not allowed because this NetFileClose 11901fcced4cSJordan Brown * request may depend on this ofile. 11911fcced4cSJordan Brown */ 11921fcced4cSJordan Brown boolean_t 11931fcced4cSJordan Brown smb_ofile_disallow_fclose(smb_ofile_t *of) 11941fcced4cSJordan Brown { 11951fcced4cSJordan Brown ASSERT(of); 11961fcced4cSJordan Brown ASSERT(of->f_magic == SMB_OFILE_MAGIC); 11971fcced4cSJordan Brown ASSERT(of->f_refcnt); 11981fcced4cSJordan Brown 11991fcced4cSJordan Brown switch (of->f_ftype) { 12001fcced4cSJordan Brown case SMB_FTYPE_DISK: 12011fcced4cSJordan Brown ASSERT(of->f_tree); 12021fcced4cSJordan Brown return (of->f_node == of->f_tree->t_snode); 12031fcced4cSJordan Brown 12041fcced4cSJordan Brown case SMB_FTYPE_MESG_PIPE: 12051fcced4cSJordan Brown ASSERT(of->f_pipe); 1206bbf6f00cSJordan Brown if (smb_strcasecmp(of->f_pipe->p_name, "SRVSVC", 0) == 0) 12071fcced4cSJordan Brown return (B_TRUE); 12081fcced4cSJordan Brown break; 12091fcced4cSJordan Brown default: 12101fcced4cSJordan Brown break; 12111fcced4cSJordan Brown } 12121fcced4cSJordan Brown 12131fcced4cSJordan Brown return (B_FALSE); 12141fcced4cSJordan Brown } 12151fcced4cSJordan Brown 12161fcced4cSJordan Brown /* 1217da6c28aaSamw * smb_ofile_set_flags 1218da6c28aaSamw * 1219da6c28aaSamw * Return value: 1220da6c28aaSamw * 1221da6c28aaSamw * Current flags value 1222da6c28aaSamw * 1223da6c28aaSamw */ 1224da6c28aaSamw void 1225da6c28aaSamw smb_ofile_set_flags( 1226da6c28aaSamw smb_ofile_t *of, 1227da6c28aaSamw uint32_t flags) 1228da6c28aaSamw { 1229da6c28aaSamw ASSERT(of); 1230da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 1231da6c28aaSamw ASSERT(of->f_refcnt); 1232da6c28aaSamw 1233da6c28aaSamw mutex_enter(&of->f_mutex); 1234da6c28aaSamw of->f_flags |= flags; 1235da6c28aaSamw mutex_exit(&of->f_mutex); 1236da6c28aaSamw } 1237f96bd5c8SAlan Wright 1238da6c28aaSamw /* 1239da6c28aaSamw * smb_ofile_seek 1240da6c28aaSamw * 1241da6c28aaSamw * Return value: 1242da6c28aaSamw * 1243da6c28aaSamw * 0 Success 1244da6c28aaSamw * EINVAL Unknown mode 1245da6c28aaSamw * EOVERFLOW offset too big 1246da6c28aaSamw * 1247da6c28aaSamw */ 1248da6c28aaSamw int 1249da6c28aaSamw smb_ofile_seek( 1250da6c28aaSamw smb_ofile_t *of, 1251da6c28aaSamw ushort_t mode, 1252da6c28aaSamw int32_t off, 1253da6c28aaSamw uint32_t *retoff) 1254da6c28aaSamw { 125555bf511dSas200622 u_offset_t newoff = 0; 1256da6c28aaSamw int rc = 0; 1257037cac00Sjoyce mcintosh smb_attr_t attr; 1258da6c28aaSamw 1259da6c28aaSamw ASSERT(of); 1260da6c28aaSamw ASSERT(of->f_magic == SMB_OFILE_MAGIC); 1261da6c28aaSamw ASSERT(of->f_refcnt); 1262da6c28aaSamw 1263da6c28aaSamw mutex_enter(&of->f_mutex); 1264da6c28aaSamw switch (mode) { 1265da6c28aaSamw case SMB_SEEK_SET: 1266da6c28aaSamw if (off < 0) 1267da6c28aaSamw newoff = 0; 1268da6c28aaSamw else 126955bf511dSas200622 newoff = (u_offset_t)off; 1270da6c28aaSamw break; 1271da6c28aaSamw 1272da6c28aaSamw case SMB_SEEK_CUR: 1273da6c28aaSamw if (off < 0 && (-off) > of->f_seek_pos) 1274da6c28aaSamw newoff = 0; 1275da6c28aaSamw else 127655bf511dSas200622 newoff = of->f_seek_pos + (u_offset_t)off; 1277da6c28aaSamw break; 1278da6c28aaSamw 1279da6c28aaSamw case SMB_SEEK_END: 1280037cac00Sjoyce mcintosh bzero(&attr, sizeof (smb_attr_t)); 1281037cac00Sjoyce mcintosh attr.sa_mask |= SMB_AT_SIZE; 12828622ec45SGordon Ross rc = smb_fsop_getattr(NULL, zone_kcred(), of->f_node, &attr); 1283037cac00Sjoyce mcintosh if (rc != 0) { 1284037cac00Sjoyce mcintosh mutex_exit(&of->f_mutex); 1285037cac00Sjoyce mcintosh return (rc); 1286037cac00Sjoyce mcintosh } 1287037cac00Sjoyce mcintosh if (off < 0 && (-off) > attr.sa_vattr.va_size) 1288da6c28aaSamw newoff = 0; 1289da6c28aaSamw else 1290037cac00Sjoyce mcintosh newoff = attr.sa_vattr.va_size + (u_offset_t)off; 1291da6c28aaSamw break; 1292da6c28aaSamw 1293da6c28aaSamw default: 1294da6c28aaSamw mutex_exit(&of->f_mutex); 1295da6c28aaSamw return (EINVAL); 1296da6c28aaSamw } 1297da6c28aaSamw 129855bf511dSas200622 /* 129955bf511dSas200622 * See comments at the beginning of smb_seek.c. 130055bf511dSas200622 * If the offset is greater than UINT_MAX, we will return an error. 130155bf511dSas200622 */ 130255bf511dSas200622 130355bf511dSas200622 if (newoff > UINT_MAX) { 1304da6c28aaSamw rc = EOVERFLOW; 1305da6c28aaSamw } else { 1306da6c28aaSamw of->f_seek_pos = newoff; 1307da6c28aaSamw *retoff = (uint32_t)newoff; 1308da6c28aaSamw } 1309da6c28aaSamw mutex_exit(&of->f_mutex); 1310da6c28aaSamw return (rc); 1311da6c28aaSamw } 1312da6c28aaSamw 1313da6c28aaSamw /* 13146d1c73b5SDan Vatca * smb_ofile_flush 13156d1c73b5SDan Vatca * 13166d1c73b5SDan Vatca * If writes on this file are not synchronous, flush it using the NFSv3 13176d1c73b5SDan Vatca * commit interface. 13186d1c73b5SDan Vatca * 13196d1c73b5SDan Vatca * XXX - todo: Flush named pipe should drain writes. 13206d1c73b5SDan Vatca */ 13216d1c73b5SDan Vatca void 13226d1c73b5SDan Vatca smb_ofile_flush(struct smb_request *sr, struct smb_ofile *of) 13236d1c73b5SDan Vatca { 13246d1c73b5SDan Vatca switch (of->f_ftype) { 13256d1c73b5SDan Vatca case SMB_FTYPE_DISK: 13266d1c73b5SDan Vatca if ((of->f_node->flags & NODE_FLAGS_WRITE_THROUGH) == 0) 13276d1c73b5SDan Vatca (void) smb_fsop_commit(sr, of->f_cr, of->f_node); 13286d1c73b5SDan Vatca break; 13296d1c73b5SDan Vatca default: 13306d1c73b5SDan Vatca break; 13316d1c73b5SDan Vatca } 13326d1c73b5SDan Vatca } 13336d1c73b5SDan Vatca 13346d1c73b5SDan Vatca /* 1335da6c28aaSamw * smb_ofile_is_open 1336da6c28aaSamw */ 1337da6c28aaSamw boolean_t 13382c2961f8Sjose borrego smb_ofile_is_open(smb_ofile_t *of) 1339da6c28aaSamw { 13401fcced4cSJordan Brown boolean_t rc; 1341da6c28aaSamw 13422c2961f8Sjose borrego SMB_OFILE_VALID(of); 1343da6c28aaSamw 1344da6c28aaSamw mutex_enter(&of->f_mutex); 13451fcced4cSJordan Brown rc = smb_ofile_is_open_locked(of); 1346da6c28aaSamw mutex_exit(&of->f_mutex); 1347da6c28aaSamw return (rc); 1348da6c28aaSamw } 1349da6c28aaSamw 1350da6c28aaSamw /* *************************** Static Functions ***************************** */ 1351da6c28aaSamw 1352da6c28aaSamw /* 13531fcced4cSJordan Brown * Determine whether or not an ofile is open. 13541fcced4cSJordan Brown * This function must be called with the mutex held. 13551fcced4cSJordan Brown */ 13561fcced4cSJordan Brown static boolean_t 13571fcced4cSJordan Brown smb_ofile_is_open_locked(smb_ofile_t *of) 13581fcced4cSJordan Brown { 1359811599a4SMatt Barden ASSERT(MUTEX_HELD(&of->f_mutex)); 1360811599a4SMatt Barden 13611fcced4cSJordan Brown switch (of->f_state) { 13621fcced4cSJordan Brown case SMB_OFILE_STATE_OPEN: 1363811599a4SMatt Barden case SMB_OFILE_STATE_SAVE_DH: 1364811599a4SMatt Barden case SMB_OFILE_STATE_SAVING: 1365811599a4SMatt Barden case SMB_OFILE_STATE_ORPHANED: 1366811599a4SMatt Barden case SMB_OFILE_STATE_RECONNECT: 13671fcced4cSJordan Brown return (B_TRUE); 13681fcced4cSJordan Brown 13691fcced4cSJordan Brown case SMB_OFILE_STATE_CLOSING: 13701fcced4cSJordan Brown case SMB_OFILE_STATE_CLOSED: 1371811599a4SMatt Barden case SMB_OFILE_STATE_EXPIRED: 13721fcced4cSJordan Brown return (B_FALSE); 13731fcced4cSJordan Brown 13741fcced4cSJordan Brown default: 13751fcced4cSJordan Brown ASSERT(0); 13761fcced4cSJordan Brown return (B_FALSE); 13771fcced4cSJordan Brown } 13781fcced4cSJordan Brown } 13791fcced4cSJordan Brown 13801fcced4cSJordan Brown /* 1381811599a4SMatt Barden * smb_ofile_save_dh 1382811599a4SMatt Barden * 1383811599a4SMatt Barden * Called via smb_llist_post (after smb_llist_exit) when the last ref. 1384811599a4SMatt Barden * on this ofile has gone, and this ofile is a "durable handle" (DH) 1385811599a4SMatt Barden * that has state we've decided to save. 1386811599a4SMatt Barden * 1387811599a4SMatt Barden * This does parts of what smb_ofile_delete would do, including: 1388811599a4SMatt Barden * remove the ofile from the tree ofile list and related. 1389811599a4SMatt Barden * 1390811599a4SMatt Barden * We leave the ofile in state ORPHANED, ready for reconnect 1391811599a4SMatt Barden * or expiration via smb2_dh_expire (see smb_ofile_delete). 1392da6c28aaSamw */ 1393811599a4SMatt Barden static void 1394811599a4SMatt Barden smb_ofile_save_dh(void *arg) 1395da6c28aaSamw { 1396811599a4SMatt Barden smb_ofile_t *of = (smb_ofile_t *)arg; 1397811599a4SMatt Barden smb_tree_t *tree = of->f_tree; 1398da6c28aaSamw 1399811599a4SMatt Barden SMB_OFILE_VALID(of); 1400811599a4SMatt Barden ASSERT(of->f_refcnt == 0); 1401811599a4SMatt Barden ASSERT(of->f_ftype == SMB_FTYPE_DISK); 1402811599a4SMatt Barden ASSERT(of->f_state == SMB_OFILE_STATE_SAVING); 1403da6c28aaSamw 1404811599a4SMatt Barden atomic_dec_32(&of->f_session->s_file_cnt); 1405811599a4SMatt Barden atomic_dec_32(&of->f_tree->t_open_files); 1406811599a4SMatt Barden smb_llist_enter(&tree->t_ofile_list, RW_WRITER); 1407811599a4SMatt Barden smb_llist_remove(&tree->t_ofile_list, of); 1408811599a4SMatt Barden smb_llist_exit(&tree->t_ofile_list); 1409811599a4SMatt Barden 1410da6c28aaSamw /* 1411811599a4SMatt Barden * This ofile is no longer on t_ofile_list, however... 1412811599a4SMatt Barden * 1413811599a4SMatt Barden * This is called via smb_llist_post, which means it may run 1414811599a4SMatt Barden * BEFORE smb_ofile_release drops f_mutex (if another thread 1415811599a4SMatt Barden * flushes the delete queue before we do). Synchronize. 1416da6c28aaSamw */ 1417811599a4SMatt Barden mutex_enter(&of->f_mutex); 1418811599a4SMatt Barden DTRACE_PROBE1(ofile__exit, smb_ofile_t, of); 1419da6c28aaSamw mutex_exit(&of->f_mutex); 1420811599a4SMatt Barden 1421811599a4SMatt Barden /* 1422811599a4SMatt Barden * Keep f_notify state, lease, and 1423811599a4SMatt Barden * keep on node ofile list. 1424811599a4SMatt Barden * Keep of->f_cr until reclaim. 1425811599a4SMatt Barden */ 1426811599a4SMatt Barden 1427811599a4SMatt Barden ASSERT(of->f_fid != 0); 1428811599a4SMatt Barden smb_idpool_free(&tree->t_fid_pool, of->f_fid); 1429811599a4SMatt Barden of->f_fid = 0; 1430811599a4SMatt Barden smb_tree_release(of->f_tree); 1431811599a4SMatt Barden of->f_tree = NULL; 1432811599a4SMatt Barden smb_user_release(of->f_user); 1433811599a4SMatt Barden of->f_user = NULL; 1434811599a4SMatt Barden of->f_session = NULL; 1435811599a4SMatt Barden 1436811599a4SMatt Barden /* 1437811599a4SMatt Barden * Make it "orphaned" so it can now be reclaimed. 1438811599a4SMatt Barden * Note that smb_ofile_hold_olbrk() may have blocked 1439811599a4SMatt Barden * for state SMB_OFILE_STATE_SAVING, so wake it. 1440811599a4SMatt Barden */ 1441811599a4SMatt Barden mutex_enter(&of->f_mutex); 1442811599a4SMatt Barden of->dh_expire_time = gethrtime() + of->dh_timeout_offset; 1443811599a4SMatt Barden of->f_state = SMB_OFILE_STATE_ORPHANED; 1444811599a4SMatt Barden cv_broadcast(&of->f_cv); 1445da6c28aaSamw mutex_exit(&of->f_mutex); 1446da6c28aaSamw } 1447da6c28aaSamw 1448da6c28aaSamw /* 14499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Delete an ofile. 1450da6c28aaSamw * 145194047d49SGordon Ross * Approximately the inverse of smb_ofile_alloc() 1452811599a4SMatt Barden * Called via smb_llist_post (after smb_llist_exit) 1453811599a4SMatt Barden * when the last ref. on this ofile has gone. 1454811599a4SMatt Barden * 1455811599a4SMatt Barden * Normally,this removes the ofile from the tree list and 1456811599a4SMatt Barden * then frees resources held on the ofile. However, when 1457811599a4SMatt Barden * we're expiring an orphaned durable handle, the linkage 1458811599a4SMatt Barden * into the tree lists etc. have already been destroyed. 1459811599a4SMatt Barden * This case is distinguished by of->f_tree == NULL. 1460da6c28aaSamw */ 1461811599a4SMatt Barden static void 14629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_delete(void *arg) 1463da6c28aaSamw { 14649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_t *of = (smb_ofile_t *)arg; 1465811599a4SMatt Barden smb_tree_t *tree = of->f_tree; 14669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 14679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_OFILE_VALID(of); 1468da6c28aaSamw ASSERT(of->f_refcnt == 0); 1469da6c28aaSamw ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED); 1470da6c28aaSamw 1471811599a4SMatt Barden if (tree != NULL) { 1472811599a4SMatt Barden ASSERT(of->f_user != NULL); 1473811599a4SMatt Barden ASSERT(of->f_session != NULL); 1474811599a4SMatt Barden atomic_dec_32(&of->f_session->s_file_cnt); 1475811599a4SMatt Barden atomic_dec_32(&of->f_tree->t_open_files); 14769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_enter(&tree->t_ofile_list, RW_WRITER); 14779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_remove(&tree->t_ofile_list, of); 14789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_exit(&tree->t_ofile_list); 1479811599a4SMatt Barden } 14809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1481bfe5e737SGordon Ross /* 1482bfe5e737SGordon Ross * Remove this ofile from the node's n_ofile_list so it 1483bfe5e737SGordon Ross * can't be found by list walkers like notify or oplock. 1484bfe5e737SGordon Ross * Keep the node ref. until later in this function so 1485bfe5e737SGordon Ross * of->f_node remains valid while we destroy the ofile. 1486bfe5e737SGordon Ross */ 1487bfe5e737SGordon Ross if (of->f_ftype == SMB_FTYPE_DISK || 1488bfe5e737SGordon Ross of->f_ftype == SMB_FTYPE_PRINTER) { 14891f0845f1SGordon Ross smb_node_t *node = of->f_node; 14901f0845f1SGordon Ross 14911f0845f1SGordon Ross /* 14921f0845f1SGordon Ross * Oplock cleanup should have made sure that 14931f0845f1SGordon Ross * excl_open does not point to this ofile. 14941f0845f1SGordon Ross */ 14951f0845f1SGordon Ross VERIFY(node->n_oplock.excl_open != of); 14961f0845f1SGordon Ross 1497bfe5e737SGordon Ross /* 1498bfe5e737SGordon Ross * Note smb_ofile_close did smb_node_dec_open_ofiles() 1499bfe5e737SGordon Ross */ 15001f0845f1SGordon Ross smb_node_rem_ofile(node, of); 1501bfe5e737SGordon Ross } 1502bfe5e737SGordon Ross 1503811599a4SMatt Barden /* 1504811599a4SMatt Barden * This ofile is no longer on any lists, however... 1505811599a4SMatt Barden * 1506811599a4SMatt Barden * This is called via smb_llist_post, which means it may run 1507811599a4SMatt Barden * BEFORE smb_ofile_release drops f_mutex (if another thread 1508811599a4SMatt Barden * flushes the delete queue before we do). Synchronize. 1509811599a4SMatt Barden */ 15109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&of->f_mutex); 151194047d49SGordon Ross of->f_state = SMB_OFILE_STATE_ALLOC; 151294047d49SGordon Ross DTRACE_PROBE1(ofile__exit, smb_ofile_t, of); 15139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&of->f_mutex); 1514da6c28aaSamw 1515a90cf9f2SGordon Ross switch (of->f_ftype) { 1516a90cf9f2SGordon Ross case SMB_FTYPE_BYTE_PIPE: 1517a90cf9f2SGordon Ross case SMB_FTYPE_MESG_PIPE: 15189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_dealloc(of->f_pipe); 15193db3f65cSamw of->f_pipe = NULL; 1520a90cf9f2SGordon Ross break; 1521a90cf9f2SGordon Ross case SMB_FTYPE_DISK: 1522bfe5e737SGordon Ross ASSERT(of->f_notify.nc_subscribed == B_FALSE); 1523bfe5e737SGordon Ross MBC_FLUSH(&of->f_notify.nc_buffer); 1524a90cf9f2SGordon Ross if (of->f_odir != NULL) 1525a90cf9f2SGordon Ross smb_odir_release(of->f_odir); 152694047d49SGordon Ross if (of->f_lease != NULL) { 152794047d49SGordon Ross smb2_lease_rele(of->f_lease); 152894047d49SGordon Ross of->f_lease = NULL; 152994047d49SGordon Ross } 1530bfe5e737SGordon Ross /* FALLTHROUGH */ 1531bfe5e737SGordon Ross case SMB_FTYPE_PRINTER: 1532bfe5e737SGordon Ross /* 1533bfe5e737SGordon Ross * Did smb_node_rem_ofile above. 1534bfe5e737SGordon Ross */ 1535bfe5e737SGordon Ross ASSERT(of->f_node != NULL); 1536da6c28aaSamw smb_node_release(of->f_node); 1537a90cf9f2SGordon Ross break; 1538a90cf9f2SGordon Ross default: 1539a90cf9f2SGordon Ross ASSERT(!"f_ftype"); 1540a90cf9f2SGordon Ross break; 1541da6c28aaSamw } 1542da6c28aaSamw 154394047d49SGordon Ross smb_ofile_free(of); 154494047d49SGordon Ross } 154594047d49SGordon Ross 154694047d49SGordon Ross void 154794047d49SGordon Ross smb_ofile_free(smb_ofile_t *of) 154894047d49SGordon Ross { 154994047d49SGordon Ross smb_tree_t *tree = of->f_tree; 155094047d49SGordon Ross 155194047d49SGordon Ross ASSERT(of->f_state == SMB_OFILE_STATE_ALLOC); 155294047d49SGordon Ross 1553817fa55fSGordon Ross /* Make sure it's not in the persistid hash. */ 1554817fa55fSGordon Ross ASSERT(of->f_persistid == 0); 1555817fa55fSGordon Ross 1556811599a4SMatt Barden if (tree != NULL) { 1557811599a4SMatt Barden if (of->f_fid != 0) 1558811599a4SMatt Barden smb_idpool_free(&tree->t_fid_pool, of->f_fid); 1559811599a4SMatt Barden smb_tree_release(of->f_tree); 1560811599a4SMatt Barden smb_user_release(of->f_user); 1561811599a4SMatt Barden } 1562811599a4SMatt Barden 1563811599a4SMatt Barden if (of->f_cr != NULL) 1564811599a4SMatt Barden crfree(of->f_cr); 1565811599a4SMatt Barden 1566da6c28aaSamw of->f_magic = (uint32_t)~SMB_OFILE_MAGIC; 1567bfe5e737SGordon Ross list_destroy(&of->f_notify.nc_waiters); 15688d94f651SGordon Ross mutex_destroy(&of->dh_nvlock); 1569da6c28aaSamw mutex_destroy(&of->f_mutex); 15708622ec45SGordon Ross kmem_cache_free(smb_cache_ofile, of); 1571da6c28aaSamw } 1572da6c28aaSamw 1573da6c28aaSamw /* 1574da6c28aaSamw * smb_ofile_access 1575da6c28aaSamw * 1576da6c28aaSamw * This function will check to see if the access requested is granted. 1577da6c28aaSamw * Returns NT status codes. 1578da6c28aaSamw */ 1579da6c28aaSamw uint32_t 1580da6c28aaSamw smb_ofile_access(smb_ofile_t *of, cred_t *cr, uint32_t access) 1581da6c28aaSamw { 1582da6c28aaSamw 15838622ec45SGordon Ross if ((of == NULL) || (cr == zone_kcred())) 1584da6c28aaSamw return (NT_STATUS_SUCCESS); 1585da6c28aaSamw 1586da6c28aaSamw /* 1587da6c28aaSamw * If the request is for something 1588da6c28aaSamw * I don't grant it is an error 1589da6c28aaSamw */ 1590da6c28aaSamw if (~(of->f_granted_access) & access) { 1591da6c28aaSamw if (!(of->f_granted_access & ACCESS_SYSTEM_SECURITY) && 1592da6c28aaSamw (access & ACCESS_SYSTEM_SECURITY)) { 1593da6c28aaSamw return (NT_STATUS_PRIVILEGE_NOT_HELD); 1594da6c28aaSamw } 1595da6c28aaSamw return (NT_STATUS_ACCESS_DENIED); 1596da6c28aaSamw } 1597da6c28aaSamw 1598da6c28aaSamw return (NT_STATUS_SUCCESS); 1599da6c28aaSamw } 16003ad684d6Sjb150015 1601cb174861Sjoyce mcintosh /* 1602cb174861Sjoyce mcintosh * smb_ofile_share_check 1603cb174861Sjoyce mcintosh * 1604cb174861Sjoyce mcintosh * Check if ofile was opened with share access NONE (0). 1605cb174861Sjoyce mcintosh * Returns: B_TRUE - share access non-zero 1606cb174861Sjoyce mcintosh * B_FALSE - share access NONE 1607cb174861Sjoyce mcintosh */ 1608cb174861Sjoyce mcintosh boolean_t 1609cb174861Sjoyce mcintosh smb_ofile_share_check(smb_ofile_t *of) 1610cb174861Sjoyce mcintosh { 1611cb174861Sjoyce mcintosh return (!SMB_DENY_ALL(of->f_share_access)); 1612cb174861Sjoyce mcintosh } 16133ad684d6Sjb150015 16143ad684d6Sjb150015 /* 16153ad684d6Sjb150015 * check file sharing rules for current open request 16163ad684d6Sjb150015 * against existing open instances of the same file 16173ad684d6Sjb150015 * 16183ad684d6Sjb150015 * Returns NT_STATUS_SHARING_VIOLATION if there is any 16193ad684d6Sjb150015 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 16203ad684d6Sjb150015 */ 16213ad684d6Sjb150015 uint32_t 16229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_open_check(smb_ofile_t *of, uint32_t desired_access, 16233ad684d6Sjb150015 uint32_t share_access) 16243ad684d6Sjb150015 { 1625811599a4SMatt Barden uint32_t ret; 1626811599a4SMatt Barden 16273ad684d6Sjb150015 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 16283ad684d6Sjb150015 16293ad684d6Sjb150015 mutex_enter(&of->f_mutex); 16303ad684d6Sjb150015 1631811599a4SMatt Barden if (!smb_ofile_is_open_locked(of)) { 1632811599a4SMatt Barden ret = NT_STATUS_INVALID_HANDLE; 1633811599a4SMatt Barden goto out; 16343ad684d6Sjb150015 } 16353ad684d6Sjb150015 16363ad684d6Sjb150015 /* if it's just meta data */ 16373ad684d6Sjb150015 if ((of->f_granted_access & FILE_DATA_ALL) == 0) { 1638811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1639811599a4SMatt Barden goto out; 16403ad684d6Sjb150015 } 16413ad684d6Sjb150015 16423ad684d6Sjb150015 /* 16433ad684d6Sjb150015 * Check requested share access against the 16443ad684d6Sjb150015 * open granted (desired) access 16453ad684d6Sjb150015 */ 16463ad684d6Sjb150015 if (SMB_DENY_DELETE(share_access) && (of->f_granted_access & DELETE)) { 1647811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1648811599a4SMatt Barden goto out; 16493ad684d6Sjb150015 } 16503ad684d6Sjb150015 16513ad684d6Sjb150015 if (SMB_DENY_READ(share_access) && 16523ad684d6Sjb150015 (of->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE))) { 1653811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1654811599a4SMatt Barden goto out; 16553ad684d6Sjb150015 } 16563ad684d6Sjb150015 16573ad684d6Sjb150015 if (SMB_DENY_WRITE(share_access) && 16583ad684d6Sjb150015 (of->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) { 1659811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1660811599a4SMatt Barden goto out; 16613ad684d6Sjb150015 } 16623ad684d6Sjb150015 16633ad684d6Sjb150015 /* check requested desired access against the open share access */ 16643ad684d6Sjb150015 if (SMB_DENY_DELETE(of->f_share_access) && (desired_access & DELETE)) { 1665811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1666811599a4SMatt Barden goto out; 16673ad684d6Sjb150015 } 16683ad684d6Sjb150015 16693ad684d6Sjb150015 if (SMB_DENY_READ(of->f_share_access) && 16703ad684d6Sjb150015 (desired_access & (FILE_READ_DATA | FILE_EXECUTE))) { 1671811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1672811599a4SMatt Barden goto out; 16733ad684d6Sjb150015 } 16743ad684d6Sjb150015 16753ad684d6Sjb150015 if (SMB_DENY_WRITE(of->f_share_access) && 16763ad684d6Sjb150015 (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) { 1677811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1678811599a4SMatt Barden goto out; 16793ad684d6Sjb150015 } 16803ad684d6Sjb150015 1681811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1682811599a4SMatt Barden out: 16833ad684d6Sjb150015 mutex_exit(&of->f_mutex); 1684811599a4SMatt Barden return (ret); 16853ad684d6Sjb150015 } 16863ad684d6Sjb150015 16873ad684d6Sjb150015 /* 16883ad684d6Sjb150015 * smb_ofile_rename_check 16893ad684d6Sjb150015 * 1690575d359dSGordon Ross * This does the work described in MS-FSA 2.1.5.1.2.2 (Algorithm 1691575d359dSGordon Ross * to Check Sharing Access to an Existing Stream or Directory), 1692575d359dSGordon Ross * where the "open in-progress" has DesiredAccess = DELETE and 1693575d359dSGordon Ross * SharingMode = SHARE_READ | SHARE_WRITE | SHARE_DELETE. 16943ad684d6Sjb150015 */ 16953ad684d6Sjb150015 16963ad684d6Sjb150015 uint32_t 16973ad684d6Sjb150015 smb_ofile_rename_check(smb_ofile_t *of) 16983ad684d6Sjb150015 { 1699811599a4SMatt Barden uint32_t ret; 1700811599a4SMatt Barden 17013ad684d6Sjb150015 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 17023ad684d6Sjb150015 17033ad684d6Sjb150015 mutex_enter(&of->f_mutex); 17043ad684d6Sjb150015 1705811599a4SMatt Barden if (!smb_ofile_is_open_locked(of)) { 1706811599a4SMatt Barden ret = NT_STATUS_INVALID_HANDLE; 1707811599a4SMatt Barden goto out; 17083ad684d6Sjb150015 } 17093ad684d6Sjb150015 1710575d359dSGordon Ross if ((of->f_granted_access & FILE_DATA_ALL) == 0) { 1711811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1712811599a4SMatt Barden goto out; 17133ad684d6Sjb150015 } 17143ad684d6Sjb150015 17153ad684d6Sjb150015 if ((of->f_share_access & FILE_SHARE_DELETE) == 0) { 1716811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1717811599a4SMatt Barden goto out; 17183ad684d6Sjb150015 } 17193ad684d6Sjb150015 1720811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1721811599a4SMatt Barden out: 17223ad684d6Sjb150015 mutex_exit(&of->f_mutex); 1723811599a4SMatt Barden return (ret); 17243ad684d6Sjb150015 } 17253ad684d6Sjb150015 17263ad684d6Sjb150015 /* 17273ad684d6Sjb150015 * smb_ofile_delete_check 17283ad684d6Sjb150015 * 17293ad684d6Sjb150015 * An open file can be deleted only if opened for 17303ad684d6Sjb150015 * accessing meta data. Share modes aren't important 17313ad684d6Sjb150015 * in this case. 17323ad684d6Sjb150015 * 17333ad684d6Sjb150015 * NOTE: there is another mechanism for deleting an 17343ad684d6Sjb150015 * open file that NT clients usually use. 17353ad684d6Sjb150015 * That's setting "Delete on close" flag for an open 17363ad684d6Sjb150015 * file. In this way the file will be deleted after 17373ad684d6Sjb150015 * last close. This flag can be set by SmbTrans2SetFileInfo 17383ad684d6Sjb150015 * with FILE_DISPOSITION_INFO information level. 17393ad684d6Sjb150015 * For setting this flag, the file should be opened by 17403ad684d6Sjb150015 * DELETE access in the FID that is passed in the Trans2 17413ad684d6Sjb150015 * request. 17423ad684d6Sjb150015 */ 17433ad684d6Sjb150015 17443ad684d6Sjb150015 uint32_t 17453ad684d6Sjb150015 smb_ofile_delete_check(smb_ofile_t *of) 17463ad684d6Sjb150015 { 1747811599a4SMatt Barden uint32_t ret; 1748811599a4SMatt Barden 17493ad684d6Sjb150015 ASSERT(of->f_magic == SMB_OFILE_MAGIC); 17503ad684d6Sjb150015 17513ad684d6Sjb150015 mutex_enter(&of->f_mutex); 17523ad684d6Sjb150015 1753811599a4SMatt Barden if (!smb_ofile_is_open_locked(of)) { 1754811599a4SMatt Barden ret = NT_STATUS_INVALID_HANDLE; 1755811599a4SMatt Barden goto out; 17563ad684d6Sjb150015 } 17573ad684d6Sjb150015 17583ad684d6Sjb150015 if (of->f_granted_access & 17593ad684d6Sjb150015 (FILE_READ_DATA | FILE_WRITE_DATA | 17603ad684d6Sjb150015 FILE_APPEND_DATA | FILE_EXECUTE | DELETE)) { 1761811599a4SMatt Barden ret = NT_STATUS_SHARING_VIOLATION; 1762811599a4SMatt Barden goto out; 17633ad684d6Sjb150015 } 17643ad684d6Sjb150015 1765811599a4SMatt Barden ret = NT_STATUS_SUCCESS; 1766811599a4SMatt Barden out: 17673ad684d6Sjb150015 mutex_exit(&of->f_mutex); 1768811599a4SMatt Barden return (ret); 17693ad684d6Sjb150015 } 1770b89a8333Snatalie li - Sun Microsystems - Irvine United States 1771b89a8333Snatalie li - Sun Microsystems - Irvine United States cred_t * 1772b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ofile_getcred(smb_ofile_t *of) 1773b89a8333Snatalie li - Sun Microsystems - Irvine United States { 1774b89a8333Snatalie li - Sun Microsystems - Irvine United States return (of->f_cr); 1775b89a8333Snatalie li - Sun Microsystems - Irvine United States } 17768b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 17778b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States /* 17788b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * smb_ofile_set_delete_on_close 17798b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 17808b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * Set the DeleteOnClose flag on the smb file. When the file is closed, 17818b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * the flag will be transferred to the smb node, which will commit the 17828b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * delete operation and inhibit subsequent open requests. 17838b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 17848b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * When DeleteOnClose is set on an smb_node, the common open code will 17858b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * reject subsequent open requests for the file. Observation of Windows 17868b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 2000 indicates that subsequent opens should be allowed (assuming 17878b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * there would be no sharing violation) until the file is closed using 17888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * the fid on which the DeleteOnClose was requested. 17898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States */ 17908b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States void 179194047d49SGordon Ross smb_ofile_set_delete_on_close(smb_request_t *sr, smb_ofile_t *of) 17928b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States { 179394047d49SGordon Ross uint32_t status; 179494047d49SGordon Ross 179594047d49SGordon Ross /* 179694047d49SGordon Ross * Break any oplock handle caching. 179794047d49SGordon Ross */ 179894047d49SGordon Ross status = smb_oplock_break_SETINFO(of->f_node, of, 179994047d49SGordon Ross FileDispositionInformation); 180094047d49SGordon Ross if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) { 180194047d49SGordon Ross if (sr->session->dialect >= SMB_VERS_2_BASE) 180294047d49SGordon Ross (void) smb2sr_go_async(sr); 1803525641e8SGordon Ross (void) smb_oplock_wait_break(sr, of->f_node, 0); 180494047d49SGordon Ross } 180594047d49SGordon Ross 18068b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&of->f_mutex); 18078b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States of->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE; 18088b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&of->f_mutex); 18098b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States } 18101fcced4cSJordan Brown 18111fcced4cSJordan Brown /* 18121fcced4cSJordan Brown * Encode open file information into a buffer; needed in user space to 18131fcced4cSJordan Brown * support RPC requests. 18141fcced4cSJordan Brown */ 18151fcced4cSJordan Brown static int 18161fcced4cSJordan Brown smb_ofile_netinfo_encode(smb_ofile_t *of, uint8_t *buf, size_t buflen, 18171fcced4cSJordan Brown uint32_t *nbytes) 18181fcced4cSJordan Brown { 18191fcced4cSJordan Brown smb_netfileinfo_t fi; 18201fcced4cSJordan Brown int rc; 18211fcced4cSJordan Brown 18221fcced4cSJordan Brown rc = smb_ofile_netinfo_init(of, &fi); 18231fcced4cSJordan Brown if (rc == 0) { 18241fcced4cSJordan Brown rc = smb_netfileinfo_encode(&fi, buf, buflen, nbytes); 18251fcced4cSJordan Brown smb_ofile_netinfo_fini(&fi); 18261fcced4cSJordan Brown } 18271fcced4cSJordan Brown 18281fcced4cSJordan Brown return (rc); 18291fcced4cSJordan Brown } 18301fcced4cSJordan Brown 18311fcced4cSJordan Brown static int 18321fcced4cSJordan Brown smb_ofile_netinfo_init(smb_ofile_t *of, smb_netfileinfo_t *fi) 18331fcced4cSJordan Brown { 18341fcced4cSJordan Brown smb_user_t *user; 18351fcced4cSJordan Brown smb_tree_t *tree; 18361fcced4cSJordan Brown smb_node_t *node; 18371fcced4cSJordan Brown char *path; 18381fcced4cSJordan Brown char *buf; 18391fcced4cSJordan Brown int rc; 18401fcced4cSJordan Brown 18411fcced4cSJordan Brown ASSERT(of); 18421fcced4cSJordan Brown user = of->f_user; 18431fcced4cSJordan Brown tree = of->f_tree; 18441fcced4cSJordan Brown ASSERT(user); 18451fcced4cSJordan Brown ASSERT(tree); 18461fcced4cSJordan Brown 18471fcced4cSJordan Brown buf = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 18481fcced4cSJordan Brown 18491fcced4cSJordan Brown switch (of->f_ftype) { 18501fcced4cSJordan Brown case SMB_FTYPE_DISK: 18511fcced4cSJordan Brown node = of->f_node; 18521fcced4cSJordan Brown ASSERT(node); 18531fcced4cSJordan Brown 18541fcced4cSJordan Brown fi->fi_permissions = of->f_granted_access; 1855148c5f43SAlan Wright fi->fi_numlocks = smb_lock_get_lock_count(node, of); 18561fcced4cSJordan Brown 18571fcced4cSJordan Brown path = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 18581fcced4cSJordan Brown 18591fcced4cSJordan Brown if (node != tree->t_snode) { 1860148c5f43SAlan Wright rc = smb_node_getshrpath(node, tree, path, MAXPATHLEN); 1861148c5f43SAlan Wright if (rc != 0) 18621fcced4cSJordan Brown (void) strlcpy(path, node->od_name, MAXPATHLEN); 18631fcced4cSJordan Brown } 18641fcced4cSJordan Brown 18651fcced4cSJordan Brown (void) snprintf(buf, MAXPATHLEN, "%s:%s", tree->t_sharename, 18661fcced4cSJordan Brown path); 18671fcced4cSJordan Brown kmem_free(path, MAXPATHLEN); 18681fcced4cSJordan Brown break; 18691fcced4cSJordan Brown 18701fcced4cSJordan Brown case SMB_FTYPE_MESG_PIPE: 18711fcced4cSJordan Brown ASSERT(of->f_pipe); 18721fcced4cSJordan Brown 18731fcced4cSJordan Brown fi->fi_permissions = FILE_READ_DATA | FILE_WRITE_DATA | 18741fcced4cSJordan Brown FILE_EXECUTE; 18751fcced4cSJordan Brown fi->fi_numlocks = 0; 18761fcced4cSJordan Brown (void) snprintf(buf, MAXPATHLEN, "\\PIPE\\%s", 18771fcced4cSJordan Brown of->f_pipe->p_name); 18781fcced4cSJordan Brown break; 18791fcced4cSJordan Brown 18801fcced4cSJordan Brown default: 18811fcced4cSJordan Brown kmem_free(buf, MAXPATHLEN); 18821fcced4cSJordan Brown return (-1); 18831fcced4cSJordan Brown } 18841fcced4cSJordan Brown 18851fcced4cSJordan Brown fi->fi_fid = of->f_fid; 18861fcced4cSJordan Brown fi->fi_uniqid = of->f_uniqid; 18871fcced4cSJordan Brown fi->fi_pathlen = strlen(buf) + 1; 18889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States fi->fi_path = smb_mem_strdup(buf); 18891fcced4cSJordan Brown kmem_free(buf, MAXPATHLEN); 18901fcced4cSJordan Brown 18911fcced4cSJordan Brown fi->fi_namelen = user->u_domain_len + user->u_name_len + 2; 18921fcced4cSJordan Brown fi->fi_username = kmem_alloc(fi->fi_namelen, KM_SLEEP); 18931fcced4cSJordan Brown (void) snprintf(fi->fi_username, fi->fi_namelen, "%s\\%s", 18941fcced4cSJordan Brown user->u_domain, user->u_name); 18951fcced4cSJordan Brown return (0); 18961fcced4cSJordan Brown } 18971fcced4cSJordan Brown 18981fcced4cSJordan Brown static void 18991fcced4cSJordan Brown smb_ofile_netinfo_fini(smb_netfileinfo_t *fi) 19001fcced4cSJordan Brown { 19011fcced4cSJordan Brown if (fi == NULL) 19021fcced4cSJordan Brown return; 19031fcced4cSJordan Brown 19041fcced4cSJordan Brown if (fi->fi_path) 19059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_mem_free(fi->fi_path); 19061fcced4cSJordan Brown if (fi->fi_username) 19071fcced4cSJordan Brown kmem_free(fi->fi_username, fi->fi_namelen); 19081fcced4cSJordan Brown 19091fcced4cSJordan Brown bzero(fi, sizeof (smb_netfileinfo_t)); 19101fcced4cSJordan Brown } 19119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 19129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 19139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * A query of user and group quotas may span multiple requests. 19149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * f_quota_resume is used to determine where the query should 19159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * be resumed, in a subsequent request. f_quota_resume contains 19169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * the SID of the last quota entry returned to the client. 19179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 19189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void 19199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_set_quota_resume(smb_ofile_t *ofile, char *resume) 19209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 19219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(ofile); 19229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&ofile->f_mutex); 19239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (resume == NULL) 19249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States bzero(ofile->f_quota_resume, SMB_SID_STRSZ); 19259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States else 19269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) strlcpy(ofile->f_quota_resume, resume, SMB_SID_STRSZ); 19279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&ofile->f_mutex); 19289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 19299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 19309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void 19319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_ofile_get_quota_resume(smb_ofile_t *ofile, char *buf, int bufsize) 19329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 19339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(ofile); 19349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_enter(&ofile->f_mutex); 19359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) strlcpy(buf, ofile->f_quota_resume, bufsize); 19369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States mutex_exit(&ofile->f_mutex); 19379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 1938