Commit 0a5e845a authored by Vikram Narayanan's avatar Vikram Narayanan
Browse files

lcd/nullnet: Add mechanism for graceful exit


Signed-off-by: Vikram Narayanan's avatarVikram Narayanan <vikram186@gmail.com>
parent 813caf8d
......@@ -145,7 +145,10 @@ int boot_lcd_thread(void *data)
once = 1;
wait_event_interruptible(wq, shutdown != 0);
}
msleep(2000);
LIBLCD_MSG("Exiting thread");
lcd_destroy_module_klcd(net_klcd,
"lcd_test_mod_nullnet_net_klcd");
if (current->lcd)
lcd_cap_delete(dummy_lcd);
if (dummy_ctx)
......
......@@ -5,53 +5,71 @@
#include <lcd_config/post_hook.h>
int dispatch_async_loop(struct thc_channel *channel, struct fipc_message *message, struct glue_cspace *cspace, struct cptr sync_ep)
#define trace(x) LIBLCD_MSG("net got " #x " msg")
extern void dummy_cleanup_module(void);
int dispatch_async_loop(struct thc_channel *channel,
struct fipc_message *message,
struct glue_cspace *cspace,
struct cptr sync_ep)
{
int fn_type;
fn_type = async_msg_get_fn_type(message);
switch (fn_type) {
case NDO_INIT:
LIBLCD_MSG("Calling function ndo_init");
return ndo_init_callee(message, channel, cspace, sync_ep);
break;
trace(NDO_INIT);
return ndo_init_callee(message, channel,
cspace, sync_ep);
case NDO_UNINIT:
LIBLCD_MSG("Calling function ndo_uninit");
return ndo_uninit_callee(message, channel, cspace, sync_ep);
break;
trace(NDO_UNINIT);
ndo_uninit_callee(message, channel,
cspace, sync_ep);
/* wait until uninit is called */
return -1;
case NDO_START_XMIT:
LIBLCD_MSG("Calling function ndo_start_xmit");
return ndo_start_xmit_callee(message, channel, cspace, sync_ep);
break;
trace(NDO_START_XMIT);
return ndo_start_xmit_callee(message,
channel, cspace, sync_ep);
case NDO_VALIDATE_ADDR:
LIBLCD_MSG("Calling function ndo_validate_addr");
return ndo_validate_addr_callee(message, channel, cspace, sync_ep);
break;
trace(NDO_VALIDATE_ADDR);
return ndo_validate_addr_callee(message,
channel, cspace, sync_ep);
case NDO_GET_STATS64:
LIBLCD_MSG("Calling function ndo_get_stats64");
return ndo_get_stats64_callee(message, channel, cspace, sync_ep);
break;
trace(NDO_GET_STATS64);
return ndo_get_stats64_callee(message,
channel, cspace, sync_ep);
case NDO_SET_RX_MODE:
LIBLCD_MSG("Calling function ndo_set_rx_mode");
return ndo_set_rx_mode_callee(message, channel, cspace, sync_ep);
break;
trace(NDO_SET_RX_MODE);
return ndo_set_rx_mode_callee(message,
channel, cspace, sync_ep);
case NDO_SET_MAC_ADDRESS:
LIBLCD_MSG("Calling function ndo_set_mac_address");
return ndo_set_mac_address_callee(message, channel, cspace, sync_ep);
break;
trace(NDO_SET_MAC_ADDRESS);
return ndo_set_mac_address_callee(message,
channel, cspace, sync_ep);
case NDO_CHANGE_CARRIER:
LIBLCD_MSG("Calling function ndo_change_carrier");
return ndo_change_carrier_callee(message, channel, cspace, sync_ep);
break;
trace(NDO_CHANGE_CARRIER);
return ndo_change_carrier_callee(message,
channel, cspace, sync_ep);
case SETUP:
LIBLCD_MSG("Calling function setup");
return setup_callee(message, channel, cspace, sync_ep);
break;
trace(SETUP);
return setup_callee(message, channel,
cspace, sync_ep);
case VALIDATE:
LIBLCD_MSG("Calling function validate");
return validate_callee(message, channel, cspace, sync_ep);
break;
trace(VALIDATE);
return validate_callee(message, channel,
cspace, sync_ep);
case TRIGGER_EXIT:
trace(TRIGGER_EXIT);
/* call nullnet exit */
dummy_cleanup_module();
return 0;
default:
LIBLCD_ERR("unexpected function label: %d",
fn_type);
return -EINVAL;
}
return 0;
}
......@@ -13,6 +13,8 @@ struct cptr sync_ep;
static struct glue_cspace *c_cspace;
extern struct thc_channel *net_async;
struct rtnl_link_ops *g_rtnl_link_ops;
int glue_nullnet_init(void)
{
int ret;
......@@ -38,7 +40,6 @@ void glue_nullnet_exit()
{
glue_cap_destroy(c_cspace);
glue_cap_exit();
}
static int setup_async_channel(cptr_t *buf1_cptr_out, cptr_t *buf2_cptr_out,
......@@ -290,6 +291,8 @@ int __rtnl_link_register(struct rtnl_link_ops *ops)
lcd_set_cr1(rx);
lcd_set_cr2(tx);
g_rtnl_link_ops = ops;
ret = lcd_sync_call(nullnet_register_channel);
/*
......@@ -643,11 +646,14 @@ void rtnl_link_unregister(struct rtnl_link_ops *ops)
LIBLCD_ERR("thc_ipc_call");
goto fail2;
}
glue_cap_remove(c_cspace, ops_container->my_ref);
fipc_recv_msg_end(thc_channel_to_fipc(net_async), response);
lcd_cap_delete(nullnet_sync_endpoint);
destroy_async_channel(net_async);
//lcd_cap_delete(nullnet_sync_endpoint);
if (0)
destroy_async_channel(net_async);
fail2:
fail1:
return;
......@@ -802,6 +808,7 @@ int ndo_uninit_callee(struct fipc_message *request, struct thc_channel *channel,
LIBLCD_ERR("lookup");
goto fail_lookup;
}
printk("%s called, triggering rpc\n", __func__);
net_dev_container->net_device.netdev_ops->ndo_uninit(&net_dev_container->net_device);
......@@ -1108,11 +1115,9 @@ int setup_callee(struct fipc_message *request, struct thc_channel *channel, stru
int ret;
struct fipc_message *response;
unsigned int request_cookie;
struct setup_container *setup_container;
struct net_device_container *net_dev_container;
struct net_device_ops_container *netdev_ops_container;
const struct net_device_ops *netdev_ops;
cptr_t setup_ref = __cptr(fipc_get_reg2(request));
cptr_t netdev_ref = __cptr(fipc_get_reg1(request));
cptr_t netdev_ops_ref = __cptr(fipc_get_reg4(request));
cptr_t netdev_other_ref = __cptr(fipc_get_reg3(request));
......@@ -1122,12 +1127,6 @@ int setup_callee(struct fipc_message *request, struct thc_channel *channel, stru
fipc_recv_msg_end(thc_channel_to_fipc(channel), request);
ret = glue_cap_lookup_setup_type(c_cspace, setup_ref, &setup_container);
if (ret) {
LIBLCD_ERR("lookup");
goto fail_lookup;
}
ret = glue_cap_lookup_net_device_type(c_cspace, netdev_ref, &net_dev_container);
if (ret) {
LIBLCD_ERR("lookup");
......@@ -1138,7 +1137,7 @@ int setup_callee(struct fipc_message *request, struct thc_channel *channel, stru
net_dev_container->other_ref = netdev_other_ref;
LIBLCD_MSG("%s, lcd other ref %p | %lu", __func__, net_dev_container, net_dev_container->other_ref.cptr);
setup_container->setup(&net_dev_container->net_device);
g_rtnl_link_ops->setup(&net_dev_container->net_device);
netdev_ops = net_dev_container->net_device.netdev_ops;
......
......@@ -77,22 +77,6 @@ static void main_and_loop(void)
);
/*
* We don't expect any requests coming back to us, so it's safe
* to just run this without a loop (it's effectively polling since
* only one awe will run in this do-finish).
*/
if (1)
DO_FINISH(
ASYNC(
dummy_cleanup_module();
LIBLCD_MSG("SUCCESSFULLY UNREGISTERED NULLNET!");
);
);
LIBLCD_MSG("EXITED PMFS DO_FINISH");
return;
......
......@@ -39,7 +39,8 @@ enum dispatch_t {
NDO_GET_STATS64,
NDO_CHANGE_CARRIER,
VALIDATE,
SETUP
SETUP,
TRIGGER_EXIT,
};
#define PMFS_ASYNC_RPC_BUFFER_ORDER 12
......
......@@ -15,6 +15,7 @@
struct thc_channel *net_async;
struct cptr sync_ep;
extern struct cspace *klcd_cspace;
struct rtnl_link_ops_container *g_ops_container;
struct trampoline_hidden_args {
void *struct_container;
......@@ -491,9 +492,6 @@ int ndo_start_xmit(struct sk_buff *skb, struct net_device *dev, struct trampolin
struct net_device_container *net_dev_container;
if (!get_current()->ptstate) {
LIBLCD_MSG("%s:Called from userspace", __func__);
// dump_stack();
// return for now
LIBLCD_MSG("\nskb %p | skb->len %d | skb->datalen %d\n"
"skb->end %p | skb->end_off %u | skb->head %p | skb->data %p\n"
"truesize %d | skb->tail %p",
......@@ -502,7 +500,6 @@ int ndo_start_xmit(struct sk_buff *skb, struct net_device *dev, struct trampolin
skb->truesize, skb->tail);
LIBLCD_MSG("headlen %d | pagelen %d",
skb_headlen(skb), skb_pagelen(skb));
{
unsigned char nr_frags = skb_shinfo(skb)->nr_frags;
int i;
......@@ -1418,7 +1415,8 @@ void setup(struct net_device *dev, struct trampoline_hidden_args *hidden_args)
net_dev_container->net_device.netdev_ops = &netdev_ops_container->net_device_ops;
setup_device_ops_trampolines(netdev_ops_container, hidden_args);
net_dev_container->net_device.rtnl_link_ops
= &g_ops_container->rtnl_link_ops;
fail_alloc:
fail_async:
fail_insert:
......@@ -1700,7 +1698,6 @@ fail_lookup:
return ret;
}
extern struct rtnl_link_ops_container *main_ops_container;
//DONE
int __rtnl_link_register_callee(void)
......@@ -1711,14 +1708,14 @@ int __rtnl_link_register_callee(void)
cptr_t sync_endpoint;
int ret;
struct trampoline_hidden_args *validate_hidden_args;
struct trampoline_hidden_args *setup_hidden_args;
int err;
struct fs_info *fs_info;
struct net_info *net_info;
ops_container = kzalloc(sizeof( struct rtnl_link_ops_container ), GFP_KERNEL);
if (!ops_container) {
LIBLCD_ERR("kzalloc");
goto fail7;
}
main_ops_container = ops_container;
err = glue_cap_insert_rtnl_link_ops_type(c_cspace, ops_container, &ops_container->my_ref);
if (err) {
LIBLCD_ERR("lcd insert");
......@@ -1739,18 +1736,22 @@ int __rtnl_link_register_callee(void)
/*
* Add to dispatch loop
*/
fs_info = add_fs(chnl, c_cspace, sync_endpoint);
if (!fs_info) {
net_info = add_fs(chnl, c_cspace, sync_endpoint);
if (!net_info) {
LIBLCD_ERR("error adding to dispatch loop");
goto fail7;
}
ops_container->fs_info = fs_info;
/*setup_hidden_args = kzalloc(sizeof( *setup_hidden_args ), GFP_KERNEL);
setup_hidden_args = kzalloc(sizeof(*setup_hidden_args),
GFP_KERNEL);
if (!setup_hidden_args) {
LIBLCD_ERR("kzalloc hidden args");
lcd_exit(-1);
}
setup_hidden_args->t_handle = LCD_DUP_TRAMPOLINE(setup_trampoline);
setup_hidden_args->t_handle = LCD_DUP_TRAMPOLINE(
setup_trampoline);
if (!setup_hidden_args->t_handle) {
LIBLCD_ERR("duplicate trampoline");
lcd_exit(-1);
......@@ -1768,7 +1769,7 @@ int __rtnl_link_register_callee(void)
LIBLCD_ERR("set mem nx");
goto fail3;
}
*/
validate_hidden_args = kzalloc(sizeof( *validate_hidden_args ), GFP_KERNEL);
if (!validate_hidden_args) {
LIBLCD_ERR("kzalloc hidden args");
......@@ -1784,19 +1785,26 @@ int __rtnl_link_register_callee(void)
validate_hidden_args->cspace = c_cspace;
validate_hidden_args->sync_ep = sync_endpoint;
validate_hidden_args->async_chnl = chnl;
ret = set_memory_x(((unsigned long)validate_hidden_args->t_handle) & PAGE_MASK,
ALIGN(LCD_TRAMPOLINE_SIZE(validate_trampoline),
ret = set_memory_x((
(unsigned long)validate_hidden_args->t_handle)
& PAGE_MASK,
ALIGN(LCD_TRAMPOLINE_SIZE(
validate_trampoline),
PAGE_SIZE) >> PAGE_SHIFT);
if (ret) {
LIBLCD_ERR("set mem nx");
goto fail3;
}
LIBLCD_MSG("Calling real function ");
ops_container->rtnl_link_ops.validate = LCD_HANDLE_TO_TRAMPOLINE(validate_hidden_args->t_handle);
ops_container->rtnl_link_ops.validate =
LCD_HANDLE_TO_TRAMPOLINE(
validate_hidden_args->t_handle);
ops_container->rtnl_link_ops.kind = "dummy";
ret = __rtnl_link_register(( &ops_container->rtnl_link_ops ));
lcd_set_r1(ops_container->my_ref.cptr);
g_ops_container = ops_container;
goto out;
fail7:
fail6:
......@@ -1848,36 +1856,38 @@ int rtnl_link_unregister_callee(struct fipc_message *request, struct thc_channel
{
struct rtnl_link_ops_container *ops_container;
int ret;
int err;
struct fipc_message *response;
unsigned int request_cookie;
//struct trampoline_hidden_args *setup_hidden_args;
struct trampoline_hidden_args *validate_hidden_args;
request_cookie = thc_get_request_cookie(request);
fipc_recv_msg_end(thc_channel_to_fipc(channel), request);
err = glue_cap_lookup_rtnl_link_ops_type(c_cspace, __cptr(fipc_get_reg2(request)), &ops_container);
if (err) {
ret = glue_cap_lookup_rtnl_link_ops_type(c_cspace, __cptr(fipc_get_reg2(request)), &ops_container);
if (ret) {
LIBLCD_ERR("lookup");
lcd_exit(-1);
goto fail_lookup;
}
LIBLCD_MSG("Calling real function %s", __func__);
rtnl_link_unregister(( &ops_container->rtnl_link_ops ));
glue_cap_remove(c_cspace, ops_container->my_ref);
/*setup_hidden_args = LCD_TRAMPOLINE_TO_HIDDEN_ARGS(ops_container->rtnl_link_ops.setup);
kfree(setup_hidden_args->t_handle);
kfree(setup_hidden_args);*/
validate_hidden_args = LCD_TRAMPOLINE_TO_HIDDEN_ARGS(ops_container->rtnl_link_ops.validate);
validate_hidden_args = LCD_TRAMPOLINE_TO_HIDDEN_ARGS(
ops_container->rtnl_link_ops.validate);
kfree(validate_hidden_args->t_handle);
kfree(validate_hidden_args);
kfree(ops_container);
if (async_msg_blocking_send_start(channel, &response)) {
LIBLCD_ERR("error getting response msg");
return -EIO;
}
thc_ipc_reply(channel, request_cookie, response);
thc_ipc_reply(channel, request_cookie, response);
fail_lookup:
return ret;
}
//DONE
......@@ -1944,7 +1954,10 @@ int alloc_netdev_mqs_callee(struct fipc_message *request, struct thc_channel *ch
goto fail3;
}
net_device = alloc_netdev_mqs_lcd(sizeof_priv, name, name_assign_type, (temp->setup ), txqs, rxqs, fipc_get_reg6(request));
net_device = alloc_netdev_mqs_lcd(sizeof_priv, name,
name_assign_type,
g_ops_container->rtnl_link_ops.setup,
txqs, rxqs, fipc_get_reg6(request));
dev_container = container_of(net_device, struct net_device_container, net_device);
......@@ -1992,3 +2005,33 @@ int consume_skb_callee(struct fipc_message *request, struct thc_channel *channel
return ret;
}
int trigger_exit_to_lcd(struct thc_channel *_channel)
{
struct fipc_message *_request;
int ret;
unsigned int request_cookie;
ret = async_msg_blocking_send_start(_channel,
&_request);
if (ret) {
LIBLCD_ERR("failed to get a send slot");
goto fail_async;
}
async_msg_set_fn_type(_request,
TRIGGER_EXIT);
/* No need to wait for a response here */
ret = thc_ipc_send_request(_channel,
_request,
&request_cookie);
if (ret) {
LIBLCD_ERR("thc_ipc send");
goto fail_ipc;
}
fail_async:
fail_ipc:
return ret;
}
#include <lcd_config/pre_hook.h>
#include <linux/module.h>
#include <linux/kernel.h>
......@@ -13,22 +13,27 @@
/* COMPILER: This is always included after all includes. */
#include <lcd_config/post_hook.h>
/* mechanism for unloading LCD gracefully */
static bool unload_lcd =0;
module_param_named(unload, unload_lcd, bool, S_IWUSR);
/* LOOP ------------------------------------------------------------ */
struct fs_info {
struct net_info {
struct thc_channel *chnl;
struct glue_cspace *cspace;
cptr_t sync_endpoint;
struct list_head list;
};
static LIST_HEAD(fs_infos);
static LIST_HEAD(net_infos);
struct rtnl_link_ops_container *main_ops_container;
extern int trigger_exit_to_lcd(struct thc_channel *_channel);
struct fs_info *
struct net_info *
add_fs(struct thc_channel *chnl, struct glue_cspace *cspace,
cptr_t sync_endpoint)
{
struct fs_info *fs_info;
struct net_info *fs_info;
fs_info = kmalloc(sizeof(*fs_info), GFP_KERNEL);
if (!fs_info)
......@@ -37,7 +42,7 @@ add_fs(struct thc_channel *chnl, struct glue_cspace *cspace,
fs_info->cspace = cspace;
fs_info->sync_endpoint = sync_endpoint;
INIT_LIST_HEAD(&fs_info->list);
list_add(&fs_info->list, &fs_infos);
list_add(&fs_info->list, &net_infos);
return fs_info;
......@@ -45,20 +50,27 @@ fail1:
return NULL;
}
void remove_fs(struct fs_info *fs)
void remove_fs(struct net_info *fs)
{
list_del_init(&fs->list);
kfree(fs);
}
static int __get_net(struct net_info **net_out)
{
struct net_info *first;
first = list_first_entry_or_null(&net_infos, struct net_info, list);
if (first)
*net_out = first;
return first ? 1 : 0;
}
static int async_loop(struct fs_info **fs_out, struct fipc_message **msg_out)
static int async_loop(struct net_info **fs_out, struct fipc_message **msg_out)
{
struct fs_info *cursor, *next;
struct net_info *cursor, *next;
int ret;
list_for_each_entry_safe(cursor, next, &fs_infos, list) {
list_for_each_entry_safe(cursor, next, &net_infos, list) {
ret = thc_ipc_poll_recv(cursor->chnl, msg_out);
if (ret == -EPIPE) {
......@@ -156,7 +168,7 @@ static void loop(cptr_t register_chnl)
{
unsigned long tics = jiffies + REGISTER_FREQ;
struct fipc_message *msg;
struct fs_info *fs;
struct net_info *net;
int stop = 0;
int ret;
......@@ -176,26 +188,28 @@ static void loop(cptr_t register_chnl)
tics = jiffies + REGISTER_FREQ;
continue;
}
/*
if (pmfs_ready) {
pmfs_ready = 0;
ASYNC(
stop = do_pmfs_test();
);
}
*/
if (stop)
break;
ret = async_loop(&fs, &msg);
/*
* will be updated by a write into sysfs
* from userspace.
*/
if (unload_lcd) {
unload_lcd = 0;
if (__get_net(&net))
trigger_exit_to_lcd(net->chnl);
}
ret = async_loop(&net, &msg);
if (!ret) {
ASYNC(
ret = dispatch_async_loop(
fs->chnl,
net->chnl,
msg,
fs->cspace,
fs->sync_endpoint);
net->cspace,
net->sync_endpoint);
if (ret) {
LIBLCD_ERR("fs dispatch err");
LIBLCD_ERR("net dispatch err");
/* (break won't work here) */
stop = 1;
}
......@@ -226,22 +240,7 @@ static void loop(cptr_t register_chnl)
);
/*
* NOTE: If the vfs klcd quits / is killed before
* unregister_filesystem runs, it could cause some proc fs
* crap to crash (the struct file_system_type is still in
* the registered fs list, but e.g. the const char *name just
* went bye-bye when we unloaded the vfs's .ko.)
*/
if (main_ops_container) {
LIBLCD_MSG("Forcefully unregister %s", main_ops_container->rtnl_link_ops.kind);
rtnl_link_unregister(( &main_ops_container->rtnl_link_ops ));
kfree(main_ops_container);