Commit 39ac466e authored by David S. Miller's avatar David S. Miller

Merge nuts.davemloft.net:/disk1/BK/network-2.6

into nuts.davemloft.net:/disk1/BK/net-2.6
parents d6d29b7d ebc68c9c
...@@ -797,6 +797,8 @@ extern int proc_dointvec_jiffies(ctl_table *, int, struct file *, ...@@ -797,6 +797,8 @@ extern int proc_dointvec_jiffies(ctl_table *, int, struct file *,
void __user *, size_t *, loff_t *); void __user *, size_t *, loff_t *);
extern int proc_dointvec_userhz_jiffies(ctl_table *, int, struct file *, extern int proc_dointvec_userhz_jiffies(ctl_table *, int, struct file *,
void __user *, size_t *, loff_t *); 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 *, extern int proc_doulongvec_minmax(ctl_table *, int, struct file *,
void __user *, size_t *, loff_t *); void __user *, size_t *, loff_t *);
extern int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int, extern int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int,
...@@ -814,6 +816,7 @@ extern int do_sysctl_strategy (ctl_table *table, ...@@ -814,6 +816,7 @@ extern int do_sysctl_strategy (ctl_table *table,
extern ctl_handler sysctl_string; extern ctl_handler sysctl_string;
extern ctl_handler sysctl_intvec; extern ctl_handler sysctl_intvec;
extern ctl_handler sysctl_jiffies; extern ctl_handler sysctl_jiffies;
extern ctl_handler sysctl_ms_jiffies;
/* /*
......
...@@ -149,6 +149,8 @@ extern atomic_t inet6_sock_nr; ...@@ -149,6 +149,8 @@ extern atomic_t inet6_sock_nr;
int snmp6_register_dev(struct inet6_dev *idev); int snmp6_register_dev(struct inet6_dev *idev);
int snmp6_unregister_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); int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign);
void snmp6_mib_free(void *ptr[2]); void snmp6_mib_free(void *ptr[2]);
......
...@@ -1902,6 +1902,27 @@ static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp, ...@@ -1902,6 +1902,27 @@ static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp,
return 0; 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 * proc_dointvec_jiffies - read a vector of integers as seconds
* @table: the sysctl table * @table: the sysctl table
...@@ -1946,6 +1967,28 @@ int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp, ...@@ -1946,6 +1967,28 @@ int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp,
do_proc_dointvec_userhz_jiffies_conv,NULL); 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 */ #else /* CONFIG_PROC_FS */
int proc_dostring(ctl_table *table, int write, struct file *filp, 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, ...@@ -1990,6 +2033,12 @@ int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp,
return -ENOSYS; 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, int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos) void __user *buffer, size_t *lenp, loff_t *ppos)
{ {
...@@ -2119,6 +2168,33 @@ int sysctl_jiffies(ctl_table *table, int __user *name, int nlen, ...@@ -2119,6 +2168,33 @@ int sysctl_jiffies(ctl_table *table, int __user *name, int nlen,
return 1; 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 */ #else /* CONFIG_SYSCTL */
...@@ -2149,6 +2225,13 @@ int sysctl_jiffies(ctl_table *table, int __user *name, int nlen, ...@@ -2149,6 +2225,13 @@ int sysctl_jiffies(ctl_table *table, int __user *name, int nlen,
return -ENOSYS; 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, int proc_dostring(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos) 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, ...@@ -2185,6 +2268,12 @@ int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp,
return -ENOSYS; 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, int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos) void __user *buffer, size_t *lenp, loff_t *ppos)
{ {
...@@ -2219,11 +2308,13 @@ EXPORT_SYMBOL(proc_dointvec); ...@@ -2219,11 +2308,13 @@ EXPORT_SYMBOL(proc_dointvec);
EXPORT_SYMBOL(proc_dointvec_jiffies); EXPORT_SYMBOL(proc_dointvec_jiffies);
EXPORT_SYMBOL(proc_dointvec_minmax); EXPORT_SYMBOL(proc_dointvec_minmax);
EXPORT_SYMBOL(proc_dointvec_userhz_jiffies); EXPORT_SYMBOL(proc_dointvec_userhz_jiffies);
EXPORT_SYMBOL(proc_dointvec_ms_jiffies);
EXPORT_SYMBOL(proc_dostring); EXPORT_SYMBOL(proc_dostring);
EXPORT_SYMBOL(proc_doulongvec_minmax); EXPORT_SYMBOL(proc_doulongvec_minmax);
EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
EXPORT_SYMBOL(register_sysctl_table); EXPORT_SYMBOL(register_sysctl_table);
EXPORT_SYMBOL(sysctl_intvec); EXPORT_SYMBOL(sysctl_intvec);
EXPORT_SYMBOL(sysctl_jiffies); EXPORT_SYMBOL(sysctl_jiffies);
EXPORT_SYMBOL(sysctl_ms_jiffies);
EXPORT_SYMBOL(sysctl_string); EXPORT_SYMBOL(sysctl_string);
EXPORT_SYMBOL(unregister_sysctl_table); EXPORT_SYMBOL(unregister_sysctl_table);
...@@ -104,6 +104,8 @@ ...@@ -104,6 +104,8 @@
* Corrections from Nikolai Malykh (nmalykh@bilim.com) * Corrections from Nikolai Malykh (nmalykh@bilim.com)
* Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230 * 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/sys.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -135,6 +137,7 @@ ...@@ -135,6 +137,7 @@
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <linux/udp.h> #include <linux/udp.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/wait.h>
#include <net/checksum.h> #include <net/checksum.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/addrconf.h> #include <net/addrconf.h>
...@@ -148,7 +151,7 @@ ...@@ -148,7 +151,7 @@
#include <asm/timex.h> #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) a */
#define PG_DEBUG(a) #define PG_DEBUG(a)
...@@ -808,6 +811,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, ...@@ -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); struct pktgen_dev *pkt_dev = (struct pktgen_dev*)(data);
char* pg_result = NULL; char* pg_result = NULL;
int tmp = 0; int tmp = 0;
char buf[128];
pg_result = &(pkt_dev->result[0]); pg_result = &(pkt_dev->result[0]);
...@@ -1068,7 +1072,6 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, ...@@ -1068,7 +1072,6 @@ static int proc_if_write(struct file *file, const char __user *user_buffer,
return count; return count;
} }
if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) { 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); len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_min) - 1);
if (len < 0) { return len; } if (len < 0) { return len; }
...@@ -1088,7 +1091,6 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, ...@@ -1088,7 +1091,6 @@ static int proc_if_write(struct file *file, const char __user *user_buffer,
return count; return count;
} }
if (!strcmp(name, "dst_max")) { if (!strcmp(name, "dst_max")) {
char buf[IP_NAME_SZ];
len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1); len = strn_len(&user_buffer[i], sizeof(pkt_dev->dst_max) - 1);
if (len < 0) { return len; } if (len < 0) { return len; }
...@@ -1109,9 +1111,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, ...@@ -1109,9 +1111,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer,
return count; return count;
} }
if (!strcmp(name, "dst6")) { if (!strcmp(name, "dst6")) {
char buf[128]; len = strn_len(&user_buffer[i], sizeof(buf) - 1);
len = strn_len(&user_buffer[i], 128 - 1);
if (len < 0) return len; if (len < 0) return len;
pkt_dev->flags |= F_IPV6; pkt_dev->flags |= F_IPV6;
...@@ -1133,9 +1133,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, ...@@ -1133,9 +1133,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer,
return count; return count;
} }
if (!strcmp(name, "dst6_min")) { if (!strcmp(name, "dst6_min")) {
char buf[128]; len = strn_len(&user_buffer[i], sizeof(buf) - 1);
len = strn_len(&user_buffer[i], 128 - 1);
if (len < 0) return len; if (len < 0) return len;
pkt_dev->flags |= F_IPV6; pkt_dev->flags |= F_IPV6;
...@@ -1156,9 +1154,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, ...@@ -1156,9 +1154,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer,
return count; return count;
} }
if (!strcmp(name, "dst6_max")) { if (!strcmp(name, "dst6_max")) {
char buf[128]; len = strn_len(&user_buffer[i], sizeof(buf) - 1);
len = strn_len(&user_buffer[i], 128 - 1);
if (len < 0) return len; if (len < 0) return len;
pkt_dev->flags |= F_IPV6; pkt_dev->flags |= F_IPV6;
...@@ -1178,9 +1174,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, ...@@ -1178,9 +1174,7 @@ static int proc_if_write(struct file *file, const char __user *user_buffer,
return count; return count;
} }
if (!strcmp(name, "src6")) { if (!strcmp(name, "src6")) {
char buf[128]; len = strn_len(&user_buffer[i], sizeof(buf) - 1);
len = strn_len(&user_buffer[i], 128 - 1);
if (len < 0) return len; if (len < 0) return len;
pkt_dev->flags |= F_IPV6; pkt_dev->flags |= F_IPV6;
...@@ -1202,7 +1196,6 @@ static int proc_if_write(struct file *file, const char __user *user_buffer, ...@@ -1202,7 +1196,6 @@ static int proc_if_write(struct file *file, const char __user *user_buffer,
return count; return count;
} }
if (!strcmp(name, "src_min")) { if (!strcmp(name, "src_min")) {
char buf[IP_NAME_SZ];
len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1); len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_min) - 1);
if (len < 0) { return len; } if (len < 0) { return len; }
if (copy_from_user(buf, &user_buffer[i], 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, ...@@ -1221,7 +1214,6 @@ static int proc_if_write(struct file *file, const char __user *user_buffer,
return count; return count;
} }
if (!strcmp(name, "src_max")) { if (!strcmp(name, "src_max")) {
char buf[IP_NAME_SZ];
len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1); len = strn_len(&user_buffer[i], sizeof(pkt_dev->src_max) - 1);
if (len < 0) { return len; } if (len < 0) { return len; }
if (copy_from_user(buf, &user_buffer[i], len)) if (copy_from_user(buf, &user_buffer[i], len))
...@@ -2402,16 +2394,14 @@ static int thread_is_running(struct pktgen_thread *t ) ...@@ -2402,16 +2394,14 @@ static int thread_is_running(struct pktgen_thread *t )
static int pktgen_wait_thread_run(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); if_lock(t);
while(thread_is_running(t)) { while(thread_is_running(t)) {
if_unlock(t); if_unlock(t);
interruptible_sleep_on_timeout(&queue, HZ/10); msleep_interruptible(100);
if (signal_pending(current)) if (signal_pending(current))
goto signal; goto signal;
if_lock(t); if_lock(t);
...@@ -2738,6 +2728,7 @@ __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) ...@@ -2738,6 +2728,7 @@ __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
static void pktgen_thread_worker(struct pktgen_thread *t) static void pktgen_thread_worker(struct pktgen_thread *t)
{ {
DEFINE_WAIT(wait);
struct pktgen_dev *pkt_dev = NULL; struct pktgen_dev *pkt_dev = NULL;
int cpu = t->cpu; int cpu = t->cpu;
sigset_t tmpsig; sigset_t tmpsig;
...@@ -2805,9 +2796,11 @@ static void pktgen_thread_worker(struct pktgen_thread *t) ...@@ -2805,9 +2796,11 @@ static void pktgen_thread_worker(struct pktgen_thread *t)
do_softirq(); do_softirq();
tx_since_softirq = 0; 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. * Back from sleep, either due to the timeout or signal.
...@@ -3117,8 +3110,7 @@ static void __exit pg_cleanup(void) ...@@ -3117,8 +3110,7 @@ static void __exit pg_cleanup(void)
struct pktgen_thread *t = pktgen_threads; struct pktgen_thread *t = pktgen_threads;
pktgen_threads->control |= (T_TERMINATE); pktgen_threads->control |= (T_TERMINATE);
while( t == pktgen_threads) wait_event_interruptible_timeout(queue, (t != pktgen_threads), HZ);
interruptible_sleep_on_timeout(&queue, HZ);
} }
/* Un-register us from receiving netdevice events */ /* Un-register us from receiving netdevice events */
......
...@@ -384,10 +384,12 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum, ...@@ -384,10 +384,12 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum,
const struct net_device *out, const struct net_device *out,
int (*okfn)(struct sk_buff *)) int (*okfn)(struct sk_buff *))
{ {
#if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE)
/* Previously seen (loopback)? Ignore. Do this before /* Previously seen (loopback)? Ignore. Do this before
fragment check. */ fragment check. */
if ((*pskb)->nfct) if ((*pskb)->nfct)
return NF_ACCEPT; return NF_ACCEPT;
#endif
/* Gather fragments. */ /* Gather fragments. */
if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
......
...@@ -98,6 +98,7 @@ struct ipt_hashlimit_htable { ...@@ -98,6 +98,7 @@ struct ipt_hashlimit_htable {
}; };
static DECLARE_RWLOCK(hashlimit_lock); /* protects htables list */ static DECLARE_RWLOCK(hashlimit_lock); /* protects htables list */
static DECLARE_MUTEX(hlimit_mutex); /* additional checkentry protection */
static LIST_HEAD(hashlimit_htables); static LIST_HEAD(hashlimit_htables);
static kmem_cache_t *hashlimit_cachep; static kmem_cache_t *hashlimit_cachep;
...@@ -531,10 +532,19 @@ hashlimit_checkentry(const char *tablename, ...@@ -531,10 +532,19 @@ hashlimit_checkentry(const char *tablename,
if (!r->cfg.expire) if (!r->cfg.expire)
return 0; 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); r->hinfo = htable_find_get(r->name);
if (!r->hinfo && (htable_create(r) != 0)) { if (!r->hinfo && (htable_create(r) != 0)) {
up(&hlimit_mutex);
return 0; return 0;
} }
up(&hlimit_mutex);
/* Ugly hack: For SMP, we only want to use one set */ /* Ugly hack: For SMP, we only want to use one set */
r->u.master = r; r->u.master = r;
......
...@@ -2545,10 +2545,10 @@ ctl_table ipv4_route_table[] = { ...@@ -2545,10 +2545,10 @@ ctl_table ipv4_route_table[] = {
.ctl_name = NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS, .ctl_name = NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS,
.procname = "gc_min_interval_ms", .procname = "gc_min_interval_ms",
.data = &ip_rt_gc_min_interval, .data = &ip_rt_gc_min_interval,
.maxlen = sizeof(unsigned long), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_doulongvec_ms_jiffies_minmax, .proc_handler = &proc_dointvec_ms_jiffies,
.strategy = &sysctl_jiffies, .strategy = &sysctl_ms_jiffies,
}, },
{ {
.ctl_name = NET_IPV4_ROUTE_GC_TIMEOUT, .ctl_name = NET_IPV4_ROUTE_GC_TIMEOUT,
......
...@@ -308,7 +308,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) ...@@ -308,7 +308,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
printk("Freeing alive inet6 device %p\n", idev); printk("Freeing alive inet6 device %p\n", idev);
return; return;
} }
snmp6_unregister_dev(idev); snmp6_free_dev(idev);
kfree(idev); kfree(idev);
} }
...@@ -339,6 +339,16 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) ...@@ -339,6 +339,16 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
/* We refer to the device */ /* We refer to the device */
dev_hold(dev); 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) { if (snmp6_register_dev(ndev) < 0) {
ADBG((KERN_WARNING ADBG((KERN_WARNING
"%s(): cannot create /proc/net/dev_snmp6/%s\n", "%s(): cannot create /proc/net/dev_snmp6/%s\n",
...@@ -2013,6 +2023,10 @@ static int addrconf_ifdown(struct net_device *dev, int how) ...@@ -2013,6 +2023,10 @@ static int addrconf_ifdown(struct net_device *dev, int how)
dev->ip6_ptr = NULL; dev->ip6_ptr = NULL;
idev->dead = 1; idev->dead = 1;
write_unlock_bh(&addrconf_lock); write_unlock_bh(&addrconf_lock);
/* Step 1.5: remove snmp6 entry */
snmp6_unregister_dev(idev);
} }
/* Step 2: clear hash table */ /* Step 2: clear hash table */
......
...@@ -652,8 +652,10 @@ snmp6_mib_free(void *ptr[2]) ...@@ -652,8 +652,10 @@ snmp6_mib_free(void *ptr[2])
{ {
if (ptr == NULL) if (ptr == NULL)
return; return;
free_percpu(ptr[0]); if (ptr[0])
free_percpu(ptr[1]); free_percpu(ptr[0]);
if (ptr[1])
free_percpu(ptr[1]);
ptr[0] = ptr[1] = NULL; ptr[0] = ptr[1] = NULL;
} }
......
...@@ -201,33 +201,23 @@ static struct file_operations snmp6_seq_fops = { ...@@ -201,33 +201,23 @@ static struct file_operations snmp6_seq_fops = {
int snmp6_register_dev(struct inet6_dev *idev) int snmp6_register_dev(struct inet6_dev *idev)
{ {
int err = -ENOMEM;
struct proc_dir_entry *p; struct proc_dir_entry *p;
if (!idev || !idev->dev) if (!idev || !idev->dev)
return -EINVAL; return -EINVAL;
if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib), if (!proc_net_devsnmp6)
__alignof__(struct icmpv6_mib)) < 0) return -ENOENT;
goto err_icmp;
if (!proc_net_devsnmp6) {
err = -ENOENT;
goto err_proc;
}
p = create_proc_entry(idev->dev->name, S_IRUGO, proc_net_devsnmp6); p = create_proc_entry(idev->dev->name, S_IRUGO, proc_net_devsnmp6);
if (!p) if (!p)
goto err_proc; return -ENOMEM;
p->data = idev; p->data = idev;
p->proc_fops = &snmp6_seq_fops; p->proc_fops = &snmp6_seq_fops;
idev->stats.proc_dir_entry = p; idev->stats.proc_dir_entry = p;
return 0; return 0;
err_proc:
snmp6_mib_free((void **)idev->stats.icmpv6);
err_icmp:
return err;
} }
int snmp6_unregister_dev(struct inet6_dev *idev) int snmp6_unregister_dev(struct inet6_dev *idev)
...@@ -238,8 +228,6 @@ int snmp6_unregister_dev(struct inet6_dev *idev) ...@@ -238,8 +228,6 @@ int snmp6_unregister_dev(struct inet6_dev *idev)
return -EINVAL; return -EINVAL;
remove_proc_entry(idev->stats.proc_dir_entry->name, remove_proc_entry(idev->stats.proc_dir_entry->name,
proc_net_devsnmp6); proc_net_devsnmp6);
snmp6_mib_free((void **)idev->stats.icmpv6);
return 0; return 0;
} }
...@@ -279,6 +267,17 @@ void ipv6_misc_proc_exit(void) ...@@ -279,6 +267,17 @@ void ipv6_misc_proc_exit(void)
int snmp6_register_dev(struct inet6_dev *idev) 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; int err = -ENOMEM;
...@@ -295,11 +294,10 @@ int snmp6_register_dev(struct inet6_dev *idev) ...@@ -295,11 +294,10 @@ int snmp6_register_dev(struct inet6_dev *idev)
return err; 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); snmp6_mib_free((void **)idev->stats.icmpv6);
return 0; return 0;
} }
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment