Add an exported function ng_rmhook_self() that removes a hook

from a node, but does it via the locking queue, thus ensuring that the
node is locked when it's hook is removed.

Add 'deadnode' and 'deadhook' structures for when a node or hook is
invalidated but not yet freed. (not yet freed)
This commit is contained in:
Julian Elischer 2001-01-11 19:27:54 +00:00
parent cdbfe12417
commit 954c4772dd
3 changed files with 106 additions and 7 deletions

View File

@ -106,6 +106,7 @@ struct ng_hook {
#define HK_INVALID 0x0001 /* don't trust it! */
#define HK_QUEUE 0x0002 /* queue for later delivery */
#define HK_FORCE_WRITER 0x0004 /* Incoming data queued as a writer */
#define HK_DEAD 0x0008 /* This is the dead hook.. don't free */
/*
* Public Methods for hook
@ -1009,7 +1010,8 @@ item_p ng_package_data(struct mbuf *m, meta_p meta);
item_p ng_package_msg(struct ng_mesg *msg);
item_p ng_package_msg_self(node_p here, hook_p hook, struct ng_mesg *msg);
void ng_replace_retaddr(node_p here, item_p item, ng_ID_t retaddr);
int ng_rmnode_self(node_p here);
int ng_rmhook_self(hook_p hook); /* if a node wants to kill a hook */
int ng_rmnode_self(node_p here); /* if a node wants to suicide */
int ng_snd_item(item_p item, int queue);
/*

View File

@ -81,7 +81,72 @@ static void ng_dumpnodes(void);
static void ng_dumphooks(void);
#endif /* NETGRAPH_DEBUG */
/*
* DEAD versions of the structures.
* In order to avoid races, it is sometimes neccesary to point
* at SOMETHING even though theoretically, the current entity is
* INVALID. Use these to avoid these races.
*/
struct ng_type ng_deadtype = {
NG_ABI_VERSION,
"dead",
NULL, /* modevent */
NULL, /* constructor */
NULL, /* rcvmsg */
NULL, /* shutdown */
NULL, /* newhook */
NULL, /* findhook */
NULL, /* connect */
NULL, /* rcvdata */
NULL, /* disconnect */
NULL, /* cmdlist */
};
struct ng_node ng_deadnode = {
"dead",
&ng_deadtype,
NG_INVALID,
1, /* refs */
0, /* numhooks */
NULL, /* private */
0, /* ID */
LIST_HEAD_INITIALIZER(ng_deadnode.hooks),
{}, /* all_nodes list entry */
{}, /* id hashtable list entry */
{}, /* workqueue entry */
{ 0,
{}, /* should never use! (should hang) */
NULL,
&ng_deadnode.nd_input_queue.queue,
&ng_deadnode
},
#ifdef NETGRAPH_DEBUG
ND_MAGIC,
__FILE__,
__LINE__,
{NULL}
#endif /* NETGRAPH_DEBUG */
};
struct ng_hook ng_deadhook = {
"dead",
NULL, /* private */
HK_INVALID | HK_DEAD,
1, /* refs always >= 1 */
&ng_deadhook, /* Peer is self */
&ng_deadnode, /* attached to deadnode */
{}, /* hooks list */
#ifdef NETGRAPH_DEBUG
HK_MAGIC,
__FILE__,
__LINE__,
{NULL}
#endif /* NETGRAPH_DEBUG */
};
/*
* END DEAD STRUCTURES
*/
/* List nodes with unallocated work */
static TAILQ_HEAD(, ng_node) ng_worklist = TAILQ_HEAD_INITIALIZER(ng_worklist);
static struct mtx ng_worklist_mtx;
@ -500,7 +565,7 @@ ng_make_node(const char *typename, node_p *nodepp)
/*
* Node has no constructor. We cannot ask for one
* to be made. It must be brought into existance by
* some external agency. The external acency should
* some external agency. The external agency should
* call ng_make_node_common() directly to get the
* netgraph part initialised.
*/
@ -904,12 +969,12 @@ ng_add_hook(node_p node, const char *name, hook_p *hookp)
NG_NODE_REF(node); /* each hook counts as a reference */
/* Check if the node type code has something to say about it */
if (node->nd_type->newhook != NULL)
if ((error = (*node->nd_type->newhook)(node, hook, name)) != 0) {
if (node->nd_type->newhook != NULL) {
if ((error = (*node->nd_type->newhook)(node, hook, name))) {
NG_HOOK_UNREF(hook); /* this frees the hook */
return (error);
}
}
/*
* The 'type' agrees so far, so go ahead and link it in.
* We'll ask again later when we actually connect the hooks.
@ -1207,6 +1272,35 @@ ng_rmnode_self(node_p here)
return (ng_snd_item(item, 0));
}
#define NG_INTERNAL_RMHOOK 0x123456
int
ng_rmhook_self(hook_p hook)
{
item_p item;
struct ng_mesg *msg;
node_p node = NG_HOOK_NODE(hook);
NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NG_INTERNAL_RMHOOK, 0, M_NOWAIT);
/*
* Try get a queue item to send it with.
* Hopefully since it has a reserve, we can get one.
* If we can't we are screwed anyhow.
* Increase the chances by flushing our queue first.
* We may free an item, (if we were the hog).
* Work in progress is allowed to complete.
* We also pretty much ensure that we come straight
* back in to do the shutdown. It may be a good idea
* to hold a reference actually to stop it from all
* going up in smoke.
*/
item = ng_package_msg_self(node, hook, msg);
if (item == NULL) { /* couldn't allocate item. Freed msg */
/* try again after flushing our queue */
panic("Couldn't allocate item to remove hook");
}
return (ng_snd_item(item, 0));
}
/***********************************************************************
* Parse and verify a string of the form: <NODE:><PATH>
*
@ -2231,6 +2325,9 @@ ng_generic_msg(node_p here, item_p item, hook_p lasthook)
ng_destroy_hook(hook);
break;
}
case NG_INTERNAL_RMHOOK:
ng_destroy_hook(lasthook);
break;
case NGM_NODEINFO:
{
struct nodeinfo *ni;

View File

@ -1167,7 +1167,7 @@ AAA
/* send message to creator */
/* close hook */
if (sendhook) {
ng_destroy_hook(sendhook);
ng_rmhook_self(sendhook);
}
break;
default:
@ -1511,7 +1511,7 @@ AAA
case PPPOE_PRIMED:
case PPPOE_SOFFER:
/* a timeout on these says "give up" */
ng_destroy_hook(hook);
ng_rmhook_self(hook);
break;
default:
/* timeouts have no meaning in other states */