diff options
Diffstat (limited to 'net/tipc/name_table.c')
| -rw-r--r-- | net/tipc/name_table.c | 225 |
1 files changed, 137 insertions, 88 deletions
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 010f24a59da..9d7d37d9518 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -41,7 +41,7 @@ #include "subscr.h" #include "port.h" -static int tipc_nametbl_size = 1024; /* must be a power of 2 */ +#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */ /** * struct name_info - name sequence publication info @@ -114,7 +114,7 @@ DEFINE_RWLOCK(tipc_nametbl_lock); static int hash(int x) { - return x & (tipc_nametbl_size - 1); + return x & (TIPC_NAMETBL_SIZE - 1); } /** @@ -126,7 +126,7 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper, { struct publication *publ = kzalloc(sizeof(*publ), GFP_ATOMIC); if (publ == NULL) { - warn("Publication creation failure, no memory\n"); + pr_warn("Publication creation failure, no memory\n"); return NULL; } @@ -148,8 +148,7 @@ static struct publication *publ_create(u32 type, u32 lower, u32 upper, */ static struct sub_seq *tipc_subseq_alloc(u32 cnt) { - struct sub_seq *sseq = kcalloc(cnt, sizeof(struct sub_seq), GFP_ATOMIC); - return sseq; + return kcalloc(cnt, sizeof(struct sub_seq), GFP_ATOMIC); } /** @@ -163,7 +162,7 @@ static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_hea struct sub_seq *sseq = tipc_subseq_alloc(1); if (!nseq || !sseq) { - warn("Name sequence creation failed, no memory\n"); + pr_warn("Name sequence creation failed, no memory\n"); kfree(nseq); kfree(sseq); return NULL; @@ -191,7 +190,7 @@ static void nameseq_delete_empty(struct name_seq *seq) } } -/* +/** * nameseq_find_subseq - find sub-sequence (if any) matching a name instance * * Very time-critical, so binary searches through sub-sequence array. @@ -263,8 +262,8 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, /* Lower end overlaps existing entry => need an exact match */ if ((sseq->lower != lower) || (sseq->upper != upper)) { - warn("Cannot publish {%u,%u,%u}, overlap error\n", - type, lower, upper); + pr_warn("Cannot publish {%u,%u,%u}, overlap error\n", + type, lower, upper); return NULL; } @@ -286,8 +285,8 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, /* Fail if upper end overlaps into an existing entry */ if ((inspos < nseq->first_free) && (upper >= nseq->sseqs[inspos].lower)) { - warn("Cannot publish {%u,%u,%u}, overlap error\n", - type, lower, upper); + pr_warn("Cannot publish {%u,%u,%u}, overlap error\n", + type, lower, upper); return NULL; } @@ -296,8 +295,8 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, struct sub_seq *sseqs = tipc_subseq_alloc(nseq->alloc * 2); if (!sseqs) { - warn("Cannot publish {%u,%u,%u}, no memory\n", - type, lower, upper); + pr_warn("Cannot publish {%u,%u,%u}, no memory\n", + type, lower, upper); return NULL; } memcpy(sseqs, nseq->sseqs, @@ -309,8 +308,8 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq, info = kzalloc(sizeof(*info), GFP_ATOMIC); if (!info) { - warn("Cannot publish {%u,%u,%u}, no memory\n", - type, lower, upper); + pr_warn("Cannot publish {%u,%u,%u}, no memory\n", + type, lower, upper); return NULL; } @@ -435,12 +434,12 @@ found: } /** - * tipc_nameseq_subscribe: attach a subscription, and issue + * tipc_nameseq_subscribe - attach a subscription, and issue * the prescribed number of events if there is any sub- * sequence overlapping with the requested sequence */ static void tipc_nameseq_subscribe(struct name_seq *nseq, - struct tipc_subscription *s) + struct tipc_subscription *s) { struct sub_seq *sseq = nseq->sseqs; @@ -473,11 +472,10 @@ static void tipc_nameseq_subscribe(struct name_seq *nseq, static struct name_seq *nametbl_find_seq(u32 type) { struct hlist_head *seq_head; - struct hlist_node *seq_node; struct name_seq *ns; seq_head = &table.types[hash(type)]; - hlist_for_each_entry(ns, seq_node, seq_head, ns_list) { + hlist_for_each_entry(ns, seq_head, ns_list) { if (ns->type == type) return ns; } @@ -492,8 +490,8 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper, if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE) || (lower > upper)) { - dbg("Failed to publish illegal {%u,%u,%u} with scope %u\n", - type, lower, upper, scope); + pr_debug("Failed to publish illegal {%u,%u,%u} with scope %u\n", + type, lower, upper, scope); return NULL; } @@ -520,7 +518,7 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, return publ; } -/* +/** * tipc_nametbl_translate - perform name translation * * On entry, 'destnode' is the search domain used during translation. @@ -663,13 +661,14 @@ exit: * tipc_nametbl_publish - add name publication to network name tables */ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, - u32 scope, u32 port_ref, u32 key) + u32 scope, u32 port_ref, u32 key) { struct publication *publ; + struct sk_buff *buf = NULL; - if (table.local_publ_count >= tipc_max_publications) { - warn("Publication failed, local publication limit reached (%u)\n", - tipc_max_publications); + if (table.local_publ_count >= TIPC_MAX_PUBLICATIONS) { + pr_warn("Publication failed, local publication limit reached (%u)\n", + TIPC_MAX_PUBLICATIONS); return NULL; } @@ -678,9 +677,12 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, tipc_own_addr, port_ref, key); if (likely(publ)) { table.local_publ_count++; - tipc_named_publish(publ); + buf = tipc_named_publish(publ); } write_unlock_bh(&tipc_nametbl_lock); + + if (buf) + named_cluster_distribute(buf); return publ; } @@ -690,21 +692,25 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper, int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key) { struct publication *publ; + struct sk_buff *buf; write_lock_bh(&tipc_nametbl_lock); publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key); if (likely(publ)) { table.local_publ_count--; - tipc_named_withdraw(publ); + buf = tipc_named_withdraw(publ); write_unlock_bh(&tipc_nametbl_lock); list_del_init(&publ->pport_list); kfree(publ); + + if (buf) + named_cluster_distribute(buf); return 1; } write_unlock_bh(&tipc_nametbl_lock); - err("Unable to remove local publication\n" - "(type=%u, lower=%u, ref=%u, key=%u)\n", - type, lower, ref, key); + pr_err("Unable to remove local publication\n" + "(type=%u, lower=%u, ref=%u, key=%u)\n", + type, lower, ref, key); return 0; } @@ -725,8 +731,8 @@ void tipc_nametbl_subscribe(struct tipc_subscription *s) tipc_nameseq_subscribe(seq, s); spin_unlock_bh(&seq->lock); } else { - warn("Failed to create subscription for {%u,%u,%u}\n", - s->seq.type, s->seq.lower, s->seq.upper); + pr_warn("Failed to create subscription for {%u,%u,%u}\n", + s->seq.type, s->seq.lower, s->seq.upper); } write_unlock_bh(&tipc_nametbl_lock); } @@ -751,21 +757,22 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s) /** - * subseq_list: print specified sub-sequence contents into the given buffer + * 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) +static int subseq_list(struct sub_seq *sseq, char *buf, int len, u32 depth, + u32 index) { char portIdStr[27]; const char *scope_str[] = {"", " zone", " cluster", " node"}; struct publication *publ; struct name_info *info; + int ret; - tipc_printf(buf, "%-10u %-10u ", sseq->lower, sseq->upper); + ret = tipc_snprintf(buf, len, "%-10u %-10u ", sseq->lower, sseq->upper); if (depth == 2) { - tipc_printf(buf, "\n"); - return; + ret += tipc_snprintf(buf - ret, len + ret, "\n"); + return ret; } info = sseq->info; @@ -774,52 +781,58 @@ static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth, 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); + ret += tipc_snprintf(buf + ret, len - ret, "%-26s ", portIdStr); if (depth > 3) { - tipc_printf(buf, "%-10u %s", publ->key, - scope_str[publ->scope]); + ret += tipc_snprintf(buf + ret, len - ret, "%-10u %s", + publ->key, scope_str[publ->scope]); } if (!list_is_last(&publ->zone_list, &info->zone_list)) - tipc_printf(buf, "\n%33s", " "); - }; + ret += tipc_snprintf(buf + ret, len - ret, + "\n%33s", " "); + } - tipc_printf(buf, "\n"); + ret += tipc_snprintf(buf + ret, len - ret, "\n"); + return ret; } /** - * nameseq_list: print specified name sequence contents into the given buffer + * 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) +static int nameseq_list(struct name_seq *seq, char *buf, int len, u32 depth, + u32 type, u32 lowbound, u32 upbound, u32 index) { struct sub_seq *sseq; char typearea[11]; + int ret = 0; if (seq->first_free == 0) - return; + return 0; sprintf(typearea, "%-10u", seq->type); if (depth == 1) { - tipc_printf(buf, "%s\n", typearea); - return; + ret += tipc_snprintf(buf, len, "%s\n", typearea); + return ret; } for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) { if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) { - tipc_printf(buf, "%s ", typearea); + ret += tipc_snprintf(buf + ret, len - ret, "%s ", + typearea); spin_lock_bh(&seq->lock); - subseq_list(sseq, buf, depth, index); + ret += subseq_list(sseq, buf + ret, len - ret, + depth, index); spin_unlock_bh(&seq->lock); sprintf(typearea, "%10s", " "); } } + return ret; } /** * nametbl_header - print name table header into the given buffer */ -static void nametbl_header(struct print_buf *buf, u32 depth) +static int nametbl_header(char *buf, int len, u32 depth) { const char *header[] = { "Type ", @@ -829,24 +842,26 @@ static void nametbl_header(struct print_buf *buf, u32 depth) }; int i; + int ret = 0; if (depth > 4) depth = 4; for (i = 0; i < depth; i++) - tipc_printf(buf, header[i]); - tipc_printf(buf, "\n"); + ret += tipc_snprintf(buf + ret, len - ret, header[i]); + ret += tipc_snprintf(buf + ret, len - ret, "\n"); + return ret; } /** * 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) +static int nametbl_list(char *buf, int len, 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; + int ret = 0; u32 depth; u32 i; @@ -854,65 +869,69 @@ static void nametbl_list(struct print_buf *buf, u32 depth_info, depth = (depth_info & ~TIPC_NTQ_ALLTYPES); if (depth == 0) - return; + return 0; if (all_types) { /* display all entries in name table to specified depth */ - nametbl_header(buf, depth); + ret += nametbl_header(buf, len, depth); lowbound = 0; upbound = ~0; - for (i = 0; i < tipc_nametbl_size; i++) { + 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); + hlist_for_each_entry(seq, seq_head, ns_list) { + ret += nameseq_list(seq, buf + ret, len - ret, + 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; + ret += tipc_snprintf(buf + ret, len - ret, + "invalid name sequence specified\n"); + return ret; } - nametbl_header(buf, depth); + ret += nametbl_header(buf + ret, len - ret, depth); i = hash(type); seq_head = &table.types[i]; - hlist_for_each_entry(seq, seq_node, seq_head, ns_list) { + hlist_for_each_entry(seq, seq_head, ns_list) { if (seq->type == type) { - nameseq_list(seq, buf, depth, type, - lowbound, upbound, i); + ret += nameseq_list(seq, buf + ret, len - ret, + depth, type, + lowbound, upbound, i); break; } } } + return ret; } -#define MAX_NAME_TBL_QUERY 32768 - struct sk_buff *tipc_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; + char *pb; + int pb_len; int str_len; if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NAME_TBL_QUERY)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); - buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_NAME_TBL_QUERY)); + buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN)); if (!buf) return NULL; rep_tlv = (struct tlv_desc *)buf->data; - tipc_printbuf_init(&b, TLV_DATA(rep_tlv), MAX_NAME_TBL_QUERY); + pb = TLV_DATA(rep_tlv); + pb_len = ULTRA_STRING_MAX_LEN; argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area); read_lock_bh(&tipc_nametbl_lock); - nametbl_list(&b, ntohl(argv->depth), ntohl(argv->type), - ntohl(argv->lowbound), ntohl(argv->upbound)); + str_len = nametbl_list(pb, pb_len, ntohl(argv->depth), + ntohl(argv->type), + ntohl(argv->lowbound), ntohl(argv->upbound)); read_unlock_bh(&tipc_nametbl_lock); - str_len = tipc_printbuf_validate(&b); - + str_len += 1; /* for "\0" */ skb_put(buf, TLV_SPACE(str_len)); TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len); @@ -921,7 +940,7 @@ struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space) int tipc_nametbl_init(void) { - table.types = kcalloc(tipc_nametbl_size, sizeof(struct hlist_head), + table.types = kcalloc(TIPC_NAMETBL_SIZE, sizeof(struct hlist_head), GFP_ATOMIC); if (!table.types) return -ENOMEM; @@ -930,18 +949,48 @@ int tipc_nametbl_init(void) return 0; } -void tipc_nametbl_stop(void) +/** + * tipc_purge_publications - remove all publications for a given type + * + * tipc_nametbl_lock must be held when calling this function + */ +static void tipc_purge_publications(struct name_seq *seq) { - u32 i; + struct publication *publ, *safe; + struct sub_seq *sseq; + struct name_info *info; - if (!table.types) + if (!seq->sseqs) { + nameseq_delete_empty(seq); return; + } + sseq = seq->sseqs; + info = sseq->info; + list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) { + tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node, + publ->ref, publ->key); + kfree(publ); + } +} - /* Verify name table is empty, then release it */ +void tipc_nametbl_stop(void) +{ + u32 i; + struct name_seq *seq; + struct hlist_head *seq_head; + struct hlist_node *safe; + + /* Verify name table is empty and purge any lingering + * publications, then release the name table + */ write_lock_bh(&tipc_nametbl_lock); - for (i = 0; i < tipc_nametbl_size; i++) { - if (!hlist_empty(&table.types[i])) - err("tipc_nametbl_stop(): hash chain %u is non-null\n", i); + for (i = 0; i < TIPC_NAMETBL_SIZE; i++) { + if (hlist_empty(&table.types[i])) + continue; + seq_head = &table.types[i]; + hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) { + tipc_purge_publications(seq); + } } kfree(table.types); table.types = NULL; |
