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