sol_uobj.c revision c39526b769298791ff5b0b6c5e761f49aabaeb4e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* User Objects.
*
* User objects are used to manage and protect resources that
* have been created for a user context. Each user object
* provide the appropriate access to the object depending
* on the operation at hand.
*
* For example when initializing or creating a PD user object,
* the active context would hold a write lock, but to simply
* reference the PD object as in a CQ create operation, a
* read lock is only required.
*
* Each user object also maintains a "live" flag. If this flag
* is not set, then lookups on this user object will fail
* even if it still resides in the associated user object
* management table. This specifically handles the case
* where a get operation blocks and does not acquire the lock
* until after the object has been destroyed (but not yet
* released). Destroy operations set the "live" flag to 0
* prior to dropping their write lock on the user object.
* This allows the reader to realize when it receives the
* lock that the object has been destroyed so it can then
* release it's reference to the user object, and allow it to
* be freed (the storage will not be freed until the last reference
* is released).
*/
extern char *sol_ofs_dbg_str;
uint_t, int);
/*
* Function:
* sol_ofs_uobj_tbl_init
* Input:
* uo_tbl - A pointer to the user object resource management table
* to initialize.
* Output:
* None
* Returns:
* None
* Description:
* Initializes the specified user object resource managment table.
*/
void
{
uo_tbl->uobj_tbl_used_blks = 0;
uo_tbl->uobj_tbl_num_blks = 0;
uo_tbl->uobj_tbl_uo_cnt = 0;
}
/*
* Function:
* sol_ofs_uobj_tbl_fini
* Input:
* uo_tbl - A pointer to the user object resource management table
* to be released.
* Output:
* None
* Returns:
* None
* Description:
* Releases any resources held by the specified user object resource
* managment table. The table is no longer valid upon return. NOTE:
* the table should be empty when this routine is called, so this
* really is more of just a sanity check.
*/
void
{
int i, j;
if (uo_tbl->uobj_tbl_uo_cnt > 0) {
"UOBJ TBL FINI: object count not zero (cnt=%d)",
}
/*
* Go through the roots looking for blocks to free. Warn if any
* our found (there shouldn't be any).
*/
for (i = 0; i < uo_tbl->uobj_tbl_used_blks; i++) {
if (!blk) {
continue;
}
for (j = 0; j < SOL_OFS_UO_BLKSZ; j++) {
if (blk->ofs_uoblk_blks[j]) {
/*
* This is an error, we may want to free
* ultimately sol_ofs_uobj_free
* (blk->ofs_uoblk_blks[j]);
*/
"UOBJ TBL FINI: blk %p, slot %d non null",
blk, j);
}
}
}
if (uo_tbl->uobj_tbl_uo_root) {
sizeof (sol_ofs_uobj_blk_t *);
}
}
/*
* Function:
* uverbs_uob_init
* Input:
* uobj - Pointer to the user object to initialize.
* user_handle - A user space handle to associates with the object.
* Generally used to identify object in asynchronous
* notifications.
* uob_type - The type of user object.
* Ouput:
* uobj - Initialized user object.
* Returns:
* None
* Description:
* Initialize a new user object. The object will have one reference
* placed on it.
*/
void
{
}
/*
* Function:
* ofs_uobj_fini
* Input:
* uobj - Pointer to the user object to be cleaned up.
* Ouput:
* None
* Returns:
* None
* Description:
* Performs user object cleanup prior to releasing memory.
*/
static void
{
}
/*
* Function:
* sol_ofs_uobj_ref
* Input:
* uobj - Pointer to the user object
* Ouput:
* None
* Returns:
* None
* Description:
* Place a reference on the specified user object.
*/
void
{
}
/*
* Function:
* sol_ofs_uobj_deref
* Input:
* uobj - Pointer to the user object
* free_func - Pointer to release function, called if the
* last reference is removed for the user object.
* Ouput:
* None
* Returns:
* None
* Description:
* Remove a reference to a user object. If a free function
* was specified and the last reference is released, then the
* free function is invoked to release the user object.
*/
void
{
if (free_func)
} else {
}
}
/*
* Function:
* sol_ofs_uobj_add
* Input:
* uo_tbl - A pointer to the user object resource management table
* to which the object should be added.
* uobj - A pointer ot the user object to be added; a reference
* should exist on this object prior to addition, and the
* object should be removed prior to all references being
* removed.
* Output:
* uobj - The user object "uo_id" is updated and should be
* used in subsequent lookup operations.
* Returns:
* DDI_SUCCESS on success, else error code.
* Description:
* Add a user object to the specified user object resource management
* table.
*
*/
int
{
int i, j, empty = -1;
/*
* Try to find an empty slot for the new user object.
*/
for (i = 0; i < uo_tbl->uobj_tbl_used_blks; i++) {
"UOBJ ADD: table:%p, available blks:%d",
for (j = 0; j < SOL_OFS_UO_BLKSZ; j++) {
uobj->uo_uobj_sz =
blk->ofs_uo_blk_avail--;
goto obj_added;
}
}
/*
* Remember the first empty blk we came across.
*/
empty = i;
}
}
/*
* No entries were available, we must allocate a new block. If we did
* not find a empty block available, then we must allocate/reallocate
* the root array (copying any existing blk pointers to it).
*/
if (empty < 0) {
sol_ofs_uobj_blk_t **p;
"UOBJ ADD: Increasing uobj table size to %d",
newsz);
if (!p) {
"UOBJ ADD: Mem alloc fail\n");
return (1);
}
if (uo_tbl->uobj_tbl_uo_root) {
(int)(sizeof (*p));
}
uo_tbl->uobj_tbl_uo_root = p;
}
}
/*
* There are enough free block pointers in the root, allocate
* a new block.
*/
if (!blk) {
"UOBJ ADD: Mem alloc fail\n");
return (1);
}
/*
* Use the first slot in this new block to add the new user object.
*/
return (0);
}
/*
* Function:
* sol_ofs_uobj_remove
* Input:
* uo_tbl - A pointer to the user object resource management table
* from which the object should be removed.
* uobj - A pointer ot the user object to be removed.
* Output:
* None
* Returns:
* A pointer to the user object that was removed on success, otherwise
* NULL.
* Description:
* Remove a user object from the specified user resource management
* table.
*
* The uobj uo_lock must be held as a writer before calling this.
*/
{
uint_t i, j;
sol_ofs_uobj_t *p;
p = NULL;
"UOBJ REMOVE: object 0x%P, already removed", (void *)uobj);
goto remove_done;
}
/*
* The table is empty, just return not found
* Don't panic, userland app could have double free'd
* let them deal with it.
*/
"UOBJ REMOVE: table 0x%P empty", (void *)uo_tbl);
goto remove_done;
}
if (i >= uo_tbl->uobj_tbl_used_blks) {
"UOBJ REMOVE: object id %d exceeds table size",
goto remove_done;
}
"UOBJ REMOVE: object id %d points to invalid root",
goto remove_done;
}
"UOBJ REMOVE: object id %d points to invalid block",
goto remove_done;
}
/*
* Mark as dead
*/
p = blk->ofs_uoblk_blks[j];
blk->ofs_uo_blk_avail++;
}
return (p);
}
/*
* Function:
* ofs_uobj_find
* Input:
* uo_tbl - A pointer to the user object resource management table
* to be used for the lookup.
* uo_id - The user object ID to lookup. This ID was set when
* the object was added to the resource management table.
* add_ref - A non zero value indicates that the user objects reference
* count should be updated to reflect and additional
* reference before it is returned.
* Output:
* None
* Returns:
* A pointer to the user object associated with the uo_id if found,
* otherwise NULL.
* Description:
* Lookup and return a user object from the specified user resource
* management table.
*/
static sol_ofs_uobj_t *
{
uint32_t i, j;
/*
* The table is empty, just return not found
* Don't panic, userland app could have double free'd
* let them deal with it.
*/
"UOBJ FIND: id %d in tbl 0x%P - tbl empty", uo_id,
(void *)uo_tbl);
goto find_done;
}
i = uo_id / SOL_OFS_UO_BLKSZ;
j = uo_id % SOL_OFS_UO_BLKSZ;
if (i >= uo_tbl->uobj_tbl_used_blks) {
"UOBJ FIND: Index not valid, %d", uo_id);
goto find_done;
}
/*
* Get the user object, and if valid perform a get (ref++).
* The caller issuing the find, must release the reference
* when done.
*/
"UOBJ FIND: Index %d not found, blk = %p",
} else if (add_ref) {
}
} else {
"UOBJ FIND: Uobject not found, %d", uo_id);
goto find_done;
}
return (uobj);
}
/*
* Function:
* sol_ofs_uobj_get_read
* Input:
* tbl - Pointer to the user object managment table to
* be used in the lookup.
* uo_id - The ID to object mapping, assigned to the user
* object at addition to the table.
* Ouput:
* None
* Returns:
* A pointer to the user object associated with uo_id or NULL
* if the entry does not exist.
* Description:
* Lookup a user object and place a reference on it. Acquires
* the object with a READ lock. The reference and lock should
* be released using the sol_ofs_uobj_put() call.
*/
{
if (!uobj)
return (NULL);
/*
* If object was destroyed before we got the lock, just release
* our reference and indicate we didn't find the object.
*/
return (NULL);
}
return (uobj);
}
/*
* Function:
* sol_ofs_uobj_get_write
* Input:
* tbl - Pointer to the user object managment table to
* be used in the lookup.
* uo_id - The ID to object mapping, assigned to the user
* object at addition to the table.
* Ouput:
* None
* Returns:
* A pointer to the user object associated with uo_id or NULL
* if the entry does not exist.
* Description:
* Lookup a user object and place a reference on it. Acquires
* the object with a WRITE lock. The reference and lock should
* be released using the sol_ofs_uobj_put() call.
*/
{
if (!uobj)
return (NULL);
/*
* If object was destroyed before we got the lock, just release
* our reference and indicate we didn't find the object.
*/
return (NULL);
}
return (uobj);
}
/*
* Function:
* sol_ofs_uobj_free
* Input:
* uobj - A pointer to the Solaris User Verbs kernel agent user
* object to be freed.
* Output:
* None.
* Returns:
* None.
* Description:
* Called when the user object is no longer referenced, it will release
* any user object resources and free the container object memory.
* NOTE: Currently there is a stipulation that the user object be the
* first element of any user object specialization.
*/
void
{
/*
* Cleanup common user object and then free memory using
* length based on associated object type.
*/
if (sz)
}
/*
* Function:
* sol_ofs_uobj_put
* Input:
* uobj - Pointer to the user object
* Ouput:
* None
* Returns:
* None
* Description:
* Remove a lock associated with a user object, and decrement
* the reference held. On the last deference the user object
* will be freed.
*/
void
{
}