git: 325aa4dbd10d - main - linuxkpi: Introduce a properly typed jiffies

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Tue, 29 Apr 2025 13:56:05 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=325aa4dbd10d04a61a9529e1d76212b5649b3c73

commit 325aa4dbd10d04a61a9529e1d76212b5649b3c73
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-01-11 23:06:06 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-04-29 13:53:40 +0000

    linuxkpi: Introduce a properly typed jiffies
    
    Now that we have a long-sized tick counter, we can migrate to using
    properly typed timeout parameters in various bits of the LinuxKPI.  This
    fixes a subtle incompatibility that is otherwise difficult to paper over
    and leads to bugs when ticks values are sign-extended.
    
    - Introduce a "jiffies" symbol in subr_ticks.S, declared only in the
      LinuxKPI as an unsigned long.
    - Remove all references to "ticks" from the LinuxKPI.
    - Convert interfaces to match Linux's type signatures where it makes
      sense.
    
    Reviewed by:    manu
    Tested by:      bz
    Differential Revision:  https://reviews.freebsd.org/D48523
---
 .../linuxkpi/common/include/linux/completion.h     |  3 +-
 sys/compat/linuxkpi/common/include/linux/jiffies.h | 39 +++++++++++-----------
 sys/compat/linuxkpi/common/include/linux/sched.h   |  4 +--
 sys/compat/linuxkpi/common/include/linux/timer.h   |  6 ++--
 sys/compat/linuxkpi/common/include/linux/wait.h    | 12 +++----
 .../linuxkpi/common/include/linux/workqueue.h      |  4 +--
 sys/compat/linuxkpi/common/src/linux_80211.c       |  4 +--
 .../linuxkpi/common/src/linux_80211_macops.c       |  4 +--
 sys/compat/linuxkpi/common/src/linux_compat.c      | 10 +++---
 sys/compat/linuxkpi/common/src/linux_netdev.c      | 16 ++++-----
 sys/compat/linuxkpi/common/src/linux_schedule.c    | 16 ++++-----
 sys/compat/linuxkpi/common/src/linux_work.c        |  2 +-
 sys/kern/subr_ticks.S                              |  8 ++++-
 13 files changed, 68 insertions(+), 60 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/completion.h b/sys/compat/linuxkpi/common/include/linux/completion.h
index 26e41a51c10b..9f8bebb4cf82 100644
--- a/sys/compat/linuxkpi/common/include/linux/completion.h
+++ b/sys/compat/linuxkpi/common/include/linux/completion.h
@@ -60,7 +60,8 @@ struct completion {
 
 extern void linux_complete_common(struct completion *, int);
 extern int linux_wait_for_common(struct completion *, int);
-extern int linux_wait_for_timeout_common(struct completion *, int, int);
+extern unsigned long linux_wait_for_timeout_common(struct completion *,
+    unsigned long, int);
 extern int linux_try_wait_for_completion(struct completion *);
 extern int linux_completion_done(struct completion *);
 
diff --git a/sys/compat/linuxkpi/common/include/linux/jiffies.h b/sys/compat/linuxkpi/common/include/linux/jiffies.h
index f099caa1ce18..df6ca129b37c 100644
--- a/sys/compat/linuxkpi/common/include/linux/jiffies.h
+++ b/sys/compat/linuxkpi/common/include/linux/jiffies.h
@@ -32,21 +32,21 @@
 #include <linux/types.h>
 #include <linux/time.h>
 
-#include <sys/time.h>
 #include <sys/kernel.h>
 #include <sys/limits.h>
+#include <sys/time.h>
 
-#define	jiffies			ticks
-#define	jiffies_64		ticks
+extern unsigned long jiffies;	/* defined in sys/kern/subr_ticks.S */
+#define	jiffies_64		jiffies	/* XXX-MJ wrong on 32-bit platforms */
 #define	jiffies_to_msecs(x)     ((unsigned int)(((int64_t)(int)(x)) * 1000 / hz))
 
-#define	MAX_JIFFY_OFFSET	((INT_MAX >> 1) - 1)
+#define	MAX_JIFFY_OFFSET	((LONG_MAX >> 1) - 1)
 
-#define	time_after(a, b)	((int)((b) - (a)) < 0)
+#define	time_after(a, b)	((long)((b) - (a)) < 0)
 #define	time_after32(a, b)	((int32_t)((uint32_t)(b) - (uint32_t)(a)) < 0)
 #define	time_before(a, b)	time_after(b,a)
 #define	time_before32(a, b)	time_after32(b, a)
-#define	time_after_eq(a, b)	((int)((a) - (b)) >= 0)
+#define	time_after_eq(a, b)	((long)((a) - (b)) >= 0)
 #define	time_before_eq(a, b)	time_after_eq(b, a)
 #define	time_in_range(a,b,c)	\
 	(time_after_eq(a,b) && time_before_eq(a,c))
@@ -68,7 +68,7 @@ extern uint64_t lkpi_msec2hz_rem;
 extern uint64_t lkpi_msec2hz_div;
 extern uint64_t lkpi_msec2hz_max;
 
-static inline int
+static inline unsigned long
 msecs_to_jiffies(uint64_t msec)
 {
 	uint64_t result;
@@ -79,10 +79,10 @@ msecs_to_jiffies(uint64_t msec)
 	if (result > MAX_JIFFY_OFFSET)
 		result = MAX_JIFFY_OFFSET;
 
-	return ((int)result);
+	return ((unsigned long)result);
 }
 
-static inline int
+static inline unsigned long
 usecs_to_jiffies(uint64_t usec)
 {
 	uint64_t result;
@@ -93,7 +93,7 @@ usecs_to_jiffies(uint64_t usec)
 	if (result > MAX_JIFFY_OFFSET)
 		result = MAX_JIFFY_OFFSET;
 
-	return ((int)result);
+	return ((unsigned long)result);
 }
 
 static inline uint64_t
@@ -120,32 +120,33 @@ nsecs_to_jiffies(uint64_t nsec)
 }
 
 static inline uint64_t
-jiffies_to_nsecs(int j)
+jiffies_to_nsecs(unsigned long j)
 {
 
-	return ((1000000000ULL / hz) * (uint64_t)(unsigned int)j);
+	return ((1000000000ULL / hz) * (uint64_t)j);
 }
 
 static inline uint64_t
-jiffies_to_usecs(int j)
+jiffies_to_usecs(unsigned long j)
 {
 
-	return ((1000000ULL / hz) * (uint64_t)(unsigned int)j);
+	return ((1000000ULL / hz) * (uint64_t)j);
 }
 
 static inline uint64_t
 get_jiffies_64(void)
 {
 
-	return ((uint64_t)(unsigned int)ticks);
+	return ((uint64_t)jiffies);
 }
 
-static inline int
-linux_timer_jiffies_until(int expires)
+static inline unsigned long
+linux_timer_jiffies_until(unsigned long expires)
 {
-	int delta = expires - jiffies;
+	unsigned long delta = expires - jiffies;
+
 	/* guard against already expired values */
-	if (delta < 1)
+	if ((long)delta < 1)
 		delta = 1;
 	return (delta);
 }
diff --git a/sys/compat/linuxkpi/common/include/linux/sched.h b/sys/compat/linuxkpi/common/include/linux/sched.h
index 80354493f955..3ad2f8e4ce8b 100644
--- a/sys/compat/linuxkpi/common/include/linux/sched.h
+++ b/sys/compat/linuxkpi/common/include/linux/sched.h
@@ -53,7 +53,7 @@
 
 #include <asm/atomic.h>
 
-#define	MAX_SCHEDULE_TIMEOUT	INT_MAX
+#define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
 
 #define	TASK_RUNNING		0x0000
 #define	TASK_INTERRUPTIBLE	0x0001
@@ -160,7 +160,7 @@ void linux_send_sig(int signo, struct task_struct *task);
 	linux_send_sig(signo, task);			\
 } while (0)
 
-int linux_schedule_timeout(int timeout);
+long linux_schedule_timeout(long timeout);
 
 static inline void
 linux_schedule_save_interrupt_value(struct task_struct *task, int value)
diff --git a/sys/compat/linuxkpi/common/include/linux/timer.h b/sys/compat/linuxkpi/common/include/linux/timer.h
index 8bea082c3e6c..a635f0faea59 100644
--- a/sys/compat/linuxkpi/common/include/linux/timer.h
+++ b/sys/compat/linuxkpi/common/include/linux/timer.h
@@ -42,7 +42,7 @@ struct timer_list {
 		void (*function_415) (struct timer_list *);
 	};
 	unsigned long data;
-	int expires;
+	unsigned long expires;
 };
 
 extern unsigned long linux_timer_hz_mask;
@@ -76,7 +76,7 @@ extern unsigned long linux_timer_hz_mask;
 	callout_init(&(timer)->callout, 1);			\
 } while (0)
 
-extern int mod_timer(struct timer_list *, int);
+extern int mod_timer(struct timer_list *, unsigned long);
 extern void add_timer(struct timer_list *);
 extern void add_timer_on(struct timer_list *, int cpu);
 extern int del_timer(struct timer_list *);
@@ -86,7 +86,7 @@ extern int timer_shutdown_sync(struct timer_list *);
 
 #define	timer_pending(timer)	callout_pending(&(timer)->callout)
 #define	round_jiffies(j)	\
-	((int)(((j) + linux_timer_hz_mask) & ~linux_timer_hz_mask))
+	((unsigned long)(((j) + linux_timer_hz_mask) & ~linux_timer_hz_mask))
 #define	round_jiffies_relative(j) round_jiffies(j)
 #define	round_jiffies_up(j)	round_jiffies(j)
 #define	round_jiffies_up_relative(j) round_jiffies_up(j)
diff --git a/sys/compat/linuxkpi/common/include/linux/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h
index 309c7816aa7b..bd496793e27e 100644
--- a/sys/compat/linuxkpi/common/include/linux/wait.h
+++ b/sys/compat/linuxkpi/common/include/linux/wait.h
@@ -138,7 +138,7 @@ void linux_wake_up(wait_queue_head_t *, unsigned int, int, bool);
 #define	wake_up_interruptible_all(wqh)					\
 	linux_wake_up(wqh, TASK_INTERRUPTIBLE, 0, false)
 
-int linux_wait_event_common(wait_queue_head_t *, wait_queue_t *, int,
+int linux_wait_event_common(wait_queue_head_t *, wait_queue_t *, long,
     unsigned int, spinlock_t *);
 
 /*
@@ -148,9 +148,9 @@ int linux_wait_event_common(wait_queue_head_t *, wait_queue_t *, int,
  */
 #define	__wait_event_common(wqh, cond, timeout, state, lock) ({	\
 	DEFINE_WAIT(__wq);					\
-	const int __timeout = ((int)(timeout)) < 1 ? 1 : (timeout);	\
-	int __start = ticks;					\
-	int __ret = 0;						\
+	const long __timeout = ((long)(timeout)) < 1 ? 1 : (timeout); \
+	long __start = jiffies;					\
+	long __ret = 0;						\
 								\
 	for (;;) {						\
 		linux_prepare_to_wait(&(wqh), &__wq, state);	\
@@ -166,7 +166,7 @@ int linux_wait_event_common(wait_queue_head_t *, wait_queue_t *, int,
 		if (__ret == -EWOULDBLOCK)			\
 			__ret = !!(cond);			\
 		else if (__ret != -ERESTARTSYS) {		\
-			__ret = __timeout + __start - ticks;	\
+			__ret = __timeout + __start - jiffies;	\
 			/* range check return value */		\
 			if (__ret < 1)				\
 				__ret = 1;			\
@@ -284,7 +284,7 @@ void linux_finish_wait(wait_queue_head_t *, wait_queue_t *);
 #define	finish_wait(wqh, wq)		linux_finish_wait(wqh, wq)
 
 void linux_wake_up_bit(void *, int);
-int linux_wait_on_bit_timeout(unsigned long *, int, unsigned int, int);
+int linux_wait_on_bit_timeout(unsigned long *, int, unsigned int, long);
 void linux_wake_up_atomic_t(atomic_t *);
 int linux_wait_on_atomic_t(atomic_t *, unsigned int);
 
diff --git a/sys/compat/linuxkpi/common/include/linux/workqueue.h b/sys/compat/linuxkpi/common/include/linux/workqueue.h
index 7e740f0f1dfc..25ee861d3015 100644
--- a/sys/compat/linuxkpi/common/include/linux/workqueue.h
+++ b/sys/compat/linuxkpi/common/include/linux/workqueue.h
@@ -90,7 +90,7 @@ struct delayed_work {
 	struct {
 		struct callout callout;
 		struct mtx mtx;
-		int	expires;
+		long	expires;
 	} timer;
 };
 
@@ -245,7 +245,7 @@ extern struct workqueue_struct *linux_create_workqueue_common(const char *, int)
 extern void linux_destroy_workqueue(struct workqueue_struct *);
 extern bool linux_queue_work_on(int cpu, struct workqueue_struct *, struct work_struct *);
 extern bool linux_queue_delayed_work_on(int cpu, struct workqueue_struct *,
-    struct delayed_work *, unsigned delay);
+    struct delayed_work *, unsigned long delay);
 extern bool linux_cancel_work(struct work_struct *);
 extern bool linux_cancel_delayed_work(struct delayed_work *);
 extern bool linux_cancel_work_sync(struct work_struct *);
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index 1a8b32bb16f7..357f451a3f1a 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -5091,11 +5091,11 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
 	skb_queue_tail(&ltxq->skbq, skb);
 #ifdef LINUXKPI_DEBUG_80211
 	if (linuxkpi_debug_80211 & D80211_TRACE_TX)
-		printf("%s:%d mo_wake_tx_queue :: %d %u lsta %p sta %p "
+		printf("%s:%d mo_wake_tx_queue :: %d %lu lsta %p sta %p "
 		    "ni %p %6D skb %p lxtq %p { qlen %u, ac %d tid %u } "
 		    "WAKE_TX_Q ac %d prio %u qmap %u\n",
 		    __func__, __LINE__,
-		    curthread->td_tid, (unsigned int)ticks,
+		    curthread->td_tid, jiffies,
 		    lsta, sta, ni, ni->ni_macaddr, ":", skb, ltxq,
 		    skb_queue_len(&ltxq->skbq), ltxq->txq.ac,
 		    ltxq->txq.tid, ac, skb->priority, skb->qmap);
diff --git a/sys/compat/linuxkpi/common/src/linux_80211_macops.c b/sys/compat/linuxkpi/common/src/linux_80211_macops.c
index d7bd26a3d0e3..b7e232da48b0 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211_macops.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211_macops.c
@@ -40,9 +40,9 @@
 #ifdef LINUXKPI_DEBUG_80211
 #define	LKPI_80211_TRACE_MO(fmt, ...)					\
     if (linuxkpi_debug_80211 & D80211_TRACE_MO)				\
-	printf("LKPI_80211_TRACE_MO %s:%d: %d %d %u_" fmt "\n",		\
+	printf("LKPI_80211_TRACE_MO %s:%d: %d %d %lu_" fmt "\n",	\
 	    __func__, __LINE__, curcpu, curthread->td_tid,		\
-	    (unsigned int)ticks, __VA_ARGS__)
+	    jiffies, __VA_ARGS__)
 #else
 #define	LKPI_80211_TRACE_MO(...)	do { } while(0)
 #endif
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c
index e061504868fd..019e08f59d44 100644
--- a/sys/compat/linuxkpi/common/src/linux_compat.c
+++ b/sys/compat/linuxkpi/common/src/linux_compat.c
@@ -2072,7 +2072,7 @@ linux_timer_callback_wrapper(void *context)
 }
 
 int
-mod_timer(struct timer_list *timer, int expires)
+mod_timer(struct timer_list *timer, unsigned long expires)
 {
 	int ret;
 
@@ -2268,12 +2268,12 @@ intr:
 /*
  * Time limited wait for done != 0 with or without signals.
  */
-int
-linux_wait_for_timeout_common(struct completion *c, int timeout, int flags)
+unsigned long
+linux_wait_for_timeout_common(struct completion *c, unsigned long timeout,
+    int flags)
 {
 	struct task_struct *task;
-	int end = jiffies + timeout;
-	int error;
+	unsigned long end = jiffies + timeout, error;
 
 	if (SCHEDULER_STOPPED())
 		return (0);
diff --git a/sys/compat/linuxkpi/common/src/linux_netdev.c b/sys/compat/linuxkpi/common/src/linux_netdev.c
index c36684f9fd97..ce9153614104 100644
--- a/sys/compat/linuxkpi/common/src/linux_netdev.c
+++ b/sys/compat/linuxkpi/common/src/linux_netdev.c
@@ -63,22 +63,22 @@ SYSCTL_INT(_compat_linuxkpi, OID_AUTO, debug_napi, CTLFLAG_RWTUN,
 #define	DNAPI_DIRECT_DISPATCH	0x1000
 
 #define	NAPI_TRACE(_n)		if (debug_napi & DNAPI_TRACE)		\
-    printf("NAPI_TRACE %s:%d %u %p (%#jx %b)\n", __func__, __LINE__,	\
-	(unsigned int)ticks, _n, (uintmax_t)(_n)->state,		\
+    printf("NAPI_TRACE %s:%d %lu %p (%#jx %b)\n", __func__, __LINE__,	\
+	jiffies, _n, (uintmax_t)(_n)->state,				\
 	(int)(_n)->state, LKPI_NAPI_FLAGS)
 #define	NAPI_TRACE2D(_n, _d)	if (debug_napi & DNAPI_TRACE)		\
-    printf("NAPI_TRACE %s:%d %u %p (%#jx %b) %d\n", __func__, __LINE__, \
-	(unsigned int)ticks, _n, (uintmax_t)(_n)->state,		\
+    printf("NAPI_TRACE %s:%d %lu %p (%#jx %b) %d\n", __func__, __LINE__, \
+	jiffies, _n, (uintmax_t)(_n)->state,				\
 	(int)(_n)->state, LKPI_NAPI_FLAGS, _d)
 #define	NAPI_TRACE_TASK(_n, _p, _c) if (debug_napi & DNAPI_TRACE_TASK)	\
-    printf("NAPI_TRACE %s:%d %u %p (%#jx %b) pending %d count %d "	\
+    printf("NAPI_TRACE %s:%d %lu %p (%#jx %b) pending %d count %d "	\
 	"rx_count %d\n", __func__, __LINE__,				\
-	(unsigned int)ticks, _n, (uintmax_t)(_n)->state,		\
+	jiffies, _n, (uintmax_t)(_n)->state,				\
 	(int)(_n)->state, LKPI_NAPI_FLAGS, _p, _c, (_n)->rx_count)
 #define	NAPI_TODO()		if (debug_napi & DNAPI_TODO)		\
-    printf("NAPI_TODO %s:%d %d\n", __func__, __LINE__, ticks)
+    printf("NAPI_TODO %s:%d %lu\n", __func__, __LINE__, jiffies)
 #define	NAPI_IMPROVE()		if (debug_napi & DNAPI_IMPROVE)		\
-    printf("NAPI_IMPROVE %s:%d %d\n", __func__, __LINE__, ticks)
+    printf("NAPI_IMPROVE %s:%d %lu\n", __func__, __LINE__, jiffies)
 
 #define	NAPI_DIRECT_DISPATCH()	((debug_napi & DNAPI_DIRECT_DISPATCH) != 0)
 #else
diff --git a/sys/compat/linuxkpi/common/src/linux_schedule.c b/sys/compat/linuxkpi/common/src/linux_schedule.c
index fa20a11f5ec7..507d6fc417d0 100644
--- a/sys/compat/linuxkpi/common/src/linux_schedule.c
+++ b/sys/compat/linuxkpi/common/src/linux_schedule.c
@@ -40,7 +40,7 @@
 
 static int
 linux_add_to_sleepqueue(void *wchan, struct task_struct *task,
-    const char *wmesg, int timeout, int state)
+    const char *wmesg, long timeout, int state)
 {
 	int flags, ret;
 
@@ -249,7 +249,7 @@ linux_waitqueue_active(wait_queue_head_t *wqh)
 }
 
 int
-linux_wait_event_common(wait_queue_head_t *wqh, wait_queue_t *wq, int timeout,
+linux_wait_event_common(wait_queue_head_t *wqh, wait_queue_t *wq, long timeout,
     unsigned int state, spinlock_t *lock)
 {
 	struct task_struct *task;
@@ -280,13 +280,13 @@ linux_wait_event_common(wait_queue_head_t *wqh, wait_queue_t *wq, int timeout,
 	return (ret);
 }
 
-int
-linux_schedule_timeout(int timeout)
+long
+linux_schedule_timeout(long timeout)
 {
 	struct task_struct *task;
+	long remainder;
 	int ret;
 	int state;
-	int remainder;
 
 	task = current;
 
@@ -296,7 +296,7 @@ linux_schedule_timeout(int timeout)
 	else if (timeout == MAX_SCHEDULE_TIMEOUT)
 		timeout = 0;
 
-	remainder = ticks + timeout;
+	remainder = jiffies + timeout;
 
 	sleepq_lock(task);
 	state = atomic_read(&task->state);
@@ -313,7 +313,7 @@ linux_schedule_timeout(int timeout)
 		return (MAX_SCHEDULE_TIMEOUT);
 
 	/* range check return value */
-	remainder -= ticks;
+	remainder -= jiffies;
 
 	/* range check return value */
 	if (ret == -ERESTARTSYS && remainder < 1)
@@ -344,7 +344,7 @@ linux_wake_up_bit(void *word, int bit)
 
 int
 linux_wait_on_bit_timeout(unsigned long *word, int bit, unsigned int state,
-    int timeout)
+    long timeout)
 {
 	struct task_struct *task;
 	void *wchan;
diff --git a/sys/compat/linuxkpi/common/src/linux_work.c b/sys/compat/linuxkpi/common/src/linux_work.c
index 939bdbbc1434..cf15d1a9c41b 100644
--- a/sys/compat/linuxkpi/common/src/linux_work.c
+++ b/sys/compat/linuxkpi/common/src/linux_work.c
@@ -212,7 +212,7 @@ linux_flush_rcu_work(struct rcu_work *rwork)
  */
 bool
 linux_queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
-    struct delayed_work *dwork, unsigned delay)
+    struct delayed_work *dwork, unsigned long delay)
 {
 	static const uint8_t states[WORK_ST_MAX] __aligned(8) = {
 		[WORK_ST_IDLE] = WORK_ST_TIMER,		/* start timeout */
diff --git a/sys/kern/subr_ticks.S b/sys/kern/subr_ticks.S
index ad01d5d67165..5cb994293d91 100644
--- a/sys/kern/subr_ticks.S
+++ b/sys/kern/subr_ticks.S
@@ -6,7 +6,8 @@
 
 /*
  * Define the "ticks" and "ticksl" variables.  The former is overlaid onto the
- * low bits of the latter.
+ * low bits of the latter.  Also define an alias "jiffies" of "ticksl",
+ * used by the LinuxKPI.
  */
 
 #if defined(__aarch64__)
@@ -34,3 +35,8 @@ ticksl:	.zero __SIZEOF_LONG__
 	.type ticks, %object
 ticks	=ticksl + TICKS_OFFSET
 	.size ticks, __SIZEOF_INT__
+
+	.global jiffies
+	.type jiffies, %object
+jiffies	= ticksl
+	.size jiffies, __SIZEOF_LONG__