lkml.org 
[lkml]   [2006]   [Sep]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 05/23] time: fix msecs_to_jiffies() bug
    From: Ingo Molnar <mingo@elte.hu>

    fix multiple conversion bugs in msecs_to_jiffies().

    the main problem is that this condition:

    if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET))

    overflows if HZ is smaller than 1000!

    this change is user-visible: for HZ=250 SUS-compliant poll()-timeout
    value of -20 is mistakenly converted to 'immediate timeout'.

    (the new dyntick code also triggered this, as it frequently creates
    'lagging timer wheel' scenarios.)

    Signed-off-by: Ingo Molnar <mingo@elte.hu>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    --
    kernel/time.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
    1 file changed, 42 insertions(+), 1 deletion(-)

    Index: linux-2.6.18-mm2/kernel/time.c
    ===================================================================
    --- linux-2.6.18-mm2.orig/kernel/time.c 2006-09-30 01:41:15.000000000 +0200
    +++ linux-2.6.18-mm2/kernel/time.c 2006-09-30 01:41:15.000000000 +0200
    @@ -500,15 +500,56 @@ unsigned int jiffies_to_usecs(const unsi
    }
    EXPORT_SYMBOL(jiffies_to_usecs);

    +/*
    + * When we convert to jiffies then we interpret incoming values
    + * the following way:
    + *
    + * - negative values mean 'infinite timeout' (MAX_JIFFY_OFFSET)
    + *
    + * - 'too large' values [that would result in larger than
    + * MAX_JIFFY_OFFSET values] mean 'infinite timeout' too.
    + *
    + * - all other values are converted to jiffies by either multiplying
    + * the input value by a factor or dividing it with a factor
    + *
    + * We must also be careful about 32-bit overflows.
    + */
    unsigned long msecs_to_jiffies(const unsigned int m)
    {
    - if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
    + /*
    + * Negative value, means infinite timeout:
    + */
    + if ((int)m < 0)
    return MAX_JIFFY_OFFSET;
    +
    #if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
    + /*
    + * HZ is equal to or smaller than 1000, and 1000 is a nice
    + * round multiple of HZ, divide with the factor between them,
    + * but round upwards:
    + */
    return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ);
    #elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
    + /*
    + * HZ is larger than 1000, and HZ is a nice round multiple of
    + * 1000 - simply multiply with the factor between them.
    + *
    + * But first make sure the multiplication result cannot
    + * overflow:
    + */
    + if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
    + return MAX_JIFFY_OFFSET;
    +
    return m * (HZ / MSEC_PER_SEC);
    #else
    + /*
    + * Generic case - multiply, round and divide. But first
    + * check that if we are doing a net multiplication, that
    + * we wouldnt overflow:
    + */
    + if (HZ > MSEC_PER_SEC && m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
    + return MAX_JIFFY_OFFSET;
    +
    return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC;
    #endif
    }
    --

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2006-09-30 02:15    [W:0.044 / U:0.060 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site