summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@nuts.davemloft.net>2005-02-25 00:37:17 -0800
committerDavid S. Miller <davem@nuts.davemloft.net>2005-02-25 00:37:17 -0800
commit39ac466efc51f0cdca436f48cfe30847bcd83fe1 (patch)
treefb2a7d41eaa26351ee24cfaf747ad37961dae6da
parentd6d29b7df443ac7057992ecb3aca88cba17431bb (diff)
parentebc68c9c20e7ba9c8e12f2c6c3f683ea0c1a54d8 (diff)
Merge nuts.davemloft.net:/disk1/BK/network-2.6
into nuts.davemloft.net:/disk1/BK/net-2.6
-rw-r--r--include/linux/sysctl.h3
-rw-r--r--include/net/ipv6.h2
-rw-r--r--kernel/sysctl.c91
-rw-r--r--net/core/pktgen.c46
-rw-r--r--net/ipv4/netfilter/ip_conntrack_standalone.c2
-rw-r--r--net/ipv4/netfilter/ipt_hashlimit.c10
-rw-r--r--net/ipv4/route.c6
-rw-r--r--net/ipv6/addrconf.c16
-rw-r--r--net/ipv6/af_inet6.c6
-rw-r--r--net/ipv6/proc.c34
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