xref: /titanic_52/usr/src/uts/common/io/ib/clients/of/sol_ofs/sol_uobj.c (revision c39526b769298791ff5b0b6c5e761f49aabaeb4e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * User Objects.
28  *
29  * User objects are used to manage and protect resources that
30  * have been created for a user context.  Each user object
31  * maintains a reference count and a read/write mutex to
32  * provide the appropriate access to the object depending
33  * on the operation at hand.
34  *
35  * For example when initializing or creating a PD user object,
36  * the active context would hold a write lock, but to simply
37  * reference the PD object as in a CQ create operation, a
38  * read lock is only required.
39  *
40  * Each user object also maintains a "live" flag.  If this flag
41  * is not set, then lookups on this user object will fail
42  * even if it still resides in the associated user object
43  * management table.  This specifically handles the case
44  * where a get operation blocks and does not acquire the lock
45  * until after the object has been destroyed (but not yet
46  * released).  Destroy operations set the "live" flag to 0
47  * prior to dropping their write lock on the user object.
48  * This allows the reader to realize when it receives the
49  * lock that the object has been destroyed so it can then
50  * release it's reference to the user object, and allow it to
51  * be freed (the storage will not be freed until the last reference
52  * is released).
53  */
54 #include	<sys/debug.h>
55 #include	<sys/kmem.h>
56 #include	<sys/sunddi.h>
57 #include	<sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
58 
59 extern char	*sol_ofs_dbg_str;
60 static sol_ofs_uobj_t *ofs_uobj_find(sol_ofs_uobj_table_t *,
61     uint_t, int);
62 
63 /*
64  * Function:
65  *	sol_ofs_uobj_tbl_init
66  * Input:
67  *	uo_tbl	- A pointer to the user object resource management table
68  *		  to initialize.
69  * Output:
70  *	None
71  * Returns:
72  *	None
73  * Description:
74  * 	Initializes the specified user object resource managment table.
75  */
76 void
77 sol_ofs_uobj_tbl_init(sol_ofs_uobj_table_t *uo_tbl, size_t uobj_sz)
78 {
79 	ASSERT(uo_tbl != NULL);
80 
81 	rw_init(&uo_tbl->uobj_tbl_lock, NULL, RW_DRIVER, NULL);
82 	uo_tbl->uobj_tbl_used_blks = 0;
83 	uo_tbl->uobj_tbl_num_blks = 0;
84 	uo_tbl->uobj_tbl_uo_cnt = 0;
85 	uo_tbl->uobj_tbl_uo_sz = uobj_sz;
86 	uo_tbl->uobj_tbl_uo_root = NULL;
87 }
88 
89 /*
90  * Function:
91  *	sol_ofs_uobj_tbl_fini
92  * Input:
93  *	uo_tbl	- A pointer to the user object resource management table
94  *		  to be released.
95  * Output:
96  *	None
97  * Returns:
98  *	None
99  * Description:
100  * 	Releases any resources held by the specified user object resource
101  *	managment table.  The table is no longer valid upon return. NOTE:
102  *	the table should be empty when this routine is called, so this
103  *	really is more of just a sanity check.
104  */
105 void
106 sol_ofs_uobj_tbl_fini(sol_ofs_uobj_table_t *uo_tbl)
107 {
108 	int			i, j;
109 	uint32_t	size;
110 	sol_ofs_uobj_blk_t	*blk;
111 
112 	ASSERT(uo_tbl != NULL);
113 
114 	rw_enter(&uo_tbl->uobj_tbl_lock, RW_WRITER);
115 
116 	if (uo_tbl->uobj_tbl_uo_cnt > 0) {
117 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
118 		    "UOBJ TBL FINI: object count not zero (cnt=%d)",
119 		    uo_tbl->uobj_tbl_uo_cnt);
120 	}
121 
122 	/*
123 	 * Go through the roots looking for blocks to free.  Warn if any
124 	 * our found (there shouldn't be any).
125 	 */
126 	for (i = 0; i < uo_tbl->uobj_tbl_used_blks; i++) {
127 		blk = uo_tbl->uobj_tbl_uo_root[i];
128 		if (!blk) {
129 			continue;
130 		}
131 		for (j = 0; j < SOL_OFS_UO_BLKSZ; j++) {
132 			if (blk->ofs_uoblk_blks[j])   {
133 				/*
134 				 * This is an error, we may want to free
135 				 * ultimately sol_ofs_uobj_free
136 				 * (blk->ofs_uoblk_blks[j]);
137 				 */
138 				SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
139 				    "UOBJ TBL FINI: blk %p, slot %d non null",
140 				    blk, j);
141 			}
142 		}
143 		kmem_free(blk, sizeof (*blk));
144 	}
145 
146 	if (uo_tbl->uobj_tbl_uo_root) {
147 
148 		size = uo_tbl->uobj_tbl_num_blks *
149 		    sizeof (sol_ofs_uobj_blk_t *);
150 		kmem_free(uo_tbl->uobj_tbl_uo_root, size);
151 	}
152 
153 	rw_exit(&uo_tbl->uobj_tbl_lock);
154 	rw_destroy(&uo_tbl->uobj_tbl_lock);
155 }
156 
157 /*
158  * Function:
159  *	uverbs_uob_init
160  * Input:
161  * 	uobj        - Pointer to the user object to initialize.
162  *	user_handle - A user space handle to associates with the object.
163  *	              Generally used to identify object in asynchronous
164  *	              notifications.
165  *	uob_type   - The type of user object.
166  * Ouput:
167  *	uobj       - Initialized user object.
168  * Returns:
169  * 	None
170  * Description:
171  *	Initialize a new user object.  The object will have one reference
172  *	placed on it.
173  */
174 void
175 sol_ofs_uobj_init(sol_ofs_uobj_t *uobj,
176     uint64_t user_handle, sol_ofs_uobj_type_t  uobj_type)
177 {
178 	uobj->uo_user_handle = user_handle;
179 	uobj->uo_refcnt = 1;
180 	uobj->uo_type = uobj_type;
181 	uobj->uo_id = -1;
182 	uobj->uo_live = 0;
183 	rw_init(&uobj->uo_lock, NULL, RW_DRIVER, NULL);
184 	mutex_init(&uobj->uo_reflock, NULL, MUTEX_DRIVER, NULL);
185 }
186 
187 /*
188  * Function:
189  *	ofs_uobj_fini
190  * Input:
191  * 	uobj        - Pointer to the user object to be cleaned up.
192  * Ouput:
193  *	None
194  * Returns:
195  * 	None
196  * Description:
197  *	Performs user object cleanup prior to releasing memory.
198  */
199 static void
200 ofs_uobj_fini(sol_ofs_uobj_t *uobj)
201 {
202 	rw_destroy(&uobj->uo_lock);
203 	mutex_destroy(&uobj->uo_reflock);
204 }
205 
206 /*
207  * Function:
208  *	sol_ofs_uobj_ref
209  * Input:
210  * 	uobj        - Pointer to the user object
211  * Ouput:
212  *	None
213  * Returns:
214  * 	None
215  * Description:
216  *	Place a reference on the specified user object.
217  */
218 void
219 sol_ofs_uobj_ref(sol_ofs_uobj_t *uobj)
220 {
221 	mutex_enter(&uobj->uo_reflock);
222 	uobj->uo_refcnt++;
223 	ASSERT(uobj->uo_refcnt != 0);
224 	mutex_exit(&uobj->uo_reflock);
225 }
226 
227 /*
228  * Function:
229  *	sol_ofs_uobj_deref
230  * Input:
231  * 	uobj        - Pointer to the user object
232  *	free_func   - Pointer to release function, called if the
233  *                    last reference is removed for the user object.
234  * Ouput:
235  *	None
236  * Returns:
237  * 	None
238  * Description:
239  *	Remove a reference to a user object.  If a free function
240  *	was specified and the last reference is released, then the
241  *	free function is invoked to release the user object.
242  */
243 void
244 sol_ofs_uobj_deref(sol_ofs_uobj_t *uobj,
245     void (*free_func)(sol_ofs_uobj_t *uobj))
246 {
247 	SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str, "UOBJ_DEREF: uobj = %p, "
248 	    "refcnt=%d", uobj, uobj->uo_refcnt);
249 
250 	mutex_enter(&uobj->uo_reflock);
251 
252 	ASSERT(uobj->uo_refcnt != 0);
253 	uobj->uo_refcnt--;
254 	if (uobj->uo_refcnt == 0) {
255 		mutex_exit(&uobj->uo_reflock);
256 		if (free_func)
257 			free_func(uobj);
258 	} else {
259 		mutex_exit(&uobj->uo_reflock);
260 	}
261 }
262 
263 /*
264  * Function:
265  *	sol_ofs_uobj_add
266  * Input:
267  *	uo_tbl	- A pointer to the user object resource management table
268  *		  to which the object should be added.
269  *	uobj    - A pointer ot the user object to be added; a reference
270  *	          should exist on this object prior to addition, and the
271  *		  object should be removed prior to all references being
272  *		  removed.
273  * Output:
274  *	uobj	- The user object "uo_id" is updated and should be
275  *		  used in subsequent lookup operations.
276  * Returns:
277  *	DDI_SUCCESS on success, else error code.
278  * Description:
279  * 	Add a user object to the specified user object resource management
280  *	table.
281  *
282  */
283 int
284 sol_ofs_uobj_add(sol_ofs_uobj_table_t *uo_tbl, sol_ofs_uobj_t *uobj)
285 {
286 	int		i, j, empty = -1;
287 	sol_ofs_uobj_blk_t	*blk;
288 
289 	rw_enter(&uo_tbl->uobj_tbl_lock, RW_WRITER);
290 
291 	/*
292 	 * Try to find an empty slot for the new user object.
293 	 */
294 	for (i = 0; i < uo_tbl->uobj_tbl_used_blks; i++) {
295 		blk = uo_tbl->uobj_tbl_uo_root[i];
296 		if (blk != NULL && blk->ofs_uo_blk_avail > 0) {
297 			SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str,
298 			    "UOBJ ADD: table:%p, available blks:%d",
299 			    uo_tbl, blk->ofs_uo_blk_avail);
300 			for (j = 0; j < SOL_OFS_UO_BLKSZ; j++) {
301 				if (blk->ofs_uoblk_blks[j] == NULL) {
302 					blk->ofs_uoblk_blks[j] = uobj;
303 					uobj->uo_id = j + (i *
304 					    SOL_OFS_UO_BLKSZ);
305 					uobj->uo_uobj_sz =
306 					    uo_tbl->uobj_tbl_uo_sz;
307 					blk->ofs_uo_blk_avail--;
308 					uo_tbl->uobj_tbl_uo_cnt++;
309 					goto obj_added;
310 				}
311 			}
312 		} else if (blk == NULL && empty < 0) {
313 			/*
314 			 * Remember the first empty blk we came across.
315 			 */
316 			empty = i;
317 		}
318 	}
319 
320 	/*
321 	 * No entries were available, we must allocate a new block.  If we did
322 	 * not find a empty block available, then we must allocate/reallocate
323 	 * the root array (copying any existing blk pointers to it).
324 	 */
325 	if (empty < 0) {
326 		if (uo_tbl->uobj_tbl_used_blks == uo_tbl->uobj_tbl_num_blks) {
327 			sol_ofs_uobj_blk_t	**p;
328 			uint_t		newsz;
329 
330 			newsz = uo_tbl->uobj_tbl_num_blks + SOL_OFS_UO_BLKSZ;
331 			SOL_OFS_DPRINTF_L5(sol_ofs_dbg_str,
332 			    "UOBJ ADD: Increasing uobj table size to %d",
333 			    newsz);
334 
335 			p = kmem_zalloc(newsz * sizeof (*p), KM_NOSLEEP);
336 			if (!p) {
337 				SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
338 				    "UOBJ ADD: Mem alloc fail\n");
339 				rw_exit(&uo_tbl->uobj_tbl_lock);
340 				return (1);
341 			}
342 
343 			if (uo_tbl->uobj_tbl_uo_root) {
344 				uint_t	oldsz;
345 
346 				oldsz = (uint_t)uo_tbl->uobj_tbl_num_blks *
347 				    (int)(sizeof (*p));
348 				bcopy(uo_tbl->uobj_tbl_uo_root, p, oldsz);
349 				kmem_free(uo_tbl->uobj_tbl_uo_root, oldsz);
350 			}
351 			uo_tbl->uobj_tbl_uo_root = p;
352 			uo_tbl->uobj_tbl_num_blks = newsz;
353 		}
354 		empty = uo_tbl->uobj_tbl_used_blks;
355 		uo_tbl->uobj_tbl_used_blks++;
356 	}
357 
358 	/*
359 	 * There are enough free block pointers in the root, allocate
360 	 * a new block.
361 	 */
362 	blk = kmem_zalloc(sizeof (*blk), KM_NOSLEEP);
363 	if (!blk) {
364 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
365 		    "UOBJ ADD: Mem alloc fail\n");
366 		rw_exit(&uo_tbl->uobj_tbl_lock);
367 		return (1);
368 	}
369 	ASSERT(uo_tbl->uobj_tbl_uo_root[empty] == NULL);
370 	uo_tbl->uobj_tbl_uo_root[empty] = blk;
371 	blk->ofs_uo_blk_avail = SOL_OFS_UO_BLKSZ - 1;
372 
373 	/*
374 	 * Use the first slot in this new block to add the new user object.
375 	 */
376 	uobj->uo_id = empty * SOL_OFS_UO_BLKSZ;
377 	blk->ofs_uoblk_blks[0] = uobj;
378 	uobj->uo_uobj_sz = uo_tbl->uobj_tbl_uo_sz;
379 	uo_tbl->uobj_tbl_uo_cnt++;
380 
381 obj_added:
382 	rw_exit(&uo_tbl->uobj_tbl_lock);
383 	return (0);
384 }
385 
386 /*
387  * Function:
388  *	sol_ofs_uobj_remove
389  * Input:
390  *	uo_tbl	- A pointer to the user object resource management table
391  *		  from which the object should be removed.
392  *	uobj    - A pointer ot the user object to be removed.
393  * Output:
394  *	None
395  * Returns:
396  *	A pointer to the user object that was removed on success, otherwise
397  *	NULL.
398  * Description:
399  * 	Remove a user object from the specified user resource management
400  *	table.
401  *
402  *	The uobj uo_lock must be held as a writer before calling this.
403  */
404 sol_ofs_uobj_t *
405 sol_ofs_uobj_remove(sol_ofs_uobj_table_t *uo_tbl, sol_ofs_uobj_t *uobj)
406 {
407 	uint_t			i, j;
408 	sol_ofs_uobj_blk_t	*blk;
409 	sol_ofs_uobj_t		*p;
410 
411 	ASSERT(uo_tbl != NULL);
412 	ASSERT(uobj != NULL);
413 
414 	p = NULL;
415 	rw_enter(&uo_tbl->uobj_tbl_lock, RW_WRITER);
416 
417 	if (!uobj->uo_live) {
418 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
419 		    "UOBJ REMOVE: object 0x%P, already removed", (void *)uobj);
420 		goto remove_done;
421 	}
422 
423 	if ((uo_tbl->uobj_tbl_uo_cnt == 0) || !(uo_tbl->uobj_tbl_uo_root)) {
424 		/*
425 		 * The table is empty, just return not found
426 		 * Don't panic, userland app could have double free'd
427 		 * let them deal with it.
428 		 */
429 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
430 		    "UOBJ REMOVE: table 0x%P empty", (void *)uo_tbl);
431 		goto remove_done;
432 	}
433 
434 	i = uobj->uo_id / SOL_OFS_UO_BLKSZ;
435 	j = uobj->uo_id % SOL_OFS_UO_BLKSZ;
436 
437 	if (i >= uo_tbl->uobj_tbl_used_blks) {
438 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
439 		    "UOBJ REMOVE: object id %d exceeds table size",
440 		    uobj->uo_id);
441 		goto remove_done;
442 	}
443 
444 	ASSERT(i < uo_tbl->uobj_tbl_num_blks);
445 
446 	blk = uo_tbl->uobj_tbl_uo_root[i];
447 	if (blk == NULL) {
448 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
449 		    "UOBJ REMOVE: object id %d points to invalid root",
450 		    uobj->uo_id);
451 		goto remove_done;
452 	}
453 
454 	if (blk->ofs_uoblk_blks[j] == NULL) {
455 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
456 		    "UOBJ REMOVE: object id %d points to invalid block",
457 		    uobj->uo_id);
458 		goto remove_done;
459 	}
460 
461 	/*
462 	 * Mark as dead
463 	 */
464 	uobj->uo_live = 0;
465 
466 	p = blk->ofs_uoblk_blks[j];
467 	blk->ofs_uoblk_blks[j] = NULL;
468 	blk->ofs_uo_blk_avail++;
469 	if (blk->ofs_uo_blk_avail == SOL_OFS_UO_BLKSZ) {
470 		kmem_free(blk, sizeof (*blk));
471 		uo_tbl->uobj_tbl_uo_root[i] = NULL;
472 	}
473 	uo_tbl->uobj_tbl_uo_cnt--;
474 
475 remove_done:
476 	rw_exit(&uo_tbl->uobj_tbl_lock);
477 	return (p);
478 }
479 
480 /*
481  * Function:
482  *	ofs_uobj_find
483  * Input:
484  *	uo_tbl	- A pointer to the user object resource management table
485  *		  to be used for the lookup.
486  *	uo_id	- The user object ID to lookup.  This ID was set when
487  *		  the object was added to the resource management table.
488  *	add_ref	- A non zero value indicates that the user objects reference
489  *		  count should be updated to reflect and additional
490  *		  reference before it is returned.
491  * Output:
492  *	None
493  * Returns:
494  *	A pointer to the user object associated with the uo_id if found,
495  *	otherwise NULL.
496  * Description:
497  * 	Lookup and return a user object from the specified user resource
498  *	management table.
499  */
500 static sol_ofs_uobj_t *
501 ofs_uobj_find(sol_ofs_uobj_table_t *uo_tbl, uint32_t uo_id, int add_ref)
502 {
503 	uint32_t		i, j;
504 	sol_ofs_uobj_blk_t	*blk;
505 	sol_ofs_uobj_t		*uobj;
506 
507 	ASSERT(uo_tbl != NULL);
508 	uobj = NULL;
509 
510 	rw_enter(&uo_tbl->uobj_tbl_lock, RW_READER);
511 
512 	if ((uo_tbl->uobj_tbl_uo_cnt == 0) || !(uo_tbl->uobj_tbl_uo_root)) {
513 		/*
514 		 * The table is empty, just return not found
515 		 * Don't panic, userland app could have double free'd
516 		 * let them deal with it.
517 		 */
518 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
519 		    "UOBJ FIND: id %d in tbl 0x%P - tbl empty", uo_id,
520 		    (void *)uo_tbl);
521 		goto find_done;
522 	}
523 
524 	i = uo_id / SOL_OFS_UO_BLKSZ;
525 	j = uo_id % SOL_OFS_UO_BLKSZ;
526 
527 	if (i >= uo_tbl->uobj_tbl_used_blks) {
528 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
529 		    "UOBJ FIND: Index not valid, %d", uo_id);
530 		goto find_done;
531 	}
532 
533 	/*
534 	 * Get the user object, and if valid perform a get (ref++).
535 	 * The caller issuing the find, must release the reference
536 	 * when done.
537 	 */
538 	blk = uo_tbl->uobj_tbl_uo_root[i];
539 	if (blk != NULL) {
540 		ASSERT(i < uo_tbl->uobj_tbl_num_blks);
541 
542 		uobj = blk->ofs_uoblk_blks[j];
543 
544 		if (uobj == NULL) {
545 			SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
546 			    "UOBJ FIND: Index %d not found, blk = %p",
547 			    uo_id, blk->ofs_uoblk_blks[j]);
548 		} else if (add_ref) {
549 			sol_ofs_uobj_ref(uobj);
550 		}
551 	} else {
552 		SOL_OFS_DPRINTF_L2(sol_ofs_dbg_str,
553 		    "UOBJ FIND: Uobject not found, %d", uo_id);
554 		goto find_done;
555 	}
556 
557 find_done:
558 	rw_exit(&uo_tbl->uobj_tbl_lock);
559 	return (uobj);
560 }
561 
562 /*
563  * Function:
564  *	sol_ofs_uobj_get_read
565  * Input:
566  *	tbl         - Pointer to the user object managment table to
567  *	              be used in the lookup.
568  *	uo_id       - The ID to object mapping, assigned to the user
569  *	              object at addition to the table.
570  * Ouput:
571  *	None
572  * Returns:
573  * 	A pointer to the user object associated with uo_id or NULL
574  *      if the entry does not exist.
575  * Description:
576  *	Lookup a user object and place a reference on it.  Acquires
577  *	the object with a READ lock.  The reference and lock should
578  *	be released using the sol_ofs_uobj_put() call.
579  */
580 sol_ofs_uobj_t *
581 sol_ofs_uobj_get_read(sol_ofs_uobj_table_t *tbl, uint32_t uo_id)
582 {
583 	sol_ofs_uobj_t *uobj;
584 
585 	uobj = ofs_uobj_find(tbl, uo_id, 1);
586 	if (!uobj)
587 		return (NULL);
588 
589 	rw_enter(&uobj->uo_lock, RW_READER);
590 
591 	/*
592 	 * If object was destroyed before we got the lock, just release
593 	 * our reference and indicate we didn't find the object.
594 	 */
595 	if (!uobj->uo_live) {
596 		sol_ofs_uobj_put(uobj);
597 		return (NULL);
598 	}
599 	return (uobj);
600 }
601 
602 /*
603  * Function:
604  *	sol_ofs_uobj_get_write
605  * Input:
606  *	tbl         - Pointer to the user object managment table to
607  *	              be used in the lookup.
608  *	uo_id       - The ID to object mapping, assigned to the user
609  *	              object at addition to the table.
610  * Ouput:
611  *	None
612  * Returns:
613  * 	A pointer to the user object associated with uo_id or NULL
614  *      if the entry does not exist.
615  * Description:
616  *	Lookup a user object and place a reference on it.  Acquires
617  *	the object with a WRITE lock.  The reference and lock should
618  *	be released using the sol_ofs_uobj_put() call.
619  */
620 sol_ofs_uobj_t *
621 sol_ofs_uobj_get_write(sol_ofs_uobj_table_t *tbl, uint32_t uo_id)
622 {
623 	sol_ofs_uobj_t *uobj;
624 
625 
626 	uobj = ofs_uobj_find(tbl, uo_id, 1);
627 	if (!uobj)
628 		return (NULL);
629 
630 	rw_enter(&uobj->uo_lock, RW_WRITER);
631 
632 	/*
633 	 * If object was destroyed before we got the lock, just release
634 	 * our reference and indicate we didn't find the object.
635 	 */
636 	if (!uobj->uo_live) {
637 		sol_ofs_uobj_put(uobj);
638 		return (NULL);
639 	}
640 	return (uobj);
641 }
642 
643 /*
644  * Function:
645  *	sol_ofs_uobj_free
646  * Input:
647  *	uobj	-  A pointer to the Solaris User Verbs kernel agent user
648  *	           object to be freed.
649  * Output:
650  *	None.
651  * Returns:
652  *	None.
653  * Description:
654  * 	Called when the user object is no longer referenced, it will release
655  *	any user object resources and free the container object memory.
656  *	NOTE: Currently there is a stipulation that the user object be the
657  *	first element of any user object specialization.
658  */
659 void
660 sol_ofs_uobj_free(sol_ofs_uobj_t *uobj)
661 {
662 	size_t	sz;
663 
664 	ASSERT(uobj);
665 
666 	/*
667 	 * Cleanup common user object and then free memory using
668 	 * length based on associated object type.
669 	 */
670 	ofs_uobj_fini(uobj);
671 
672 	sz = uobj->uo_uobj_sz;
673 	if (sz)
674 		kmem_free(uobj, sz);
675 }
676 
677 /*
678  * Function:
679  *	sol_ofs_uobj_put
680  * Input:
681  * 	uobj        - Pointer to the user object
682  * Ouput:
683  *	None
684  * Returns:
685  * 	None
686  * Description:
687  *	Remove a lock associated with a user object, and decrement
688  *	the reference held. On the last deference the user object
689  *	will be freed.
690  */
691 void
692 sol_ofs_uobj_put(sol_ofs_uobj_t *uobj)
693 {
694 	rw_exit(&uobj->uo_lock);
695 	sol_ofs_uobj_deref(uobj, sol_ofs_uobj_free);
696 }
697