Author: hselasky
Date: Wed Mar 18 10:49:17 2015
New Revision: 280210
URL: https://svnweb.freebsd.org/changeset/base/280210

Log:
  Fix problems about 32-bit ticks wraparound and unsigned long
  conversion:
  - The linux compat API layer casts the ticks to unsigned long which
  might cause problems when the ticks value is negative.
  - Guard against already expired ticks values, by checking if the
  passed expiry tick is already elapsed.
  - While at it avoid referring the address of an inlined function.
  
  MFC after:    3 days
  Sponsored by: Mellanox Technologies

Modified:
  head/sys/ofed/include/linux/linux_compat.c
  head/sys/ofed/include/linux/timer.h

Modified: head/sys/ofed/include/linux/linux_compat.c
==============================================================================
--- head/sys/ofed/include/linux/linux_compat.c  Wed Mar 18 09:39:31 2015        
(r280209)
+++ head/sys/ofed/include/linux/linux_compat.c  Wed Mar 18 10:49:17 2015        
(r280210)
@@ -57,6 +57,7 @@
 #include <linux/io.h>
 #include <linux/vmalloc.h>
 #include <linux/netdevice.h>
+#include <linux/timer.h>
 
 #include <vm/vm_pager.h>
 
@@ -77,6 +78,8 @@ struct list_head pci_devices;
 struct net init_net;
 spinlock_t pci_lock;
 
+unsigned long linux_timer_hz_mask;
+
 int
 panic_cmp(struct rb_node *one, struct rb_node *two)
 {
@@ -724,6 +727,60 @@ kasprintf(gfp_t gfp, const char *fmt, ..
        return p;
 }
 
+static int
+linux_timer_jiffies_until(unsigned long expires)
+{
+       int delta = expires - jiffies;
+       /* guard against already expired values */
+       if (delta < 1)
+               delta = 1;
+       return (delta);
+}
+
+static void
+linux_timer_callback_wrapper(void *context)
+{
+       struct timer_list *timer;
+
+       timer = context;
+       timer->function(timer->data);
+}
+
+void
+mod_timer(struct timer_list *timer, unsigned long expires)
+{
+
+       timer->expires = expires;
+       callout_reset(&timer->timer_callout,                  
+           linux_timer_jiffies_until(expires),
+           &linux_timer_callback_wrapper, timer);
+}
+
+void
+add_timer(struct timer_list *timer)
+{
+
+       callout_reset(&timer->timer_callout,
+           linux_timer_jiffies_until(timer->expires),
+           &linux_timer_callback_wrapper, timer);
+}
+
+static void
+linux_timer_init(void *arg)
+{
+
+       /*
+        * Compute an internal HZ value which can divide 2**32 to
+        * avoid timer rounding problems when the tick value wraps
+        * around 2**32:
+        */
+       linux_timer_hz_mask = 1;
+       while (linux_timer_hz_mask < (unsigned long)hz)
+               linux_timer_hz_mask *= 2;
+       linux_timer_hz_mask--;
+}
+SYSINIT(linux_timer, SI_SUB_DRIVERS, SI_ORDER_FIRST, linux_timer_init, NULL);
+
 static void
 linux_compat_init(void)
 {

Modified: head/sys/ofed/include/linux/timer.h
==============================================================================
--- head/sys/ofed/include/linux/timer.h Wed Mar 18 09:39:31 2015        
(r280209)
+++ head/sys/ofed/include/linux/timer.h Wed Mar 18 10:49:17 2015        
(r280210)
@@ -27,7 +27,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #ifndef _LINUX_TIMER_H_
-#define _LINUX_TIMER_H_
+#define        _LINUX_TIMER_H_
 
 #include <linux/types.h>
 
@@ -36,20 +36,13 @@
 #include <sys/callout.h>
 
 struct timer_list {
-       struct callout  timer_callout;
-       void            (*function)(unsigned long);
-       unsigned long   data;
-       unsigned long   expires;
+       struct callout timer_callout;
+       void    (*function) (unsigned long);
+       unsigned long data;
+       unsigned long expires;
 };
 
-static inline void
-_timer_fn(void *context)
-{
-       struct timer_list *timer;
-
-       timer = context;
-       timer->function(timer->data);
-}
+extern unsigned long linux_timer_hz_mask;
 
 #define        setup_timer(timer, func, dat)                                   
\
 do {                                                                   \
@@ -65,28 +58,15 @@ do {                                                        
                \
        callout_init(&(timer)->timer_callout, CALLOUT_MPSAFE);          \
 } while (0)
 
-#define        mod_timer(timer, exp)                                           
\
-do {                                                                   \
-       (timer)->expires = (exp);                                       \
-       callout_reset(&(timer)->timer_callout, (exp) - jiffies,         \
-           _timer_fn, (timer));                                        \
-} while (0)
-
-#define        add_timer(timer)                                                
\
-       callout_reset(&(timer)->timer_callout,                          \
-           (timer)->expires - jiffies, _timer_fn, (timer))
+extern void mod_timer(struct timer_list *, unsigned long);
+extern void add_timer(struct timer_list *);
 
 #define        del_timer(timer)        callout_stop(&(timer)->timer_callout)
 #define        del_timer_sync(timer)   callout_drain(&(timer)->timer_callout)
-
 #define        timer_pending(timer)    callout_pending(&(timer)->timer_callout)
+#define        round_jiffies(j) \
+       ((unsigned long)(((j) + linux_timer_hz_mask) & ~linux_timer_hz_mask))
+#define        round_jiffies_relative(j) \
+       round_jiffies(j)
 
-static inline unsigned long
-round_jiffies(unsigned long j)
-{
-       return roundup(j, hz);
-}
-
-#define round_jiffies_relative(j) round_jiffies(j)
-
-#endif /* _LINUX_TIMER_H_ */
+#endif                                 /* _LINUX_TIMER_H_ */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to