diff options
| -rw-r--r-- | include/linux/sysctl.h | 3 | ||||
| -rw-r--r-- | include/net/ipv6.h | 2 | ||||
| -rw-r--r-- | kernel/sysctl.c | 91 | ||||
| -rw-r--r-- | net/core/pktgen.c | 46 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_standalone.c | 2 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ipt_hashlimit.c | 10 | ||||
| -rw-r--r-- | net/ipv4/route.c | 6 | ||||
| -rw-r--r-- | net/ipv6/addrconf.c | 16 | ||||
| -rw-r--r-- | net/ipv6/af_inet6.c | 6 | ||||
| -rw-r--r-- | net/ipv6/proc.c | 34 |
10 files changed, 165 insertions, 51 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 33642be4ce00..6b084680aaa1 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -797,6 +797,8 @@ extern int proc_dointvec_jiffies(ctl_table *, int, struct file *, void __user *, size_t *, loff_t *); extern int proc_dointvec_userhz_jiffies(ctl_table *, int, struct file *, void __user *, size_t *, loff_t *); +extern int proc_dointvec_ms_jiffies(ctl_table *, int, struct file *, + void __user *, size_t *, loff_t *); extern int proc_doulongvec_minmax(ctl_table *, int, struct file *, void __user *, size_t *, loff_t *); extern int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int, @@ -814,6 +816,7 @@ extern int do_sysctl_strategy (ctl_table *table, extern ctl_handler sysctl_string; extern ctl_handler sysctl_intvec; extern ctl_handler sysctl_jiffies; +extern ctl_handler sysctl_ms_jiffies; /* diff --git a/include/net/ipv6.h b/include/net/ipv6.h index dc1feea01acb..147d47ab7ca6 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -149,6 +149,8 @@ extern atomic_t inet6_sock_nr; int snmp6_register_dev(struct inet6_dev *idev); int snmp6_unregister_dev(struct inet6_dev *idev); +int snmp6_alloc_dev(struct inet6_dev *idev); +int snmp6_free_dev(struct inet6_dev *idev); int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign); void snmp6_mib_free(void *ptr[2]); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ec430d0e5b01..a72dd5677c8f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1902,6 +1902,27 @@ static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp, return 0; } +static int do_proc_dointvec_ms_jiffies_conv(int *negp, unsigned long *lvalp, + int *valp, + int write, void *data) +{ + if (write) { + *valp = msecs_to_jiffies(*negp ? -*lvalp : *lvalp); + } else { + int val = *valp; + unsigned long lval; + if (val < 0) { + *negp = -1; + lval = (unsigned long)-val; + } else { + *negp = 0; + lval = (unsigned long)val; + } + *lvalp = jiffies_to_msecs(lval); + } + return 0; +} + /** * proc_dointvec_jiffies - read a vector of integers as seconds * @table: the sysctl table @@ -1946,6 +1967,28 @@ int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, do_proc_dointvec_userhz_jiffies_conv,NULL); } +/** + * proc_dointvec_ms_jiffies - read a vector of integers as 1 milliseconds + * @table: the sysctl table + * @write: %TRUE if this is a write to the sysctl file + * @filp: the file structure + * @buffer: the user buffer + * @lenp: the size of the user buffer + * + * Reads/writes up to table->maxlen/sizeof(unsigned int) integer + * values from/to the user buffer, treated as an ASCII string. + * The values read are assumed to be in 1/1000 seconds, and + * are converted into jiffies. + * + * Returns 0 on success. + */ +int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + return do_proc_dointvec(table, write, filp, buffer, lenp, ppos, + do_proc_dointvec_ms_jiffies_conv, NULL); +} + #else /* CONFIG_PROC_FS */ int proc_dostring(ctl_table *table, int write, struct file *filp, @@ -1990,6 +2033,12 @@ int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, return -ENOSYS; } +int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + return -ENOSYS; +} + int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -2119,6 +2168,33 @@ int sysctl_jiffies(ctl_table *table, int __user *name, int nlen, return 1; } +/* Strategy function to convert jiffies to seconds */ +int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, void **context) +{ + if (oldval) { + size_t olen; + if (oldlenp) { + if (get_user(olen, oldlenp)) + return -EFAULT; + if (olen!=sizeof(int)) + return -EINVAL; + } + if (put_user(jiffies_to_msecs(*(int *)(table->data)), (int __user *)oldval) || + (oldlenp && put_user(sizeof(int),oldlenp))) + return -EFAULT; + } + if (newval && newlen) { + int new; + if (newlen != sizeof(int)) + return -EINVAL; + if (get_user(new, (int __user *)newval)) + return -EFAULT; + *(int *)(table->data) = msecs_to_jiffies(new); + } + return 1; +} #else /* CONFIG_SYSCTL */ @@ -2149,6 +2225,13 @@ int sysctl_jiffies(ctl_table *table, int __user *name, int nlen, return -ENOSYS; } +int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen, void **context) +{ + return -ENOSYS; +} + int proc_dostring(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -2185,6 +2268,12 @@ int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, return -ENOSYS; } +int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + return -ENOSYS; +} + int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -2219,11 +2308,13 @@ EXPORT_SYMBOL(proc_dointvec); EXPORT_SYMBOL(proc_dointvec_jiffies); EXPORT_SYMBOL(proc_dointvec_minmax); EXPORT_SYMBOL(proc_dointvec_userhz_jiffies); +EXPORT_SYMBOL(proc_dointvec_ms_jiffies); EXPORT_SYMBOL(proc_dostring); EXPORT_SYMBOL(proc_doulongvec_minmax); EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); EXPORT_SYMBOL(register_sysctl_table); EXPORT_SYMBOL(sysctl_intvec); EXPORT_SYMBOL(sysctl_jiffies); +EXPORT_SYMBOL(sysctl_ms_jiffies); EXPORT_SYMBOL(sysctl_string); EXPORT_SYMBOL(unregister_sysctl_table); diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 689db7d8df9b..a1bb213675cd 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -104,6 +104,8 @@ * Corrections from Nikolai Malykh (nmalykh@bilim.com) * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230 * + * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> + * 050103 */ #include <linux/sys.h> #include <linux/types.h> @@ -135,6 +137,7 @@ #include <linux/ipv6.h> #include <linux/udp.h> #include <linux/proc_fs.h> +#include <linux/wait.h> #include <net/checksum.h> #include <net/ipv6.h> #include <net/addrconf.h> @@ -148,7 +151,7 @@ #include <asm/timex.h> -#define VERSION "pktgen v2.56: Packet Generator for packet performance testing.\n" +#define VERSION "pktgen v2.58: Packet Generator for packet performance testing.\n" /* #define PG_DEBUG(a) a */ #define PG_DEBUG(a) @@ -808,6 +811,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, struct pktgen_dev *pkt_dev = (struct pktgen_dev*)(data); char* pg_result = NULL; int tmp = 0; + char buf[128]; pg_result = &(pkt_dev->result[0]); @@ -1068,7 +1072,6 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, return count; } if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { - char buf[IP_NAME_SZ]; len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1); if (len < 0) { return len; } @@ -1088,7 +1091,6 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, return count; } if (!strcmp(name, "dst_max")) { - char buf[IP_NAME_SZ]; len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); if (len < 0) { return len; } @@ -1109,9 +1111,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, return count; } if (!strcmp(name, "dst6")) { - char buf[128]; - - len = strn_len(&user_buffer[i], 128 - 1); + len = strn_len(&user_buffer[i], sizeof(buf) - 1); if (len < 0) return len; pkt_dev->flags |= F_IPV6; @@ -1133,9 +1133,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, return count; } if (!strcmp(name, "dst6_min")) { - char buf[128]; - - len = strn_len(&user_buffer[i], 128 - 1); + len = strn_len(&user_buffer[i], sizeof(buf) - 1); if (len < 0) return len; pkt_dev->flags |= F_IPV6; @@ -1156,9 +1154,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, return count; } if (!strcmp(name, "dst6_max")) { - char buf[128]; - - len = strn_len(&user_buffer[i], 128 - 1); + len = strn_len(&user_buffer[i], sizeof(buf) - 1); if (len < 0) return len; pkt_dev->flags |= F_IPV6; @@ -1178,9 +1174,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, return count; } if (!strcmp(name, "src6")) { - char buf[128]; - - len = strn_len(&user_buffer[i], 128 - 1); + len = strn_len(&user_buffer[i], sizeof(buf) - 1); if (len < 0) return len; pkt_dev->flags |= F_IPV6; @@ -1202,7 +1196,6 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, return count; } if (!strcmp(name, "src_min")) { - char buf[IP_NAME_SZ]; len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); if (len < 0) { return len; } if (copy_from_user(buf, &user_buffer[i], len)) @@ -1221,7 +1214,6 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, return count; } if (!strcmp(name, "src_max")) { - char buf[IP_NAME_SZ]; len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); if (len < 0) { return len; } if (copy_from_user(buf, &user_buffer[i], len)) @@ -2402,16 +2394,14 @@ static int thread_is_running(struct pktgen_thread *t ) static int pktgen_wait_thread_run(struct pktgen_thread *t ) { - wait_queue_head_t queue; - - init_waitqueue_head(&queue); - if_lock(t); while(thread_is_running(t)) { + if_unlock(t); - - interruptible_sleep_on_timeout(&queue, HZ/10); + + msleep_interruptible(100); + if (signal_pending(current)) goto signal; if_lock(t); @@ -2738,6 +2728,7 @@ retry_now: static void pktgen_thread_worker(struct pktgen_thread *t) { + DEFINE_WAIT(wait); struct pktgen_dev *pkt_dev = NULL; int cpu = t->cpu; sigset_t tmpsig; @@ -2805,9 +2796,11 @@ static void pktgen_thread_worker(struct pktgen_thread *t) do_softirq(); tx_since_softirq = 0; } + } else { + prepare_to_wait(&(t->queue), &wait, TASK_INTERRUPTIBLE); + schedule_timeout(HZ/10); + finish_wait(&(t->queue), &wait); } - else - interruptible_sleep_on_timeout(&(t->queue), HZ/10); /* * Back from sleep, either due to the timeout or signal. @@ -3117,8 +3110,7 @@ static void __exit pg_cleanup(void) struct pktgen_thread *t = pktgen_threads; pktgen_threads->control |= (T_TERMINATE); - while( t == pktgen_threads) - interruptible_sleep_on_timeout(&queue, HZ); + wait_event_interruptible_timeout(queue, (t != pktgen_threads), HZ); } /* Un-register us from receiving netdevice events */ diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index dd9f125ff650..16d60222b051 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -384,10 +384,12 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { +#if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE) /* Previously seen (loopback)? Ignore. Do this before fragment check. */ if ((*pskb)->nfct) return NF_ACCEPT; +#endif /* Gather fragments. */ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c index 9d80cac77089..6e4d8e0e65d5 100644 --- a/net/ipv4/netfilter/ipt_hashlimit.c +++ b/net/ipv4/netfilter/ipt_hashlimit.c @@ -98,6 +98,7 @@ struct ipt_hashlimit_htable { }; static DECLARE_RWLOCK(hashlimit_lock); /* protects htables list */ +static DECLARE_MUTEX(hlimit_mutex); /* additional checkentry protection */ static LIST_HEAD(hashlimit_htables); static kmem_cache_t *hashlimit_cachep; @@ -531,10 +532,19 @@ hashlimit_checkentry(const char *tablename, if (!r->cfg.expire) return 0; + /* This is the best we've got: We cannot release and re-grab lock, + * since checkentry() is called before ip_tables.c grabs ipt_mutex. + * We also cannot grab the hashtable spinlock, since htable_create will + * call vmalloc, and that can sleep. And we cannot just re-search + * the list of htable's in htable_create(), since then we would + * create duplicate proc files. -HW */ + down(&hlimit_mutex); r->hinfo = htable_find_get(r->name); if (!r->hinfo && (htable_create(r) != 0)) { + up(&hlimit_mutex); return 0; } + up(&hlimit_mutex); /* Ugly hack: For SMP, we only want to use one set */ r->u.master = r; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 24e7f12f1972..6a3e73b0ecf1 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2545,10 +2545,10 @@ ctl_table ipv4_route_table[] = { .ctl_name = NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS, .procname = "gc_min_interval_ms", .data = &ip_rt_gc_min_interval, - .maxlen = sizeof(unsigned long), + .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_doulongvec_ms_jiffies_minmax, - .strategy = &sysctl_jiffies, + .proc_handler = &proc_dointvec_ms_jiffies, + .strategy = &sysctl_ms_jiffies, }, { .ctl_name = NET_IPV4_ROUTE_GC_TIMEOUT, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f4eeb8629a0e..5a17c3246f62 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -308,7 +308,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) printk("Freeing alive inet6 device %p\n", idev); return; } - snmp6_unregister_dev(idev); + snmp6_free_dev(idev); kfree(idev); } @@ -339,6 +339,16 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) /* We refer to the device */ dev_hold(dev); + if (snmp6_alloc_dev(ndev) < 0) { + ADBG((KERN_WARNING + "%s(): cannot allocate memory for statistics; dev=%s.\n", + __FUNCTION__, dev->name)); + neigh_parms_release(&nd_tbl, ndev->nd_parms); + ndev->dead = 1; + in6_dev_finish_destroy(ndev); + return NULL; + } + if (snmp6_register_dev(ndev) < 0) { ADBG((KERN_WARNING "%s(): cannot create /proc/net/dev_snmp6/%s\n", @@ -2013,6 +2023,10 @@ static int addrconf_ifdown(struct net_device *dev, int how) dev->ip6_ptr = NULL; idev->dead = 1; write_unlock_bh(&addrconf_lock); + + /* Step 1.5: remove snmp6 entry */ + snmp6_unregister_dev(idev); + } /* Step 2: clear hash table */ diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index d5d1d83416fe..56e502e3fd3b 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -652,8 +652,10 @@ snmp6_mib_free(void *ptr[2]) { if (ptr == NULL) return; - free_percpu(ptr[0]); - free_percpu(ptr[1]); + if (ptr[0]) + free_percpu(ptr[0]); + if (ptr[1]) + free_percpu(ptr[1]); ptr[0] = ptr[1] = NULL; } diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 3330ba6cf538..334a5967831e 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -201,33 +201,23 @@ static struct file_operations snmp6_seq_fops = { int snmp6_register_dev(struct inet6_dev *idev) { - int err = -ENOMEM; struct proc_dir_entry *p; if (!idev || !idev->dev) return -EINVAL; - if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib), - __alignof__(struct icmpv6_mib)) < 0) - goto err_icmp; + if (!proc_net_devsnmp6) + return -ENOENT; - if (!proc_net_devsnmp6) { - err = -ENOENT; - goto err_proc; - } p = create_proc_entry(idev->dev->name, S_IRUGO, proc_net_devsnmp6); if (!p) - goto err_proc; + return -ENOMEM; + p->data = idev; p->proc_fops = &snmp6_seq_fops; idev->stats.proc_dir_entry = p; return 0; - -err_proc: - snmp6_mib_free((void **)idev->stats.icmpv6); -err_icmp: - return err; } int snmp6_unregister_dev(struct inet6_dev *idev) @@ -238,8 +228,6 @@ int snmp6_unregister_dev(struct inet6_dev *idev) return -EINVAL; remove_proc_entry(idev->stats.proc_dir_entry->name, proc_net_devsnmp6); - snmp6_mib_free((void **)idev->stats.icmpv6); - return 0; } @@ -280,6 +268,17 @@ void ipv6_misc_proc_exit(void) int snmp6_register_dev(struct inet6_dev *idev) { + return 0; +} + +int snmp6_unregister_dev(struct inet6_dev *idev) +{ + return 0; +} +#endif /* CONFIG_PROC_FS */ + +int snmp6_alloc_dev(struct inet6_dev *idev) +{ int err = -ENOMEM; if (!idev || !idev->dev) @@ -295,11 +294,10 @@ err_icmp: return err; } -int snmp6_unregister_dev(struct inet6_dev *idev) +int snmp6_free_dev(struct inet6_dev *idev) { snmp6_mib_free((void **)idev->stats.icmpv6); return 0; } -#endif |
