aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/module.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-03-23 05:07:49 -0400
committerIngo Molnar <mingo@elte.hu>2009-03-23 05:07:49 -0400
commitb3e3b302cf6dc8d60b67f0e84d1fa5648889c038 (patch)
tree3f6150291664b4c62e328f6b1dcff79b54db612a /kernel/module.c
parenta6bc3262c561780d2a6587aa3d5715b1e7d8fa13 (diff)
parent59fcbddaff6f862cc1584b488866d9c4a5579085 (diff)
Merge branches 'irq/sparseirq' and 'linus' into irq/core
Diffstat (limited to 'kernel/module.c')
-rw-r--r--kernel/module.c26
1 files changed, 14 insertions, 12 deletions
diff --git a/kernel/module.c b/kernel/module.c
index ba22484a987e..1196f5d11700 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2015,14 +2015,6 @@ static noinline struct module *load_module(void __user *umod,
2015 if (err < 0) 2015 if (err < 0)
2016 goto free_mod; 2016 goto free_mod;
2017 2017
2018#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
2019 mod->refptr = percpu_modalloc(sizeof(local_t), __alignof__(local_t),
2020 mod->name);
2021 if (!mod->refptr) {
2022 err = -ENOMEM;
2023 goto free_mod;
2024 }
2025#endif
2026 if (pcpuindex) { 2018 if (pcpuindex) {
2027 /* We have a special allocation for this section. */ 2019 /* We have a special allocation for this section. */
2028 percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size, 2020 percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size,
@@ -2030,7 +2022,7 @@ static noinline struct module *load_module(void __user *umod,
2030 mod->name); 2022 mod->name);
2031 if (!percpu) { 2023 if (!percpu) {
2032 err = -ENOMEM; 2024 err = -ENOMEM;
2033 goto free_percpu; 2025 goto free_mod;
2034 } 2026 }
2035 sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC; 2027 sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
2036 mod->percpu = percpu; 2028 mod->percpu = percpu;
@@ -2082,6 +2074,14 @@ static noinline struct module *load_module(void __user *umod,
2082 /* Module has been moved. */ 2074 /* Module has been moved. */
2083 mod = (void *)sechdrs[modindex].sh_addr; 2075 mod = (void *)sechdrs[modindex].sh_addr;
2084 2076
2077#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
2078 mod->refptr = percpu_modalloc(sizeof(local_t), __alignof__(local_t),
2079 mod->name);
2080 if (!mod->refptr) {
2081 err = -ENOMEM;
2082 goto free_init;
2083 }
2084#endif
2085 /* Now we've moved module, initialize linked lists, etc. */ 2085 /* Now we've moved module, initialize linked lists, etc. */
2086 module_unload_init(mod); 2086 module_unload_init(mod);
2087 2087
@@ -2288,15 +2288,17 @@ static noinline struct module *load_module(void __user *umod,
2288 ftrace_release(mod->module_core, mod->core_size); 2288 ftrace_release(mod->module_core, mod->core_size);
2289 free_unload: 2289 free_unload:
2290 module_unload_free(mod); 2290 module_unload_free(mod);
2291 free_init:
2292#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
2293 percpu_modfree(mod->refptr);
2294#endif
2291 module_free(mod, mod->module_init); 2295 module_free(mod, mod->module_init);
2292 free_core: 2296 free_core:
2293 module_free(mod, mod->module_core); 2297 module_free(mod, mod->module_core);
2298 /* mod will be freed with core. Don't access it beyond this line! */
2294 free_percpu: 2299 free_percpu:
2295 if (percpu) 2300 if (percpu)
2296 percpu_modfree(percpu); 2301 percpu_modfree(percpu);
2297#if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
2298 percpu_modfree(mod->refptr);
2299#endif
2300 free_mod: 2302 free_mod:
2301 kfree(args); 2303 kfree(args);
2302 free_hdr: 2304 free_hdr:
CPOLEN_WINDOW << 8) | opts->wscale); } EXPORT_SYMBOL_GPL(synproxy_build_options); void synproxy_init_timestamp_cookie(const struct xt_synproxy_info *info, struct synproxy_options *opts) { opts->tsecr = opts->tsval; opts->tsval = tcp_time_stamp & ~0x3f; if (opts->options & XT_SYNPROXY_OPT_WSCALE) { opts->tsval |= opts->wscale; opts->wscale = info->wscale; } else opts->tsval |= 0xf; if (opts->options & XT_SYNPROXY_OPT_SACK_PERM) opts->tsval |= 1 << 4; if (opts->options & XT_SYNPROXY_OPT_ECN) opts->tsval |= 1 << 5; } EXPORT_SYMBOL_GPL(synproxy_init_timestamp_cookie); void synproxy_check_timestamp_cookie(struct synproxy_options *opts) { opts->wscale = opts->tsecr & 0xf; if (opts->wscale != 0xf) opts->options |= XT_SYNPROXY_OPT_WSCALE; opts->options |= opts->tsecr & (1 << 4) ? XT_SYNPROXY_OPT_SACK_PERM : 0; opts->options |= opts->tsecr & (1 << 5) ? XT_SYNPROXY_OPT_ECN : 0; } EXPORT_SYMBOL_GPL(synproxy_check_timestamp_cookie); unsigned int synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, struct tcphdr *th, struct nf_conn *ct, enum ip_conntrack_info ctinfo, const struct nf_conn_synproxy *synproxy) { unsigned int optoff, optend; u32 *ptr, old; if (synproxy->tsoff == 0) return 1; optoff = protoff + sizeof(struct tcphdr); optend = protoff + th->doff * 4; if (!skb_make_writable(skb, optend)) return 0; while (optoff < optend) { unsigned char *op = skb->data + optoff; switch (op[0]) { case TCPOPT_EOL: return 1; case TCPOPT_NOP: optoff++; continue; default: if (optoff + 1 == optend || optoff + op[1] > optend || op[1] < 2) return 0; if (op[0] == TCPOPT_TIMESTAMP && op[1] == TCPOLEN_TIMESTAMP) { if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { ptr = (u32 *)&op[2]; old = *ptr; *ptr = htonl(ntohl(*ptr) - synproxy->tsoff); } else { ptr = (u32 *)&op[6]; old = *ptr; *ptr = htonl(ntohl(*ptr) + synproxy->tsoff); } inet_proto_csum_replace4(&th->check, skb, old, *ptr, 0); return 1; } optoff += op[1]; } } return 1; } EXPORT_SYMBOL_GPL(synproxy_tstamp_adjust); static struct nf_ct_ext_type nf_ct_synproxy_extend __read_mostly = { .len = sizeof(struct nf_conn_synproxy), .align = __alignof__(struct nf_conn_synproxy), .id = NF_CT_EXT_SYNPROXY, }; #ifdef CONFIG_PROC_FS static void *synproxy_cpu_seq_start(struct seq_file *seq, loff_t *pos) { struct synproxy_net *snet = synproxy_pernet(seq_file_net(seq)); int cpu; if (*pos == 0) return SEQ_START_TOKEN; for (cpu = *pos - 1; cpu < nr_cpu_ids; cpu++) { if (!cpu_possible(cpu)) continue; *pos = cpu + 1; return per_cpu_ptr(snet->stats, cpu); } return NULL; } static void *synproxy_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct synproxy_net *snet = synproxy_pernet(seq_file_net(seq)); int cpu; for (cpu = *pos; cpu < nr_cpu_ids; cpu++) { if (!cpu_possible(cpu)) continue; *pos = cpu + 1; return per_cpu_ptr(snet->stats, cpu); } return NULL; } static void synproxy_cpu_seq_stop(struct seq_file *seq, void *v) { return; } static int synproxy_cpu_seq_show(struct seq_file *seq, void *v) { struct synproxy_stats *stats = v; if (v == SEQ_START_TOKEN) { seq_printf(seq, "entries\t\tsyn_received\t" "cookie_invalid\tcookie_valid\t" "cookie_retrans\tconn_reopened\n"); return 0; } seq_printf(seq, "%08x\t%08x\t%08x\t%08x\t%08x\t%08x\n", 0, stats->syn_received, stats->cookie_invalid, stats->cookie_valid, stats->cookie_retrans, stats->conn_reopened); return 0; } static const struct seq_operations synproxy_cpu_seq_ops = { .start = synproxy_cpu_seq_start, .next = synproxy_cpu_seq_next, .stop = synproxy_cpu_seq_stop, .show = synproxy_cpu_seq_show, }; static int synproxy_cpu_seq_open(struct inode *inode, struct file *file) { return seq_open_net(inode, file, &synproxy_cpu_seq_ops, sizeof(struct seq_net_private)); } static const struct file_operations synproxy_cpu_seq_fops = { .owner = THIS_MODULE, .open = synproxy_cpu_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_net, }; static int __net_init synproxy_proc_init(struct net *net) { if (!proc_create("synproxy", S_IRUGO, net->proc_net_stat, &synproxy_cpu_seq_fops)) return -ENOMEM; return 0; } static void __net_exit synproxy_proc_exit(struct net *net) { remove_proc_entry("synproxy", net->proc_net_stat); } #else static int __net_init synproxy_proc_init(struct net *net) { return 0; } static void __net_exit synproxy_proc_exit(struct net *net) { return; } #endif /* CONFIG_PROC_FS */ static int __net_init synproxy_net_init(struct net *net) { struct synproxy_net *snet = synproxy_pernet(net); struct nf_conntrack_tuple t; struct nf_conn *ct; int err = -ENOMEM; memset(&t, 0, sizeof(t)); ct = nf_conntrack_alloc(net, 0, &t, &t, GFP_KERNEL); if (IS_ERR(ct)) { err = PTR_ERR(ct); goto err1; } if (!nfct_seqadj_ext_add(ct)) goto err2; if (!nfct_synproxy_ext_add(ct)) goto err2; nf_conntrack_tmpl_insert(net, ct); snet->tmpl = ct; snet->stats = alloc_percpu(struct synproxy_stats); if (snet->stats == NULL) goto err2; err = synproxy_proc_init(net); if (err < 0) goto err3; return 0; err3: free_percpu(snet->stats); err2: nf_conntrack_free(ct); err1: return err; } static void __net_exit synproxy_net_exit(struct net *net) { struct synproxy_net *snet = synproxy_pernet(net); nf_ct_put(snet->tmpl); synproxy_proc_exit(net); free_percpu(snet->stats); } static struct pernet_operations synproxy_net_ops = { .init = synproxy_net_init, .exit = synproxy_net_exit, .id = &synproxy_net_id, .size = sizeof(struct synproxy_net), }; static int __init synproxy_core_init(void) { int err; err = nf_ct_extend_register(&nf_ct_synproxy_extend); if (err < 0) goto err1; err = register_pernet_subsys(&synproxy_net_ops); if (err < 0) goto err2; return 0; err2: nf_ct_extend_unregister(&nf_ct_synproxy_extend); err1: return err; } static void __exit synproxy_core_exit(void) { unregister_pernet_subsys(&synproxy_net_ops); nf_ct_extend_unregister(&nf_ct_synproxy_extend); } module_init(synproxy_core_init); module_exit(synproxy_core_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");