2006-01-02 21:04:38 +03:00
/*
* net / tipc / name_table . c : TIPC name table code
2007-02-09 17:25:21 +03:00
*
2006-01-11 21:14:19 +03:00
* Copyright ( c ) 2000 - 2006 , Ericsson AB
2008-07-15 09:45:33 +04:00
* Copyright ( c ) 2004 - 2008 , Wind River Systems
2006-01-02 21:04:38 +03:00
* All rights reserved .
*
2006-01-11 15:30:43 +03:00
* Redistribution and use in source and binary forms , with or without
2006-01-02 21:04:38 +03:00
* 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 .
2006-01-02 21:04:38 +03:00
*
2006-01-11 15:30:43 +03:00
* 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 .
*
* 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
2006-01-02 21:04:38 +03:00
* POSSIBILITY OF SUCH DAMAGE .
*/
# include "core.h"
# include "config.h"
# include "dbg.h"
# include "name_table.h"
# include "name_distr.h"
# include "addr.h"
# include "node_subscr.h"
# include "subscr.h"
# include "port.h"
# include "cluster.h"
# include "bcast.h"
2006-03-21 09:37:52 +03:00
static int tipc_nametbl_size = 1024 ; /* must be a power of 2 */
2006-01-02 21:04:38 +03:00
/**
* struct sub_seq - container for all published instances of a name sequence
* @ lower : name sequence lower bound
* @ upper : name sequence upper bound
2008-07-15 09:45:33 +04:00
* @ node_list : circular list of publications made by own node
* @ cluster_list : circular list of publications made by own cluster
* @ zone_list : circular list of publications made by own zone
* @ node_list_size : number of entries in " node_list "
* @ cluster_list_size : number of entries in " cluster_list "
* @ zone_list_size : number of entries in " zone_list "
*
* Note : The zone list always contains at least one entry , since all
* publications of the associated name sequence belong to it .
* ( The cluster and node lists may be empty . )
2006-01-02 21:04:38 +03:00
*/
struct sub_seq {
u32 lower ;
u32 upper ;
struct publication * node_list ;
struct publication * cluster_list ;
struct publication * zone_list ;
2008-07-15 09:45:33 +04:00
u32 node_list_size ;
u32 cluster_list_size ;
u32 zone_list_size ;
2006-01-02 21:04:38 +03:00
} ;
2007-02-09 17:25:21 +03:00
/**
2006-01-02 21:04:38 +03:00
* struct name_seq - container for all published instances of a name type
* @ type : 32 bit ' type ' value for name sequence
* @ sseq : pointer to dynamically - sized array of sub - sequences of this ' type ' ;
* sub - sequences are sorted in ascending order
* @ alloc : number of sub - sequences currently in array
2006-06-26 10:51:37 +04:00
* @ first_free : array index of first unused sub - sequence entry
2006-01-02 21:04:38 +03:00
* @ ns_list : links to adjacent name sequences in hash chain
* @ subscriptions : list of subscriptions for this ' type '
2008-06-05 04:38:22 +04:00
* @ lock : spinlock controlling access to publication lists of all sub - sequences
2006-01-02 21:04:38 +03:00
*/
struct name_seq {
u32 type ;
struct sub_seq * sseqs ;
u32 alloc ;
u32 first_free ;
struct hlist_node ns_list ;
struct list_head subscriptions ;
spinlock_t lock ;
} ;
/**
* struct name_table - table containing all existing port name publications
2007-02-09 17:25:21 +03:00
* @ types : pointer to fixed - sized array of name sequence lists ,
2006-01-02 21:04:38 +03:00
* accessed via hashing on ' type ' ; name sequence lists are * not * sorted
* @ local_publ_count : number of publications issued by this node
*/
struct name_table {
struct hlist_head * types ;
u32 local_publ_count ;
} ;
2006-01-18 02:38:21 +03:00
static struct name_table table = { NULL } ;
2006-01-02 21:04:38 +03:00
static atomic_t rsv_publ_ok = ATOMIC_INIT ( 0 ) ;
2006-06-27 13:53:55 +04:00
DEFINE_RWLOCK ( tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
2006-03-21 09:37:04 +03:00
static int hash ( int x )
2006-01-02 21:04:38 +03:00
{
2010-09-23 00:43:57 +04:00
return x & ( tipc_nametbl_size - 1 ) ;
2006-01-02 21:04:38 +03:00
}
/**
* publ_create - create a publication structure
*/
2007-02-09 17:25:21 +03:00
static struct publication * publ_create ( u32 type , u32 lower , u32 upper ,
u32 scope , u32 node , u32 port_ref ,
2006-01-02 21:04:38 +03:00
u32 key )
{
2006-07-22 01:51:30 +04:00
struct publication * publ = kzalloc ( sizeof ( * publ ) , GFP_ATOMIC ) ;
2006-01-02 21:04:38 +03:00
if ( publ = = NULL ) {
2006-06-26 10:52:17 +04:00
warn ( " Publication creation failure, no memory \n " ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
publ - > type = type ;
publ - > lower = lower ;
publ - > upper = upper ;
publ - > scope = scope ;
publ - > node = node ;
publ - > ref = port_ref ;
publ - > key = key ;
INIT_LIST_HEAD ( & publ - > local_list ) ;
INIT_LIST_HEAD ( & publ - > pport_list ) ;
INIT_LIST_HEAD ( & publ - > subscr . nodesub_list ) ;
return publ ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_subseq_alloc - allocate a specified number of sub - sequence structures
2006-01-02 21:04:38 +03:00
*/
2006-03-21 09:37:52 +03:00
static struct sub_seq * tipc_subseq_alloc ( u32 cnt )
2006-01-02 21:04:38 +03:00
{
2006-07-22 01:51:30 +04:00
struct sub_seq * sseq = kcalloc ( cnt , sizeof ( struct sub_seq ) , GFP_ATOMIC ) ;
2006-01-02 21:04:38 +03:00
return sseq ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nameseq_create - create a name sequence structure for the specified ' type '
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Allocates a single sub - sequence structure and sets it to all 0 ' s .
*/
2006-03-21 09:37:52 +03:00
static struct name_seq * tipc_nameseq_create ( u32 type , struct hlist_head * seq_head )
2006-01-02 21:04:38 +03:00
{
2006-07-22 01:51:30 +04:00
struct name_seq * nseq = kzalloc ( sizeof ( * nseq ) , GFP_ATOMIC ) ;
2006-01-18 02:38:21 +03:00
struct sub_seq * sseq = tipc_subseq_alloc ( 1 ) ;
2006-01-02 21:04:38 +03:00
if ( ! nseq | | ! sseq ) {
2006-06-26 10:52:17 +04:00
warn ( " Name sequence creation failed, no memory \n " ) ;
2006-01-02 21:04:38 +03:00
kfree ( nseq ) ;
kfree ( sseq ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2006-06-27 13:53:55 +04:00
spin_lock_init ( & nseq - > lock ) ;
2006-01-02 21:04:38 +03:00
nseq - > type = type ;
nseq - > sseqs = sseq ;
2006-06-26 10:51:37 +04:00
dbg ( " tipc_nameseq_create(): nseq = %p, type %u, ssseqs %p, ff: %u \n " ,
2006-01-02 21:04:38 +03:00
nseq , type , nseq - > sseqs , nseq - > first_free ) ;
nseq - > alloc = 1 ;
INIT_HLIST_NODE ( & nseq - > ns_list ) ;
INIT_LIST_HEAD ( & nseq - > subscriptions ) ;
hlist_add_head ( & nseq - > ns_list , seq_head ) ;
return nseq ;
}
/**
* nameseq_find_subseq - find sub - sequence ( if any ) matching a name instance
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Very time - critical , so binary searches through sub - sequence array .
*/
2006-03-21 09:37:04 +03:00
static struct sub_seq * nameseq_find_subseq ( struct name_seq * nseq ,
u32 instance )
2006-01-02 21:04:38 +03:00
{
struct sub_seq * sseqs = nseq - > sseqs ;
int low = 0 ;
int high = nseq - > first_free - 1 ;
int mid ;
while ( low < = high ) {
mid = ( low + high ) / 2 ;
if ( instance < sseqs [ mid ] . lower )
high = mid - 1 ;
else if ( instance > sseqs [ mid ] . upper )
low = mid + 1 ;
else
return & sseqs [ mid ] ;
}
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
/**
* nameseq_locate_subseq - determine position of name instance in sub - sequence
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Returns index in sub - sequence array of the entry that contains the specified
* instance value ; if no entry contains that value , returns the position
* where a new entry for it would be inserted in the array .
*
* Note : Similar to binary search code for locating a sub - sequence .
*/
static u32 nameseq_locate_subseq ( struct name_seq * nseq , u32 instance )
{
struct sub_seq * sseqs = nseq - > sseqs ;
int low = 0 ;
int high = nseq - > first_free - 1 ;
int mid ;
while ( low < = high ) {
mid = ( low + high ) / 2 ;
if ( instance < sseqs [ mid ] . lower )
high = mid - 1 ;
else if ( instance > sseqs [ mid ] . upper )
low = mid + 1 ;
else
return mid ;
}
return low ;
}
/**
2007-02-09 17:25:21 +03:00
* tipc_nameseq_insert_publ -
2006-01-02 21:04:38 +03:00
*/
2006-03-21 09:37:52 +03:00
static struct publication * tipc_nameseq_insert_publ ( struct name_seq * nseq ,
u32 type , u32 lower , u32 upper ,
u32 scope , u32 node , u32 port , u32 key )
2006-01-02 21:04:38 +03:00
{
struct subscription * s ;
struct subscription * st ;
struct publication * publ ;
struct sub_seq * sseq ;
int created_subseq = 0 ;
sseq = nameseq_find_subseq ( nseq , lower ) ;
2006-06-26 10:51:37 +04:00
dbg ( " nameseq_ins: for seq %p, {%u,%u}, found sseq %p \n " ,
2006-01-02 21:04:38 +03:00
nseq , type , lower , sseq ) ;
if ( sseq ) {
/* Lower end overlaps existing entry => need an exact match */
if ( ( sseq - > lower ! = lower ) | | ( sseq - > upper ! = upper ) ) {
2006-06-26 10:51:37 +04:00
warn ( " Cannot publish {%u,%u,%u}, overlap error \n " ,
type , lower , upper ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
} else {
u32 inspos ;
struct sub_seq * freesseq ;
/* Find where lower end should be inserted */
inspos = nameseq_locate_subseq ( nseq , lower ) ;
/* Fail if upper end overlaps into an existing entry */
if ( ( inspos < nseq - > first_free ) & &
( upper > = nseq - > sseqs [ inspos ] . lower ) ) {
2006-06-26 10:51:37 +04:00
warn ( " Cannot publish {%u,%u,%u}, overlap error \n " ,
type , lower , upper ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
/* Ensure there is space for new sub-sequence */
if ( nseq - > first_free = = nseq - > alloc ) {
2006-06-26 10:37:24 +04:00
struct sub_seq * sseqs = tipc_subseq_alloc ( nseq - > alloc * 2 ) ;
if ( ! sseqs ) {
2006-06-26 10:51:37 +04:00
warn ( " Cannot publish {%u,%u,%u}, no memory \n " ,
type , lower , upper ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2006-06-26 10:37:24 +04:00
dbg ( " Allocated %u more sseqs \n " , nseq - > alloc ) ;
memcpy ( sseqs , nseq - > sseqs ,
nseq - > alloc * sizeof ( struct sub_seq ) ) ;
kfree ( nseq - > sseqs ) ;
nseq - > sseqs = sseqs ;
nseq - > alloc * = 2 ;
2006-01-02 21:04:38 +03:00
}
dbg ( " Have %u sseqs for type %u \n " , nseq - > alloc , type ) ;
/* Insert new sub-sequence */
dbg ( " ins in pos %u, ff = %u \n " , inspos , nseq - > first_free ) ;
sseq = & nseq - > sseqs [ inspos ] ;
freesseq = & nseq - > sseqs [ nseq - > first_free ] ;
memmove ( sseq + 1 , sseq , ( freesseq - sseq ) * sizeof ( * sseq ) ) ;
memset ( sseq , 0 , sizeof ( * sseq ) ) ;
nseq - > first_free + + ;
sseq - > lower = lower ;
sseq - > upper = upper ;
created_subseq = 1 ;
}
2006-06-26 10:51:37 +04:00
dbg ( " inserting {%u,%u,%u} from <0x%x:%u> into sseq %p(%u,%u) of seq %p \n " ,
2006-01-02 21:04:38 +03:00
type , lower , upper , node , port , sseq ,
sseq - > lower , sseq - > upper , nseq ) ;
/* Insert a publication: */
publ = publ_create ( type , lower , upper , scope , node , port , key ) ;
if ( ! publ )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-06-26 10:51:37 +04:00
dbg ( " inserting publ %p, node=0x%x publ->node=0x%x, subscr->node=%p \n " ,
2006-01-02 21:04:38 +03:00
publ , node , publ - > node , publ - > subscr . node ) ;
2008-07-15 09:45:33 +04:00
sseq - > zone_list_size + + ;
2006-01-02 21:04:38 +03:00
if ( ! sseq - > zone_list )
sseq - > zone_list = publ - > zone_list_next = publ ;
else {
publ - > zone_list_next = sseq - > zone_list - > zone_list_next ;
sseq - > zone_list - > zone_list_next = publ ;
}
if ( in_own_cluster ( node ) ) {
2008-07-15 09:45:33 +04:00
sseq - > cluster_list_size + + ;
2006-01-02 21:04:38 +03:00
if ( ! sseq - > cluster_list )
sseq - > cluster_list = publ - > cluster_list_next = publ ;
else {
publ - > cluster_list_next =
sseq - > cluster_list - > cluster_list_next ;
sseq - > cluster_list - > cluster_list_next = publ ;
}
}
if ( node = = tipc_own_addr ) {
2008-07-15 09:45:33 +04:00
sseq - > node_list_size + + ;
2006-01-02 21:04:38 +03:00
if ( ! sseq - > node_list )
sseq - > node_list = publ - > node_list_next = publ ;
else {
publ - > node_list_next = sseq - > node_list - > node_list_next ;
sseq - > node_list - > node_list_next = publ ;
}
}
2007-02-09 17:25:21 +03:00
/*
* Any subscriptions waiting for notification ?
2006-01-02 21:04:38 +03:00
*/
list_for_each_entry_safe ( s , st , & nseq - > subscriptions , nameseq_list ) {
dbg ( " calling report_overlap() \n " ) ;
2006-01-18 02:38:21 +03:00
tipc_subscr_report_overlap ( s ,
publ - > lower ,
publ - > upper ,
TIPC_PUBLISHED ,
2007-02-09 17:25:21 +03:00
publ - > ref ,
2006-01-18 02:38:21 +03:00
publ - > node ,
created_subseq ) ;
2006-01-02 21:04:38 +03:00
}
return publ ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nameseq_remove_publ -
2007-02-09 17:25:21 +03:00
*
2006-06-26 10:51:37 +04:00
* NOTE : There may be cases where TIPC is asked to remove a publication
* that is not in the name table . For example , if another node issues a
* publication for a name sequence that overlaps an existing name sequence
* the publication will not be recorded , which means the publication won ' t
* be found when the name sequence is later withdrawn by that node .
* A failed withdraw request simply returns a failure indication and lets the
* caller issue any error or warning messages associated with such a problem .
2006-01-02 21:04:38 +03:00
*/
2006-03-21 09:37:52 +03:00
static struct publication * tipc_nameseq_remove_publ ( struct name_seq * nseq , u32 inst ,
u32 node , u32 ref , u32 key )
2006-01-02 21:04:38 +03:00
{
struct publication * publ ;
2006-06-26 10:51:37 +04:00
struct publication * curr ;
2006-01-02 21:04:38 +03:00
struct publication * prev ;
struct sub_seq * sseq = nameseq_find_subseq ( nseq , inst ) ;
struct sub_seq * free ;
struct subscription * s , * st ;
int removed_subseq = 0 ;
2006-06-26 10:51:37 +04:00
if ( ! sseq )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-06-26 10:51:37 +04:00
dbg ( " tipc_nameseq_remove_publ: seq: %p, sseq %p, {%u,%u}, key %u \n " ,
2006-01-02 21:04:38 +03:00
nseq , sseq , nseq - > type , inst , key ) ;
2006-06-26 10:51:37 +04:00
/* Remove publication from zone scope list */
2006-01-02 21:04:38 +03:00
prev = sseq - > zone_list ;
publ = sseq - > zone_list - > zone_list_next ;
2007-02-09 17:25:21 +03:00
while ( ( publ - > key ! = key ) | | ( publ - > ref ! = ref ) | |
2006-01-02 21:04:38 +03:00
( publ - > node & & ( publ - > node ! = node ) ) ) {
prev = publ ;
publ = publ - > zone_list_next ;
2006-06-26 10:51:37 +04:00
if ( prev = = sseq - > zone_list ) {
2007-02-09 17:25:21 +03:00
2006-06-26 10:51:37 +04:00
/* Prevent endless loop if publication not found */
return NULL ;
}
2006-01-02 21:04:38 +03:00
}
if ( publ ! = sseq - > zone_list )
prev - > zone_list_next = publ - > zone_list_next ;
else if ( publ - > zone_list_next ! = publ ) {
prev - > zone_list_next = publ - > zone_list_next ;
sseq - > zone_list = publ - > zone_list_next ;
} else {
2006-03-21 09:36:47 +03:00
sseq - > zone_list = NULL ;
2006-01-02 21:04:38 +03:00
}
2008-07-15 09:45:33 +04:00
sseq - > zone_list_size - - ;
2006-01-02 21:04:38 +03:00
2006-06-26 10:51:37 +04:00
/* Remove publication from cluster scope list, if present */
2006-01-02 21:04:38 +03:00
if ( in_own_cluster ( node ) ) {
prev = sseq - > cluster_list ;
2006-06-26 10:51:37 +04:00
curr = sseq - > cluster_list - > cluster_list_next ;
while ( curr ! = publ ) {
prev = curr ;
curr = curr - > cluster_list_next ;
if ( prev = = sseq - > cluster_list ) {
/* Prevent endless loop for malformed list */
err ( " Unable to de-list cluster publication \n "
" {%u%u}, node=0x%x, ref=%u, key=%u) \n " ,
2007-02-09 17:25:21 +03:00
publ - > type , publ - > lower , publ - > node ,
2006-06-26 10:51:37 +04:00
publ - > ref , publ - > key ) ;
goto end_cluster ;
}
2006-01-02 21:04:38 +03:00
}
if ( publ ! = sseq - > cluster_list )
prev - > cluster_list_next = publ - > cluster_list_next ;
else if ( publ - > cluster_list_next ! = publ ) {
prev - > cluster_list_next = publ - > cluster_list_next ;
sseq - > cluster_list = publ - > cluster_list_next ;
} else {
2006-03-21 09:36:47 +03:00
sseq - > cluster_list = NULL ;
2006-01-02 21:04:38 +03:00
}
2008-07-15 09:45:33 +04:00
sseq - > cluster_list_size - - ;
2006-01-02 21:04:38 +03:00
}
2006-06-26 10:51:37 +04:00
end_cluster :
/* Remove publication from node scope list, if present */
2006-01-02 21:04:38 +03:00
if ( node = = tipc_own_addr ) {
prev = sseq - > node_list ;
2006-06-26 10:51:37 +04:00
curr = sseq - > node_list - > node_list_next ;
while ( curr ! = publ ) {
prev = curr ;
curr = curr - > node_list_next ;
if ( prev = = sseq - > node_list ) {
/* Prevent endless loop for malformed list */
err ( " Unable to de-list node publication \n "
" {%u%u}, node=0x%x, ref=%u, key=%u) \n " ,
2007-02-09 17:25:21 +03:00
publ - > type , publ - > lower , publ - > node ,
2006-06-26 10:51:37 +04:00
publ - > ref , publ - > key ) ;
goto end_node ;
}
2006-01-02 21:04:38 +03:00
}
if ( publ ! = sseq - > node_list )
prev - > node_list_next = publ - > node_list_next ;
else if ( publ - > node_list_next ! = publ ) {
prev - > node_list_next = publ - > node_list_next ;
sseq - > node_list = publ - > node_list_next ;
} else {
2006-03-21 09:36:47 +03:00
sseq - > node_list = NULL ;
2006-01-02 21:04:38 +03:00
}
2008-07-15 09:45:33 +04:00
sseq - > node_list_size - - ;
2006-01-02 21:04:38 +03:00
}
2006-06-26 10:51:37 +04:00
end_node :
2006-01-02 21:04:38 +03:00
2006-06-26 10:51:37 +04:00
/* Contract subseq list if no more publications for that subseq */
if ( ! sseq - > zone_list ) {
2006-01-02 21:04:38 +03:00
free = & nseq - > sseqs [ nseq - > first_free - - ] ;
memmove ( sseq , sseq + 1 , ( free - ( sseq + 1 ) ) * sizeof ( * sseq ) ) ;
removed_subseq = 1 ;
}
2006-06-26 10:51:37 +04:00
/* Notify any waiting subscriptions */
2006-01-02 21:04:38 +03:00
list_for_each_entry_safe ( s , st , & nseq - > subscriptions , nameseq_list ) {
2006-01-18 02:38:21 +03:00
tipc_subscr_report_overlap ( s ,
publ - > lower ,
publ - > upper ,
2007-02-09 17:25:21 +03:00
TIPC_WITHDRAWN ,
publ - > ref ,
2006-01-18 02:38:21 +03:00
publ - > node ,
removed_subseq ) ;
2006-01-02 21:04:38 +03:00
}
2006-06-26 10:51:37 +04:00
2006-01-02 21:04:38 +03:00
return publ ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nameseq_subscribe : attach a subscription , and issue
2006-01-02 21:04:38 +03:00
* the prescribed number of events if there is any sub -
* sequence overlapping with the requested sequence
*/
2007-08-03 06:26:23 +04:00
static void tipc_nameseq_subscribe ( struct name_seq * nseq , struct subscription * s )
2006-01-02 21:04:38 +03:00
{
struct sub_seq * sseq = nseq - > sseqs ;
list_add ( & s - > nameseq_list , & nseq - > subscriptions ) ;
if ( ! sseq )
return ;
while ( sseq ! = & nseq - > sseqs [ nseq - > first_free ] ) {
struct publication * zl = sseq - > zone_list ;
2006-01-18 02:38:21 +03:00
if ( zl & & tipc_subscr_overlap ( s , sseq - > lower , sseq - > upper ) ) {
2006-01-02 21:04:38 +03:00
struct publication * crs = zl ;
int must_report = 1 ;
do {
2007-02-09 17:25:21 +03:00
tipc_subscr_report_overlap ( s ,
sseq - > lower ,
2006-01-18 02:38:21 +03:00
sseq - > upper ,
TIPC_PUBLISHED ,
crs - > ref ,
crs - > node ,
must_report ) ;
2006-01-02 21:04:38 +03:00
must_report = 0 ;
crs = crs - > zone_list_next ;
} while ( crs ! = zl ) ;
}
sseq + + ;
}
}
static struct name_seq * nametbl_find_seq ( u32 type )
{
struct hlist_head * seq_head ;
struct hlist_node * seq_node ;
struct name_seq * ns ;
dbg ( " find_seq %u,(%u,0x%x) table = %p, hash[type] = %u \n " ,
2008-11-08 10:37:50 +03:00
type , htonl ( type ) , type , table . types , hash ( type ) ) ;
2006-01-02 21:04:38 +03:00
seq_head = & table . types [ hash ( type ) ] ;
hlist_for_each_entry ( ns , seq_node , seq_head , ns_list ) {
if ( ns - > type = = type ) {
2006-06-26 10:51:37 +04:00
dbg ( " found %p \n " , ns ) ;
2006-01-02 21:04:38 +03:00
return ns ;
}
}
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
} ;
2006-01-18 02:38:21 +03:00
struct publication * tipc_nametbl_insert_publ ( u32 type , u32 lower , u32 upper ,
u32 scope , u32 node , u32 port , u32 key )
2006-01-02 21:04:38 +03:00
{
struct name_seq * seq = nametbl_find_seq ( type ) ;
2006-06-26 10:51:37 +04:00
dbg ( " tipc_nametbl_insert_publ: {%u,%u,%u} found %p \n " , type , lower , upper , seq ) ;
2006-01-02 21:04:38 +03:00
if ( lower > upper ) {
2006-06-26 10:51:37 +04:00
warn ( " Failed to publish illegal {%u,%u,%u} \n " ,
2006-01-02 21:04:38 +03:00
type , lower , upper ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2006-06-26 10:51:37 +04:00
dbg ( " Publishing {%u,%u,%u} from 0x%x \n " , type , lower , upper , node ) ;
2006-01-02 21:04:38 +03:00
if ( ! seq ) {
2006-01-18 02:38:21 +03:00
seq = tipc_nameseq_create ( type , & table . types [ hash ( type ) ] ) ;
2006-06-26 10:51:37 +04:00
dbg ( " tipc_nametbl_insert_publ: created %p \n " , seq ) ;
2006-01-02 21:04:38 +03:00
}
if ( ! seq )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
return tipc_nameseq_insert_publ ( seq , type , lower , upper ,
scope , node , port , key ) ;
2006-01-02 21:04:38 +03:00
}
2007-02-09 17:25:21 +03:00
struct publication * tipc_nametbl_remove_publ ( u32 type , u32 lower ,
2006-01-18 02:38:21 +03:00
u32 node , u32 ref , u32 key )
2006-01-02 21:04:38 +03:00
{
struct publication * publ ;
struct name_seq * seq = nametbl_find_seq ( type ) ;
if ( ! seq )
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
2006-06-26 10:51:37 +04:00
dbg ( " Withdrawing {%u,%u} from 0x%x \n " , type , lower , node ) ;
2006-01-18 02:38:21 +03:00
publ = tipc_nameseq_remove_publ ( seq , lower , node , ref , key ) ;
2006-01-02 21:04:38 +03:00
if ( ! seq - > first_free & & list_empty ( & seq - > subscriptions ) ) {
hlist_del_init ( & seq - > ns_list ) ;
kfree ( seq - > sseqs ) ;
kfree ( seq ) ;
}
return publ ;
}
/*
2010-09-03 12:33:39 +04:00
* tipc_nametbl_translate - translate name to port id
2006-01-02 21:04:38 +03:00
*
* Note : on entry ' destnode ' is the search domain used during translation ;
* on exit it passes back the node address of the matching port ( if any )
*/
2006-01-18 02:38:21 +03:00
u32 tipc_nametbl_translate ( u32 type , u32 instance , u32 * destnode )
2006-01-02 21:04:38 +03:00
{
struct sub_seq * sseq ;
2006-03-21 09:36:47 +03:00
struct publication * publ = NULL ;
2006-01-02 21:04:38 +03:00
struct name_seq * seq ;
u32 ref ;
2010-05-11 18:30:12 +04:00
if ( ! tipc_in_scope ( * destnode , tipc_own_addr ) )
2006-01-02 21:04:38 +03:00
return 0 ;
2006-01-18 02:38:21 +03:00
read_lock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
seq = nametbl_find_seq ( type ) ;
if ( unlikely ( ! seq ) )
goto not_found ;
sseq = nameseq_find_subseq ( seq , instance ) ;
if ( unlikely ( ! sseq ) )
goto not_found ;
spin_lock_bh ( & seq - > lock ) ;
/* Closest-First Algorithm: */
if ( likely ( ! * destnode ) ) {
publ = sseq - > node_list ;
if ( publ ) {
sseq - > node_list = publ - > node_list_next ;
found :
ref = publ - > ref ;
* destnode = publ - > node ;
spin_unlock_bh ( & seq - > lock ) ;
2006-01-18 02:38:21 +03:00
read_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
return ref ;
}
publ = sseq - > cluster_list ;
if ( publ ) {
sseq - > cluster_list = publ - > cluster_list_next ;
goto found ;
}
publ = sseq - > zone_list ;
if ( publ ) {
sseq - > zone_list = publ - > zone_list_next ;
goto found ;
}
}
/* Round-Robin Algorithm: */
else if ( * destnode = = tipc_own_addr ) {
publ = sseq - > node_list ;
if ( publ ) {
sseq - > node_list = publ - > node_list_next ;
goto found ;
}
} else if ( in_own_cluster ( * destnode ) ) {
publ = sseq - > cluster_list ;
if ( publ ) {
sseq - > cluster_list = publ - > cluster_list_next ;
goto found ;
}
} else {
publ = sseq - > zone_list ;
if ( publ ) {
sseq - > zone_list = publ - > zone_list_next ;
goto found ;
}
}
spin_unlock_bh ( & seq - > lock ) ;
not_found :
2006-01-18 02:38:21 +03:00
read_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
return 0 ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nametbl_mc_translate - find multicast destinations
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Creates list of all local ports that overlap the given multicast address ;
* also determines if any off - node ports overlap .
*
* Note : Publications with a scope narrower than ' limit ' are ignored .
* ( i . e . local node - scope publications mustn ' t receive messages arriving
* from another node , even if the multcast link brought it here )
2007-02-09 17:25:21 +03:00
*
2006-01-02 21:04:38 +03:00
* Returns non - zero if any off - node ports overlap
*/
2006-01-18 02:38:21 +03:00
int tipc_nametbl_mc_translate ( u32 type , u32 lower , u32 upper , u32 limit ,
struct port_list * dports )
2006-01-02 21:04:38 +03:00
{
struct name_seq * seq ;
struct sub_seq * sseq ;
struct sub_seq * sseq_stop ;
int res = 0 ;
2006-01-18 02:38:21 +03:00
read_lock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
seq = nametbl_find_seq ( type ) ;
if ( ! seq )
goto exit ;
spin_lock_bh ( & seq - > lock ) ;
sseq = seq - > sseqs + nameseq_locate_subseq ( seq , lower ) ;
sseq_stop = seq - > sseqs + seq - > first_free ;
for ( ; sseq ! = sseq_stop ; sseq + + ) {
struct publication * publ ;
if ( sseq - > lower > upper )
break ;
2008-07-15 09:45:33 +04:00
publ = sseq - > node_list ;
if ( publ ) {
2006-01-02 21:04:38 +03:00
do {
2008-07-15 09:45:33 +04:00
if ( publ - > scope < = limit )
2006-01-18 02:38:21 +03:00
tipc_port_list_add ( dports , publ - > ref ) ;
2008-07-15 09:45:33 +04:00
publ = publ - > node_list_next ;
} while ( publ ! = sseq - > node_list ) ;
}
if ( sseq - > cluster_list_size ! = sseq - > node_list_size )
res = 1 ;
2006-01-02 21:04:38 +03:00
}
spin_unlock_bh ( & seq - > lock ) ;
exit :
2006-01-18 02:38:21 +03:00
read_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
return res ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nametbl_publish_rsv - publish port name using a reserved name type
2006-01-02 21:04:38 +03:00
*/
2007-02-09 17:25:21 +03:00
int tipc_nametbl_publish_rsv ( u32 ref , unsigned int scope ,
2006-01-02 21:04:38 +03:00
struct tipc_name_seq const * seq )
{
int res ;
atomic_inc ( & rsv_publ_ok ) ;
res = tipc_publish ( ref , scope , seq ) ;
atomic_dec ( & rsv_publ_ok ) ;
return res ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nametbl_publish - add name publication to network name tables
2006-01-02 21:04:38 +03:00
*/
2007-02-09 17:25:21 +03:00
struct publication * tipc_nametbl_publish ( u32 type , u32 lower , u32 upper ,
2006-01-02 21:04:38 +03:00
u32 scope , u32 port_ref , u32 key )
{
struct publication * publ ;
if ( table . local_publ_count > = tipc_max_publications ) {
2007-02-09 17:25:21 +03:00
warn ( " Publication failed, local publication limit reached (%u) \n " ,
2006-01-02 21:04:38 +03:00
tipc_max_publications ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
if ( ( type < TIPC_RESERVED_TYPES ) & & ! atomic_read ( & rsv_publ_ok ) ) {
2006-06-26 10:51:37 +04:00
warn ( " Publication failed, reserved name {%u,%u,%u} \n " ,
2006-01-02 21:04:38 +03:00
type , lower , upper ) ;
2006-03-21 09:36:47 +03:00
return NULL ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
write_lock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
table . local_publ_count + + ;
2006-01-18 02:38:21 +03:00
publ = tipc_nametbl_insert_publ ( type , lower , upper , scope ,
2006-01-02 21:04:38 +03:00
tipc_own_addr , port_ref , key ) ;
if ( publ & & ( scope ! = TIPC_NODE_SCOPE ) ) {
2006-01-18 02:38:21 +03:00
tipc_named_publish ( publ ) ;
2006-01-02 21:04:38 +03:00
}
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
return publ ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nametbl_withdraw - withdraw name publication from network name tables
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
int tipc_nametbl_withdraw ( u32 type , u32 lower , u32 ref , u32 key )
2006-01-02 21:04:38 +03:00
{
struct publication * publ ;
2006-06-26 10:51:37 +04:00
dbg ( " tipc_nametbl_withdraw: {%u,%u}, key=%u \n " , type , lower , key ) ;
2006-01-18 02:38:21 +03:00
write_lock_bh ( & tipc_nametbl_lock ) ;
publ = tipc_nametbl_remove_publ ( type , lower , tipc_own_addr , ref , key ) ;
2006-06-26 10:51:37 +04:00
if ( likely ( publ ) ) {
2006-01-02 21:04:38 +03:00
table . local_publ_count - - ;
if ( publ - > scope ! = TIPC_NODE_SCOPE )
2006-01-18 02:38:21 +03:00
tipc_named_withdraw ( publ ) ;
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
list_del_init ( & publ - > pport_list ) ;
kfree ( publ ) ;
return 1 ;
}
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-06-26 10:51:37 +04:00
err ( " Unable to remove local publication \n "
" (type=%u, lower=%u, ref=%u, key=%u) \n " ,
type , lower , ref , key ) ;
2006-01-02 21:04:38 +03:00
return 0 ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nametbl_subscribe - add a subscription object to the name table
2006-01-02 21:04:38 +03:00
*/
2006-06-26 10:51:37 +04:00
void tipc_nametbl_subscribe ( struct subscription * s )
2006-01-02 21:04:38 +03:00
{
u32 type = s - > seq . type ;
struct name_seq * seq ;
2007-02-09 17:25:21 +03:00
write_lock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
seq = nametbl_find_seq ( type ) ;
if ( ! seq ) {
2006-01-18 02:38:21 +03:00
seq = tipc_nameseq_create ( type , & table . types [ hash ( type ) ] ) ;
2006-01-02 21:04:38 +03:00
}
2007-02-09 17:25:21 +03:00
if ( seq ) {
spin_lock_bh ( & seq - > lock ) ;
dbg ( " tipc_nametbl_subscribe:found %p for {%u,%u,%u} \n " ,
seq , type , s - > seq . lower , s - > seq . upper ) ;
tipc_nameseq_subscribe ( seq , s ) ;
spin_unlock_bh ( & seq - > lock ) ;
} else {
2006-06-26 10:51:37 +04:00
warn ( " Failed to create subscription for {%u,%u,%u} \n " ,
s - > seq . type , s - > seq . lower , s - > seq . upper ) ;
2007-02-09 17:25:21 +03:00
}
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
}
/**
2006-01-18 02:38:21 +03:00
* tipc_nametbl_unsubscribe - remove a subscription object from name table
2006-01-02 21:04:38 +03:00
*/
2006-06-26 10:51:37 +04:00
void tipc_nametbl_unsubscribe ( struct subscription * s )
2006-01-02 21:04:38 +03:00
{
struct name_seq * seq ;
2007-02-09 17:25:21 +03:00
write_lock_bh ( & tipc_nametbl_lock ) ;
seq = nametbl_find_seq ( s - > seq . type ) ;
2006-01-02 21:04:38 +03:00
if ( seq ! = NULL ) {
2007-02-09 17:25:21 +03:00
spin_lock_bh ( & seq - > lock ) ;
list_del_init ( & s - > nameseq_list ) ;
spin_unlock_bh ( & seq - > lock ) ;
if ( ( seq - > first_free = = 0 ) & & list_empty ( & seq - > subscriptions ) ) {
hlist_del_init ( & seq - > ns_list ) ;
kfree ( seq - > sseqs ) ;
kfree ( seq ) ;
}
}
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
}
/**
* subseq_list : print specified sub - sequence contents into the given buffer
*/
static void subseq_list ( struct sub_seq * sseq , struct print_buf * buf , u32 depth ,
u32 index )
{
char portIdStr [ 27 ] ;
2010-08-17 15:00:14 +04:00
const char * scope_str [ ] = { " " , " zone " , " cluster " , " node " } ;
2006-01-02 21:04:38 +03:00
struct publication * publ = sseq - > zone_list ;
tipc_printf ( buf , " %-10u %-10u " , sseq - > lower , sseq - > upper ) ;
if ( depth = = 2 | | ! publ ) {
tipc_printf ( buf , " \n " ) ;
return ;
}
do {
sprintf ( portIdStr , " <%u.%u.%u:%u> " ,
tipc_zone ( publ - > node ) , tipc_cluster ( publ - > node ) ,
tipc_node ( publ - > node ) , publ - > ref ) ;
tipc_printf ( buf , " %-26s " , portIdStr ) ;
if ( depth > 3 ) {
2010-08-17 15:00:14 +04:00
tipc_printf ( buf , " %-10u %s " , publ - > key ,
scope_str [ publ - > scope ] ) ;
2006-01-02 21:04:38 +03:00
}
publ = publ - > zone_list_next ;
if ( publ = = sseq - > zone_list )
break ;
tipc_printf ( buf , " \n %33s " , " " ) ;
} while ( 1 ) ;
tipc_printf ( buf , " \n " ) ;
}
/**
* nameseq_list : print specified name sequence contents into the given buffer
*/
static void nameseq_list ( struct name_seq * seq , struct print_buf * buf , u32 depth ,
u32 type , u32 lowbound , u32 upbound , u32 index )
{
struct sub_seq * sseq ;
char typearea [ 11 ] ;
2008-06-05 04:37:59 +04:00
if ( seq - > first_free = = 0 )
return ;
2006-01-02 21:04:38 +03:00
sprintf ( typearea , " %-10u " , seq - > type ) ;
if ( depth = = 1 ) {
tipc_printf ( buf , " %s \n " , typearea ) ;
return ;
}
for ( sseq = seq - > sseqs ; sseq ! = & seq - > sseqs [ seq - > first_free ] ; sseq + + ) {
if ( ( lowbound < = sseq - > upper ) & & ( upbound > = sseq - > lower ) ) {
tipc_printf ( buf , " %s " , typearea ) ;
2008-06-05 04:38:22 +04:00
spin_lock_bh ( & seq - > lock ) ;
2006-01-02 21:04:38 +03:00
subseq_list ( sseq , buf , depth , index ) ;
2008-06-05 04:38:22 +04:00
spin_unlock_bh ( & seq - > lock ) ;
2006-01-02 21:04:38 +03:00
sprintf ( typearea , " %10s " , " " ) ;
}
}
}
/**
* nametbl_header - print name table header into the given buffer
*/
static void nametbl_header ( struct print_buf * buf , u32 depth )
{
2010-08-17 15:00:14 +04:00
const char * header [ ] = {
" Type " ,
" Lower Upper " ,
" Port Identity " ,
" Publication Scope "
} ;
int i ;
if ( depth > 4 )
depth = 4 ;
for ( i = 0 ; i < depth ; i + + )
tipc_printf ( buf , header [ i ] ) ;
2006-01-02 21:04:38 +03:00
tipc_printf ( buf , " \n " ) ;
}
/**
* nametbl_list - print specified name table contents into the given buffer
*/
2007-02-09 17:25:21 +03:00
static void nametbl_list ( struct print_buf * buf , u32 depth_info ,
2006-01-02 21:04:38 +03:00
u32 type , u32 lowbound , u32 upbound )
{
struct hlist_head * seq_head ;
struct hlist_node * seq_node ;
struct name_seq * seq ;
int all_types ;
u32 depth ;
u32 i ;
all_types = ( depth_info & TIPC_NTQ_ALLTYPES ) ;
depth = ( depth_info & ~ TIPC_NTQ_ALLTYPES ) ;
if ( depth = = 0 )
return ;
if ( all_types ) {
/* display all entries in name table to specified depth */
nametbl_header ( buf , depth ) ;
lowbound = 0 ;
upbound = ~ 0 ;
for ( i = 0 ; i < tipc_nametbl_size ; i + + ) {
seq_head = & table . types [ i ] ;
hlist_for_each_entry ( seq , seq_node , seq_head , ns_list ) {
2007-02-09 17:25:21 +03:00
nameseq_list ( seq , buf , depth , seq - > type ,
2006-01-02 21:04:38 +03:00
lowbound , upbound , i ) ;
}
}
} else {
/* display only the sequence that matches the specified type */
if ( upbound < lowbound ) {
tipc_printf ( buf , " invalid name sequence specified \n " ) ;
return ;
}
nametbl_header ( buf , depth ) ;
i = hash ( type ) ;
seq_head = & table . types [ i ] ;
hlist_for_each_entry ( seq , seq_node , seq_head , ns_list ) {
if ( seq - > type = = type ) {
2007-02-09 17:25:21 +03:00
nameseq_list ( seq , buf , depth , type ,
2006-01-02 21:04:38 +03:00
lowbound , upbound , i ) ;
break ;
}
}
}
}
# define MAX_NAME_TBL_QUERY 32768
2006-01-18 02:38:21 +03:00
struct sk_buff * tipc_nametbl_get ( const void * req_tlv_area , int req_tlv_space )
2006-01-02 21:04:38 +03:00
{
struct sk_buff * buf ;
struct tipc_name_table_query * argv ;
struct tlv_desc * rep_tlv ;
struct print_buf b ;
int str_len ;
if ( ! TLV_CHECK ( req_tlv_area , req_tlv_space , TIPC_TLV_NAME_TBL_QUERY ) )
2006-01-18 02:38:21 +03:00
return tipc_cfg_reply_error_string ( TIPC_CFG_TLV_ERROR ) ;
2006-01-02 21:04:38 +03:00
2006-01-18 02:38:21 +03:00
buf = tipc_cfg_reply_alloc ( TLV_SPACE ( MAX_NAME_TBL_QUERY ) ) ;
2006-01-02 21:04:38 +03:00
if ( ! buf )
return NULL ;
rep_tlv = ( struct tlv_desc * ) buf - > data ;
2006-01-18 02:38:21 +03:00
tipc_printbuf_init ( & b , TLV_DATA ( rep_tlv ) , MAX_NAME_TBL_QUERY ) ;
2006-01-02 21:04:38 +03:00
argv = ( struct tipc_name_table_query * ) TLV_DATA ( req_tlv_area ) ;
2006-01-18 02:38:21 +03:00
read_lock_bh ( & tipc_nametbl_lock ) ;
2007-02-09 17:25:21 +03:00
nametbl_list ( & b , ntohl ( argv - > depth ) , ntohl ( argv - > type ) ,
2006-01-02 21:04:38 +03:00
ntohl ( argv - > lowbound ) , ntohl ( argv - > upbound ) ) ;
2006-01-18 02:38:21 +03:00
read_unlock_bh ( & tipc_nametbl_lock ) ;
str_len = tipc_printbuf_validate ( & b ) ;
2006-01-02 21:04:38 +03:00
skb_put ( buf , TLV_SPACE ( str_len ) ) ;
TLV_SET ( rep_tlv , TIPC_TLV_ULTRA_STRING , NULL , str_len ) ;
return buf ;
}
2006-01-18 02:38:21 +03:00
int tipc_nametbl_init ( void )
2006-01-02 21:04:38 +03:00
{
2008-05-13 02:41:53 +04:00
table . types = kcalloc ( tipc_nametbl_size , sizeof ( struct hlist_head ) ,
GFP_ATOMIC ) ;
2006-01-02 21:04:38 +03:00
if ( ! table . types )
return - ENOMEM ;
table . local_publ_count = 0 ;
return 0 ;
}
2006-01-18 02:38:21 +03:00
void tipc_nametbl_stop ( void )
2006-01-02 21:04:38 +03:00
{
u32 i ;
if ( ! table . types )
return ;
2006-06-26 10:51:37 +04:00
/* Verify name table is empty, then release it */
2006-01-18 02:38:21 +03:00
write_lock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
for ( i = 0 ; i < tipc_nametbl_size ; i + + ) {
2006-06-26 10:51:37 +04:00
if ( ! hlist_empty ( & table . types [ i ] ) )
err ( " tipc_nametbl_stop(): hash chain %u is non-null \n " , i ) ;
2006-01-02 21:04:38 +03:00
}
kfree ( table . types ) ;
table . types = NULL ;
2006-01-18 02:38:21 +03:00
write_unlock_bh ( & tipc_nametbl_lock ) ;
2006-01-02 21:04:38 +03:00
}
2006-06-26 10:51:37 +04:00