From d44866f634f044cf89936ab49452be5bb140b45c Mon Sep 17 00:00:00 2001 From: Michael Blizek Date: Sun, 11 Apr 2010 17:18:59 +0200 Subject: [PATCH] conn reset on neighbor stall, neighbor free --- net/cor/common.c | 27 ++++++++++----- net/cor/cor.h | 10 +++++- net/cor/neighbor.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++--- net/cor/settings.h | 6 +++- 4 files changed, 127 insertions(+), 15 deletions(-) diff --git a/net/cor/common.c b/net/cor/common.c index 2048d0b9b73..20c3048e14f 100644 --- a/net/cor/common.c +++ b/net/cor/common.c @@ -301,10 +301,12 @@ out: int conn_init_out(struct conn *rconn, struct neighbor *nb) { struct conn *sconn = rconn->reversedir; - - BUG_ON(TARGET_UNCONNECTED != rconn->targettype); - BUG_ON(0 == sconn); - BUG_ON(SOURCE_NONE != sconn->sourcetype); + + __u32 stall_timeout_ms = rconn->target.unconnected.stall_timeout_ms; + + BUG_ON(rconn->targettype != TARGET_UNCONNECTED); + BUG_ON(sconn == 0); + BUG_ON(sconn->sourcetype != SOURCE_NONE); memset(&(rconn->target.out), 0, sizeof(rconn->target.out)); memset(&(sconn->source.in), 0, sizeof(sconn->source.in)); @@ -315,6 +317,7 @@ int conn_init_out(struct conn *rconn, struct neighbor *nb) rconn->target.out.nb = nb; sconn->source.in.nb = nb; + rconn->target.out.stall_timeout_ms = stall_timeout_ms; skb_queue_head_init(&(sconn->source.in.reorder_queue)); /* @@ -339,11 +342,8 @@ int conn_init_out(struct conn *rconn, struct neighbor *nb) void conn_init_sock_source(struct conn *conn) { BUG_ON(conn == 0); - conn->sourcetype = SOURCE_SOCK; - memset(&(conn->source.sock), 0, sizeof(conn->source.sock)); - init_waitqueue_head(&(conn->source.sock.wait)); } @@ -351,6 +351,7 @@ void conn_init_sock_target(struct conn *conn) { BUG_ON(conn == 0); conn->targettype = TARGET_SOCK; + memset(&(conn->target.sock), 0, sizeof(conn->target.sock)); init_waitqueue_head(&(conn->target.sock.wait)); } @@ -385,6 +386,16 @@ struct conn* alloc_conn(gfp_t allocflags) databuf_init(&(rconn->buf)); databuf_init(&(sconn->buf)); + rconn->sourcetype = SOURCE_NONE; + sconn->sourcetype = SOURCE_NONE; + rconn->targettype = TARGET_UNCONNECTED; + sconn->targettype = TARGET_UNCONNECTED; + + rconn->target.unconnected.stall_timeout_ms = + CONN_STALL_DEFAULT_TIMEOUT_MS; + sconn->target.unconnected.stall_timeout_ms = + CONN_STALL_DEFAULT_TIMEOUT_MS; + return rconn; out_err1: @@ -619,7 +630,7 @@ static int __init cor_common_init(void) printk(KERN_ERR " conn.source: %d", sizeof(c.source)); printk(KERN_ERR " conn.target: %d", sizeof(c.target)); printk(KERN_ERR " conn.target.out: %d", sizeof(c.target.out)); - printk(KERN_ERR " conn.target.buf: %d", sizeof(c.buf)); + printk(KERN_ERR " conn.buf: %d", sizeof(c.buf)); printk(KERN_ERR " mutex: %d", sizeof(struct mutex)); printk(KERN_ERR " spinlock: %d", sizeof(spinlock_t)); diff --git a/net/cor/cor.h b/net/cor/cor.h index 281c53300f2..c3d92c17169 100644 --- a/net/cor/cor.h +++ b/net/cor/cor.h @@ -284,11 +284,15 @@ struct neighbor{ * time of the last sent packet which has been acked or * otherwise responded to (e.g. pong) */ - unsigned long last_roundtrip;/* active state */ + unsigned long last_roundtrip;/* active/stalled state */ }state_time; __u8 state; __u16 ping_success; + #warning todo + struct delayed_work stalltimeout_timer; + __u8 str_timer_pending; + atomic_t kpacket_seqno; atomic_t ooo_packets; @@ -450,6 +454,8 @@ struct conn{ __u32 cmdread; __u16 cmd; __u8 *cmdparams; + + __u32 stall_timeout_ms; }unconnected; struct{ @@ -462,6 +468,8 @@ struct conn{ __u32 conn_id; __u32 seqno; + + __u32 stall_timeout_ms; }out; struct{ diff --git a/net/cor/neighbor.c b/net/cor/neighbor.c index e8481bb98b5..ae6eb0b226d 100644 --- a/net/cor/neighbor.c +++ b/net/cor/neighbor.c @@ -99,7 +99,8 @@ static int get_addrtype(__u32 addrtypelen, char *addrtype) void neighbor_free(struct kref *ref) { struct neighbor *nb = container_of(ref, struct neighbor, ref); - BUG_ON(nb->nb_list.next != 0 || nb->nb_list.prev != 0); + BUG_ON(nb->nb_list.next != LIST_POISON1); + BUG_ON(nb->nb_list.prev != LIST_POISON2); if (nb->addr != 0) kfree(nb->addr); nb->addr = 0; @@ -297,6 +298,94 @@ void set_last_routdtrip(struct neighbor *nb, unsigned long time) mutex_unlock(&(nb->state_lock)); } +static int reset_stall_conns(struct neighbor *nb, + int stall_time_ms, int resetall) +{ + struct list_head *currlh; + +start: + mutex_lock(&(nb->conn_list_lock)); + currlh = nb->snd_conn_list.next; + + while (currlh != &(nb->snd_conn_list)) { + struct conn *rconn = container_of(currlh, struct conn, + target.out.nb_list); + BUG_ON(rconn->targettype != TARGET_OUT); + + if (resetall || stall_time_ms >= + rconn->target.out.stall_timeout_ms) { + /** + * reset_conn must not be called with conn_list_lock + * held + */ + mutex_unlock(&(nb->conn_list_lock)); + reset_conn(rconn); + goto start; + } + currlh = currlh->next; + } + mutex_unlock(&(nb->conn_list_lock)); +} + +static void stall_timerfunc(struct work_struct *work); + +static void stall_timer(struct neighbor *nb, int fromtimer) +{ + int stall_time_ms; + __u8 nbstate; + + int resetall; + + mutex_lock(&(nb->state_lock)); + stall_time_ms = jiffies_to_msecs(nb->state_time.last_roundtrip - + jiffies); + nbstate = nb->state; + + if (unlikely(nbstate != NEIGHBOR_STATE_STALLED)) + nb->str_timer_pending = 0; + mutex_unlock(&(nb->state_lock)); + + if (unlikely(nbstate != NEIGHBOR_STATE_STALLED)) { + kref_put(&(nb->ref), neighbor_free); + return; + } + + resetall = (stall_time_ms > NB_KILL_TIME_MS); + + reset_stall_conns(nb, stall_time_ms, resetall); + + if (resetall) { + list_del(&(nb->nb_list)); + kref_put(&(nb->ref), neighbor_free); /* nb_list */ + + kref_put(&(nb->ref), neighbor_free); /* stall_timer */ + } else { + if (fromtimer == 0) { + int pending; + mutex_lock(&(nb->state_lock)); + pending = nb->str_timer_pending; + mutex_unlock(&(nb->state_lock)); + + if (pending) + return; + + kref_get(&(nb->ref)); + } + + INIT_DELAYED_WORK(&(nb->stalltimeout_timer), stall_timerfunc); + schedule_delayed_work(&(nb->stalltimeout_timer), + msecs_to_jiffies(STALL_TIMER_INTERVAL_MS)); + } +} + +static void stall_timerfunc(struct work_struct *work) +{ + struct neighbor *nb = container_of(to_delayed_work(work), + struct neighbor, stalltimeout_timer); + stall_timer(nb, 1); +} + + int get_neigh_state(struct neighbor *nb) { int ret; @@ -307,8 +396,8 @@ int get_neigh_state(struct neighbor *nb) mutex_lock(&(nb->state_lock)); if (unlikely(likely(nb->state == NEIGHBOR_STATE_ACTIVE) && unlikely( - time_after(nb->state_time.last_roundtrip + - msecs_to_jiffies(STALL_START_TIME_MS), jiffies)))) { + time_after_eq(jiffies, nb->state_time.last_roundtrip + + msecs_to_jiffies(NB_STALL_TIME_MS))))) { nb->state = NEIGHBOR_STATE_STALLED; switchedtostalled = 1; } @@ -319,7 +408,7 @@ int get_neigh_state(struct neighbor *nb) if (switchedtostalled) { printk(KERN_ERR "switched to stalled"); - #warning todo reset conns + stall_timer(nb, 0); } return ret; @@ -487,7 +576,7 @@ static void add_neighbor(struct neighbor *nb) currlh = currlh->next; } - #warning todo kref + kref_get(&(nb->ref)); list_add_tail(&(nb->nb_list), &nb_list); schedule_controlmsg_timerfunc(nb); setup_timer(&(nb->retrans_timer), retransmit_timerfunc, diff --git a/net/cor/settings.h b/net/cor/settings.h index a2386ca2f5c..14e64b5b805 100644 --- a/net/cor/settings.h +++ b/net/cor/settings.h @@ -15,4 +15,8 @@ #define INITIAL_TIME_MS 10000 #define PING_SUCCESS_CNT 10 -#define STALL_START_TIME_MS 10000 +#define NB_STALL_TIME_MS 10000 +#define NB_KILL_TIME_MS 300000 +#define CONN_STALL_DEFAULT_TIMEOUT_MS 30000 + +#define STALL_TIMER_INTERVAL_MS 1000 -- 2.11.4.GIT