xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_odir.c (revision 5331:3047ad28a67b)
1*5331Samw /*
2*5331Samw  * CDDL HEADER START
3*5331Samw  *
4*5331Samw  * The contents of this file are subject to the terms of the
5*5331Samw  * Common Development and Distribution License (the "License").
6*5331Samw  * You may not use this file except in compliance with the License.
7*5331Samw  *
8*5331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5331Samw  * or http://www.opensolaris.org/os/licensing.
10*5331Samw  * See the License for the specific language governing permissions
11*5331Samw  * and limitations under the License.
12*5331Samw  *
13*5331Samw  * When distributing Covered Code, include this CDDL HEADER in each
14*5331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5331Samw  * If applicable, add the following below this CDDL HEADER, with the
16*5331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
17*5331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5331Samw  *
19*5331Samw  * CDDL HEADER END
20*5331Samw  */
21*5331Samw /*
22*5331Samw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*5331Samw  * Use is subject to license terms.
24*5331Samw  */
25*5331Samw 
26*5331Samw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*5331Samw 
28*5331Samw /*
29*5331Samw  * General Structures Layout
30*5331Samw  * -------------------------
31*5331Samw  *
32*5331Samw  * This is a simplified diagram showing the relationship between most of the
33*5331Samw  * main structures.
34*5331Samw  *
35*5331Samw  * +-------------------+
36*5331Samw  * |     SMB_INFO      |
37*5331Samw  * +-------------------+
38*5331Samw  *          |
39*5331Samw  *          |
40*5331Samw  *          v
41*5331Samw  * +-------------------+       +-------------------+      +-------------------+
42*5331Samw  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
43*5331Samw  * +-------------------+       +-------------------+      +-------------------+
44*5331Samw  *          |
45*5331Samw  *          |
46*5331Samw  *          v
47*5331Samw  * +-------------------+       +-------------------+      +-------------------+
48*5331Samw  * |       USER        |<----->|       USER        |......|       USER        |
49*5331Samw  * +-------------------+       +-------------------+      +-------------------+
50*5331Samw  *          |
51*5331Samw  *          |
52*5331Samw  *          v
53*5331Samw  * +-------------------+       +-------------------+      +-------------------+
54*5331Samw  * |       TREE        |<----->|       TREE        |......|       TREE        |
55*5331Samw  * +-------------------+       +-------------------+      +-------------------+
56*5331Samw  *      |         |
57*5331Samw  *      |         |
58*5331Samw  *      |         v
59*5331Samw  *      |     +-------+       +-------+      +-------+
60*5331Samw  *      |     | OFILE |<----->| OFILE |......| OFILE |
61*5331Samw  *      |     +-------+       +-------+      +-------+
62*5331Samw  *      |
63*5331Samw  *      |
64*5331Samw  *      v
65*5331Samw  *  +-------+       +------+      +------+
66*5331Samw  *  | ODIR  |<----->| ODIR |......| ODIR |
67*5331Samw  *  +-------+       +------+      +------+
68*5331Samw  *
69*5331Samw  *
70*5331Samw  * Odir State Machine
71*5331Samw  * ------------------
72*5331Samw  *
73*5331Samw  *    +-------------------------+	 T0
74*5331Samw  *    |  SMB_ODIR_STATE_OPEN   |<----------- Creation/Allocation
75*5331Samw  *    +-------------------------+
76*5331Samw  *		    |
77*5331Samw  *		    | T1
78*5331Samw  *		    |
79*5331Samw  *		    v
80*5331Samw  *    +-------------------------+
81*5331Samw  *    | SMB_ODIR_STATE_CLOSING |
82*5331Samw  *    +-------------------------+
83*5331Samw  *		    |
84*5331Samw  *		    | T2
85*5331Samw  *		    |
86*5331Samw  *		    v
87*5331Samw  *    +-------------------------+    T3
88*5331Samw  *    | SMB_ODIR_STATE_CLOSED  |----------> Deletion/Free
89*5331Samw  *    +-------------------------+
90*5331Samw  *
91*5331Samw  * SMB_ODIR_STATE_OPEN
92*5331Samw  *
93*5331Samw  *    While in this state:
94*5331Samw  *      - The odir is queued in the list of odirs of its tree.
95*5331Samw  *      - References will be given out if the odir is looked up.
96*5331Samw  *
97*5331Samw  * SMB_ODIR_STATE_CLOSING
98*5331Samw  *
99*5331Samw  *    While in this state:
100*5331Samw  *      - The odir is queued in the list of odirs of its tree.
101*5331Samw  *      - References will not be given out if the odir is looked up.
102*5331Samw  *      - The odir is closed.
103*5331Samw  *      - The resources associated with the odir remain.
104*5331Samw  *
105*5331Samw  * SMB_ODIR_STATE_CLOSED
106*5331Samw  *
107*5331Samw  *    While in this state:
108*5331Samw  *      - The odir is queued in the list of odirs of its tree.
109*5331Samw  *      - References will not be given out if the odir is looked up.
110*5331Samw  *      - The resources associated with the odir remain.
111*5331Samw  *
112*5331Samw  * Transition T0
113*5331Samw  *
114*5331Samw  *    This transition occurs in smb_odir_open(). A new odir is created and
115*5331Samw  *    added to the list of odirs of a tree.
116*5331Samw  *
117*5331Samw  * Transition T1
118*5331Samw  *
119*5331Samw  *    This transition occurs in smb_odir_close().
120*5331Samw  *
121*5331Samw  * Transition T2
122*5331Samw  *
123*5331Samw  *    This transition occurs in smb_odir_release(). The resources associated
124*5331Samw  *    with the odir are freed as well as the odir structure. For the
125*5331Samw  *    transition to occur, the odir must be in the SMB_ODIR_STATE_CLOSED
126*5331Samw  *    state and the reference count be zero.
127*5331Samw  *
128*5331Samw  * Comments
129*5331Samw  * --------
130*5331Samw  *
131*5331Samw  *    The state machine of the odir structures is controlled by 3 elements:
132*5331Samw  *      - The list of odirs of the tree it belongs to.
133*5331Samw  *      - The mutex embedded in the structure itself.
134*5331Samw  *      - The reference count.
135*5331Samw  *
136*5331Samw  *    There's a mutex embedded in the odir structure used to protect its fields
137*5331Samw  *    and there's a lock embedded in the list of odirs of a tree. To
138*5331Samw  *    increment or to decrement the reference count the mutex must be entered.
139*5331Samw  *    To insert the odir into the list of odirs of the tree and to remove
140*5331Samw  *    the odir from it, the lock must be entered in RW_WRITER mode.
141*5331Samw  *
142*5331Samw  *    Rules of access to a odir structure:
143*5331Samw  *
144*5331Samw  *    1) In order to avoid deadlocks, when both (mutex and lock of the odir
145*5331Samw  *       list) have to be entered, the lock must be entered first.
146*5331Samw  *
147*5331Samw  *    2) All actions applied to an odir require a reference count.
148*5331Samw  *
149*5331Samw  *    3) There are 2 ways of getting a reference count. One is when the odir
150*5331Samw  *       is opened. The other when the odir is looked up. This translates
151*5331Samw  *       into 2 functions: smb_odir_open() and smb_odir_lookup_by_fid().
152*5331Samw  *
153*5331Samw  *    It should be noted that the reference count of an odir registers the
154*5331Samw  *    number of references to the odir in other structures (such as an smb
155*5331Samw  *    request). The reference count is not incremented in these 2 instances:
156*5331Samw  *
157*5331Samw  *    1) The odir is open. An odir is anchored by his state. If there's
158*5331Samw  *       no activity involving an odir currently open, the reference count
159*5331Samw  *       of that odir is zero.
160*5331Samw  *
161*5331Samw  *    2) The odir is queued in the list of odirs of its tree. The fact of
162*5331Samw  *       being queued in that list is NOT registered by incrementing the
163*5331Samw  *       reference count.
164*5331Samw  */
165*5331Samw #include <smbsrv/smb_incl.h>
166*5331Samw #include <smbsrv/smb_kproto.h>
167*5331Samw #include <smbsrv/smb_fsops.h>
168*5331Samw 
169*5331Samw /* Static functions defined further down this file. */
170*5331Samw static void		smb_odir_delete(smb_odir_t *of);
171*5331Samw static smb_odir_t	*smb_odir_close_and_next(smb_odir_t *od);
172*5331Samw 
173*5331Samw #include <smbsrv/smb_incl.h>
174*5331Samw #include <smbsrv/smb_fsops.h>
175*5331Samw 
176*5331Samw /*
177*5331Samw  * smb_odir_open
178*5331Samw  */
179*5331Samw smb_odir_t *
180*5331Samw smb_odir_open(
181*5331Samw     smb_tree_t		*tree,
182*5331Samw     smb_node_t		*node,
183*5331Samw     char		*pattern,
184*5331Samw     uint16_t		pid,
185*5331Samw     unsigned short	sattr)
186*5331Samw {
187*5331Samw 	smb_odir_t	*dir;
188*5331Samw 
189*5331Samw 	ASSERT(tree);
190*5331Samw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
191*5331Samw 	ASSERT(node);
192*5331Samw 	ASSERT(node->n_magic == SMB_NODE_MAGIC);
193*5331Samw 	ASSERT(pattern);
194*5331Samw 
195*5331Samw 	if (strlen(pattern) >= sizeof (dir->d_pattern)) {
196*5331Samw 		return (NULL);
197*5331Samw 	}
198*5331Samw 
199*5331Samw 	dir = kmem_cache_alloc(smb_info.si_cache_odir, KM_SLEEP);
200*5331Samw 	bzero(dir, sizeof (smb_odir_t));
201*5331Samw 	dir->d_refcnt = 1;
202*5331Samw 	dir->d_session = tree->t_session;
203*5331Samw 	dir->d_user = tree->t_user;
204*5331Samw 	dir->d_tree = tree;
205*5331Samw 	(void) strlcpy(dir->d_pattern, pattern, sizeof (dir->d_pattern));
206*5331Samw 	dir->d_wildcards = smb_convert_unicode_wildcards(pattern);
207*5331Samw 	dir->d_state = SMB_ODIR_STATE_OPEN;
208*5331Samw 
209*5331Samw 	if (smb_idpool_alloc(&dir->d_tree->t_sid_pool, &dir->d_sid)) {
210*5331Samw 		kmem_cache_free(smb_info.si_cache_odir, dir);
211*5331Samw 		return (NULL);
212*5331Samw 	}
213*5331Samw 	mutex_init(&dir->d_mutex, NULL, MUTEX_DEFAULT, NULL);
214*5331Samw 	dir->d_sattr = sattr;
215*5331Samw 	dir->d_opened_by_pid = pid;
216*5331Samw 	dir->d_dir_snode = node;
217*5331Samw 	dir->d_state = SMB_ODIR_STATE_OPEN;
218*5331Samw 	dir->d_magic = SMB_ODIR_MAGIC;
219*5331Samw 
220*5331Samw 	smb_llist_enter(&tree->t_odir_list, RW_WRITER);
221*5331Samw 	smb_llist_insert_tail(&tree->t_odir_list, dir);
222*5331Samw 	smb_llist_exit(&tree->t_odir_list);
223*5331Samw 
224*5331Samw 	atomic_inc_32(&tree->t_session->s_dir_cnt);
225*5331Samw 	return (dir);
226*5331Samw }
227*5331Samw 
228*5331Samw /*
229*5331Samw  * smb_odir_close
230*5331Samw  */
231*5331Samw void
232*5331Samw smb_odir_close(
233*5331Samw     smb_odir_t		*od)
234*5331Samw {
235*5331Samw 	ASSERT(od);
236*5331Samw 	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
237*5331Samw 
238*5331Samw 	mutex_enter(&od->d_mutex);
239*5331Samw 	ASSERT(od->d_refcnt);
240*5331Samw 	switch (od->d_state) {
241*5331Samw 	case SMB_ODIR_STATE_OPEN:
242*5331Samw 		od->d_state = SMB_ODIR_STATE_CLOSED;
243*5331Samw 		break;
244*5331Samw 	case SMB_ODIR_STATE_CLOSING:
245*5331Samw 	case SMB_ODIR_STATE_CLOSED:
246*5331Samw 		break;
247*5331Samw 	default:
248*5331Samw 		ASSERT(0);
249*5331Samw 		break;
250*5331Samw 	}
251*5331Samw 	mutex_exit(&od->d_mutex);
252*5331Samw }
253*5331Samw 
254*5331Samw /*
255*5331Samw  * smb_odir_close_all
256*5331Samw  *
257*5331Samw  *
258*5331Samw  */
259*5331Samw void
260*5331Samw smb_odir_close_all(
261*5331Samw     smb_tree_t		*tree)
262*5331Samw {
263*5331Samw 	smb_odir_t	*od;
264*5331Samw 
265*5331Samw 	ASSERT(tree);
266*5331Samw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
267*5331Samw 
268*5331Samw 	smb_llist_enter(&tree->t_odir_list, RW_READER);
269*5331Samw 	od = smb_llist_head(&tree->t_odir_list);
270*5331Samw 	while (od) {
271*5331Samw 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
272*5331Samw 		ASSERT(od->d_tree == tree);
273*5331Samw 		od = smb_odir_close_and_next(od);
274*5331Samw 	}
275*5331Samw 	smb_llist_exit(&tree->t_odir_list);
276*5331Samw }
277*5331Samw 
278*5331Samw /*
279*5331Samw  * smb_odir_close_all_by_pid
280*5331Samw  *
281*5331Samw  *
282*5331Samw  */
283*5331Samw void
284*5331Samw smb_odir_close_all_by_pid(
285*5331Samw     smb_tree_t		*tree,
286*5331Samw     uint16_t		pid)
287*5331Samw {
288*5331Samw 	smb_odir_t	*od;
289*5331Samw 
290*5331Samw 	ASSERT(tree);
291*5331Samw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
292*5331Samw 
293*5331Samw 	smb_llist_enter(&tree->t_odir_list, RW_READER);
294*5331Samw 	od = smb_llist_head(&tree->t_odir_list);
295*5331Samw 	while (od) {
296*5331Samw 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
297*5331Samw 		ASSERT(od->d_tree == tree);
298*5331Samw 		if (od->d_opened_by_pid == pid) {
299*5331Samw 			od = smb_odir_close_and_next(od);
300*5331Samw 		} else {
301*5331Samw 			od = smb_llist_next(&tree->t_odir_list, od);
302*5331Samw 		}
303*5331Samw 	}
304*5331Samw 	smb_llist_exit(&tree->t_odir_list);
305*5331Samw }
306*5331Samw 
307*5331Samw /*
308*5331Samw  * smb_odir_release
309*5331Samw  */
310*5331Samw void
311*5331Samw smb_odir_release(
312*5331Samw     smb_odir_t	*od)
313*5331Samw {
314*5331Samw 	ASSERT(od);
315*5331Samw 	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
316*5331Samw 
317*5331Samw 	mutex_enter(&od->d_mutex);
318*5331Samw 	ASSERT(od->d_refcnt);
319*5331Samw 	od->d_refcnt--;
320*5331Samw 	switch (od->d_state) {
321*5331Samw 	case SMB_ODIR_STATE_CLOSING:
322*5331Samw 	case SMB_ODIR_STATE_OPEN:
323*5331Samw 		break;
324*5331Samw 
325*5331Samw 	case SMB_ODIR_STATE_CLOSED:
326*5331Samw 		if (od->d_refcnt == 0) {
327*5331Samw 			mutex_exit(&od->d_mutex);
328*5331Samw 			smb_odir_delete(od);
329*5331Samw 			return;
330*5331Samw 		}
331*5331Samw 		break;
332*5331Samw 
333*5331Samw 	default:
334*5331Samw 		ASSERT(0);
335*5331Samw 		break;
336*5331Samw 	}
337*5331Samw 	mutex_exit(&od->d_mutex);
338*5331Samw }
339*5331Samw 
340*5331Samw /*
341*5331Samw  * smb_odir_lookup_by_sid
342*5331Samw  */
343*5331Samw smb_odir_t *
344*5331Samw smb_odir_lookup_by_sid(
345*5331Samw 	smb_tree_t	*tree,
346*5331Samw 	uint16_t	sid)
347*5331Samw {
348*5331Samw 	smb_llist_t	*od_list;
349*5331Samw 	smb_odir_t	*od;
350*5331Samw 
351*5331Samw 	ASSERT(tree);
352*5331Samw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
353*5331Samw 
354*5331Samw 	od_list = &tree->t_odir_list;
355*5331Samw 
356*5331Samw 	smb_llist_enter(od_list, RW_READER);
357*5331Samw 	od = smb_llist_head(od_list);
358*5331Samw 	while (od) {
359*5331Samw 		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
360*5331Samw 		ASSERT(od->d_tree == tree);
361*5331Samw 		if (od->d_sid == sid) {
362*5331Samw 			mutex_enter(&od->d_mutex);
363*5331Samw 			if (od->d_state != SMB_ODIR_STATE_OPEN) {
364*5331Samw 				mutex_exit(&od->d_mutex);
365*5331Samw 				smb_llist_exit(od_list);
366*5331Samw 				return (NULL);
367*5331Samw 			}
368*5331Samw 			od->d_refcnt++;
369*5331Samw 			mutex_exit(&od->d_mutex);
370*5331Samw 			break;
371*5331Samw 		}
372*5331Samw 		od = smb_llist_next(od_list, od);
373*5331Samw 	}
374*5331Samw 	smb_llist_exit(od_list);
375*5331Samw 	return (od);
376*5331Samw }
377*5331Samw 
378*5331Samw /* *************************** Static Functions ***************************** */
379*5331Samw 
380*5331Samw /*
381*5331Samw  * smb_odir_close_and_next
382*5331Samw  *
383*5331Samw  * This function closes the directory passed in (if appropriate) and returns the
384*5331Samw  * next directory in the list of directories of the tree of the directory passed
385*5331Samw  * in. It requires that the list of directories of the tree be entered in
386*5331Samw  * RW_READER mode before being called.
387*5331Samw  */
388*5331Samw static smb_odir_t *
389*5331Samw smb_odir_close_and_next(
390*5331Samw     smb_odir_t		*od)
391*5331Samw {
392*5331Samw 	smb_odir_t	*next_od;
393*5331Samw 	smb_tree_t	*tree;
394*5331Samw 
395*5331Samw 	ASSERT(od);
396*5331Samw 	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
397*5331Samw 
398*5331Samw 	mutex_enter(&od->d_mutex);
399*5331Samw 	switch (od->d_state) {
400*5331Samw 	case SMB_ODIR_STATE_OPEN:
401*5331Samw 		/* The directory is still opened. */
402*5331Samw 		od->d_refcnt++;
403*5331Samw 		ASSERT(od->d_refcnt);
404*5331Samw 		tree = od->d_tree;
405*5331Samw 		mutex_exit(&od->d_mutex);
406*5331Samw 		smb_llist_exit(&od->d_tree->t_odir_list);
407*5331Samw 		smb_odir_close(od);
408*5331Samw 		smb_odir_release(od);
409*5331Samw 		smb_llist_enter(&tree->t_odir_list, RW_READER);
410*5331Samw 		next_od = smb_llist_head(&tree->t_odir_list);
411*5331Samw 		break;
412*5331Samw 	case SMB_ODIR_STATE_CLOSING:
413*5331Samw 	case SMB_ODIR_STATE_CLOSED:
414*5331Samw 		/*
415*5331Samw 		 * The odir exists but is closed or is in the process
416*5331Samw 		 * of being closed.
417*5331Samw 		 */
418*5331Samw 		mutex_exit(&od->d_mutex);
419*5331Samw 		next_od = smb_llist_next(&od->d_tree->t_odir_list, od);
420*5331Samw 		break;
421*5331Samw 	default:
422*5331Samw 		ASSERT(0);
423*5331Samw 		mutex_exit(&od->d_mutex);
424*5331Samw 		next_od = smb_llist_next(&od->d_tree->t_odir_list, od);
425*5331Samw 		break;
426*5331Samw 	}
427*5331Samw 	return (next_od);
428*5331Samw }
429*5331Samw 
430*5331Samw /*
431*5331Samw  * smb_odir_delete
432*5331Samw  */
433*5331Samw static void
434*5331Samw smb_odir_delete(
435*5331Samw     smb_odir_t		*od)
436*5331Samw {
437*5331Samw 	ASSERT(od);
438*5331Samw 	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
439*5331Samw 	ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED);
440*5331Samw 	ASSERT(od->d_refcnt == 0);
441*5331Samw 
442*5331Samw 	/*
443*5331Samw 	 * Let's remove the odir from the list of odirs of the tree. This has
444*5331Samw 	 * to be done before any resources associated with the odir are
445*5331Samw 	 * released.
446*5331Samw 	 */
447*5331Samw 	smb_llist_enter(&od->d_tree->t_odir_list, RW_WRITER);
448*5331Samw 	smb_llist_remove(&od->d_tree->t_odir_list, od);
449*5331Samw 	smb_llist_exit(&od->d_tree->t_odir_list);
450*5331Samw 
451*5331Samw 	smb_node_release(od->d_dir_snode);
452*5331Samw 	atomic_dec_32(&od->d_tree->t_session->s_dir_cnt);
453*5331Samw 	smb_idpool_free(&od->d_tree->t_sid_pool, od->d_sid);
454*5331Samw 	mutex_destroy(&od->d_mutex);
455*5331Samw 	kmem_cache_free(smb_info.si_cache_odir, od);
456*5331Samw }
457