From 520372a5f8d229afd7daaf2f5fa27707d6461f4f Mon Sep 17 00:00:00 2001
From: Stephen Hemminger <shemminger@osdl.org>
Date: Wed, 23 Apr 2003 10:32:52 -0700
Subject: [PATCH] [BRIDGE]: Bridge confuses kernel user HZ.

---
 net/bridge/br_ioctl.c | 45 ++++++++++++++++++++++++++++---------------
 1 file changed, 30 insertions(+), 15 deletions(-)

diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 7eda6d33c284..7e4e833ffc99 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -19,6 +19,21 @@
 #include <asm/uaccess.h>
 #include "br_private.h"
 
+
+/* Report time remaining in user HZ for compatibility. */
+static inline unsigned long timer_residue(const struct br_timer *timer)
+{
+	return timer->running 
+		? ((jiffies - timer->expires) * USER_HZ)/HZ 
+		: 0;
+}
+
+/* Convert API times in USER_HZ to kernel */
+static inline unsigned long user_to_ticks(unsigned long utick)
+{
+	return (utick * HZ) / USER_HZ;
+}
+
 static int br_ioctl_device(struct net_bridge *br,
 			   unsigned int cmd,
 			   unsigned long arg0,
@@ -70,10 +85,10 @@ static int br_ioctl_device(struct net_bridge *br,
 		b.stp_enabled = br->stp_enabled;
 		b.ageing_time = br->ageing_time;
 		b.gc_interval = br->gc_interval;
-		b.hello_timer_value = br_timer_get_residue(&br->hello_timer);
-		b.tcn_timer_value = br_timer_get_residue(&br->tcn_timer);
-		b.topology_change_timer_value = br_timer_get_residue(&br->topology_change_timer);
-		b.gc_timer_value = br_timer_get_residue(&br->gc_timer);
+		b.hello_timer_value = timer_residue(&br->hello_timer);
+		b.tcn_timer_value = timer_residue(&br->tcn_timer);
+		b.topology_change_timer_value = timer_residue(&br->topology_change_timer);
+		b.gc_timer_value = timer_residue(&br->gc_timer);
 	        read_unlock(&br->lock);
 
 		if (copy_to_user((void *)arg0, &b, sizeof(b)))
@@ -102,34 +117,34 @@ static int br_ioctl_device(struct net_bridge *br,
 
 	case BRCTL_SET_BRIDGE_FORWARD_DELAY:
 		write_lock(&br->lock);
-		br->bridge_forward_delay = arg0;
+		br->bridge_forward_delay = user_to_ticks(arg0);
 		if (br_is_root_bridge(br))
-			br->forward_delay = arg0;
+			br->forward_delay = br->bridge_forward_delay;
 		write_unlock(&br->lock);
 		return 0;
 
 	case BRCTL_SET_BRIDGE_HELLO_TIME:
 		write_lock(&br->lock);
-		br->bridge_hello_time = arg0;
+		br->bridge_hello_time = user_to_ticks(arg0);
 		if (br_is_root_bridge(br))
-			br->hello_time = arg0;
+			br->hello_time = br->bridge_hello_time;
 		write_unlock(&br->lock);
 		return 0;
 
 	case BRCTL_SET_BRIDGE_MAX_AGE:
 		write_lock(&br->lock);
-		br->bridge_max_age = arg0;
+		br->bridge_max_age = user_to_ticks(arg0);
 		if (br_is_root_bridge(br))
-			br->max_age = arg0;
+			br->max_age = br->bridge_max_age;
 		write_unlock(&br->lock);
 		return 0;
 
 	case BRCTL_SET_AGEING_TIME:
-		br->ageing_time = arg0;
+		br->ageing_time = user_to_ticks(arg0);
 		return 0;
 
 	case BRCTL_SET_GC_INTERVAL:
-		br->gc_interval = arg0;
+		br->gc_interval = user_to_ticks(arg0);
 		return 0;
 
 	case BRCTL_GET_PORT_INFO:
@@ -153,9 +168,9 @@ static int br_ioctl_device(struct net_bridge *br,
 		p.state = pt->state;
 		p.top_change_ack = pt->topology_change_ack;
 		p.config_pending = pt->config_pending;
-		p.message_age_timer_value = br_timer_get_residue(&pt->message_age_timer);
-		p.forward_delay_timer_value = br_timer_get_residue(&pt->forward_delay_timer);
-		p.hold_timer_value = br_timer_get_residue(&pt->hold_timer);
+		p.message_age_timer_value = timer_residue(&pt->message_age_timer);
+		p.forward_delay_timer_value = timer_residue(&pt->forward_delay_timer);
+		p.hold_timer_value = timer_residue(&pt->hold_timer);
 
 		read_unlock(&br->lock);
 
-- 
2.30.9