2006-01-02 21:04:38 +03:00
/*
* net / tipc / ref . c : TIPC object registry code
2007-02-09 17:25:21 +03:00
*
2006-01-11 21:14:19 +03:00
* Copyright ( c ) 1991 - 2006 , Ericsson AB
2008-04-17 05:21:16 +04:00
* Copyright ( c ) 2004 - 2007 , Wind River Systems
2006-01-02 21:04:38 +03:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
2006-01-11 15:30:43 +03:00
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission .
*
* Alternatively , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) version 2 as published by the Free
* Software Foundation .
2006-01-02 21:04:38 +03:00
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
* CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE .
*/
# include "core.h"
# include "ref.h"
2008-04-17 05:21:16 +04:00
/**
* struct reference - TIPC object reference entry
* @ object : pointer to object associated with reference entry
* @ lock : spinlock controlling access to object
2008-04-17 05:22:20 +04:00
* @ ref : reference value for object ( combines instance & array index info )
2008-04-17 05:21:16 +04:00
*/
struct reference {
void * object ;
spinlock_t lock ;
2008-04-17 05:22:20 +04:00
u32 ref ;
2008-04-17 05:21:16 +04:00
} ;
/**
* struct tipc_ref_table - table of TIPC object reference entries
* @ entries : pointer to array of reference entries
2008-04-17 05:21:47 +04:00
* @ capacity : array index of first unusable entry
* @ init_point : array index of first uninitialized entry
2008-04-17 05:21:16 +04:00
* @ first_free : array index of first unused object reference entry
* @ last_free : array index of last unused object reference entry
2008-04-17 05:21:47 +04:00
* @ index_mask : bitmask for array index portion of reference values
* @ start_mask : initial value for instance value portion of reference values
2008-04-17 05:21:16 +04:00
*/
struct ref_table {
struct reference * entries ;
2008-04-17 05:21:47 +04:00
u32 capacity ;
u32 init_point ;
2008-04-17 05:21:16 +04:00
u32 first_free ;
u32 last_free ;
2008-04-17 05:21:47 +04:00
u32 index_mask ;
u32 start_mask ;
2008-04-17 05:21:16 +04:00
} ;
2006-01-02 21:04:38 +03:00
/*
* Object reference table consists of 2 * * N entries .
*
2008-04-17 05:21:47 +04:00
* State Object ptr Reference
* - - - - - - - - - - - - - - - - - - - - - - - -
* In use non - NULL XXXX | own index
* ( XXXX changes each time entry is acquired )
* Free NULL YYYY | next free index
* ( YYYY is one more than last used XXXX )
* Uninitialized NULL 0
2006-01-02 21:04:38 +03:00
*
2008-04-17 05:21:47 +04:00
* Entry 0 is not used ; this allows index 0 to denote the end of the free list .
2006-01-02 21:04:38 +03:00
*
2008-04-17 05:21:47 +04:00
* Note that a reference value of 0 does not necessarily indicate that an
* entry is uninitialized , since the last entry in the free list could also
* have a reference value of 0 ( although this is unlikely ) .
2006-01-02 21:04:38 +03:00
*/
2010-12-31 21:59:34 +03:00
static struct ref_table tipc_ref_table ;
2006-01-02 21:04:38 +03:00
2006-06-27 13:53:55 +04:00
static DEFINE_RWLOCK ( ref_table_lock ) ;
2006-01-02 21:04:38 +03:00
/**
2006-01-18 02:38:21 +03:00
* tipc_ref_table_init - create reference table for objects
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
int tipc_ref_table_init ( u32 requested_size , u32 start )
2006-01-02 21:04:38 +03:00
{
struct reference * table ;
2008-04-17 05:21:47 +04:00
u32 actual_size ;
2006-01-02 21:04:38 +03:00
2008-04-17 05:21:47 +04:00
/* account for unused entry, then round up size to a power of 2 */
requested_size + + ;
for ( actual_size = 16 ; actual_size < requested_size ; actual_size < < = 1 )
/* do nothing */ ;
/* allocate table & mark all entries as uninitialized */
2011-12-20 01:01:38 +04:00
table = vzalloc ( actual_size * sizeof ( struct reference ) ) ;
2006-01-02 21:04:38 +03:00
if ( table = = NULL )
return - ENOMEM ;
2006-01-18 02:38:21 +03:00
tipc_ref_table . entries = table ;
2008-04-17 05:21:47 +04:00
tipc_ref_table . capacity = requested_size ;
tipc_ref_table . init_point = 1 ;
tipc_ref_table . first_free = 0 ;
tipc_ref_table . last_free = 0 ;
tipc_ref_table . index_mask = actual_size - 1 ;
tipc_ref_table . start_mask = start & ~ tipc_ref_table . index_mask ;
2008-07-15 09:44:01 +04:00
return 0 ;
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_ref_table_stop - destroy reference table for objects
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
void tipc_ref_table_stop ( void )
2006-01-02 21:04:38 +03:00
{
2006-01-18 02:38:21 +03:00
if ( ! tipc_ref_table . entries )
2006-01-02 21:04:38 +03:00
return ;
2006-01-18 02:38:21 +03:00
vfree ( tipc_ref_table . entries ) ;
2006-03-21 09:36:47 +03:00
tipc_ref_table . entries = NULL ;
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_ref_acquire - create reference to an object
2007-02-09 17:25:21 +03:00
*
2008-05-13 02:42:28 +04:00
* Register an object pointer in reference table and lock the object .
* Returns a unique reference value that is used from then on to retrieve the
* object pointer , or to determine that the object has been deregistered .
*
* Note : The object is returned in the locked state so that the caller can
* register a partially initialized object , without running the risk that
* the object will be accessed before initialization is complete .
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
u32 tipc_ref_acquire ( void * object , spinlock_t * * lock )
2006-01-02 21:04:38 +03:00
{
u32 index ;
u32 index_mask ;
u32 next_plus_upper ;
2008-04-17 05:22:20 +04:00
u32 ref ;
2010-03-16 11:14:33 +03:00
struct reference * entry = NULL ;
2006-01-02 21:04:38 +03:00
2006-06-26 10:51:37 +04:00
if ( ! object ) {
2012-06-29 08:16:37 +04:00
pr_err ( " Attempt to acquire ref. to non-existent obj \n " ) ;
2006-06-26 10:51:37 +04:00
return 0 ;
}
if ( ! tipc_ref_table . entries ) {
2012-06-29 08:16:37 +04:00
pr_err ( " Ref. table not found in acquisition attempt \n " ) ;
2006-06-26 10:51:37 +04:00
return 0 ;
}
2006-01-02 21:04:38 +03:00
2008-04-17 05:21:47 +04:00
/* take a free entry, if available; otherwise initialize a new entry */
2006-01-18 02:38:21 +03:00
write_lock_bh ( & ref_table_lock ) ;
if ( tipc_ref_table . first_free ) {
index = tipc_ref_table . first_free ;
entry = & ( tipc_ref_table . entries [ index ] ) ;
index_mask = tipc_ref_table . index_mask ;
2008-04-17 05:22:20 +04:00
next_plus_upper = entry - > ref ;
2006-01-18 02:38:21 +03:00
tipc_ref_table . first_free = next_plus_upper & index_mask ;
2008-04-17 05:22:20 +04:00
ref = ( next_plus_upper & ~ index_mask ) + index ;
2010-12-31 21:59:32 +03:00
} else if ( tipc_ref_table . init_point < tipc_ref_table . capacity ) {
2008-04-17 05:21:47 +04:00
index = tipc_ref_table . init_point + + ;
entry = & ( tipc_ref_table . entries [ index ] ) ;
spin_lock_init ( & entry - > lock ) ;
2008-04-17 05:22:20 +04:00
ref = tipc_ref_table . start_mask + index ;
2010-12-31 21:59:32 +03:00
} else {
2008-04-17 05:22:20 +04:00
ref = 0 ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & ref_table_lock ) ;
2008-04-17 05:21:47 +04:00
2010-03-16 11:14:33 +03:00
/*
* Grab the lock so no one else can modify this entry
* While we assign its ref value & object pointer
*/
if ( entry ) {
spin_lock_bh ( & entry - > lock ) ;
entry - > ref = ref ;
entry - > object = object ;
* lock = & entry - > lock ;
/*
* keep it locked , the caller is responsible
* for unlocking this when they ' re done with it
*/
}
2008-04-17 05:22:20 +04:00
return ref ;
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_ref_discard - invalidate references to an object
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Disallow future references to an object and free up the entry for re - use .
* Note : The entry ' s spin_lock may still be busy after discard
*/
2006-01-18 02:38:21 +03:00
void tipc_ref_discard ( u32 ref )
2006-01-02 21:04:38 +03:00
{
struct reference * entry ;
2007-02-09 17:25:21 +03:00
u32 index ;
2006-01-02 21:04:38 +03:00
u32 index_mask ;
2006-06-26 10:51:37 +04:00
if ( ! tipc_ref_table . entries ) {
2012-06-29 08:16:37 +04:00
pr_err ( " Ref. table not found during discard attempt \n " ) ;
2006-06-26 10:51:37 +04:00
return ;
}
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
index_mask = tipc_ref_table . index_mask ;
2006-01-02 21:04:38 +03:00
index = ref & index_mask ;
2006-01-18 02:38:21 +03:00
entry = & ( tipc_ref_table . entries [ index ] ) ;
2006-06-26 10:51:37 +04:00
2008-04-17 05:21:47 +04:00
write_lock_bh ( & ref_table_lock ) ;
2006-06-26 10:51:37 +04:00
if ( ! entry - > object ) {
2012-06-29 08:16:37 +04:00
pr_err ( " Attempt to discard ref. to non-existent obj \n " ) ;
2006-06-26 10:51:37 +04:00
goto exit ;
}
2008-04-17 05:22:20 +04:00
if ( entry - > ref ! = ref ) {
2012-06-29 08:16:37 +04:00
pr_err ( " Attempt to discard non-existent reference \n " ) ;
2006-06-26 10:51:37 +04:00
goto exit ;
}
2006-01-02 21:04:38 +03:00
2008-04-17 05:21:47 +04:00
/*
2008-04-17 05:22:20 +04:00
* mark entry as unused ; increment instance part of entry ' s reference
2008-04-17 05:21:47 +04:00
* to invalidate any subsequent references
*/
2006-03-21 09:36:47 +03:00
entry - > object = NULL ;
2008-04-17 05:22:20 +04:00
entry - > ref = ( ref & ~ index_mask ) + ( index_mask + 1 ) ;
2008-04-17 05:21:47 +04:00
/* append entry to free entry list */
2006-01-18 02:38:21 +03:00
if ( tipc_ref_table . first_free = = 0 )
tipc_ref_table . first_free = index ;
2006-01-02 21:04:38 +03:00
else
2008-04-17 05:22:20 +04:00
tipc_ref_table . entries [ tipc_ref_table . last_free ] . ref | = index ;
2006-01-18 02:38:21 +03:00
tipc_ref_table . last_free = index ;
2006-01-02 21:04:38 +03:00
2006-06-26 10:51:37 +04:00
exit :
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & ref_table_lock ) ;
2006-01-02 21:04:38 +03:00
}
2008-04-17 05:21:16 +04:00
/**
* tipc_ref_lock - lock referenced object and return pointer to it
*/
void * tipc_ref_lock ( u32 ref )
{
if ( likely ( tipc_ref_table . entries ) ) {
2008-04-17 05:22:20 +04:00
struct reference * entry ;
entry = & tipc_ref_table . entries [ ref &
tipc_ref_table . index_mask ] ;
if ( likely ( entry - > ref ! = 0 ) ) {
spin_lock_bh ( & entry - > lock ) ;
if ( likely ( ( entry - > ref = = ref ) & & ( entry - > object ) ) )
return entry - > object ;
spin_unlock_bh ( & entry - > lock ) ;
2008-04-17 05:21:47 +04:00
}
2008-04-17 05:21:16 +04:00
}
return NULL ;
}
/**
* tipc_ref_deref - return pointer referenced object ( without locking it )
*/
void * tipc_ref_deref ( u32 ref )
{
if ( likely ( tipc_ref_table . entries ) ) {
2008-04-17 05:22:20 +04:00
struct reference * entry ;
2008-04-17 05:21:16 +04:00
2008-04-17 05:22:20 +04:00
entry = & tipc_ref_table . entries [ ref &
tipc_ref_table . index_mask ] ;
if ( likely ( entry - > ref = = ref ) )
return entry - > object ;
2008-04-17 05:21:16 +04:00
}
return NULL ;
}