Skip to content

Commit

Permalink
Fix problems about 32-bit ticks wraparound and unsigned long
Browse files Browse the repository at this point in the history
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
  • Loading branch information
hselasky committed Mar 18, 2015
1 parent 58cb7b5 commit 47d10f1
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 33 deletions.
57 changes: 57 additions & 0 deletions sys/ofed/include/linux/linux_compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand All @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down
46 changes: 13 additions & 33 deletions sys/ofed/include/linux/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand All @@ -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 { \
Expand All @@ -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_ */

0 comments on commit 47d10f1

Please sign in to comment.