diff options
Diffstat (limited to 'net/tipc/name_table.c')
| -rw-r--r-- | net/tipc/name_table.c | 1076 | 
1 files changed, 1076 insertions, 0 deletions
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c new file mode 100644 index 00000000000..9626c5b3067 --- /dev/null +++ b/net/tipc/name_table.c @@ -0,0 +1,1076 @@ +/* + * net/tipc/name_table.c: TIPC name table code + *  + * Copyright (c) 2003-2005, Ericsson Research Canada + * Copyright (c) 2004-2005, Wind River Systems + * Copyright (c) 2005-2006, Ericsson AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without  + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this  + * list of conditions and the following disclaimer. + * 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. + * 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. + * + * 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 "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" + +int tipc_nametbl_size = 1024;		/* must be a power of 2 */ + +/** + * struct sub_seq - container for all published instances of a name sequence + * @lower: name sequence lower bound + * @upper: name sequence upper bound + * @node_list: circular list of matching publications with >= node scope + * @cluster_list: circular list of matching publications with >= cluster scope + * @zone_list: circular list of matching publications with >= zone scope + */ + +struct sub_seq { +	u32 lower; +	u32 upper; +	struct publication *node_list; +	struct publication *cluster_list; +	struct publication *zone_list; +}; + +/**  + * 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 + * @first_free: upper bound of highest sub-sequence + 1 + * @ns_list: links to adjacent name sequences in hash chain + * @subscriptions: list of subscriptions for this 'type' + * @lock: spinlock controlling access to name sequence structure + */ + +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 + * @types: pointer to fixed-sized array of name sequence lists,  + *         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; +}; + +struct name_table table = { NULL } ; +static atomic_t rsv_publ_ok = ATOMIC_INIT(0); +rwlock_t nametbl_lock = RW_LOCK_UNLOCKED; + + +static inline int hash(int x) +{ +	return(x & (tipc_nametbl_size - 1)); +} + +/** + * publ_create - create a publication structure + */ + +static struct publication *publ_create(u32 type, u32 lower, u32 upper,  +				       u32 scope, u32 node, u32 port_ref,    +				       u32 key) +{ +	struct publication *publ = +		(struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC); +	if (publ == NULL) { +		warn("Memory squeeze; failed to create publication\n"); +		return 0; +	} + +	memset(publ, 0, sizeof(*publ)); +	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; +} + +/** + * subseq_alloc - allocate a specified number of sub-sequence structures + */ + +struct sub_seq *subseq_alloc(u32 cnt) +{ +	u32 sz = cnt * sizeof(struct sub_seq); +	struct sub_seq *sseq = (struct sub_seq *)kmalloc(sz, GFP_ATOMIC); + +	if (sseq) +		memset(sseq, 0, sz); +	return sseq; +} + +/** + * nameseq_create - create a name sequence structure for the specified 'type' + *  + * Allocates a single sub-sequence structure and sets it to all 0's. + */ + +struct name_seq *nameseq_create(u32 type, struct hlist_head *seq_head) +{ +	struct name_seq *nseq =  +		(struct name_seq *)kmalloc(sizeof(*nseq), GFP_ATOMIC); +	struct sub_seq *sseq = subseq_alloc(1); + +	if (!nseq || !sseq) { +		warn("Memory squeeze; failed to create name sequence\n"); +		kfree(nseq); +		kfree(sseq); +		return 0; +	} + +	memset(nseq, 0, sizeof(*nseq)); +	nseq->lock = SPIN_LOCK_UNLOCKED; +	nseq->type = type; +	nseq->sseqs = sseq; +	dbg("nameseq_create() nseq = %x type %u, ssseqs %x, ff: %u\n", +	    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 + *   + * Very time-critical, so binary searches through sub-sequence array. + */ + +static inline struct sub_seq *nameseq_find_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 &sseqs[mid]; +	} +	return 0; +} + +/** + * nameseq_locate_subseq - determine position of name instance in sub-sequence + *  + * 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; +} + +/** + * nameseq_insert_publ -  + */ + +struct publication *nameseq_insert_publ(struct name_seq *nseq, +					u32 type, u32 lower, u32 upper, +					u32 scope, u32 node, u32 port, u32 key) +{ +	struct subscription *s; +	struct subscription *st; +	struct publication *publ; +	struct sub_seq *sseq; +	int created_subseq = 0; + +	assert(nseq->first_free <= nseq->alloc); +	sseq = nameseq_find_subseq(nseq, lower); +	dbg("nameseq_ins: for seq %x,<%u,%u>, found sseq %x\n", +	    nseq, type, lower, sseq); +	if (sseq) { + +		/* Lower end overlaps existing entry => need an exact match */ + +		if ((sseq->lower != lower) || (sseq->upper != upper)) { +			warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper); +			return 0; +		} +	} 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)) { +			warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper); +			return 0; +		} + +		/* Ensure there is space for new sub-sequence */ + +		if (nseq->first_free == nseq->alloc) { +			struct sub_seq *sseqs = nseq->sseqs; +			nseq->sseqs = subseq_alloc(nseq->alloc * 2); +			if (nseq->sseqs != NULL) { +				memcpy(nseq->sseqs, sseqs, +				       nseq->alloc * sizeof (struct sub_seq)); +				kfree(sseqs); +				dbg("Allocated %u sseqs\n", nseq->alloc); +				nseq->alloc *= 2; +			} else { +				warn("Memory squeeze; failed to create sub-sequence\n"); +				return 0; +			} +		} +		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; +	} +	dbg("inserting (%u %u %u) from %x:%u into sseq %x(%u,%u) of seq %x\n", +	    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) +		return 0; +	dbg("inserting publ %x, node=%x publ->node=%x, subscr->node=%x\n", +	    publ, node, publ->node, publ->subscr.node); + +	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)) { +		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) { +		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; +		} +	} + +	/*  +	 * Any subscriptions waiting for notification?  +	 */ +	list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) { +		dbg("calling report_overlap()\n"); +		subscr_report_overlap(s, +				      publ->lower, +				      publ->upper, +				      TIPC_PUBLISHED, +				      publ->ref,  +				      publ->node, +				      created_subseq); +	} +	return publ; +} + +/** + * nameseq_remove_publ - + */ + +struct publication *nameseq_remove_publ(struct name_seq *nseq, u32 inst, +					u32 node, u32 ref, u32 key) +{ +	struct publication *publ; +	struct publication *prev; +	struct sub_seq *sseq = nameseq_find_subseq(nseq, inst); +	struct sub_seq *free; +	struct subscription *s, *st; +	int removed_subseq = 0; + +	assert(nseq); + +	if (!sseq) { +		int i; + +		warn("Withdraw unknown <%u,%u>?\n", nseq->type, inst); +		assert(nseq->sseqs); +		dbg("Dumping subseqs %x for %x, alloc = %u,ff=%u\n", +		    nseq->sseqs, nseq, nseq->alloc,  +		    nseq->first_free); +		for (i = 0; i < nseq->first_free; i++) { +			dbg("Subseq %u(%x): lower = %u,upper = %u\n", +			    i, &nseq->sseqs[i], nseq->sseqs[i].lower, +			    nseq->sseqs[i].upper); +		} +		return 0; +	} +	dbg("nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u\n", +	    nseq, sseq, nseq->type, inst, key); + +	prev = sseq->zone_list; +	publ = sseq->zone_list->zone_list_next; +	while ((publ->key != key) || (publ->ref != ref) ||  +	       (publ->node && (publ->node != node))) { +		prev = publ; +		publ = publ->zone_list_next; +		assert(prev != sseq->zone_list); +	} +	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 { +		sseq->zone_list = 0; +	} + +	if (in_own_cluster(node)) { +		prev = sseq->cluster_list; +		publ = sseq->cluster_list->cluster_list_next; +		while ((publ->key != key) || (publ->ref != ref) ||  +		       (publ->node && (publ->node != node))) { +			prev = publ; +			publ = publ->cluster_list_next; +			assert(prev != sseq->cluster_list); +		} +		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 { +			sseq->cluster_list = 0; +		} +	} + +	if (node == tipc_own_addr) { +		prev = sseq->node_list; +		publ = sseq->node_list->node_list_next; +		while ((publ->key != key) || (publ->ref != ref) ||  +		       (publ->node && (publ->node != node))) { +			prev = publ; +			publ = publ->node_list_next; +			assert(prev != sseq->node_list); +		} +		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 { +			sseq->node_list = 0; +		} +	} +	assert(!publ->node || (publ->node == node)); +	assert(publ->ref == ref); +	assert(publ->key == key); + +	/*  +	 * Contract subseq list if no more publications: +	 */ +	if (!sseq->node_list && !sseq->cluster_list && !sseq->zone_list) { +		free = &nseq->sseqs[nseq->first_free--]; +		memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof (*sseq)); +		removed_subseq = 1; +	} + +	/*  +	 * Any subscriptions waiting ?  +	 */ +	list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) { +		subscr_report_overlap(s, +				      publ->lower, +				      publ->upper, +				      TIPC_WITHDRAWN,  +				      publ->ref,  +				      publ->node, +				      removed_subseq); +	} +	return publ; +} + +/** + * nameseq_subscribe: attach a subscription, and issue + * the prescribed number of events if there is any sub- + * sequence overlapping with the requested sequence + */ + +void nameseq_subscribe(struct name_seq *nseq, struct subscription *s) +{ +	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; +		if (zl && subscr_overlap(s,sseq->lower,sseq->upper)) { +			struct publication *crs = zl; +			int must_report = 1; + +			do { +				subscr_report_overlap(s,  +						       sseq->lower,  +						       sseq->upper, +						       TIPC_PUBLISHED, +						       crs->ref, +						       crs->node, +						       must_report); +				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", +	    type, ntohl(type), type, table.types, hash(type)); + +	seq_head = &table.types[hash(type)]; +	hlist_for_each_entry(ns, seq_node, seq_head, ns_list) { +		if (ns->type == type) { +			dbg("found %x\n", ns); +			return ns; +		} +	} + +	return 0; +}; + +struct publication *nametbl_insert_publ(u32 type, u32 lower, u32 upper, +		    u32 scope, u32 node, u32 port, u32 key) +{ +	struct name_seq *seq = nametbl_find_seq(type); + +	dbg("ins_publ: <%u,%x,%x> found %x\n", type, lower, upper, seq); +	if (lower > upper) { +		warn("Failed to publish illegal <%u,%u,%u>\n", +		     type, lower, upper); +		return 0; +	} + +	dbg("Publishing <%u,%u,%u> from %x\n", type, lower, upper, node); +	if (!seq) { +		seq = nameseq_create(type, &table.types[hash(type)]); +		dbg("nametbl_insert_publ: created %x\n", seq); +	} +	if (!seq) +		return 0; + +	assert(seq->type == type); +	return nameseq_insert_publ(seq, type, lower, upper, +				   scope, node, port, key); +} + +struct publication *nametbl_remove_publ(u32 type, u32 lower,  +					u32 node, u32 ref, u32 key) +{ +	struct publication *publ; +	struct name_seq *seq = nametbl_find_seq(type); + +	if (!seq) +		return 0; + +	dbg("Withdrawing <%u,%u> from %x\n", type, lower, node); +	publ = nameseq_remove_publ(seq, lower, node, ref, key); + +	if (!seq->first_free && list_empty(&seq->subscriptions)) { +		hlist_del_init(&seq->ns_list); +		kfree(seq->sseqs); +		kfree(seq); +	} +	return publ; +} + +/* + * nametbl_translate(): Translate tipc_name -> tipc_portid. + *                      Very time-critical. + * + * 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) + */ + +u32 nametbl_translate(u32 type, u32 instance, u32 *destnode) +{ +	struct sub_seq *sseq; +	struct publication *publ = 0; +	struct name_seq *seq; +	u32 ref; + +	if (!in_scope(*destnode, tipc_own_addr)) +		return 0; + +	read_lock_bh(&nametbl_lock); +	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); +			read_unlock_bh(&nametbl_lock); +			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: +	*destnode = 0; +	read_unlock_bh(&nametbl_lock); +	return 0; +} + +/** + * nametbl_mc_translate - find multicast destinations + *  + * 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) + *  + * Returns non-zero if any off-node ports overlap + */ + +int nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit, +			 struct port_list *dports) +{ +	struct name_seq *seq; +	struct sub_seq *sseq; +	struct sub_seq *sseq_stop; +	int res = 0; + +	read_lock_bh(&nametbl_lock); +	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; +		publ = sseq->cluster_list; +		if (publ && (publ->scope <= limit)) +			do { +				if (publ->node == tipc_own_addr) +					port_list_add(dports, publ->ref); +				else +					res = 1; +				publ = publ->cluster_list_next; +			} while (publ != sseq->cluster_list); +	} + +	spin_unlock_bh(&seq->lock); +exit: +	read_unlock_bh(&nametbl_lock); +	return res; +} + +/** + * nametbl_publish_rsv - publish port name using a reserved name type + */ + +int nametbl_publish_rsv(u32 ref, unsigned int scope,  +			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; +} + +/** + * nametbl_publish - add name publication to network name tables + */ + +struct publication *nametbl_publish(u32 type, u32 lower, u32 upper,  +				    u32 scope, u32 port_ref, u32 key) +{ +	struct publication *publ; + +	if (table.local_publ_count >= tipc_max_publications) { +		warn("Failed publish: max %u local publication\n",  +		     tipc_max_publications); +		return 0; +	} +	if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) { +		warn("Failed to publish reserved name <%u,%u,%u>\n", +		     type, lower, upper); +		return 0; +	} + +	write_lock_bh(&nametbl_lock); +	table.local_publ_count++; +	publ = nametbl_insert_publ(type, lower, upper, scope, +				   tipc_own_addr, port_ref, key); +	if (publ && (scope != TIPC_NODE_SCOPE)) { +		named_publish(publ); +	} +	write_unlock_bh(&nametbl_lock); +	return publ; +} + +/** + * nametbl_withdraw - withdraw name publication from network name tables + */ + +int nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key) +{ +	struct publication *publ; + +	dbg("nametbl_withdraw:<%d,%d,%d>\n", type, lower, key); +	write_lock_bh(&nametbl_lock); +	publ = nametbl_remove_publ(type, lower, tipc_own_addr, ref, key); +	if (publ) { +		table.local_publ_count--; +		if (publ->scope != TIPC_NODE_SCOPE) +			named_withdraw(publ); +		write_unlock_bh(&nametbl_lock); +		list_del_init(&publ->pport_list); +		kfree(publ); +		return 1; +	} +	write_unlock_bh(&nametbl_lock); +	return 0; +} + +/** + * nametbl_subscribe - add a subscription object to the name table + */ + +void +nametbl_subscribe(struct subscription *s) +{ +	u32 type = s->seq.type; +	struct name_seq *seq; + +        write_lock_bh(&nametbl_lock); +	seq = nametbl_find_seq(type); +	if (!seq) { +		seq = nameseq_create(type, &table.types[hash(type)]); +	} +        if (seq){ +                spin_lock_bh(&seq->lock); +                dbg("nametbl_subscribe:found %x for <%u,%u,%u>\n", +                    seq, type, s->seq.lower, s->seq.upper); +                assert(seq->type == type); +                nameseq_subscribe(seq, s); +                spin_unlock_bh(&seq->lock); +        } +        write_unlock_bh(&nametbl_lock); +} + +/** + * nametbl_unsubscribe - remove a subscription object from name table + */ + +void +nametbl_unsubscribe(struct subscription *s) +{ +	struct name_seq *seq; + +        write_lock_bh(&nametbl_lock); +        seq = nametbl_find_seq(s->seq.type); +	if (seq != NULL){ +                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(&nametbl_lock); +} + + +/** + * 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]; +	char *scopeStr; +	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) { +			if (publ->node != tipc_own_addr) +				scopeStr = ""; +			else if (publ->scope == TIPC_NODE_SCOPE) +				scopeStr = "node"; +			else if (publ->scope == TIPC_CLUSTER_SCOPE) +				scopeStr = "cluster"; +			else +				scopeStr = "zone"; +			tipc_printf(buf, "%-10u %s", publ->key, scopeStr); +		} + +		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]; + +	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); +			subseq_list(sseq, buf, depth, index); +			sprintf(typearea, "%10s", " "); +		} +	} +} + +/** + * nametbl_header - print name table header into the given buffer + */ + +static void nametbl_header(struct print_buf *buf, u32 depth) +{ +	tipc_printf(buf, "Type       "); + +	if (depth > 1) +		tipc_printf(buf, "Lower      Upper      "); +	if (depth > 2) +		tipc_printf(buf, "Port Identity              "); +	if (depth > 3) +		tipc_printf(buf, "Publication"); + +	tipc_printf(buf, "\n-----------"); + +	if (depth > 1) +		tipc_printf(buf, "--------------------- "); +	if (depth > 2) +		tipc_printf(buf, "-------------------------- "); +	if (depth > 3) +		tipc_printf(buf, "------------------"); + +	tipc_printf(buf, "\n"); +} + +/** + * nametbl_list - print specified name table contents into the given buffer + */ + +static void nametbl_list(struct print_buf *buf, u32 depth_info,  +			 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) { +				nameseq_list(seq, buf, depth, seq->type,  +					     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) { +				nameseq_list(seq, buf, depth, type,  +					     lowbound, upbound, i); +				break; +			} +		} +	} +} + +void nametbl_print(struct print_buf *buf, const char *str) +{ +	tipc_printf(buf, str); +	read_lock_bh(&nametbl_lock); +	nametbl_list(buf, 0, 0, 0, 0); +	read_unlock_bh(&nametbl_lock); +} + +#define MAX_NAME_TBL_QUERY 32768 + +struct sk_buff *nametbl_get(const void *req_tlv_area, int req_tlv_space) +{ +	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)) +		return cfg_reply_error_string(TIPC_CFG_TLV_ERROR); + +	buf = cfg_reply_alloc(TLV_SPACE(MAX_NAME_TBL_QUERY)); +	if (!buf) +		return NULL; + +	rep_tlv = (struct tlv_desc *)buf->data; +	printbuf_init(&b, TLV_DATA(rep_tlv), MAX_NAME_TBL_QUERY); +	argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area); +	read_lock_bh(&nametbl_lock); +	nametbl_list(&b, ntohl(argv->depth), ntohl(argv->type),  +		     ntohl(argv->lowbound), ntohl(argv->upbound)); +	read_unlock_bh(&nametbl_lock); +	str_len = printbuf_validate(&b); + +	skb_put(buf, TLV_SPACE(str_len)); +	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len); + +	return buf; +} + +void nametbl_dump(void) +{ +	nametbl_list(CONS, 0, 0, 0, 0); +} + +int nametbl_init(void) +{ +	int array_size = sizeof(struct hlist_head) * tipc_nametbl_size; + +	table.types = (struct hlist_head *)kmalloc(array_size, GFP_ATOMIC); +	if (!table.types) +		return -ENOMEM; + +	write_lock_bh(&nametbl_lock); +	memset(table.types, 0, array_size); +	table.local_publ_count = 0; +	write_unlock_bh(&nametbl_lock); +	return 0; +} + +void nametbl_stop(void) +{ +	struct hlist_head *seq_head; +	struct hlist_node *seq_node; +	struct hlist_node *tmp; +	struct name_seq *seq; +	u32 i; + +	if (!table.types) +		return; + +	write_lock_bh(&nametbl_lock); +	for (i = 0; i < tipc_nametbl_size; i++) { +		seq_head = &table.types[i]; +		hlist_for_each_entry_safe(seq, seq_node, tmp, seq_head, ns_list) { +			struct sub_seq *sseq = seq->sseqs; + +			for (; sseq != &seq->sseqs[seq->first_free]; sseq++) { +				struct publication *publ = sseq->zone_list; +				assert(publ); +				do { +					struct publication *next = +						publ->zone_list_next; +					kfree(publ); +					publ = next; +				} +				while (publ != sseq->zone_list); +			} +		} +	} +	kfree(table.types); +	table.types = NULL; +	write_unlock_bh(&nametbl_lock); +}  |