Why the return type of jiffies_to_usecs() is 'unsigned int' but not 'unsigned long'

From: Dongli Zhang
Date: Tue Feb 26 2019 - 20:12:15 EST


Hi,

I am writing to ask about why the return type of jiffies_to_usecs() and
jiffies_to_msecs() are 'unsigned int', but not 'unsigned long'?

For instance, about jiffies_to_usecs(), suppose the input is 0x7770ef70
(2003893872), that is, jiffies_to_usecs(0x7770ef70).

Suppose USEC_PER_SEC=1000000L and HZ=1000, we expect the result to be
0x000001d291274d80. However, as the return type is 'unsigned int', the leading
32 bits are ignored and the actual result is 0x91274d80.

expected jiffies_to_usecs(0x7770ef70) : 0x000001d291274d80
current jiffies_to_usecs(0x7770ef70) : 0x91274d80

I think jiffies_to_msecs() would have the same issue.

As both jiffies_to_usecs() and jiffies_to_msecs() are totally called by 680
locations in the lasted mainline linux kernel, the below patch would generate
lots of warnings. Almost all warnings are due to printk or trace event.



diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index fa92824..d961b30 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -288,8 +288,8 @@ extern unsigned long preset_lpj;
/*
* Convert various time units to each other:
*/
-extern unsigned int jiffies_to_msecs(const unsigned long j);
-extern unsigned int jiffies_to_usecs(const unsigned long j);
+extern unsigned long jiffies_to_msecs(const unsigned long j);
+extern unsigned long jiffies_to_usecs(const unsigned long j);

static inline u64 jiffies_to_nsecs(const unsigned long j)
{
diff --git a/kernel/time/time.c b/kernel/time/time.c
index 2edb508..72c139d 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -305,7 +305,7 @@ COMPAT_SYSCALL_DEFINE1(adjtimex, struct compat_timex __user
*, utp)
* Avoid unnecessary multiplications/divisions in the
* two most common HZ cases:
*/
-unsigned int jiffies_to_msecs(const unsigned long j)
+unsigned long jiffies_to_msecs(const unsigned long j)
{
#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
return (MSEC_PER_SEC / HZ) * j;
@@ -322,7 +322,7 @@ unsigned int jiffies_to_msecs(const unsigned long j)
}
EXPORT_SYMBOL(jiffies_to_msecs);

-unsigned int jiffies_to_usecs(const unsigned long j)
+unsigned long jiffies_to_usecs(const unsigned long j)
{
/*
* Hz usually doesn't go much further MSEC_PER_SEC.
--
2.7.4

------------------------------------------------------



While I am still struggling on those warnings, would you please confirm if the
'unsigned int' return type is by design on purpose or it is a bug as I mentioned
above?

So far the latest 4.9.x stable kernel is affected by a steal usage 100% issue
and the root cause is the incorrect return type of jiffies_to_usecs(). I will
discuss that in another email thread for more details later to facilitate people
to grep/search for similar/same issue on google in the future. That issue is not
reproducible after I change the return type of jiffies_to_usecs() to 'unsigned
long'.

Thank you very much!

Dongli Zhang