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
2006-01-02 21:04:38 +03:00
* Copyright ( c ) 2004 - 2005 , Wind River Systems
* 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"
# include "port.h"
# include "subscr.h"
# include "name_distr.h"
# include "name_table.h"
# include "config.h"
# include "discover.h"
# include "bearer.h"
# include "node.h"
# include "bcast.h"
/*
* Object reference table consists of 2 * * N entries .
*
* A used entry has object ptr ! = 0 , reference = = XXXX | own index
2007-02-09 17:25:21 +03:00
* ( XXXX changes each time entry is acquired )
2006-01-02 21:04:38 +03:00
* A free entry has object ptr = = 0 , reference = = YYYY | next free index
* ( YYYY is one more than last used XXXX )
*
2007-02-09 17:25:21 +03:00
* Free list is initially chained from entry ( 2 * * N ) - 1 to entry 1.
2006-01-02 21:04:38 +03:00
* Entry 0 is not used to allow index 0 to indicate the end of the free list .
*
* Note : Any accidental reference of the form XXXX | 0 - - 0 won ' t match entry 0
* because entry 0 ' s reference field has the form XXXX | 1 - - 1.
*/
2006-03-21 09:36:47 +03:00
struct ref_table tipc_ref_table = { NULL } ;
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 ;
u32 sz = 1 < < 4 ;
u32 index_mask ;
int i ;
while ( sz < requested_size ) {
sz < < = 1 ;
}
2006-07-22 02:52:20 +04:00
table = vmalloc ( sz * sizeof ( * table ) ) ;
2006-01-02 21:04:38 +03:00
if ( table = = NULL )
return - ENOMEM ;
2006-01-18 02:38:21 +03:00
write_lock_bh ( & ref_table_lock ) ;
2006-01-02 21:04:38 +03:00
index_mask = sz - 1 ;
for ( i = sz - 1 ; i > = 0 ; i - - ) {
2006-03-21 09:36:47 +03:00
table [ i ] . object = NULL ;
2006-06-27 13:53:55 +04:00
spin_lock_init ( & table [ i ] . lock ) ;
2006-01-02 21:04:38 +03:00
table [ i ] . data . next_plus_upper = ( start & ~ index_mask ) + i - 1 ;
}
2006-01-18 02:38:21 +03:00
tipc_ref_table . entries = table ;
tipc_ref_table . index_mask = index_mask ;
tipc_ref_table . first_free = sz - 1 ;
tipc_ref_table . last_free = 1 ;
write_unlock_bh ( & ref_table_lock ) ;
2006-01-02 21:04:38 +03:00
return TIPC_OK ;
}
/**
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
*
2006-01-02 21:04:38 +03:00
* Return a unique reference value which can be translated back to the pointer
2007-02-09 17:25:21 +03:00
* ' object ' at a later time . Also , pass back a pointer to the lock protecting
2006-01-02 21:04:38 +03:00
* the object , but without locking it .
*/
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
{
struct reference * entry ;
u32 index ;
u32 index_mask ;
u32 next_plus_upper ;
u32 reference = 0 ;
2006-06-26 10:51:37 +04:00
if ( ! object ) {
err ( " Attempt to acquire reference to non-existent object \n " ) ;
return 0 ;
}
if ( ! tipc_ref_table . entries ) {
err ( " Reference table not found during acquisition attempt \n " ) ;
return 0 ;
}
2006-01-02 21:04:38 +03:00
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 ;
2007-02-09 17:25:21 +03:00
/* take lock in case a previous user of entry still holds it */
spin_lock_bh ( & entry - > lock ) ;
2006-01-02 21:04:38 +03:00
next_plus_upper = entry - > data . next_plus_upper ;
2006-01-18 02:38:21 +03:00
tipc_ref_table . first_free = next_plus_upper & index_mask ;
2006-01-02 21:04:38 +03:00
reference = ( next_plus_upper & ~ index_mask ) + index ;
entry - > data . reference = reference ;
entry - > object = object ;
2007-02-09 17:25:21 +03:00
if ( lock ! = 0 )
* lock = & entry - > lock ;
2006-01-02 21:04:38 +03:00
spin_unlock_bh ( & entry - > lock ) ;
}
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & ref_table_lock ) ;
2006-01-02 21:04:38 +03:00
return reference ;
}
/**
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 ( ! ref ) {
err ( " Attempt to discard reference 0 \n " ) ;
return ;
}
if ( ! tipc_ref_table . entries ) {
err ( " Reference table not found during discard attempt \n " ) ;
return ;
}
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
write_lock_bh ( & ref_table_lock ) ;
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
if ( ! entry - > object ) {
err ( " Attempt to discard reference to non-existent object \n " ) ;
goto exit ;
}
if ( entry - > data . reference ! = ref ) {
err ( " Attempt to discard non-existent reference \n " ) ;
goto exit ;
}
2006-01-02 21:04:38 +03:00
/* mark entry as unused */
2006-03-21 09:36:47 +03:00
entry - > object = NULL ;
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
/* next_plus_upper is always XXXX|0--0 for last free entry */
2007-02-09 17:25:21 +03:00
tipc_ref_table . entries [ tipc_ref_table . last_free ] . data . next_plus_upper
2006-01-02 21:04:38 +03:00
| = index ;
2006-01-18 02:38:21 +03:00
tipc_ref_table . last_free = index ;
2006-01-02 21:04:38 +03:00
/* increment upper bits of entry to invalidate subsequent references */
entry - > data . next_plus_upper = ( ref & ~ index_mask ) + ( index_mask + 1 ) ;
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
}