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
sol_ofs_uobj_tbl_init(sol_ofs_uobj_table_t * uo_tbl,size_t uobj_sz)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
sol_ofs_uobj_tbl_fini(sol_ofs_uobj_table_t * uo_tbl)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
sol_ofs_uobj_init(sol_ofs_uobj_t * uobj,uint64_t user_handle,sol_ofs_uobj_type_t uobj_type)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
ofs_uobj_fini(sol_ofs_uobj_t * uobj)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
sol_ofs_uobj_ref(sol_ofs_uobj_t * uobj)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
sol_ofs_uobj_deref(sol_ofs_uobj_t * uobj,void (* free_func)(sol_ofs_uobj_t * uobj))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
sol_ofs_uobj_add(sol_ofs_uobj_table_t * uo_tbl,sol_ofs_uobj_t * uobj)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 *
sol_ofs_uobj_remove(sol_ofs_uobj_table_t * uo_tbl,sol_ofs_uobj_t * uobj)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 *
ofs_uobj_find(sol_ofs_uobj_table_t * uo_tbl,uint32_t uo_id,int add_ref)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 *
sol_ofs_uobj_get_read(sol_ofs_uobj_table_t * tbl,uint32_t uo_id)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 *
sol_ofs_uobj_get_write(sol_ofs_uobj_table_t * tbl,uint32_t uo_id)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
sol_ofs_uobj_free(sol_ofs_uobj_t * uobj)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
sol_ofs_uobj_put(sol_ofs_uobj_t * uobj)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