[PATCH OLK-6.6] net/oenetcls: Fix crash when removing module

hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ICS3XV -------------------------------- Destroy workqueue in oecls_ntuple_res_clean() and use 'oecls_worker_count' to avoid visiting oenetcls code after removed module. Moreover, call synchronize_rcu() to keep the rcu data consistency. Fixes: c9f5e390a63c ("net/oenetcls: use workqueue for ntuple cfg") Signed-off-by: Wang Liang <wangliang74@huawei.com> --- net/oenetcls/oenetcls.h | 6 ++-- net/oenetcls/oenetcls_flow.c | 5 ++- net/oenetcls/oenetcls_main.c | 43 +++++++++---------------- net/oenetcls/oenetcls_ntuple.c | 57 ++++++++++++++++++++++++---------- 4 files changed, 62 insertions(+), 49 deletions(-) diff --git a/net/oenetcls/oenetcls.h b/net/oenetcls/oenetcls.h index f4a06214f320..0be09b153428 100644 --- a/net/oenetcls/oenetcls.h +++ b/net/oenetcls/oenetcls.h @@ -74,7 +74,7 @@ struct oecls_sk_rule { int dport; int action; int ruleid; - int nid; + int cpu; }; struct oecls_sk_entry { @@ -124,11 +124,9 @@ struct rmgr_ctrl { struct cfg_param { struct work_struct work; struct cmd_context ctx; - struct oecls_sk_rule *rule; struct sock *sk; bool is_del; - int devid; - int nid; + int cpu; }; extern int match_ip_flag; diff --git a/net/oenetcls/oenetcls_flow.c b/net/oenetcls/oenetcls_flow.c index 9a7550544305..87efb5e6a126 100644 --- a/net/oenetcls/oenetcls_flow.c +++ b/net/oenetcls/oenetcls_flow.c @@ -406,12 +406,15 @@ int oecls_flow_res_init(void) } RCU_INIT_POINTER(oecls_ops, &oecls_flow_ops); + synchronize_rcu(); return 0; } void oecls_flow_res_clean(void) { - RCU_INIT_POINTER(oecls_ops, NULL); + rcu_assign_pointer(oecls_ops, NULL); + synchronize_rcu(); + oecls_sock_flow_table_release(); oecls_dev_flow_table_release(); } diff --git a/net/oenetcls/oenetcls_main.c b/net/oenetcls/oenetcls_main.c index 181e480d571b..aa5c63bf612a 100644 --- a/net/oenetcls/oenetcls_main.c +++ b/net/oenetcls/oenetcls_main.c @@ -23,11 +23,11 @@ static int mode; module_param(mode, int, 0444); MODULE_PARM_DESC(mode, "mode, default 0"); -static char ifname[64] = { 0 }; +static char ifname[128] = { 0 }; module_param_string(ifname, ifname, sizeof(ifname), 0444); MODULE_PARM_DESC(ifname, "ifname"); -static char appname[64] = "redis-server"; +static char appname[256] = "redis-server"; module_param_string(appname, appname, sizeof(appname), 0644); MODULE_PARM_DESC(appname, "appname, default redis-server"); @@ -39,6 +39,10 @@ static int strategy; module_param(strategy, int, 0444); MODULE_PARM_DESC(strategy, "strategy, default 0"); +static int check_cap = 1; +module_param(check_cap, int, 0444); +MODULE_PARM_DESC(check_cap, "check_cap, default 1"); + static bool check_params(void) { if (mode != 0 && mode != 1) @@ -218,20 +222,6 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, return ret; } -static noinline_for_stack int ethtool_get_channels(struct net_device *dev, - void *useraddr) -{ - struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS }; - - if (!dev->ethtool_ops->get_channels) - return -EOPNOTSUPP; - - dev->ethtool_ops->get_channels(dev, &channels); - - memcpy_r(useraddr, &channels, sizeof(channels)); - return 0; -} - static int ethtool_get_value(struct net_device *dev, char *useraddr, u32 cmd, u32 (*actor)(struct net_device *)) { @@ -285,10 +275,9 @@ static int dev_ethtool_kern(struct net *net, struct ifreq *ifr) case ETHTOOL_GRXCLSRLCNT: case ETHTOOL_GRXCLSRULE: case ETHTOOL_GRXCLSRLALL: - case ETHTOOL_GCHANNELS: break; default: - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) + if (check_cap && !ns_capable(net->user_ns, CAP_NET_ADMIN)) return -EPERM; } @@ -319,9 +308,6 @@ static int dev_ethtool_kern(struct net *net, struct ifreq *ifr) case ETHTOOL_SRXCLSRLINS: rc = ethtool_set_rxnfc(dev, ethcmd, useraddr); break; - case ETHTOOL_GCHANNELS: - rc = ethtool_get_channels(dev, useraddr); - break; default: rc = -EOPNOTSUPP; } @@ -400,7 +386,7 @@ static void get_netdev_queue_info(struct oecls_netdev_info *oecls_dev) cpu = cpumask_first(irq_data_get_effective_affinity_mask(&desc->irq_data)); rxq_info->affinity_cpu = cpu; oecls_debug("irq=%d, [%s], rxq_id=%d affinity_cpu:%d\n", - irq, desc->action->name, oecls_dev->rxq_num, cpu); + irq, desc->action->name, oecls_dev->rxq_num - 1, cpu); } } @@ -669,9 +655,8 @@ static int init_numa_rxq_bitmap(int nid, struct oecls_numa_info *numa_info) return ret; } -static int get_cluster_rxq(struct oecls_numa_bound_dev_info *bound_dev) +static int get_cluster_rxq(int cpu, struct oecls_numa_bound_dev_info *bound_dev) { - int cpu = raw_smp_processor_id(); int cluster_id = cpu / oecls_cluster_cpu_num; int i, j, rxq_id; @@ -710,10 +695,11 @@ static int put_cluster_rxq(struct oecls_numa_bound_dev_info *bound_dev, int rxq_ return -1; } -int alloc_rxq_id(int nid, int devid) +int alloc_rxq_id(int cpu, int devid) { struct oecls_numa_bound_dev_info *bound_dev; struct oecls_numa_info *numa_info; + int nid = cpu_to_node(cpu); int rxq_id; numa_info = get_oecls_numa_info(nid); @@ -729,7 +715,7 @@ int alloc_rxq_id(int nid, int devid) bound_dev = &numa_info->bound_dev[devid]; if (strategy == 1) { - rxq_id = get_cluster_rxq(bound_dev); + rxq_id = get_cluster_rxq(cpu, bound_dev); if (rxq_id < 0 || rxq_id >= OECLS_MAX_RXQ_NUM_PER_DEV) pr_info("failed to get rxq_id:%d in cluster, try numa\n", rxq_id); else @@ -744,14 +730,15 @@ int alloc_rxq_id(int nid, int devid) found: clear_bit(rxq_id, bound_dev->bitmap_rxq); - oecls_debug("alloc nid:%d, dev_id:%d, rxq_id:%d\n", nid, devid, rxq_id); + oecls_debug("alloc cpu:%d, nid:%d, devid:%d, rxq_id:%d\n", cpu, nid, devid, rxq_id); return rxq_id; } -void free_rxq_id(int nid, int devid, int rxq_id) +void free_rxq_id(int cpu, int devid, int rxq_id) { struct oecls_numa_bound_dev_info *bound_dev; struct oecls_numa_info *numa_info; + int nid = cpu_to_node(cpu); numa_info = get_oecls_numa_info(nid); if (!numa_info) { diff --git a/net/oenetcls/oenetcls_ntuple.c b/net/oenetcls/oenetcls_ntuple.c index 86fc9138b0df..a8d572270f7f 100644 --- a/net/oenetcls/oenetcls_ntuple.c +++ b/net/oenetcls/oenetcls_ntuple.c @@ -13,6 +13,7 @@ struct oecls_sk_rule_list oecls_sk_rules, oecls_sk_list; static struct workqueue_struct *do_cfg_workqueue; +static atomic_t oecls_worker_count = ATOMIC_INIT(0); static void init_oecls_sk_rules(void) { @@ -33,8 +34,7 @@ static inline struct hlist_head *get_sk_hashlist(void *sk) return oecls_sk_list.hash + (jhash(sk, sizeof(sk), 0) & OECLS_SK_RULE_HASHMASK); } -static void add_sk_rule(int devid, u32 dip4, u16 dport, void *sk, int action, - int ruleid, int nid) +static void add_sk_rule(int devid, u32 dip4, u16 dport, void *sk, int action, int ruleid, int cpu) { struct hlist_head *hlist = get_rule_hashlist(dip4, dport); struct hlist_head *sk_hlist = get_sk_hashlist(sk); @@ -52,7 +52,7 @@ static void add_sk_rule(int devid, u32 dip4, u16 dport, void *sk, int action, rule->devid = devid; rule->action = action; rule->ruleid = ruleid; - rule->nid = nid; + rule->cpu = cpu; hlist_add_head(&rule->node, hlist); entry->sk = sk; @@ -442,7 +442,7 @@ static void cfg_work(struct work_struct *work) } // Calculate the bound queue - rxq_id = alloc_rxq_id(ctx_p->nid, devid); + rxq_id = alloc_rxq_id(ctx_p->cpu, devid); if (rxq_id < 0) continue; @@ -451,38 +451,55 @@ static void cfg_work(struct work_struct *work) err = cfg_ethtool_rule(&ctx_p->ctx, ctx_p->is_del); // Add sk rule only on success if (err) { - free_rxq_id(ctx_p->nid, devid, rxq_id); + free_rxq_id(ctx_p->cpu, devid, rxq_id); continue; } - add_sk_rule(ctx_p->devid, ctx_p->ctx.dip4, ctx_p->ctx.dport, ctx_p->sk, - ctx_p->ctx.action, ctx_p->ctx.ret_loc, ctx_p->nid); + add_sk_rule(devid, ctx_p->ctx.dip4, ctx_p->ctx.dport, ctx_p->sk, + ctx_p->ctx.action, ctx_p->ctx.ret_loc, ctx_p->cpu); } else { - rule = get_rule_from_sk(ctx_p->devid, ctx_p->sk); + rule = get_rule_from_sk(devid, ctx_p->sk); if (!rule) { oecls_debug("rule not found! sk:%p, devid:%d, dip4:%pI4, dport:%d\n", - ctx_p->sk, ctx_p->devid, &ctx_p->ctx.dip4, + ctx_p->sk, devid, &ctx_p->ctx.dip4, ntohs(ctx_p->ctx.dport)); continue; } // Config Ntuple rule to dev ctx_p->ctx.del_ruleid = rule->ruleid; - ctx_p->rule = rule; err = cfg_ethtool_rule(&ctx_p->ctx, ctx_p->is_del); // Free the bound queue - free_rxq_id(ctx_p->rule->nid, ctx_p->devid, ctx_p->rule->action); + free_rxq_id(rule->cpu, devid, rule->action); // Delete sk rule - del_sk_rule(ctx_p->rule); + del_sk_rule(rule); } } mutex_unlock(&oecls_sk_rules.mutex); kfree(ctx_p); + atomic_dec(&oecls_worker_count); +} + +static bool has_sock_rule(struct sock *sk) +{ + struct oecls_netdev_info *oecls_dev; + struct oecls_sk_rule *rule; + int devid; + + for_each_oecls_netdev(devid, oecls_dev) { + rule = get_rule_from_sk(devid, sk); + if (rule) + return true; + } + return false; } static void del_ntuple_rule(struct sock *sk) { struct cfg_param *ctx_p; + if (!has_sock_rule(sk)) + return; + ctx_p = kzalloc(sizeof(*ctx_p), GFP_ATOMIC); if (!ctx_p) return; @@ -492,13 +509,12 @@ static void del_ntuple_rule(struct sock *sk) ctx_p->sk = sk; INIT_WORK(&ctx_p->work, cfg_work); queue_work(do_cfg_workqueue, &ctx_p->work); + atomic_inc(&oecls_worker_count); } static void add_ntuple_rule(struct sock *sk) { struct cfg_param *ctx_p; - int cpu = raw_smp_processor_id(); - int nid = cpu_to_node(cpu); if (check_appname(current->comm)) return; @@ -510,9 +526,10 @@ static void add_ntuple_rule(struct sock *sk) ctx_p->is_del = false; ctx_p->sk = sk; - ctx_p->nid = nid; + ctx_p->cpu = raw_smp_processor_id(); INIT_WORK(&ctx_p->work, cfg_work); queue_work(do_cfg_workqueue, &ctx_p->work); + atomic_inc(&oecls_worker_count); } static void ethtool_cfg_rxcls(struct sock *sk, int is_del) @@ -581,11 +598,19 @@ int oecls_ntuple_res_init(void) init_oecls_sk_rules(); RCU_INIT_POINTER(oecls_ops, &oecls_ntuple_ops); + synchronize_rcu(); return 0; } void oecls_ntuple_res_clean(void) { - RCU_INIT_POINTER(oecls_ops, NULL); + rcu_assign_pointer(oecls_ops, NULL); + synchronize_rcu(); + + oecls_debug("oecls_worker_count:%d\n", atomic_read(&oecls_worker_count)); + while (atomic_read(&oecls_worker_count) != 0) + mdelay(1); + + destroy_workqueue(do_cfg_workqueue); clean_oecls_sk_rules(); } -- 2.34.1

反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/18088 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/HLL... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/18088 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/HLL...
participants (2)
-
patchwork bot
-
Wang Liang