summaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/config.c11
-rw-r--r--net/tipc/core.c13
-rw-r--r--net/tipc/core.h126
-rw-r--r--net/tipc/dbg.c231
-rw-r--r--net/tipc/dbg.h12
-rw-r--r--net/tipc/discover.c5
-rw-r--r--net/tipc/link.c20
-rw-r--r--net/tipc/msg.c10
-rw-r--r--net/tipc/name_distr.c3
-rw-r--r--net/tipc/name_table.c7
-rw-r--r--net/tipc/net.c10
-rw-r--r--net/tipc/net.h2
-rw-r--r--net/tipc/netlink.c16
-rw-r--r--net/tipc/node.c26
-rw-r--r--net/tipc/port.c21
-rw-r--r--net/tipc/ref.c12
-rw-r--r--net/tipc/socket.c5
-rw-r--r--net/tipc/subscr.c249
-rw-r--r--net/tipc/subscr.h34
19 files changed, 458 insertions, 355 deletions
diff --git a/net/tipc/config.c b/net/tipc/config.c
index c71337a22d33..ca3544d030c7 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -2,7 +2,7 @@
* net/tipc/config.c: TIPC configuration management code
*
* Copyright (c) 2002-2006, Ericsson AB
- * Copyright (c) 2004-2006, Wind River Systems
+ * Copyright (c) 2004-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -293,7 +293,6 @@ static struct sk_buff *cfg_set_own_addr(void)
if (tipc_mode == TIPC_NET_MODE)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change node address once assigned)");
- tipc_own_addr = addr;
/*
* Must release all spinlocks before calling start_net() because
@@ -306,7 +305,7 @@ static struct sk_buff *cfg_set_own_addr(void)
*/
spin_unlock_bh(&config_lock);
- tipc_core_start_net();
+ tipc_core_start_net(addr);
spin_lock_bh(&config_lock);
return tipc_cfg_reply_none();
}
@@ -529,7 +528,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
break;
#endif
case TIPC_CMD_SET_LOG_SIZE:
- rep_tlv_buf = tipc_log_resize(req_tlv_area, req_tlv_space);
+ rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space);
break;
case TIPC_CMD_DUMP_LOG:
rep_tlv_buf = tipc_log_dump();
@@ -602,6 +601,10 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
case TIPC_CMD_GET_NETID:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
break;
+ case TIPC_CMD_NOT_NET_ADMIN:
+ rep_tlv_buf =
+ tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
+ break;
default:
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (unknown command)");
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 740aac5cdfb6..3256bd7d398f 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -49,7 +49,7 @@
#include "config.h"
-#define TIPC_MOD_VER "1.6.3"
+#define TIPC_MOD_VER "1.6.4"
#ifndef CONFIG_TIPC_ZONES
#define CONFIG_TIPC_ZONES 3
@@ -117,11 +117,11 @@ void tipc_core_stop_net(void)
* start_net - start TIPC networking sub-systems
*/
-int tipc_core_start_net(void)
+int tipc_core_start_net(unsigned long addr)
{
int res;
- if ((res = tipc_net_start()) ||
+ if ((res = tipc_net_start(addr)) ||
(res = tipc_eth_media_start())) {
tipc_core_stop_net();
}
@@ -164,8 +164,7 @@ int tipc_core_start(void)
tipc_mode = TIPC_NODE_MODE;
if ((res = tipc_handler_start()) ||
- (res = tipc_ref_table_init(tipc_max_ports + tipc_max_subscriptions,
- tipc_random)) ||
+ (res = tipc_ref_table_init(tipc_max_ports, tipc_random)) ||
(res = tipc_reg_start()) ||
(res = tipc_nametbl_init()) ||
(res = tipc_k_signal((Handler)tipc_subscr_start, 0)) ||
@@ -182,7 +181,7 @@ static int __init tipc_init(void)
{
int res;
- tipc_log_reinit(CONFIG_TIPC_LOG);
+ tipc_log_resize(CONFIG_TIPC_LOG);
info("Activated (version " TIPC_MOD_VER
" compiled " __DATE__ " " __TIME__ ")\n");
@@ -209,7 +208,7 @@ static void __exit tipc_exit(void)
tipc_core_stop_net();
tipc_core_stop();
info("Deactivated\n");
- tipc_log_stop();
+ tipc_log_resize(0);
}
module_init(tipc_init);
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 5a0e4878d3b7..a881f92a8537 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -2,7 +2,7 @@
* net/tipc/core.h: Include file for TIPC global declarations
*
* Copyright (c) 2005-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -59,84 +59,108 @@
#include <linux/vmalloc.h>
/*
- * TIPC debugging code
+ * TIPC sanity test macros
*/
#define assert(i) BUG_ON(!(i))
-struct tipc_msg;
-extern struct print_buf *TIPC_NULL, *TIPC_CONS, *TIPC_LOG;
-extern struct print_buf *TIPC_TEE(struct print_buf *, struct print_buf *);
-void tipc_msg_print(struct print_buf*,struct tipc_msg *,const char*);
-void tipc_printf(struct print_buf *, const char *fmt, ...);
-void tipc_dump(struct print_buf*,const char *fmt, ...);
-
-#ifdef CONFIG_TIPC_DEBUG
-
/*
- * TIPC debug support included:
- * - system messages are printed to TIPC_OUTPUT print buffer
- * - debug messages are printed to DBG_OUTPUT print buffer
+ * TIPC system monitoring code
*/
-#define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_ERR "TIPC: " fmt, ## arg)
-#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg)
-#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg)
+/*
+ * TIPC's print buffer subsystem supports the following print buffers:
+ *
+ * TIPC_NULL : null buffer (i.e. print nowhere)
+ * TIPC_CONS : system console
+ * TIPC_LOG : TIPC log buffer
+ * &buf : user-defined buffer (struct print_buf *)
+ *
+ * Note: TIPC_LOG is configured to echo its output to the system console;
+ * user-defined buffers can be configured to do the same thing.
+ */
-#define dbg(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
-#define msg_dbg(msg, txt) do {if (DBG_OUTPUT != TIPC_NULL) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0)
-#define dump(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
+extern struct print_buf *const TIPC_NULL;
+extern struct print_buf *const TIPC_CONS;
+extern struct print_buf *const TIPC_LOG;
+void tipc_printf(struct print_buf *, const char *fmt, ...);
/*
- * By default, TIPC_OUTPUT is defined to be system console and TIPC log buffer,
- * while DBG_OUTPUT is the null print buffer. These defaults can be changed
- * here, or on a per .c file basis, by redefining these symbols. The following
- * print buffer options are available:
- *
- * TIPC_NULL : null buffer (i.e. print nowhere)
- * TIPC_CONS : system console
- * TIPC_LOG : TIPC log buffer
- * &buf : user-defined buffer (struct print_buf *)
- * TIPC_TEE(&buf_a,&buf_b) : list of buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG))
+ * TIPC_OUTPUT is the destination print buffer for system messages.
*/
#ifndef TIPC_OUTPUT
-#define TIPC_OUTPUT TIPC_TEE(TIPC_CONS,TIPC_LOG)
-#endif
-
-#ifndef DBG_OUTPUT
-#define DBG_OUTPUT TIPC_NULL
+#define TIPC_OUTPUT TIPC_LOG
#endif
-#else
-
/*
- * TIPC debug support not included:
- * - system messages are printed to system console
- * - debug messages are not printed
+ * TIPC can be configured to send system messages to TIPC_OUTPUT
+ * or to the system console only.
*/
+#ifdef CONFIG_TIPC_DEBUG
+
+#define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, \
+ KERN_ERR "TIPC: " fmt, ## arg)
+#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, \
+ KERN_WARNING "TIPC: " fmt, ## arg)
+#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, \
+ KERN_NOTICE "TIPC: " fmt, ## arg)
+
+#else
+
#define err(fmt, arg...) printk(KERN_ERR "TIPC: " fmt , ## arg)
#define info(fmt, arg...) printk(KERN_INFO "TIPC: " fmt , ## arg)
#define warn(fmt, arg...) printk(KERN_WARNING "TIPC: " fmt , ## arg)
-#define dbg(fmt, arg...) do {} while (0)
-#define msg_dbg(msg,txt) do {} while (0)
-#define dump(fmt,arg...) do {} while (0)
+#endif
+/*
+ * DBG_OUTPUT is the destination print buffer for debug messages.
+ * It defaults to the the null print buffer, but can be redefined
+ * (typically in the individual .c files being debugged) to allow
+ * selected debug messages to be generated where needed.
+ */
+
+#ifndef DBG_OUTPUT
+#define DBG_OUTPUT TIPC_NULL
+#endif
/*
- * TIPC_OUTPUT is defined to be the system console, while DBG_OUTPUT is
- * the null print buffer. Thes ensures that any system or debug messages
- * that are generated without using the above macros are handled correctly.
+ * TIPC can be configured to send debug messages to the specified print buffer
+ * (typically DBG_OUTPUT) or to suppress them entirely.
*/
-#undef TIPC_OUTPUT
-#define TIPC_OUTPUT TIPC_CONS
+#ifdef CONFIG_TIPC_DEBUG
-#undef DBG_OUTPUT
-#define DBG_OUTPUT TIPC_NULL
+#define dbg(fmt, arg...) \
+ do { \
+ if (DBG_OUTPUT != TIPC_NULL) \
+ tipc_printf(DBG_OUTPUT, fmt, ## arg); \
+ } while (0)
+#define msg_dbg(msg, txt) \
+ do { \
+ if (DBG_OUTPUT != TIPC_NULL) \
+ tipc_msg_dbg(DBG_OUTPUT, msg, txt); \
+ } while (0)
+#define dump(fmt, arg...) \
+ do { \
+ if (DBG_OUTPUT != TIPC_NULL) \
+ tipc_dump_dbg(DBG_OUTPUT, fmt, ##arg); \
+ } while (0)
+
+void tipc_msg_dbg(struct print_buf *, struct tipc_msg *, const char *);
+void tipc_dump_dbg(struct print_buf *, const char *fmt, ...);
+
+#else
+
+#define dbg(fmt, arg...) do {} while (0)
+#define msg_dbg(msg, txt) do {} while (0)
+#define dump(fmt, arg...) do {} while (0)
+
+#define tipc_msg_dbg(...) do {} while (0)
+#define tipc_dump_dbg(...) do {} while (0)
#endif
@@ -178,7 +202,7 @@ extern atomic_t tipc_user_count;
extern int tipc_core_start(void);
extern void tipc_core_stop(void);
-extern int tipc_core_start_net(void);
+extern int tipc_core_start_net(unsigned long addr);
extern void tipc_core_stop_net(void);
extern int tipc_handler_start(void);
extern void tipc_handler_stop(void);
diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c
index e809d2a2ce06..29ecae851668 100644
--- a/net/tipc/dbg.c
+++ b/net/tipc/dbg.c
@@ -2,7 +2,7 @@
* net/tipc/dbg.c: TIPC print buffer routines for debugging
*
* Copyright (c) 1996-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,17 +38,43 @@
#include "config.h"
#include "dbg.h"
-static char print_string[TIPC_PB_MAX_STR];
-static DEFINE_SPINLOCK(print_lock);
+/*
+ * TIPC pre-defines the following print buffers:
+ *
+ * TIPC_NULL : null buffer (i.e. print nowhere)
+ * TIPC_CONS : system console
+ * TIPC_LOG : TIPC log buffer
+ *
+ * Additional user-defined print buffers are also permitted.
+ */
-static struct print_buf null_buf = { NULL, 0, NULL, NULL };
-struct print_buf *TIPC_NULL = &null_buf;
+static struct print_buf null_buf = { NULL, 0, NULL, 0 };
+struct print_buf *const TIPC_NULL = &null_buf;
-static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
-struct print_buf *TIPC_CONS = &cons_buf;
+static struct print_buf cons_buf = { NULL, 0, NULL, 1 };
+struct print_buf *const TIPC_CONS = &cons_buf;
-static struct print_buf log_buf = { NULL, 0, NULL, NULL };
-struct print_buf *TIPC_LOG = &log_buf;
+static struct print_buf log_buf = { NULL, 0, NULL, 1 };
+struct print_buf *const TIPC_LOG = &log_buf;
+
+/*
+ * Locking policy when using print buffers.
+ *
+ * 1) tipc_printf() uses 'print_lock' to protect against concurrent access to
+ * 'print_string' when writing to a print buffer. This also protects against
+ * concurrent writes to the print buffer being written to.
+ *
+ * 2) tipc_dump() and tipc_log_XXX() leverage the aforementioned
+ * use of 'print_lock' to protect against all types of concurrent operations
+ * on their associated print buffer (not just write operations).
+ *
+ * Note: All routines of the form tipc_printbuf_XXX() are lock-free, and rely
+ * on the caller to prevent simultaneous use of the print buffer(s) being
+ * manipulated.
+ */
+
+static char print_string[TIPC_PB_MAX_STR];
+static DEFINE_SPINLOCK(print_lock);
#define FORMAT(PTR,LEN,FMT) \
@@ -60,27 +86,14 @@ struct print_buf *TIPC_LOG = &log_buf;
*(PTR + LEN) = '\0';\
}
-/*
- * Locking policy when using print buffers.
- *
- * The following routines use 'print_lock' for protection:
- * 1) tipc_printf() - to protect its print buffer(s) and 'print_string'
- * 2) TIPC_TEE() - to protect its print buffer(s)
- * 3) tipc_dump() - to protect its print buffer(s) and 'print_string'
- * 4) tipc_log_XXX() - to protect TIPC_LOG
- *
- * All routines of the form tipc_printbuf_XXX() rely on the caller to prevent
- * simultaneous use of the print buffer(s) being manipulated.
- */
-
/**
* tipc_printbuf_init - initialize print buffer to empty
* @pb: pointer to print buffer structure
* @raw: pointer to character array used by print buffer
* @size: size of character array
*
- * Makes the print buffer a null device that discards anything written to it
- * if the character array is too small (or absent).
+ * Note: If the character array is too small (or absent), the print buffer
+ * becomes a null device that discards anything written to it.
*/
void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
@@ -88,13 +101,13 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
pb->buf = raw;
pb->crs = raw;
pb->size = size;
- pb->next = NULL;
+ pb->echo = 0;
if (size < TIPC_PB_MIN_SIZE) {
pb->buf = NULL;
} else if (raw) {
pb->buf[0] = 0;
- pb->buf[size-1] = ~0;
+ pb->buf[size - 1] = ~0;
}
}
@@ -105,7 +118,11 @@ void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
void tipc_printbuf_reset(struct print_buf *pb)
{
- tipc_printbuf_init(pb, pb->buf, pb->size);
+ if (pb->buf) {
+ pb->crs = pb->buf;
+ pb->buf[0] = 0;
+ pb->buf[pb->size - 1] = ~0;
+ }
}
/**
@@ -141,7 +158,7 @@ int tipc_printbuf_validate(struct print_buf *pb)
if (pb->buf[pb->size - 1] == 0) {
cp_buf = kmalloc(pb->size, GFP_ATOMIC);
- if (cp_buf != NULL){
+ if (cp_buf) {
tipc_printbuf_init(&cb, cp_buf, pb->size);
tipc_printbuf_move(&cb, pb);
tipc_printbuf_move(pb, &cb);
@@ -179,15 +196,16 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
}
if (pb_to->size < pb_from->size) {
- tipc_printbuf_reset(pb_to);
- tipc_printf(pb_to, "*** PRINT BUFFER MOVE ERROR ***");
+ strcpy(pb_to->buf, "*** PRINT BUFFER MOVE ERROR ***");
+ pb_to->buf[pb_to->size - 1] = ~0;
+ pb_to->crs = strchr(pb_to->buf, 0);
return;
}
/* Copy data from char after cursor to end (if used) */
len = pb_from->buf + pb_from->size - pb_from->crs - 2;
- if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) {
+ if ((pb_from->buf[pb_from->size - 1] == 0) && (len > 0)) {
strcpy(pb_to->buf, pb_from->crs + 1);
pb_to->crs = pb_to->buf + len;
} else
@@ -203,8 +221,8 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
}
/**
- * tipc_printf - append formatted output to print buffer chain
- * @pb: pointer to chain of print buffers (may be NULL)
+ * tipc_printf - append formatted output to print buffer
+ * @pb: pointer to print buffer
* @fmt: formatted info to be printed
*/
@@ -213,68 +231,40 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
int chars_to_add;
int chars_left;
char save_char;
- struct print_buf *pb_next;
spin_lock_bh(&print_lock);
+
FORMAT(print_string, chars_to_add, fmt);
if (chars_to_add >= TIPC_PB_MAX_STR)
strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***");
- while (pb) {
- if (pb == TIPC_CONS)
- printk(print_string);
- else if (pb->buf) {
- chars_left = pb->buf + pb->size - pb->crs - 1;
- if (chars_to_add <= chars_left) {
- strcpy(pb->crs, print_string);
- pb->crs += chars_to_add;
- } else if (chars_to_add >= (pb->size - 1)) {
- strcpy(pb->buf, print_string + chars_to_add + 1
- - pb->size);
- pb->crs = pb->buf + pb->size - 1;
- } else {
- strcpy(pb->buf, print_string + chars_left);
- save_char = print_string[chars_left];
- print_string[chars_left] = 0;
- strcpy(pb->crs, print_string);
- print_string[chars_left] = save_char;
- pb->crs = pb->buf + chars_to_add - chars_left;
- }
+ if (pb->buf) {
+ chars_left = pb->buf + pb->size - pb->crs - 1;
+ if (chars_to_add <= chars_left) {
+ strcpy(pb->crs, print_string);
+ pb->crs += chars_to_add;
+ } else if (chars_to_add >= (pb->size - 1)) {
+ strcpy(pb->buf, print_string + chars_to_add + 1
+ - pb->size);
+ pb->crs = pb->buf + pb->size - 1;
+ } else {
+ strcpy(pb->buf, print_string + chars_left);
+ save_char = print_string[chars_left];
+ print_string[chars_left] = 0;
+ strcpy(pb->crs, print_string);
+ print_string[chars_left] = save_char;
+ pb->crs = pb->buf + chars_to_add - chars_left;
}
- pb_next = pb->next;
- pb->next = NULL;
- pb = pb_next;
}
- spin_unlock_bh(&print_lock);
-}
-/**
- * TIPC_TEE - perform next output operation on both print buffers
- * @b0: pointer to chain of print buffers (may be NULL)
- * @b1: pointer to print buffer to add to chain
- *
- * Returns pointer to print buffer chain.
- */
+ if (pb->echo)
+ printk(print_string);
-struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1)
-{
- struct print_buf *pb = b0;
-
- if (!b0 || (b0 == b1))
- return b1;
-
- spin_lock_bh(&print_lock);
- while (pb->next) {
- if ((pb->next == b1) || (pb->next == b0))
- pb->next = pb->next->next;
- else
- pb = pb->next;
- }
- pb->next = b1;
spin_unlock_bh(&print_lock);
- return b0;
}
+#ifdef CONFIG_TIPC_DEBUG
+
/**
* print_to_console - write string of bytes to console in multiple chunks
*/
@@ -321,72 +311,66 @@ static void printbuf_dump(struct print_buf *pb)
}
/**
- * tipc_dump - dump non-console print buffer(s) to console
- * @pb: pointer to chain of print buffers
+ * tipc_dump_dbg - dump (non-console) print buffer to console
+ * @pb: pointer to print buffer
*/
-void tipc_dump(struct print_buf *pb, const char *fmt, ...)
+void tipc_dump_dbg(struct print_buf *pb, const char *fmt, ...)
{
- struct print_buf *pb_next;
int len;
+ if (pb == TIPC_CONS)
+ return;
+
spin_lock_bh(&print_lock);
+
FORMAT(print_string, len, fmt);
printk(print_string);
- for (; pb; pb = pb->next) {
- if (pb != TIPC_CONS) {
- printk("\n---- Start of %s log dump ----\n\n",
- (pb == TIPC_LOG) ? "global" : "local");
- printbuf_dump(pb);
- tipc_printbuf_reset(pb);
- printk("\n---- End of dump ----\n");
- }
- pb_next = pb->next;
- pb->next = NULL;
- pb = pb_next;
- }
+ printk("\n---- Start of %s log dump ----\n\n",
+ (pb == TIPC_LOG) ? "global" : "local");
+ printbuf_dump(pb);
+ tipc_printbuf_reset(pb);
+ printk("\n---- End of dump ----\n");
+
spin_unlock_bh(&print_lock);
}
+#endif
+
/**
- * tipc_log_stop - free up TIPC log print buffer
+ * tipc_log_resize - change the size of the TIPC log buffer
+ * @log_size: print buffer size to use
*/
-void tipc_log_stop(void)
+int tipc_log_resize(int log_size)
{
+ int res = 0;
+
spin_lock_bh(&print_lock);
if (TIPC_LOG->buf) {
kfree(TIPC_LOG->buf);
TIPC_LOG->buf = NULL;
}
- spin_unlock_bh(&print_lock);
-}
-
-/**
- * tipc_log_reinit - (re)initialize TIPC log print buffer
- * @log_size: print buffer size to use
- */
-
-void tipc_log_reinit(int log_size)
-{
- tipc_log_stop();
-
if (log_size) {
if (log_size < TIPC_PB_MIN_SIZE)
log_size = TIPC_PB_MIN_SIZE;
- spin_lock_bh(&print_lock);
+ res = TIPC_LOG->echo;
tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC),
log_size);
- spin_unlock_bh(&print_lock);
+ TIPC_LOG->echo = res;
+ res = !TIPC_LOG->buf;
}
+ spin_unlock_bh(&print_lock);
+
+ return res;
}
/**
- * tipc_log_resize - reconfigure size of TIPC log buffer
+ * tipc_log_resize_cmd - reconfigure size of TIPC log buffer
*/
-struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space)
+struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area, int req_tlv_space)
{
u32 value;
@@ -397,7 +381,9 @@ struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space)
if (value != delimit(value, 0, 32768))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (log size must be 0-32768)");
- tipc_log_reinit(value);
+ if (tipc_log_resize(value))
+ return tipc_cfg_reply_error_string(
+ "unable to create specified log (log size is now 0)");
return tipc_cfg_reply_none();
}
@@ -410,27 +396,32 @@ struct sk_buff *tipc_log_dump(void)
struct sk_buff *reply;
spin_lock_bh(&print_lock);
- if (!TIPC_LOG->buf)
+ if (!TIPC_LOG->buf) {
+ spin_unlock_bh(&print_lock);
reply = tipc_cfg_reply_ultra_string("log not activated\n");
- else if (tipc_printbuf_empty(TIPC_LOG))
+ } else if (tipc_printbuf_empty(TIPC_LOG)) {
+ spin_unlock_bh(&print_lock);
reply = tipc_cfg_reply_ultra_string("log is empty\n");
+ }
else {
struct tlv_desc *rep_tlv;
struct print_buf pb;
int str_len;
str_len = min(TIPC_LOG->size, 32768u);
+ spin_unlock_bh(&print_lock);
reply = tipc_cfg_reply_alloc(TLV_SPACE(str_len));
if (reply) {
rep_tlv = (struct tlv_desc *)reply->data;
tipc_printbuf_init(&pb, TLV_DATA(rep_tlv), str_len);
+ spin_lock_bh(&print_lock);
tipc_printbuf_move(&pb, TIPC_LOG);
+ spin_unlock_bh(&print_lock);
str_len = strlen(TLV_DATA(rep_tlv)) + 1;
skb_put(reply, TLV_SPACE(str_len));
TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
}
}
- spin_unlock_bh(&print_lock);
return reply;
}
diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h
index c01b085000e0..5ef1bc8f64ef 100644
--- a/net/tipc/dbg.h
+++ b/net/tipc/dbg.h
@@ -2,7 +2,7 @@
* net/tipc/dbg.h: Include file for TIPC print buffer routines
*
* Copyright (c) 1997-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,14 +42,14 @@
* @buf: pointer to character array containing print buffer contents
* @size: size of character array
* @crs: pointer to first unused space in character array (i.e. final NUL)
- * @next: used to link print buffers when printing to more than one at a time
+ * @echo: echo output to system console if non-zero
*/
struct print_buf {
char *buf;
u32 size;
char *crs;
- struct print_buf *next;
+ int echo;
};
#define TIPC_PB_MIN_SIZE 64 /* minimum size for a print buffer's array */
@@ -61,10 +61,10 @@ int tipc_printbuf_empty(struct print_buf *pb);
int tipc_printbuf_validate(struct print_buf *pb);
void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from);
-void tipc_log_reinit(int log_size);
-void tipc_log_stop(void);
+int tipc_log_resize(int log_size);
-struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space);
+struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area,
+ int req_tlv_space);
struct sk_buff *tipc_log_dump(void);
#endif
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index 5d643e5721eb..faeaf06d377e 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -200,9 +200,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
dbg(" in own cluster\n");
if (n_ptr == NULL) {
n_ptr = tipc_node_create(orig);
- }
- if (n_ptr == NULL) {
- return;
+ if (!n_ptr)
+ return;
}
spin_lock_bh(&n_ptr->lock);
link = n_ptr->links[b_ptr->identity];
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 2a26a16e269f..bd206ebe4eea 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -147,9 +147,21 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
#define LINK_LOG_BUF_SIZE 0
-#define dbg_link(fmt, arg...) do {if (LINK_LOG_BUF_SIZE) tipc_printf(&l_ptr->print_buf, fmt, ## arg); } while(0)
-#define dbg_link_msg(msg, txt) do {if (LINK_LOG_BUF_SIZE) tipc_msg_print(&l_ptr->print_buf, msg, txt); } while(0)
-#define dbg_link_state(txt) do {if (LINK_LOG_BUF_SIZE) link_print(l_ptr, &l_ptr->print_buf, txt); } while(0)
+#define dbg_link(fmt, arg...) \
+ do { \
+ if (LINK_LOG_BUF_SIZE) \
+ tipc_printf(&l_ptr->print_buf, fmt, ## arg); \
+ } while (0)
+#define dbg_link_msg(msg, txt) \
+ do { \
+ if (LINK_LOG_BUF_SIZE) \
+ tipc_msg_dbg(&l_ptr->print_buf, msg, txt); \
+ } while (0)
+#define dbg_link_state(txt) \
+ do { \
+ if (LINK_LOG_BUF_SIZE) \
+ link_print(l_ptr, &l_ptr->print_buf, txt); \
+ } while (0)
#define dbg_link_dump() do { \
if (LINK_LOG_BUF_SIZE) { \
tipc_printf(LOG, "\n\nDumping link <%s>:\n", l_ptr->name); \
@@ -1651,7 +1663,7 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
struct tipc_msg *msg = buf_msg(buf);
warn("Retransmission failure on link <%s>\n", l_ptr->name);
- tipc_msg_print(TIPC_OUTPUT, msg, ">RETR-FAIL>");
+ tipc_msg_dbg(TIPC_OUTPUT, msg, ">RETR-FAIL>");
if (l_ptr->addr) {
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 696a8633df75..38abebaae889 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -41,7 +41,9 @@
#include "bearer.h"
-void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str)
+#ifdef CONFIG_TIPC_DEBUG
+
+void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str)
{
u32 usr = msg_user(msg);
tipc_printf(buf, str);
@@ -315,9 +317,11 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str
}
tipc_printf(buf, "\n");
if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) {
- tipc_msg_print(buf,msg_get_wrapped(msg)," /");
+ tipc_msg_dbg(buf, msg_get_wrapped(msg), " /");
}
if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) {
- tipc_msg_print(buf,msg_get_wrapped(msg)," /");
+ tipc_msg_dbg(buf, msg_get_wrapped(msg), " /");
}
}
+
+#endif
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index 39fd1619febf..aecba5cd87d6 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -41,9 +41,6 @@
#include "msg.h"
#include "name_distr.h"
-#undef DBG_OUTPUT
-#define DBG_OUTPUT NULL
-
#define ITEM_SIZE sizeof(struct distr_item)
/**
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index ac7dfdda7973..892373e498e4 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -1050,15 +1050,12 @@ void tipc_nametbl_dump(void)
int tipc_nametbl_init(void)
{
- int array_size = sizeof(struct hlist_head) * tipc_nametbl_size;
-
- table.types = kzalloc(array_size, GFP_ATOMIC);
+ table.types = kcalloc(tipc_nametbl_size, sizeof(struct hlist_head),
+ GFP_ATOMIC);
if (!table.types)
return -ENOMEM;
- write_lock_bh(&tipc_nametbl_lock);
table.local_publ_count = 0;
- write_unlock_bh(&tipc_nametbl_lock);
return 0;
}
diff --git a/net/tipc/net.c b/net/tipc/net.c
index c39c76201e8e..cc51fa483672 100644
--- a/net/tipc/net.c
+++ b/net/tipc/net.c
@@ -266,7 +266,7 @@ void tipc_net_route_msg(struct sk_buff *buf)
tipc_link_send(buf, dnode, msg_link_selector(msg));
}
-int tipc_net_start(void)
+int tipc_net_start(u32 addr)
{
char addr_string[16];
int res;
@@ -274,6 +274,10 @@ int tipc_net_start(void)
if (tipc_mode != TIPC_NODE_MODE)
return -ENOPROTOOPT;
+ tipc_subscr_stop();
+ tipc_cfg_stop();
+
+ tipc_own_addr = addr;
tipc_mode = TIPC_NET_MODE;
tipc_named_reinit();
tipc_port_reinit();
@@ -284,10 +288,10 @@ int tipc_net_start(void)
(res = tipc_bclink_init())) {
return res;
}
- tipc_subscr_stop();
- tipc_cfg_stop();
+
tipc_k_signal((Handler)tipc_subscr_start, 0);
tipc_k_signal((Handler)tipc_cfg_init, 0);
+
info("Started in network mode\n");
info("Own node address %s, network identity %u\n",
addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
diff --git a/net/tipc/net.h b/net/tipc/net.h
index a6a0e9976ac9..d154ac2bda9a 100644
--- a/net/tipc/net.h
+++ b/net/tipc/net.h
@@ -58,7 +58,7 @@ void tipc_net_route_msg(struct sk_buff *buf);
struct node *tipc_net_select_remote_node(u32 addr, u32 ref);
u32 tipc_net_select_router(u32 addr, u32 ref);
-int tipc_net_start(void);
+int tipc_net_start(u32 addr);
void tipc_net_stop(void);
#endif
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index 6a7f7b4c2595..c387217bb230 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -2,7 +2,7 @@
* net/tipc/netlink.c: TIPC configuration handling
*
* Copyright (c) 2005-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,15 +45,17 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
struct nlmsghdr *req_nlh = info->nlhdr;
struct tipc_genlmsghdr *req_userhdr = info->userhdr;
int hdr_space = NLMSG_SPACE(GENL_HDRLEN + TIPC_GENL_HDRLEN);
+ u16 cmd;
if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
- rep_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
+ cmd = TIPC_CMD_NOT_NET_ADMIN;
else
- rep_buf = tipc_cfg_do_cmd(req_userhdr->dest,
- req_userhdr->cmd,
- NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
- NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
- hdr_space);
+ cmd = req_userhdr->cmd;
+
+ rep_buf = tipc_cfg_do_cmd(req_userhdr->dest, cmd,
+ NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
+ NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
+ hdr_space);
if (rep_buf) {
skb_push(rep_buf, hdr_space);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 598f4d3a0098..34e9a2bb7c19 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -52,16 +52,40 @@ static void node_established_contact(struct node *n_ptr);
struct node *tipc_nodes = NULL; /* sorted list of nodes within cluster */
+static DEFINE_SPINLOCK(node_create_lock);
+
u32 tipc_own_tag = 0;
+/**
+ * tipc_node_create - create neighboring node
+ *
+ * Currently, this routine is called by neighbor discovery code, which holds
+ * net_lock for reading only. We must take node_create_lock to ensure a node
+ * isn't created twice if two different bearers discover the node at the same
+ * time. (It would be preferable to switch to holding net_lock in write mode,
+ * but this is a non-trivial change.)
+ */
+
struct node *tipc_node_create(u32 addr)
{
struct cluster *c_ptr;
struct node *n_ptr;
struct node **curr_node;
+ spin_lock_bh(&node_create_lock);
+
+ for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
+ if (addr < n_ptr->addr)
+ break;
+ if (addr == n_ptr->addr) {
+ spin_unlock_bh(&node_create_lock);
+ return n_ptr;
+ }
+ }
+
n_ptr = kzalloc(sizeof(*n_ptr),GFP_ATOMIC);
if (!n_ptr) {
+ spin_unlock_bh(&node_create_lock);
warn("Node creation failed, no memory\n");
return NULL;
}
@@ -71,6 +95,7 @@ struct node *tipc_node_create(u32 addr)
c_ptr = tipc_cltr_create(addr);
}
if (!c_ptr) {
+ spin_unlock_bh(&node_create_lock);
kfree(n_ptr);
return NULL;
}
@@ -91,6 +116,7 @@ struct node *tipc_node_create(u32 addr)
}
}
(*curr_node) = n_ptr;
+ spin_unlock_bh(&node_create_lock);
return n_ptr;
}
diff --git a/net/tipc/port.c b/net/tipc/port.c
index 2f5806410c64..2c64ad88e3cf 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -211,15 +211,18 @@ exit:
}
/**
- * tipc_createport_raw - create a native TIPC port
+ * tipc_createport_raw - create a generic TIPC port
*
- * Returns local port reference
+ * Returns port reference, or 0 if unable to create it
+ *
+ * Note: The newly created port is returned in the locked state.
*/
u32 tipc_createport_raw(void *usr_handle,
u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
void (*wakeup)(struct tipc_port *),
- const u32 importance)
+ const u32 importance,
+ struct tipc_port **tp_ptr)
{
struct port *p_ptr;
struct tipc_msg *msg;
@@ -237,7 +240,6 @@ u32 tipc_createport_raw(void *usr_handle,
return 0;
}
- tipc_port_lock(ref);
p_ptr->publ.usr_handle = usr_handle;
p_ptr->publ.max_pkt = MAX_PKT_DEFAULT;
p_ptr->publ.ref = ref;
@@ -262,7 +264,7 @@ u32 tipc_createport_raw(void *usr_handle,
INIT_LIST_HEAD(&p_ptr->port_list);
list_add_tail(&p_ptr->port_list, &ports);
spin_unlock_bh(&tipc_port_list_lock);
- tipc_port_unlock(p_ptr);
+ *tp_ptr = &p_ptr->publ;
return ref;
}
@@ -778,6 +780,7 @@ void tipc_port_reinit(void)
msg = &p_ptr->publ.phdr;
if (msg_orignode(msg) == tipc_own_addr)
break;
+ msg_set_prevnode(msg, tipc_own_addr);
msg_set_orignode(msg, tipc_own_addr);
}
spin_unlock_bh(&tipc_port_list_lock);
@@ -1053,6 +1056,7 @@ int tipc_createport(u32 user_ref,
{
struct user_port *up_ptr;
struct port *p_ptr;
+ struct tipc_port *tp_ptr;
u32 ref;
up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
@@ -1060,12 +1064,13 @@ int tipc_createport(u32 user_ref,
warn("Port creation failed, no memory\n");
return -ENOMEM;
}
- ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance);
- p_ptr = tipc_port_lock(ref);
- if (!p_ptr) {
+ ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup,
+ importance, &tp_ptr);
+ if (ref == 0) {
kfree(up_ptr);
return -ENOMEM;
}
+ p_ptr = (struct port *)tp_ptr;
p_ptr->user_port = up_ptr;
up_ptr->user_ref = user_ref;
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
index 89cbab24d08f..a101de86824d 100644
--- a/net/tipc/ref.c
+++ b/net/tipc/ref.c
@@ -142,9 +142,13 @@ void tipc_ref_table_stop(void)
/**
* tipc_ref_acquire - create reference to an object
*
- * Return a unique reference value which can be translated back to the pointer
- * 'object' at a later time. Also, pass back a pointer to the lock protecting
- * the object, but without locking it.
+ * 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.
*/
u32 tipc_ref_acquire(void *object, spinlock_t **lock)
@@ -178,13 +182,13 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock)
ref = (next_plus_upper & ~index_mask) + index;
entry->ref = ref;
entry->object = object;
- spin_unlock_bh(&entry->lock);
*lock = &entry->lock;
}
else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
index = tipc_ref_table.init_point++;
entry = &(tipc_ref_table.entries[index]);
spin_lock_init(&entry->lock);
+ spin_lock_bh(&entry->lock);
ref = tipc_ref_table.start_mask + index;
entry->ref = ref;
entry->object = object;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 230f9ca2ad6b..38f48795b40e 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -188,6 +188,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
const struct proto_ops *ops;
socket_state state;
struct sock *sk;
+ struct tipc_port *tp_ptr;
u32 portref;
/* Validate arguments */
@@ -225,7 +226,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
/* Allocate TIPC port for socket to use */
portref = tipc_createport_raw(sk, &dispatch, &wakeupdispatch,
- TIPC_LOW_IMPORTANCE);
+ TIPC_LOW_IMPORTANCE, &tp_ptr);
if (unlikely(portref == 0)) {
sk_free(sk);
return -ENOMEM;
@@ -241,6 +242,8 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
sk->sk_backlog_rcv = backlog_rcv;
tipc_sk(sk)->p = tipc_get_port(portref);
+ spin_unlock_bh(tp_ptr->lock);
+
if (sock->state == SS_READY) {
tipc_set_portunreturnable(portref, 1);
if (sock->type == SOCK_DGRAM)
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 8c01ccd3626c..0326d3060bc7 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -1,8 +1,8 @@
/*
- * net/tipc/subscr.c: TIPC subscription service
+ * net/tipc/subscr.c: TIPC network topology service
*
* Copyright (c) 2000-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,27 +36,24 @@
#include "core.h"
#include "dbg.h"
-#include "subscr.h"
#include "name_table.h"
+#include "port.h"
#include "ref.h"
+#include "subscr.h"
/**
* struct subscriber - TIPC network topology subscriber
- * @ref: object reference to subscriber object itself
- * @lock: pointer to spinlock controlling access to subscriber object
+ * @port_ref: object reference to server port connecting to subscriber
+ * @lock: pointer to spinlock controlling access to subscriber's server port
* @subscriber_list: adjacent subscribers in top. server's list of subscribers
* @subscription_list: list of subscription objects for this subscriber
- * @port_ref: object reference to port used to communicate with subscriber
- * @swap: indicates if subscriber uses opposite endianness in its messages
*/
struct subscriber {
- u32 ref;
+ u32 port_ref;
spinlock_t *lock;
struct list_head subscriber_list;
struct list_head subscription_list;
- u32 port_ref;
- int swap;
};
/**
@@ -88,13 +85,14 @@ static struct top_srv topsrv = { 0 };
static u32 htohl(u32 in, int swap)
{
- char *c = (char *)&in;
-
- return swap ? ((c[3] << 3) + (c[2] << 2) + (c[1] << 1) + c[0]) : in;
+ return swap ? (u32)___constant_swab32(in) : in;
}
/**
* subscr_send_event - send a message containing a tipc_event to the subscriber
+ *
+ * Note: Must not hold subscriber's server port lock, since tipc_send() will
+ * try to take the lock if the message is rejected and returned!
*/
static void subscr_send_event(struct subscription *sub,
@@ -109,12 +107,12 @@ static void subscr_send_event(struct subscription *sub,
msg_sect.iov_base = (void *)&sub->evt;
msg_sect.iov_len = sizeof(struct tipc_event);
- sub->evt.event = htohl(event, sub->owner->swap);
- sub->evt.found_lower = htohl(found_lower, sub->owner->swap);
- sub->evt.found_upper = htohl(found_upper, sub->owner->swap);
- sub->evt.port.ref = htohl(port_ref, sub->owner->swap);
- sub->evt.port.node = htohl(node, sub->owner->swap);
- tipc_send(sub->owner->port_ref, 1, &msg_sect);
+ sub->evt.event = htohl(event, sub->swap);
+ sub->evt.found_lower = htohl(found_lower, sub->swap);
+ sub->evt.found_upper = htohl(found_upper, sub->swap);
+ sub->evt.port.ref = htohl(port_ref, sub->swap);
+ sub->evt.port.node = htohl(node, sub->swap);
+ tipc_send(sub->server_ref, 1, &msg_sect);
}
/**
@@ -151,13 +149,12 @@ void tipc_subscr_report_overlap(struct subscription *sub,
u32 node,
int must)
{
- dbg("Rep overlap %u:%u,%u<->%u,%u\n", sub->seq.type, sub->seq.lower,
- sub->seq.upper, found_lower, found_upper);
if (!tipc_subscr_overlap(sub, found_lower, found_upper))
return;
if (!must && !(sub->filter & TIPC_SUB_PORTS))
return;
- subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
+
+ sub->event_cb(sub, found_lower, found_upper, event, port_ref, node);
}
/**
@@ -166,20 +163,18 @@ void tipc_subscr_report_overlap(struct subscription *sub,
static void subscr_timeout(struct subscription *sub)
{
- struct subscriber *subscriber;
- u32 subscriber_ref;
+ struct port *server_port;
- /* Validate subscriber reference (in case subscriber is terminating) */
+ /* Validate server port reference (in case subscriber is terminating) */
- subscriber_ref = sub->owner->ref;
- subscriber = (struct subscriber *)tipc_ref_lock(subscriber_ref);
- if (subscriber == NULL)
+ server_port = tipc_port_lock(sub->server_ref);
+ if (server_port == NULL)
return;
/* Validate timeout (in case subscription is being cancelled) */
if (sub->timeout == TIPC_WAIT_FOREVER) {
- tipc_ref_unlock(subscriber_ref);
+ tipc_port_unlock(server_port);
return;
}
@@ -187,19 +182,21 @@ static void subscr_timeout(struct subscription *sub)
tipc_nametbl_unsubscribe(sub);
- /* Notify subscriber of timeout, then unlink subscription */
+ /* Unlink subscription from subscriber */
- subscr_send_event(sub,
- sub->evt.s.seq.lower,
- sub->evt.s.seq.upper,
- TIPC_SUBSCR_TIMEOUT,
- 0,
- 0);
list_del(&sub->subscription_list);
+ /* Release subscriber's server port */
+
+ tipc_port_unlock(server_port);
+
+ /* Notify subscriber of timeout */
+
+ subscr_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper,
+ TIPC_SUBSCR_TIMEOUT, 0, 0);
+
/* Now destroy subscription */
- tipc_ref_unlock(subscriber_ref);
k_term_timer(&sub->timer);
kfree(sub);
atomic_dec(&topsrv.subscription_count);
@@ -208,7 +205,7 @@ static void subscr_timeout(struct subscription *sub)
/**
* subscr_del - delete a subscription within a subscription list
*
- * Called with subscriber locked.
+ * Called with subscriber port locked.
*/
static void subscr_del(struct subscription *sub)
@@ -222,7 +219,7 @@ static void subscr_del(struct subscription *sub)
/**
* subscr_terminate - terminate communication with a subscriber
*
- * Called with subscriber locked. Routine must temporarily release this lock
+ * Called with subscriber port locked. Routine must temporarily release lock
* to enable subscription timeout routine(s) to finish without deadlocking;
* the lock is then reclaimed to allow caller to release it upon return.
* (This should work even in the unlikely event some other thread creates
@@ -232,14 +229,21 @@ static void subscr_del(struct subscription *sub)
static void subscr_terminate(struct subscriber *subscriber)
{
+ u32 port_ref;
struct subscription *sub;
struct subscription *sub_temp;
/* Invalidate subscriber reference */
- tipc_ref_discard(subscriber->ref);
+ port_ref = subscriber->port_ref;
+ subscriber->port_ref = 0;
spin_unlock_bh(subscriber->lock);
+ /* Sever connection to subscriber */
+
+ tipc_shutdown(port_ref);
+ tipc_deleteport(port_ref);
+
/* Destroy any existing subscriptions for subscriber */
list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
@@ -253,27 +257,25 @@ static void subscr_terminate(struct subscriber *subscriber)
subscr_del(sub);
}
- /* Sever connection to subscriber */
-
- tipc_shutdown(subscriber->port_ref);
- tipc_deleteport(subscriber->port_ref);
-
/* Remove subscriber from topology server's subscriber list */
spin_lock_bh(&topsrv.lock);
list_del(&subscriber->subscriber_list);
spin_unlock_bh(&topsrv.lock);
- /* Now destroy subscriber */
+ /* Reclaim subscriber lock */
spin_lock_bh(subscriber->lock);
+
+ /* Now destroy subscriber */
+
kfree(subscriber);
}
/**
* subscr_cancel - handle subscription cancellation request
*
- * Called with subscriber locked. Routine must temporarily release this lock
+ * Called with subscriber port locked. Routine must temporarily release lock
* to enable the subscription timeout routine to finish without deadlocking;
* the lock is then reclaimed to allow caller to release it upon return.
*
@@ -316,27 +318,25 @@ static void subscr_cancel(struct tipc_subscr *s,
/**
* subscr_subscribe - create subscription for subscriber
*
- * Called with subscriber locked
+ * Called with subscriber port locked.
*/
-static void subscr_subscribe(struct tipc_subscr *s,
- struct subscriber *subscriber)
+static struct subscription *subscr_subscribe(struct tipc_subscr *s,
+ struct subscriber *subscriber)
{
struct subscription *sub;
+ int swap;
- /* Determine/update subscriber's endianness */
+ /* Determine subscriber's endianness */
- if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE))
- subscriber->swap = 0;
- else
- subscriber->swap = 1;
+ swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE));
/* Detect & process a subscription cancellation request */
- if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) {
- s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap);
+ if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
+ s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
subscr_cancel(s, subscriber);
- return;
+ return NULL;
}
/* Refuse subscription if global limit exceeded */
@@ -345,63 +345,66 @@ static void subscr_subscribe(struct tipc_subscr *s,
warn("Subscription rejected, subscription limit reached (%u)\n",
tipc_max_subscriptions);
subscr_terminate(subscriber);
- return;
+ return NULL;
}
/* Allocate subscription object */
- sub = kzalloc(sizeof(*sub), GFP_ATOMIC);
+ sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
if (!sub) {
warn("Subscription rejected, no memory\n");
subscr_terminate(subscriber);
- return;
+ return NULL;
}
/* Initialize subscription object */
- sub->seq.type = htohl(s->seq.type, subscriber->swap);
- sub->seq.lower = htohl(s->seq.lower, subscriber->swap);
- sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
- sub->timeout = htohl(s->timeout, subscriber->swap);
- sub->filter = htohl(s->filter, subscriber->swap);
+ sub->seq.type = htohl(s->seq.type, swap);
+ sub->seq.lower = htohl(s->seq.lower, swap);
+ sub->seq.upper = htohl(s->seq.upper, swap);
+ sub->timeout = htohl(s->timeout, swap);
+ sub->filter = htohl(s->filter, swap);
if ((!(sub->filter & TIPC_SUB_PORTS)
== !(sub->filter & TIPC_SUB_SERVICE))
|| (sub->seq.lower > sub->seq.upper)) {
warn("Subscription rejected, illegal request\n");
kfree(sub);
subscr_terminate(subscriber);
- return;
+ return NULL;
}
- memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
- INIT_LIST_HEAD(&sub->subscription_list);
+ sub->event_cb = subscr_send_event;
INIT_LIST_HEAD(&sub->nameseq_list);
list_add(&sub->subscription_list, &subscriber->subscription_list);
+ sub->server_ref = subscriber->port_ref;
+ sub->swap = swap;
+ memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
atomic_inc(&topsrv.subscription_count);
if (sub->timeout != TIPC_WAIT_FOREVER) {
k_init_timer(&sub->timer,
(Handler)subscr_timeout, (unsigned long)sub);
k_start_timer(&sub->timer, sub->timeout);
}
- sub->owner = subscriber;
- tipc_nametbl_subscribe(sub);
+
+ return sub;
}
/**
* subscr_conn_shutdown_event - handle termination request from subscriber
+ *
+ * Called with subscriber's server port unlocked.
*/
static void subscr_conn_shutdown_event(void *usr_handle,
- u32 portref,
+ u32 port_ref,
struct sk_buff **buf,
unsigned char const *data,
unsigned int size,
int reason)
{
- struct subscriber *subscriber;
+ struct subscriber *subscriber = usr_handle;
spinlock_t *subscriber_lock;
- subscriber = tipc_ref_lock((u32)(unsigned long)usr_handle);
- if (subscriber == NULL)
+ if (tipc_port_lock(port_ref) == NULL)
return;
subscriber_lock = subscriber->lock;
@@ -411,6 +414,8 @@ static void subscr_conn_shutdown_event(void *usr_handle,
/**
* subscr_conn_msg_event - handle new subscription request from subscriber
+ *
+ * Called with subscriber's server port unlocked.
*/
static void subscr_conn_msg_event(void *usr_handle,
@@ -419,20 +424,46 @@ static void subscr_conn_msg_event(void *usr_handle,
const unchar *data,
u32 size)
{
- struct subscriber *subscriber;
+ struct subscriber *subscriber = usr_handle;
spinlock_t *subscriber_lock;
+ struct subscription *sub;
+
+ /*
+ * Lock subscriber's server port (& make a local copy of lock pointer,
+ * in case subscriber is deleted while processing subscription request)
+ */
- subscriber = tipc_ref_lock((u32)(unsigned long)usr_handle);
- if (subscriber == NULL)
+ if (tipc_port_lock(port_ref) == NULL)
return;
subscriber_lock = subscriber->lock;
- if (size != sizeof(struct tipc_subscr))
- subscr_terminate(subscriber);
- else
- subscr_subscribe((struct tipc_subscr *)data, subscriber);
- spin_unlock_bh(subscriber_lock);
+ if (size != sizeof(struct tipc_subscr)) {
+ subscr_terminate(subscriber);
+ spin_unlock_bh(subscriber_lock);
+ } else {
+ sub = subscr_subscribe((struct tipc_subscr *)data, subscriber);
+ spin_unlock_bh(subscriber_lock);
+ if (sub != NULL) {
+
+ /*
+ * We must release the server port lock before adding a
+ * subscription to the name table since TIPC needs to be
+ * able to (re)acquire the port lock if an event message
+ * issued by the subscription process is rejected and
+ * returned. The subscription cannot be deleted while
+ * it is being added to the name table because:
+ * a) the single-threading of the native API port code
+ * ensures the subscription cannot be cancelled and
+ * the subscriber connection cannot be broken, and
+ * b) the name table lock ensures the subscription
+ * timeout code cannot delete the subscription,
+ * so the subscription object is still protected.
+ */
+
+ tipc_nametbl_subscribe(sub);
+ }
+ }
}
/**
@@ -448,16 +479,10 @@ static void subscr_named_msg_event(void *usr_handle,
struct tipc_portid const *orig,
struct tipc_name_seq const *dest)
{
- struct subscriber *subscriber;
- struct iovec msg_sect = {NULL, 0};
- spinlock_t *subscriber_lock;
+ static struct iovec msg_sect = {NULL, 0};
- dbg("subscr_named_msg_event: orig = %x own = %x,\n",
- orig->node, tipc_own_addr);
- if (size && (size != sizeof(struct tipc_subscr))) {
- warn("Subscriber rejected, invalid subscription size\n");
- return;
- }
+ struct subscriber *subscriber;
+ u32 server_port_ref;
/* Create subscriber object */
@@ -468,17 +493,11 @@ static void subscr_named_msg_event(void *usr_handle,
}
INIT_LIST_HEAD(&subscriber->subscription_list);
INIT_LIST_HEAD(&subscriber->subscriber_list);
- subscriber->ref = tipc_ref_acquire(subscriber, &subscriber->lock);
- if (subscriber->ref == 0) {
- warn("Subscriber rejected, reference table exhausted\n");
- kfree(subscriber);
- return;
- }
- /* Establish a connection to subscriber */
+ /* Create server port & establish connection to subscriber */
tipc_createport(topsrv.user_ref,
- (void *)(unsigned long)subscriber->ref,
+ subscriber,
importance,
NULL,
NULL,
@@ -490,32 +509,36 @@ static void subscr_named_msg_event(void *usr_handle,
&subscriber->port_ref);
if (subscriber->port_ref == 0) {
warn("Subscriber rejected, unable to create port\n");
- tipc_ref_discard(subscriber->ref);
kfree(subscriber);
return;
}
tipc_connect2port(subscriber->port_ref, orig);
+ /* Lock server port (& save lock address for future use) */
+
+ subscriber->lock = tipc_port_lock(subscriber->port_ref)->publ.lock;
/* Add subscriber to topology server's subscriber list */
- tipc_ref_lock(subscriber->ref);
spin_lock_bh(&topsrv.lock);
list_add(&subscriber->subscriber_list, &topsrv.subscriber_list);
spin_unlock_bh(&topsrv.lock);
- /*
- * Subscribe now if message contains a subscription,
- * otherwise send an empty response to complete connection handshaking
- */
+ /* Unlock server port */
- subscriber_lock = subscriber->lock;
- if (size)
- subscr_subscribe((struct tipc_subscr *)data, subscriber);
- else
- tipc_send(subscriber->port_ref, 1, &msg_sect);
+ server_port_ref = subscriber->port_ref;
+ spin_unlock_bh(subscriber->lock);
- spin_unlock_bh(subscriber_lock);
+ /* Send an ACK- to complete connection handshaking */
+
+ tipc_send(server_port_ref, 1, &msg_sect);
+
+ /* Handle optional subscription request */
+
+ if (size != 0) {
+ subscr_conn_msg_event(subscriber, server_port_ref,
+ buf, data, size);
+ }
}
int tipc_subscr_start(void)
@@ -574,8 +597,8 @@ void tipc_subscr_stop(void)
list_for_each_entry_safe(subscriber, subscriber_temp,
&topsrv.subscriber_list,
subscriber_list) {
- tipc_ref_lock(subscriber->ref);
subscriber_lock = subscriber->lock;
+ spin_lock_bh(subscriber_lock);
subscr_terminate(subscriber);
spin_unlock_bh(subscriber_lock);
}
diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h
index 93a8e674fac1..45d89bf4d202 100644
--- a/net/tipc/subscr.h
+++ b/net/tipc/subscr.h
@@ -1,8 +1,8 @@
/*
- * net/tipc/subscr.h: Include file for TIPC subscription service
+ * net/tipc/subscr.h: Include file for TIPC network topology service
*
* Copyright (c) 2003-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,34 +37,44 @@
#ifndef _TIPC_SUBSCR_H
#define _TIPC_SUBSCR_H
+struct subscription;
+
+typedef void (*tipc_subscr_event) (struct subscription *sub,
+ u32 found_lower, u32 found_upper,
+ u32 event, u32 port_ref, u32 node);
+
/**
* struct subscription - TIPC network topology subscription object
* @seq: name sequence associated with subscription
* @timeout: duration of subscription (in ms)
* @filter: event filtering to be done for subscription
- * @evt: template for events generated by subscription
- * @subscription_list: adjacent subscriptions in subscriber's subscription list
+ * @event_cb: routine invoked when a subscription event is detected
+ * @timer: timer governing subscription duration (optional)
* @nameseq_list: adjacent subscriptions in name sequence's subscription list
- * @timer_ref: reference to timer governing subscription duration (may be NULL)
- * @owner: pointer to subscriber object associated with this subscription
+ * @subscription_list: adjacent subscriptions in subscriber's subscription list
+ * @server_ref: object reference of server port associated with subscription
+ * @swap: indicates if subscriber uses opposite endianness in its messages
+ * @evt: template for events generated by subscription
*/
struct subscription {
struct tipc_name_seq seq;
u32 timeout;
u32 filter;
- struct tipc_event evt;
- struct list_head subscription_list;
- struct list_head nameseq_list;
+ tipc_subscr_event event_cb;
struct timer_list timer;
- struct subscriber *owner;
+ struct list_head nameseq_list;
+ struct list_head subscription_list;
+ u32 server_ref;
+ int swap;
+ struct tipc_event evt;
};
-int tipc_subscr_overlap(struct subscription * sub,
+int tipc_subscr_overlap(struct subscription *sub,
u32 found_lower,
u32 found_upper);
-void tipc_subscr_report_overlap(struct subscription * sub,
+void tipc_subscr_report_overlap(struct subscription *sub,
u32 found_lower,
u32 found_upper,
u32 event,
OpenPOWER on IntegriCloud