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
This commit is contained in:
parent
805b1f609d
commit
54fe6f6bdf
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=280210
@ -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)
|
||||
{
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user