inconsistency in kernel/time.c with jiffies
I wrote this testcase module to prove a bug in kernel/time.c. The problem i found is in the msecs_to_jiffies() function. In my testcase the bug occurs with kernel 3.2 on a 32-Bit system. The problem is this first part of the function:
Quoted 2 lines
if ((int)m < 0)
returnMAX_JIFFY_OFFSET;
When the function has const unsigned int as parameter so it's fine to call it with a unsigned int value, for example 2147483647 for 32-Bit as the maximum value the return value is 2147483647 on a system with HZ=1000. But when the value is increased by 1 to 2147483648 the return value is 1073741822 (MAX_JIFFY_OFFSET). This means, a even higher value results in a smaller return value.
But time.c also says:
* - 'too large' values [that would result in larger than
* MAX_JIFFY_OFFSET values] mean 'infinite timeout' too.
If you read this it would mean that even 2147483647 should result in 1073741822 (MAX_JIFFY_OFFSET) as it's larger then MAX_JIFFY_OFFSET.
So there are several suggestions i would discuss:
1. Change MAX_JIFFY_OFFSET ((ULONG_MAX >> 1)-1 as i guess unsigned makes more sense, because jiffies are never < 0
2. Change the if((int)m < 0) to return MAX_JIFFY_OFFSET even with values that are valid but higher then MAX_JIFFY_OFFSET
Quoted 1 line
if (((int)m < 0) || (m >
MAX_JIFFY_OFFSET))
3. Change the parameter to signed int.
This issue came up when i worked with ipset and higher values resulted in smaller timeouts.
Any feedback is appreciated.
Here the testcase source code:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/time.h>
static int jiffiestestcase_init(void)
{
printk(KERN_ALERT "Last working msecs_to_jiffies value with 2147483647 %ld\n", msecs_to_jiffies(2147483647));
printk(KERN_ALERT "First wrong msecs_to_jiffies value with 2147483648 %ld\n", msecs_to_jiffies(2147483648));
printk(KERN_ALERT "int casts %d and %d\n", (int)2147483647, (int)2147483648);
printk(KERN_ALERT "MAX JIFFIES: %ld\n", MAX_JIFFY_OFFSET);
return 0;
}static void jiffiestestcase_exit(void)
{
printk(KERN_ALERT "ending jiffiestestcase!\n");
}module_init(jiffiestestcase_init);module_exit(jiffiestestcase_exit);
MODULE_LICENSE("GPL");MODULE_AUTHOR("Andreas Herz <[email protected]>"); MODULE_DESCRIPTION("Jiffies Testcase Module");
Signature · 1 line
Andreas Herz