Fixes a tricky bug in the pipe protocol.

When uncofiguring the pipe and the peer table, the peer table was
unlocked when pipe protocol state changed to down/flushing and not to
down/hungry. This leads to the removal of the peer table before
the routes from the pipe were flushed.

The fix leads to adding some pipe-specific hacks to the nest,
but this seems inevitable.
This commit is contained in:
Ondrej Zajicek 2010-02-11 22:27:06 +01:00
parent a2ea1bac60
commit c83876265e
4 changed files with 36 additions and 12 deletions

View file

@ -133,6 +133,11 @@ proto_init_instance(struct proto *p)
p->attn = ev_new(p->pool); p->attn = ev_new(p->pool);
p->attn->data = p; p->attn->data = p;
rt_lock_table(p->table); rt_lock_table(p->table);
#ifdef CONFIG_PIPE
if (proto_is_pipe(p))
rt_lock_table(pipe_get_peer_table(p));
#endif
} }
/** /**
@ -583,6 +588,12 @@ proto_fell_down(struct proto *p)
bzero(&p->stats, sizeof(struct proto_stats)); bzero(&p->stats, sizeof(struct proto_stats));
rt_unlock_table(p->table); rt_unlock_table(p->table);
#ifdef CONFIG_PIPE
if (proto_is_pipe(p))
rt_unlock_table(pipe_get_peer_table(p));
#endif
proto_rethink_goal(p); proto_rethink_goal(p);
} }

View file

@ -334,4 +334,18 @@ struct announce_hook {
struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *); struct announce_hook *proto_add_announce_hook(struct proto *, struct rtable *);
/*
* Some pipe-specific nest hacks
*/
#ifdef CONFIG_PIPE
static inline int proto_is_pipe(struct proto *p)
{ return p->proto == &proto_pipe; }
struct rtable *pipe_get_peer_table(struct proto *p);
#endif
#endif #endif

View file

@ -642,7 +642,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new
/* Do not filter routes going through the pipe, /* Do not filter routes going through the pipe,
they are filtered in the export filter only. */ they are filtered in the export filter only. */
#ifdef CONFIG_PIPE #ifdef CONFIG_PIPE
if (p->proto == &proto_pipe) if (proto_is_pipe(p))
filter = FILTER_ACCEPT; filter = FILTER_ACCEPT;
#endif #endif

View file

@ -138,6 +138,9 @@ pipe_start(struct proto *P)
* end of the pipe (we need to do this in order to get different * end of the pipe (we need to do this in order to get different
* filters and announce functions and it unfortunately involves * filters and announce functions and it unfortunately involves
* a couple of magic trickery). * a couple of magic trickery).
*
* The phantom protocol is used ONLY in announce hooks and
* therefore in do_rte_announce() function.
*/ */
ph = mb_alloc(P->pool, sizeof(struct pipe_proto)); ph = mb_alloc(P->pool, sizeof(struct pipe_proto));
memcpy(ph, p, sizeof(struct pipe_proto)); memcpy(ph, p, sizeof(struct pipe_proto));
@ -170,20 +173,10 @@ pipe_start(struct proto *P)
*/ */
a = proto_add_announce_hook(P, p->peer); a = proto_add_announce_hook(P, p->peer);
a->proto = &ph->p; a->proto = &ph->p;
rt_lock_table(p->peer);
return PS_UP; return PS_UP;
} }
static int
pipe_shutdown(struct proto *P)
{
struct pipe_proto *p = (struct pipe_proto *) P;
rt_unlock_table(p->peer);
return PS_DOWN;
}
static struct proto * static struct proto *
pipe_init(struct proto_config *C) pipe_init(struct proto_config *C)
{ {
@ -234,13 +227,19 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
return 1; return 1;
} }
struct rtable *
pipe_get_peer_table(struct proto *P)
{
struct pipe_proto *p = (struct pipe_proto *) P;
return p->peer;
}
struct protocol proto_pipe = { struct protocol proto_pipe = {
name: "Pipe", name: "Pipe",
template: "pipe%d", template: "pipe%d",
postconfig: pipe_postconfig, postconfig: pipe_postconfig,
init: pipe_init, init: pipe_init,
start: pipe_start, start: pipe_start,
shutdown: pipe_shutdown,
reconfigure: pipe_reconfigure, reconfigure: pipe_reconfigure,
get_status: pipe_get_status, get_status: pipe_get_status,
}; };