
From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

Recently, we added gc_min_interval_ms procfs/sysctl.

Because type of ip_rt_gc_min_interval is int, 
use of ulong helpers is inappropriate and unsafe.
I believe it breaks some archs that the size of unsigned long
is not equal to one of int.

So, let's add new sysctl helpers and use them instead.
This also fixes inconsistency between procfs and sysctl.

P.S. I will send several changesets to add other users 
(neighbour and ipv6 routing) after 2.6.12 opens.

Signed-off-by: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/include/linux/sysctl.h |    3 +
 25-akpm/kernel/sysctl.c        |   91 +++++++++++++++++++++++++++++++++++++++++
 25-akpm/net/ipv4/route.c       |    6 +-
 3 files changed, 97 insertions(+), 3 deletions(-)

diff -puN include/linux/sysctl.h~fix-ip_rt_gc_min_interval_ms-procfs-sysctl include/linux/sysctl.h
--- 25/include/linux/sysctl.h~fix-ip_rt_gc_min_interval_ms-procfs-sysctl	2005-02-22 18:14:58.000000000 -0800
+++ 25-akpm/include/linux/sysctl.h	2005-02-22 18:14:58.000000000 -0800
@@ -797,6 +797,8 @@ extern int proc_dointvec_jiffies(ctl_tab
 				 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
 extern ctl_handler sysctl_string;
 extern ctl_handler sysctl_intvec;
 extern ctl_handler sysctl_jiffies;
+extern ctl_handler sysctl_ms_jiffies;
 
 
 /*
diff -puN kernel/sysctl.c~fix-ip_rt_gc_min_interval_ms-procfs-sysctl kernel/sysctl.c
--- 25/kernel/sysctl.c~fix-ip_rt_gc_min_interval_ms-procfs-sysctl	2005-02-22 18:14:58.000000000 -0800
+++ 25-akpm/kernel/sysctl.c	2005-02-22 18:14:58.000000000 -0800
@@ -1902,6 +1902,27 @@ static int do_proc_dointvec_userhz_jiffi
 	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_tab
 		    	    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_tab
 	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
 	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
 	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_tab
 	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 -puN net/ipv4/route.c~fix-ip_rt_gc_min_interval_ms-procfs-sysctl net/ipv4/route.c
--- 25/net/ipv4/route.c~fix-ip_rt_gc_min_interval_ms-procfs-sysctl	2005-02-22 18:14:58.000000000 -0800
+++ 25-akpm/net/ipv4/route.c	2005-02-22 18:14:58.000000000 -0800
@@ -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,
_
