From 818f0a5a4f0e3b41041ff952e56e1edb49933f9f Mon Sep 17 00:00:00 2001 From: Michael Blizek Date: Fri, 16 Apr 2010 07:29:44 +0200 Subject: [PATCH] neighbor free after disconnect --- net/cor/cor.h | 4 +++- net/cor/kpacket_gen.c | 9 +++++++- net/cor/neighbor.c | 62 ++++++++++++++++++++++++++++++++++----------------- net/cor/settings.h | 4 ++-- net/cor/snd.c | 42 ++++++++++++++++++++++++++-------- 5 files changed, 88 insertions(+), 33 deletions(-) diff --git a/net/cor/cor.h b/net/cor/cor.h index 8c84dca07d2..b5735cbc225 100644 --- a/net/cor/cor.h +++ b/net/cor/cor.h @@ -248,6 +248,7 @@ struct ping_cookie{ #define NEIGHBOR_STATE_INITIAL 0 #define NEIGHBOR_STATE_ACTIVE 1 #define NEIGHBOR_STATE_STALLED 2 +#define NEIGHBOR_STATE_KILLED 3 struct neighbor{ struct list_head nb_list; @@ -283,7 +284,7 @@ struct neighbor{ __u32 lastcookie; atomic_t latency; /* microsecs */ - struct mutex state_lock; + spinlock_t state_lock; union { __u64 last_state_change;/* initial state */ /** @@ -318,6 +319,7 @@ struct neighbor{ */ spinlock_t retrans_lock; struct timer_list retrans_timer; + __u8 retrans_timer_running; /* * next_retransmit are linked with diff --git a/net/cor/kpacket_gen.c b/net/cor/kpacket_gen.c index 89ef14a5a85..c7abf881b68 100644 --- a/net/cor/kpacket_gen.c +++ b/net/cor/kpacket_gen.c @@ -438,6 +438,7 @@ static void controlmsg_timerfunc(struct work_struct *work) send_messages(nb, 1); schedule_controlmsg_timerfunc(nb); + kref_put(&(nb->ref), neighbor_free); } void schedule_controlmsg_timerfunc(struct neighbor *nb) @@ -447,6 +448,11 @@ void schedule_controlmsg_timerfunc(struct neighbor *nb) __u64 jiffies = get_jiffies_64(); long long delay; + int state = get_neigh_state(nb); + + if (state == NEIGHBOR_STATE_KILLED) + return; + mutex_lock(&(nb->cmsg_lock)); nb->timeout += target_delay_jiffies; @@ -459,6 +465,7 @@ void schedule_controlmsg_timerfunc(struct neighbor *nb) INIT_DELAYED_WORK(&(nb->cmsg_timer), controlmsg_timerfunc); schedule_delayed_work(&(nb->cmsg_timer), delay); mutex_unlock(&(nb->cmsg_lock)); + kref_get(&(nb->ref)); } static void add_control_msg(struct control_msg_out *msg, struct neighbor *nb) @@ -466,7 +473,7 @@ static void add_control_msg(struct control_msg_out *msg, struct neighbor *nb) int nbstate = get_neigh_state(nb); BUG_ON(msg == 0); - BUG_ON(cm->lh.next != LIST_POISON1 || cm->lh.prev != LIST_POISON2); + BUG_ON(msg->lh.next != LIST_POISON1 || msg->lh.prev != LIST_POISON2); mutex_lock(&(nb->cmsg_lock)); diff --git a/net/cor/neighbor.c b/net/cor/neighbor.c index ef0e40d8f1d..8acb8cc60ab 100644 --- a/net/cor/neighbor.c +++ b/net/cor/neighbor.c @@ -93,6 +93,7 @@ static int get_addrtype(__u32 addrtypelen, char *addrtype) void neighbor_free(struct kref *ref) { struct neighbor *nb = container_of(ref, struct neighbor, ref); + printk(KERN_ERR "neighbor free"); BUG_ON(nb->nb_list.next != LIST_POISON1); BUG_ON(nb->nb_list.prev != LIST_POISON2); if (nb->addr != 0) @@ -124,7 +125,7 @@ static struct neighbor *alloc_neighbor(gfp_t allocflags) get_random_bytes((char *) &seqno, sizeof(seqno)); mutex_init(&(nb->pingcookie_lock)); atomic_set(&(nb->latency), 0); - mutex_init(&(nb->state_lock)); + spin_lock_init(&(nb->state_lock)); atomic_set(&(nb->kpacket_seqno), seqno); mutex_init(&(nb->conn_list_lock)); INIT_LIST_HEAD(&(nb->rcv_conn_list)); @@ -232,10 +233,11 @@ __u32 generate_neigh_list(char *buf, __u32 buflen, __u32 limit, __u32 offset) nb_list); __u8 state; - /* get_neigh_state not used here because it would daedlock */ - mutex_lock(&(curr->state_lock)); + unsigned long iflags; + /* get_neigh_state not used here because it would deadlock */ + spin_lock_irqsave( &(curr->state_lock), iflags ); state = curr->state; - mutex_unlock(&(curr->state_lock)); + spin_unlock_irqrestore( &(curr->state_lock), iflags ); if (state != NEIGHBOR_STATE_ACTIVE) goto cont2; @@ -282,15 +284,17 @@ cont2: void set_last_routdtrip(struct neighbor *nb, unsigned long time) { + unsigned long iflags; + BUG_ON(nb == 0); - mutex_lock(&(nb->state_lock)); + spin_lock_irqsave( &(nb->state_lock), iflags ); if(likely(nb->state == NEIGHBOR_STATE_ACTIVE) && time_after(time, nb->state_time.last_roundtrip)) nb->state_time.last_roundtrip = time; - mutex_unlock(&(nb->state_lock)); + spin_unlock_irqrestore( &(nb->state_lock), iflags ); } static void reset_stall_conns(struct neighbor *nb, @@ -330,15 +334,17 @@ static void stall_timer(struct neighbor *nb, int fromtimer) __u8 nbstate; int resetall; + + unsigned long iflags; - mutex_lock(&(nb->state_lock)); - stall_time_ms = jiffies_to_msecs(nb->state_time.last_roundtrip - - jiffies); + spin_lock_irqsave( &(nb->state_lock), iflags ); + stall_time_ms = jiffies_to_msecs(jiffies - + nb->state_time.last_roundtrip); nbstate = nb->state; if (unlikely(nbstate != NEIGHBOR_STATE_STALLED)) nb->str_timer_pending = 0; - mutex_unlock(&(nb->state_lock)); + spin_unlock_irqrestore( &(nb->state_lock), iflags ); if (unlikely(nbstate != NEIGHBOR_STATE_STALLED)) { kref_put(&(nb->ref), neighbor_free); @@ -347,19 +353,27 @@ static void stall_timer(struct neighbor *nb, int fromtimer) resetall = (stall_time_ms > NB_KILL_TIME_MS); + /*if(resetall) + printk(KERN_ERR "reset_all");*/ + reset_stall_conns(nb, stall_time_ms, resetall); if (resetall) { + spin_lock_irqsave( &(nb->state_lock), iflags ); + nb->state = NEIGHBOR_STATE_KILLED; + spin_unlock_irqrestore( &(nb->state_lock), iflags ); + 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)); + spin_lock_irqsave( &(nb->state_lock), iflags ); pending = nb->str_timer_pending; - mutex_unlock(&(nb->state_lock)); + spin_unlock_irqrestore( &(nb->state_lock), iflags ); if (pending) return; @@ -385,10 +399,11 @@ int get_neigh_state(struct neighbor *nb) { int ret; int switchedtostalled = 0; + unsigned long iflags; BUG_ON(nb == 0); - mutex_lock(&(nb->state_lock)); + spin_lock_irqsave( &(nb->state_lock), iflags ); if (unlikely(likely(nb->state == NEIGHBOR_STATE_ACTIVE) && unlikely( time_after_eq(jiffies, nb->state_time.last_roundtrip + @@ -399,10 +414,10 @@ int get_neigh_state(struct neighbor *nb) ret = nb->state; - mutex_unlock(&(nb->state_lock)); + spin_unlock_irqrestore( &(nb->state_lock), iflags ); if (switchedtostalled) { - printk(KERN_ERR "switched to stalled"); + /*printk(KERN_ERR "switched to stalled");*/ stall_timer(nb, 0); } @@ -425,8 +440,11 @@ void ping_resp(struct neighbor *nb, __u32 cookie, __u32 respdelay) struct ping_cookie *c; int i; + unsigned long cookie_sendtime; __s64 newlatency; + unsigned long iflags; + mutex_lock(&(nb->pingcookie_lock)); c = find_cookie(nb, cookie); @@ -434,6 +452,8 @@ void ping_resp(struct neighbor *nb, __u32 cookie, __u32 respdelay) if (c == 0) goto out; + cookie_sendtime = c->time; + newlatency = ((((__s64) ((__u32)atomic_read(&(nb->latency)))) * 15 + jiffies_to_usecs(jiffies - c->time) - respdelay) / 16); if (unlikely(newlatency < 0)) @@ -458,7 +478,7 @@ void ping_resp(struct neighbor *nb, __u32 cookie, __u32 respdelay) } } - mutex_lock(&(nb->state_lock)); + spin_lock_irqsave( &(nb->state_lock), iflags ); if (unlikely(nb->state == NEIGHBOR_STATE_INITIAL || nb->state == NEIGHBOR_STATE_STALLED)) { @@ -474,18 +494,21 @@ void ping_resp(struct neighbor *nb, __u32 cookie, __u32 respdelay) } if (nb->ping_success >= PING_SUCCESS_CNT) { - if (nb->state == NEIGHBOR_STATE_INITIAL) + /*if (nb->state == NEIGHBOR_STATE_INITIAL) printk(KERN_ERR "switched from initial to active"); else printk(KERN_ERR "switched from stalled to active"); + */ nb->state = NEIGHBOR_STATE_ACTIVE; nb->ping_success = 0; nb->state_time.last_roundtrip = jiffies; } + } else { + nb->state_time.last_roundtrip = cookie_sendtime; } out2: - mutex_unlock(&(nb->state_lock)); + spin_unlock_irqrestore( &(nb->state_lock), iflags ); out: mutex_unlock(&(nb->pingcookie_lock)); @@ -571,7 +594,7 @@ static void add_neighbor(struct neighbor *nb) currlh = currlh->next; } - kref_get(&(nb->ref)); + /* kref_get not needed here, because the caller leaves its ref to us */ list_add_tail(&(nb->nb_list), &nb_list); schedule_controlmsg_timerfunc(nb); setup_timer(&(nb->retrans_timer), retransmit_timerfunc, @@ -696,7 +719,6 @@ static void apply_announce_cmds(char *msg, __u32 len, struct net_device *dev, dev_hold(dev); nb->dev = dev; add_neighbor(nb); - } static int check_announce_cmds(char *msg, __u32 len) diff --git a/net/cor/settings.h b/net/cor/settings.h index 14e64b5b805..cea0c3a07dc 100644 --- a/net/cor/settings.h +++ b/net/cor/settings.h @@ -16,7 +16,7 @@ #define PING_SUCCESS_CNT 10 #define NB_STALL_TIME_MS 10000 -#define NB_KILL_TIME_MS 300000 -#define CONN_STALL_DEFAULT_TIMEOUT_MS 30000 +#define NB_KILL_TIME_MS 30000 +#define CONN_STALL_DEFAULT_TIMEOUT_MS 300000 #define STALL_TIMER_INTERVAL_MS 1000 diff --git a/net/cor/snd.c b/net/cor/snd.c index 0e923b55015..503aa9abffb 100644 --- a/net/cor/snd.c +++ b/net/cor/snd.c @@ -156,6 +156,9 @@ static void cor_xmit(struct sk_buff *skb, int atomic, int clone) return; } } else { + struct skb_procstate *ps = skb_pstate(skb); + kref_put(&(ps->funcstate.retransmit_queue.nb->ref), + neighbor_free); skb2 = skb; } @@ -176,6 +179,8 @@ void retransmit_timerfunc(unsigned long arg) struct neighbor *nb = (struct neighbor *) arg; struct sk_buff *skb = 0; unsigned long timeout; + + int state = get_neigh_state(nb); while (1) { spin_lock_irqsave( &(nb->retrans_lock), iflags ); @@ -184,6 +189,14 @@ void retransmit_timerfunc(unsigned long arg) if (0 == skb) goto out; + if (state == NEIGHBOR_STATE_KILLED) { + struct skb_procstate *ps = skb_pstate(skb); + kref_put(&(ps->funcstate.retransmit_queue.nb->ref), + neighbor_free); + spin_unlock_irqrestore( &(nb->retrans_lock), iflags ); + continue; + + } timeout = skb_pstate(skb)->funcstate.retransmit_queue.timeout; if (time_after(timeout, jiffies)) { @@ -202,7 +215,11 @@ void retransmit_timerfunc(unsigned long arg) modtimer: mod_timer(&(nb->retrans_timer), timeout); + if (0) { out: + nb->retrans_timer_running = 0; + kref_put(&(nb->ref), neighbor_free); + } spin_unlock_irqrestore( &(nb->retrans_lock), iflags ); } @@ -236,7 +253,6 @@ static struct sk_buff *create_packet(struct neighbor *nb, int size, ps->funcstate.retransmit_queue.conn_id = conn_id; ps->funcstate.retransmit_queue.seqno = seqno; ps->funcstate.retransmit_queue.nb = nb; - #warning todo decr kref kref_get(&(nb->ref)); dest = skb_put(ret, 9); @@ -308,9 +324,12 @@ static void schedule_retransmit(struct sk_buff *skb, struct neighbor *nb) first = unlikely(skb_queue_empty(&(nb->retrans_list))); __skb_queue_tail(&(nb->retrans_list), skb); - if (first) { + if (unlikely(unlikely(first) && + unlikely(nb->retrans_timer_running == 0))) { mod_timer(&(nb->retrans_timer), ps->funcstate.retransmit_queue.timeout); + nb->retrans_timer_running = 1; + kref_get(&(nb->ref)); } spin_unlock_irqrestore( &(nb->retrans_lock), iflags ); @@ -369,20 +388,25 @@ void ack_received(struct neighbor *nb, __u32 conn_id, __u32 seqno) skb->next->prev = skb->prev; skb->prev->next = skb->next; + BUG_ON(nb != ps->funcstate.retransmit_queue.nb); + #warning todo ps->rconn kref ? kfree_skb(skb); - if (first) { - if (unlikely(skb_queue_empty(&(nb->retrans_list)))) { - #warning todo ??? - mod_timer(&(nb->retrans_timer), jiffies + - msecs_to_jiffies( ((__u32) - atomic_read(&(nb->latency)))/1000)); - } + if (unlikely(unlikely(first) && + unlikely(skb_queue_empty(&(nb->retrans_list))) && + unlikely(nb->retrans_timer_running == 0))) { + mod_timer(&(nb->retrans_timer), jiffies + + msecs_to_jiffies( ((__u32) + atomic_read(&(nb->latency)))/1000)); + nb->retrans_timer_running = 1; + kref_get(&(nb->ref)); } spin_unlock_irqrestore( &(nb->retrans_lock), iflags ); + + kref_put(&(nb->ref), neighbor_free); } void flush_out(struct conn *rconn) -- 2.11.4.GIT