[PATCH 0/2] Timer sync lock checking - Kernel

This is a discussion on [PATCH 0/2] Timer sync lock checking - Kernel ; Hi, Here are two patches that implement checking with lockdep that nobody tries to implement something like this: void timerfn(unsigned long data) { spin_lock(&lock); ... spin_unlock(&lock); } .... setup spin_lock_init(&lock); setup_timer(&timer, timerfn, 0); .... tear_down spin_lock_bh(&lock); del_timer_sync(&timer); spin_unlock_bh(&lock); Because of ...

+ Reply to Thread
Results 1 to 8 of 8

Thread: [PATCH 0/2] Timer sync lock checking

  1. [PATCH 0/2] Timer sync lock checking

    Hi,

    Here are two patches that implement checking with lockdep that nobody
    tries to implement something like this:

    void timerfn(unsigned long data)
    {
    spin_lock(&lock);
    ...
    spin_unlock(&lock);
    }

    ....

    setup
    spin_lock_init(&lock);
    setup_timer(&timer, timerfn, 0);

    ....

    tear_down
    spin_lock_bh(&lock);
    del_timer_sync(&timer);
    spin_unlock_bh(&lock);

    Because of the usage of the fake lock in the timer code, I first needed
    to teach lockdep about a new "check" value which means that it doesn't
    check irq-safety. This is required because we patch 2 takes a fake lock
    around the timerfn, and del_timer_sync() also takes this fake lock, but
    quite obviously the former runs in softirq context and the latter
    doesn't necessarily, but clearly it doesn't need to disable softirqs
    either.

    Unlike with the workqueue debugging where I did the same thing, I don't
    actually know about any such bug. My test code resulted in the warning
    below, as expected.

    johannes

    [ 75.083150] ================================================== =====
    [ 75.083163] [ INFO: possible circular locking dependency detected ]
    [ 75.083170] 2.6.27-wl-03435-g9b45bb6-dirty #92
    [ 75.083177] -------------------------------------------------------
    [ 75.083184] rmmod/4365 is trying to acquire lock:
    [ 75.083191] (&test_timer){-...}, at: [] .del_timer_sync+0x0/0x94
    [ 75.083219]
    [ 75.083220] but task is already holding lock:
    [ 75.083228] (&lock){-+..}, at: [] .modexit+0x38/0x70 [timer_test]
    [ 75.083253]
    [ 75.083254] which lock already depends on the new lock.
    [ 75.083257]
    [ 75.083263]
    [ 75.083265] the existing dependency chain (in reverse order) is:
    [ 75.083272]
    [ 75.083273] -> #1 (&lock){-+..}:
    [ 75.083290] [] .lock_acquire+0xa4/0xec
    [ 75.083305] [] ._spin_lock+0x50/0xac
    [ 75.083320] [] .timerfn+0x2c/0x7c [timer_test]
    [ 75.083331] [] .run_timer_softirq+0x214/0x2e4
    [ 75.083343] [] .__do_softirq+0xd8/0x1c4
    [ 75.083354] [] .do_softirq+0x5c/0xb8
    [ 75.083366] [] .irq_exit+0x74/0xe0
    [ 75.083376] [] .timer_interrupt+0xe4/0x12c
    [ 75.083389] [] decrementer_common+0x114/0x180
    [ 75.083400] [] .cpu_idle+0xd0/0x200
    [ 75.083411] [] .rest_init+0x8c/0xa4
    [ 75.083423] [] .start_kernel+0x4a0/0x4c8
    [ 75.083437] [] .start_here_common+0x3c/0x54
    [ 75.083449]
    [ 75.083450] -> #0 (&test_timer){-...}:
    [ 75.083464] [] .lock_acquire+0xa4/0xec
    [ 75.083474] [] .del_timer_sync+0x44/0x94
    [ 75.083486] [] .modexit+0x44/0x70 [timer_test]
    [ 75.083497] [] .sys_delete_module+0x278/0x314
    [ 75.083509] [] syscall_exit+0x0/0x40
    [ 75.083520]
    [ 75.083521] other info that might help us debug this:
    [ 75.083523]
    [ 75.083530] 1 lock held by rmmod/4365:
    [ 75.083536] #0: (&lock){-+..}, at: [] .modexit+0x38/0x70 [timer_test]
    [ 75.083557]
    [ 75.083558] stack backtrace:
    [ 75.083563] Call Trace:
    [ 75.083571] [c00000020ed8b8d0] [c00000000000f860] .show_stack+0x6c/0x174(unreliable)
    [ 75.083586] [c00000020ed8b980] [c00000000007e008] .print_circular_bug_tail+0xc8/0xec
    [ 75.083598] [c00000020ed8ba50] [c00000000007f4d0] .__lock_acquire+0x10ac/0x1784
    [ 75.083609] [c00000020ed8bb50] [c00000000007fc4c] .lock_acquire+0xa4/0xec
    [ 75.083621] [c00000020ed8bc10] [c00000000005c878] .del_timer_sync+0x44/0x94
    [ 75.083633] [c00000020ed8bca0] [d0000000001090c0] .modexit+0x44/0x70 [timer_test]
    [ 75.083645] [c00000020ed8bd30] [c00000000008c320] .sys_delete_module+0x278/0x314
    [ 75.083657] [c00000020ed8be30] [c0000000000076d4] syscall_exit+0x0/0x40


    -----BEGIN PGP SIGNATURE-----
    Comment: Johannes Berg (powerbook)

    iQIcBAABAgAGBQJJANIHAAoJEKVg1VMiehFYqOcQAIxiMVEzwB Z5nV23r9adIMNl
    /XARk7uU0iqNQsDY73TVUDGsaKrSu0fb8SA3fPOeFrD8H5saZop 0V/ef0YVJR2Zy
    /zlnLR2utkUFqdTknlV7ZaXDiN0E7+seoiPJ/rxlFHhF1Kys/Z0xFWrTdSGHp47f
    62vR1UkmzGtB9XbkroW2JhEmO0nscvWOP8lxZVoozj59qLv94E E0UYVxTE7M/mdB
    LOpY8dJ6hSbVJL7V7noeB4Fct1hXR1XbMjErzMIRdXI8MrAv+n qUYQklLwvOWt4D
    qe2cwLx5/6sUx82NhU44RhiFJzjOApYu1jrlpGzEwkk8EZE7pqaDKwU+hKT iXNZ+
    RDI4ti0akDUzsWQYvR0t3ZvnOLbd/dXey1QSKYK1kprlrsVstIp9vh30ZuBgz3L6
    QG2NpVvXa2Ge8AnqkrOGvAkZOPBcHI02MxGPI7POOOZiJdj74A QI2MbZrHfgukE7
    18SABsrSlzxoD7T+zOzU5g7O2Gd0UJmJi7bD5R2s0JyvE3Mw5e ouSGt92Gd6RJFD
    nefS1pQcUXWS2zcW3XulkkKKGJa9/WWrQ31fdYrE+JYcCOUzEdd/vcCwurTDLSpX
    +Om+a+qIi8sbGN2u3iMVA0hb0bHZI0G19Iad2lwiBCPX6XqLvv Mdsnusz7h3kdlr
    J3olO2ZuZT7kAPEQqpIv
    =hXoh
    -----END PGP SIGNATURE-----


  2. [PATCH 2/2] timer: implement lockdep deadlock detection

    This modifies the timer code in a way to allow lockdep to detect
    deadlocks resulting from a lock being taken in the timer function
    as well as around the del_timer_sync() call.

    Signed-off-by: Johannes Berg
    ---
    include/linux/timer.h | 93 +++++++++++++++++++++++++++++++++++++++++---------
    kernel/timer.c | 40 +++++++++++++++------
    2 files changed, 106 insertions(+), 27 deletions(-)

    --- wireless-testing.orig/include/linux/timer.h 2008-10-23 21:06:23.948352811 +0200
    +++ wireless-testing/include/linux/timer.h 2008-10-23 21:30:06.468674841 +0200
    @@ -21,52 +21,115 @@ struct timer_list {
    char start_comm[16];
    int start_pid;
    #endif
    +#ifdef CONFIG_LOCKDEP
    + struct lockdep_map lockdep_map;
    +#endif
    };

    extern struct tvec_base boot_tvec_bases;

    -#define TIMER_INITIALIZER(_function, _expires, _data) { \
    - .entry = { .prev = TIMER_ENTRY_STATIC }, \
    - .function = (_function), \
    - .expires = (_expires), \
    - .data = (_data), \
    - .base = &boot_tvec_bases, \
    +#ifdef CONFIG_LOCKDEP
    +#define __TIMER_LOCKDEP_MAP_INITIALIZER(fn, name) \
    + .lockdep_map = STATIC_LOCKDEP_MAP_INIT(name, fn),
    +#else
    +#define __TIMER_LOCKDEP_MAP_INITIALIZER(fn, name)
    +#endif
    +
    +#define TIMER_INITIALIZER(_function, _expires, _data) { \
    + .entry = { .prev = TIMER_ENTRY_STATIC }, \
    + .function = (_function), \
    + .expires = (_expires), \
    + .data = (_data), \
    + .base = &boot_tvec_bases, \
    + __TIMER_LOCKDEP_MAP_INITIALIZER((_function), #_function)\
    }

    #define DEFINE_TIMER(_name, _function, _expires, _data) \
    struct timer_list _name = \
    TIMER_INITIALIZER(_function, _expires, _data)

    -void init_timer(struct timer_list *timer);
    -void init_timer_deferrable(struct timer_list *timer);
    +void init_timer_key(struct timer_list *timer,
    + const char *name,
    + struct lock_class_key *key);
    +void init_timer_deferrable_key(struct timer_list *timer,
    + const char *name,
    + struct lock_class_key *key);
    +
    +#ifdef CONFIG_LOCKDEP
    +#define init_timer(timer) \
    + do { \
    + static struct lock_class_key __key; \
    + init_timer_key((timer), #timer, &__key); \
    + } while (0)
    +#define init_timer_deferrable(timer) \
    + do { \
    + static struct lock_class_key __key; \
    + init_timer_deferrable_key((timer), #timer, &__key); \
    + } while (0)
    +#define init_timer_on_stack(timer) \
    + do { \
    + static struct lock_class_key __key; \
    + init_timer_on_stack_key((timer), #timer, &__key); \
    + } while (0)
    +#define setup_timer(timer, fn, data) \
    + do { \
    + static struct lock_class_key __key; \
    + setup_timer_key((timer), #timer, &__key, (fn), (data));\
    + } while (0)
    +#define setup_timer_on_stack(timer, fn, data) \
    + do { \
    + static struct lock_class_key __key; \
    + setup_timer_on_stack_key((timer), #timer, &__key, \
    + (fn), (data)); \
    + } while (0)
    +#else
    +#define init_timer(timer)\
    + init_timer_key((timer), NULL, NULL)
    +#define init_timer_deferrable(timer)\
    + init_timer_deferrable_key((timer), NULL, NULL)
    +#define init_timer_on_stack(timer)\
    + init_timer_on_stack_key((timer)), NULL, NULL)
    +#define setup_timer(timer, fn, data)\
    + setup_timer_key((timer), NULL, NULL, (fn), (data))
    +#define setup_timer_on_stack(timer, fn, data)\
    + setup_timer_on_stack_key((timer), NULL, NULL, (fn), (data))
    +#endif

    #ifdef CONFIG_DEBUG_OBJECTS_TIMERS
    -extern void init_timer_on_stack(struct timer_list *timer);
    +extern void init_timer_on_stack_key(struct timer_list *timer,
    + const char *name,
    + struct lock_class_key *key);
    extern void destroy_timer_on_stack(struct timer_list *timer);
    #else
    static inline void destroy_timer_on_stack(struct timer_list *timer) { }
    -static inline void init_timer_on_stack(struct timer_list *timer)
    +static inline void init_timer_on_stack_key(struct timer_list *timer,
    + const char *name,
    + struct lock_class_key *key)
    {
    - init_timer(timer);
    + init_timer_key(timer, name, key);
    }
    #endif

    -static inline void setup_timer(struct timer_list * timer,
    +static inline void setup_timer_key(struct timer_list * timer,
    + const char *name,
    + struct lock_class_key *key,
    void (*function)(unsigned long),
    unsigned long data)
    {
    timer->function = function;
    timer->data = data;
    - init_timer(timer);
    + init_timer_key(timer, name, key);
    }

    -static inline void setup_timer_on_stack(struct timer_list *timer,
    +static inline void setup_timer_on_stack_key(struct timer_list *timer,
    + const char *name,
    + struct lock_class_key *key,
    void (*function)(unsigned long),
    unsigned long data)
    {
    timer->function = function;
    timer->data = data;
    - init_timer_on_stack(timer);
    + init_timer_on_stack_key(timer, name, key);
    }

    /**
    --- wireless-testing.orig/kernel/timer.c 2008-10-23 21:06:23.993350111 +0200
    +++ wireless-testing/kernel/timer.c 2008-10-23 21:08:10.172098297 +0200
    @@ -422,14 +422,18 @@ static inline void debug_timer_free(stru
    debug_object_free(timer, &timer_debug_descr);
    }

    -static void __init_timer(struct timer_list *timer);
    -
    -void init_timer_on_stack(struct timer_list *timer)
    +static void __init_timer(struct timer_list *timer,
    + const char *name,
    + struct lock_class_key *key);
    +
    +void init_timer_on_stack_key(struct timer_list *timer,
    + const char *name,
    + struct lock_class_key *key)
    {
    debug_object_init_on_stack(timer, &timer_debug_descr);
    - __init_timer(timer);
    + __init_timer(timer, name, key);
    }
    -EXPORT_SYMBOL_GPL(init_timer_on_stack);
    +EXPORT_SYMBOL_GPL(init_timer_on_stack_key);

    void destroy_timer_on_stack(struct timer_list *timer)
    {
    @@ -443,7 +447,9 @@ static inline void debug_timer_activate(
    static inline void debug_timer_deactivate(struct timer_list *timer) { }
    #endif

    -static void __init_timer(struct timer_list *timer)
    +static void __init_timer(struct timer_list *timer,
    + const char *name,
    + struct lock_class_key *key)
    {
    timer->entry.next = NULL;
    timer->base = __raw_get_cpu_var(tvec_bases);
    @@ -452,6 +458,7 @@ static void __init_timer(struct timer_li
    timer->start_pid = -1;
    memset(timer->start_comm, 0, TASK_COMM_LEN);
    #endif
    + lockdep_init_map(&timer->lockdep_map, name, key, 0);
    }

    /**
    @@ -461,19 +468,23 @@ static void __init_timer(struct timer_li
    * init_timer() must be done to a timer prior calling *any* of the
    * other timer functions.
    */
    -void init_timer(struct timer_list *timer)
    +void init_timer_key(struct timer_list *timer,
    + const char *name,
    + struct lock_class_key *key)
    {
    debug_timer_init(timer);
    - __init_timer(timer);
    + __init_timer(timer, name, key);
    }
    -EXPORT_SYMBOL(init_timer);
    +EXPORT_SYMBOL(init_timer_key);

    -void init_timer_deferrable(struct timer_list *timer)
    +void init_timer_deferrable_key(struct timer_list *timer,
    + const char *name,
    + struct lock_class_key *key)
    {
    - init_timer(timer);
    + init_timer_key(timer, name, key);
    timer_set_deferrable(timer);
    }
    -EXPORT_SYMBOL(init_timer_deferrable);
    +EXPORT_SYMBOL(init_timer_deferrable_key);

    static inline void detach_timer(struct timer_list *timer,
    int clear_pending)
    @@ -720,6 +731,9 @@ EXPORT_SYMBOL(try_to_del_timer_sync);
    */
    int del_timer_sync(struct timer_list *timer)
    {
    + lock_map_acquire_noirq(&timer->lockdep_map);
    + lock_map_release(&timer->lockdep_map);
    +
    for (; {
    int ret = try_to_del_timer_sync(timer);
    if (ret >= 0)
    @@ -795,7 +809,9 @@ static inline void __run_timers(struct t
    spin_unlock_irq(&base->lock);
    {
    int preempt_count = preempt_count();
    + lock_map_acquire_noirq(&timer->lockdep_map);
    fn(data);
    + lock_map_release(&timer->lockdep_map);
    if (preempt_count != preempt_count()) {
    printk(KERN_ERR "huh, entered %p "
    "with preempt_count %08x, exited"


    --
    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/

  3. [PATCH 1/2] lockdep: implement full check without irq checking

    This patch implements a new check type "3" which means "full validation
    but without irq tracing" in order to allow some certain fake locks that
    are only added for deadlock detection to not cause inconsistent state
    warnings which would be inappropriate for them.

    Signed-off-by: Johannes Berg
    ---
    include/linux/lockdep.h | 4 ++++
    kernel/lockdep.c | 2 +-
    2 files changed, 5 insertions(+), 1 deletion(-)

    --- wireless-testing.orig/include/linux/lockdep.h 2008-10-23 21:06:25.837224864 +0200
    +++ wireless-testing/include/linux/lockdep.h 2008-10-23 21:32:09.889809433 +0200
    @@ -301,6 +301,7 @@ extern void lockdep_init_map(struct lock
    * 0: disabled
    * 1: simple checks (freeing, held-at-exit-time, etc.)
    * 2: full validation
    + * 3: full validation without irq tracing
    */
    extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
    int trylock, int read, int check,
    @@ -471,12 +472,15 @@ static inline void print_irqtrace_events
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
    # ifdef CONFIG_PROVE_LOCKING
    # define lock_map_acquire(l) lock_acquire(l, 0, 0, 0, 2, NULL, _THIS_IP_)
    +# define lock_map_acquire_noirq(l) lock_acquire(l, 0, 0, 0, 3, NULL, _THIS_IP_)
    # else
    # define lock_map_acquire(l) lock_acquire(l, 0, 0, 0, 1, NULL, _THIS_IP_)
    +# define lock_map_acquire_noirq(l) lock_acquire(l, 0, 0, 0, 1, NULL, _THIS_IP_)
    # endif
    # define lock_map_release(l) lock_release(l, 1, _THIS_IP_)
    #else
    # define lock_map_acquire(l) do { } while (0)
    +# define lock_map_acquire_noirq(l) do { } while (0)
    # define lock_map_release(l) do { } while (0)
    #endif

    --- wireless-testing.orig/kernel/lockdep.c 2008-10-23 21:06:25.881976762 +0200
    +++ wireless-testing/kernel/lockdep.c 2008-10-23 21:13:43.460100511 +0200
    @@ -1695,7 +1695,7 @@ static int validate_chain(struct task_st
    * (If lookup_chain_cache() returns with 1 it acquires
    * graph_lock for us)
    */
    - if (!hlock->trylock && (hlock->check == 2) &&
    + if (!hlock->trylock && (hlock->check >= 2) &&
    lookup_chain_cache(curr, hlock, chain_key)) {
    /*
    * Check whether last held lock:


    --
    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/

  4. [PATCH 3/2] tasklet: implement lockdep deadlock detection

    The tasklet code can deadlock when you try to disable a tasklet
    under a lock that the tasklet requires. This patch implements
    lockdep checking for this situation.

    Signed-off-by: Johannes Berg
    ---
    I don't have an actual instance of this in the kernel either, but my
    test case triggers correctly.

    This was easy, but I think it's probably unlikely that somebody will do
    this mistake.

    include/linux/interrupt.h | 41 ++++++++++++++++++++++++++++++++++++-----
    kernel/softirq.c | 10 +++++++---
    2 files changed, 43 insertions(+), 8 deletions(-)

    --- wireless-testing.orig/include/linux/interrupt.h 2008-10-23 21:42:58.495547519 +0200
    +++ wireless-testing/include/linux/interrupt.h 2008-10-23 22:09:18.911743812 +0200
    @@ -299,13 +299,31 @@ struct tasklet_struct
    atomic_t count;
    void (*func)(unsigned long);
    unsigned long data;
    +#ifdef CONFIG_LOCKDEP
    + struct lockdep_map lock_map;
    +#endif
    };

    -#define DECLARE_TASKLET(name, func, data) \
    -struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
    +#ifdef CONFIG_LOCKDEP
    +#define __TASKLET_LOCK_INIT(n, k) .lock_map = STATIC_LOCKDEP_MAP_INIT(n, k),
    +#else
    +#define __TASKLET_LOCK_INIT(n, k)
    +#endif

    +#define __DECLARE_TASKLET(name, _func, _data, c)\
    +struct tasklet_struct name = { \
    + .next = NULL, \
    + .state = 0, \
    + .count = ATOMIC_INIT(c), \
    + .func = _func, \
    + .data = _data, \
    + __TASKLET_LOCK_INIT(#name, &name) \
    +}
    +
    +#define DECLARE_TASKLET(name, func, data) \
    + __DECLARE_TASKLET(name, func, data, 0)
    #define DECLARE_TASKLET_DISABLED(name, func, data) \
    -struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }
    + __DECLARE_TASKLET(name, func, data, 1)


    enum
    @@ -328,6 +346,8 @@ static inline void tasklet_unlock(struct

    static inline void tasklet_unlock_wait(struct tasklet_struct *t)
    {
    + lock_map_acquire_noirq(&t->lock_map);
    + lock_map_release(&t->lock_map);
    while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
    }
    #else
    @@ -380,8 +400,19 @@ static inline void tasklet_hi_enable(str

    extern void tasklet_kill(struct tasklet_struct *t);
    extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu);
    -extern void tasklet_init(struct tasklet_struct *t,
    - void (*func)(unsigned long), unsigned long data);
    +extern void tasklet_init_key(struct tasklet_struct *t,
    + const char *name, struct lock_class_key *key,
    + void (*func)(unsigned long), unsigned long data);
    +
    +#ifdef CONFIG_LOCKDEP
    +#define tasklet_init(t, f, d) \
    + do { \
    + static struct lock_class_key __key; \
    + tasklet_init_key((t), #t, &__key, (f), (d)); \
    + } while (0)
    +#else
    +#define tasklet_init(t, f, d) tasklet_init_key((t), NULL, NULL, (f), (d))
    +#endif

    /*
    * Autoprobing for irqs:
    --- wireless-testing.orig/kernel/softirq.c 2008-10-23 21:46:26.808921693 +0200
    +++ wireless-testing/kernel/softirq.c 2008-10-23 22:01:34.382734952 +0200
    @@ -383,7 +383,9 @@ static void tasklet_action(struct softir
    if (!atomic_read(&t->count)) {
    if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
    BUG();
    + lock_map_acquire_noirq(&t->lock_map);
    t->func(t->data);
    + lock_map_release(&t->lock_map);
    tasklet_unlock(t);
    continue;
    }
    @@ -435,17 +437,19 @@ static void tasklet_hi_action(struct sof
    }


    -void tasklet_init(struct tasklet_struct *t,
    - void (*func)(unsigned long), unsigned long data)
    +void tasklet_init_key(struct tasklet_struct *t,
    + const char *name, struct lock_class_key *key,
    + void (*func)(unsigned long), unsigned long data)
    {
    t->next = NULL;
    t->state = 0;
    atomic_set(&t->count, 0);
    t->func = func;
    t->data = data;
    + lockdep_init_map(&t->lock_map, name, key, 0);
    }

    -EXPORT_SYMBOL(tasklet_init);
    +EXPORT_SYMBOL(tasklet_init_key);

    void tasklet_kill(struct tasklet_struct *t)
    {


    --
    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/

  5. Re: [PATCH 1/2] lockdep: implement full check without irq checking

    On Thu, 2008-10-23 at 21:44 +0200, Johannes Berg wrote:
    > This patch implements a new check type "3" which means "full validation
    > but without irq tracing" in order to allow some certain fake locks that
    > are only added for deadlock detection to not cause inconsistent state
    > warnings which would be inappropriate for them.


    This thing worries me, can you help my exhausted brain a long a little..

    So I take it the idea is to couple the lock chains of the site calling
    del_timer_sync and the actual timer.

    We do this by holding a fake lock while executing the timer, so that its
    lock chain starts with that lock.

    We then acquire the fake lock on del_timer_sync so as to establish a
    relation.

    Now you get warnings about using a lock in hardirq context that was
    previously used !irq-safe, right?

    So why not simply write something like:


    del_timer_sync():

    local_irq_save(flags);
    lock_aquire(my fake timer lock);
    lock_release(...);
    local_irq_restore(flags);

    and make that conditional CONFIG_PROVE_LOCKING and or wrap it up
    somewhere..



    --
    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/

  6. Re: [PATCH 1/2] lockdep: implement full check without irq checking

    On Wed, 2008-10-29 at 16:23 +0100, Peter Zijlstra wrote:

    > This thing worries me, can you help my exhausted brain a long a little..
    >
    > So I take it the idea is to couple the lock chains of the site calling
    > del_timer_sync and the actual timer.
    >
    > We do this by holding a fake lock while executing the timer, so that its
    > lock chain starts with that lock.
    >
    > We then acquire the fake lock on del_timer_sync so as to establish a
    > relation.


    Right. Same way as the workqueue code. Mind you, I'm not sure this is
    even worth it, in running it I haven't found a bug and I because timer
    code may not sleep you can only take spinlocks in them, and I suspect
    that it's unlikely somebody will try to cancel_sync a timer under a
    spinlock, though it is of course possible.

    > Now you get warnings about using a lock in hardirq context that was
    > previously used !irq-safe, right?
    >
    > So why not simply write something like:
    >
    >
    > del_timer_sync():
    >
    > local_irq_save(flags);
    > lock_aquire(my fake timer lock);
    > lock_release(...);
    > local_irq_restore(flags);
    >
    > and make that conditional CONFIG_PROVE_LOCKING and or wrap it up
    > somewhere..


    Yeah, that is possible, but it seemed to me that would affect the
    performance of del_timer_sync() quite a bit. Not sure it matters. And on
    powerpc (which I care about) it won't actually affect performance much
    because we lazily disable IRQs, but still. The >= 2 change also seemed
    to generate smaller code?

    johannes

    -----BEGIN PGP SIGNATURE-----
    Comment: Johannes Berg (powerbook)

    iQIcBAABAgAGBQJJCY4vAAoJEKVg1VMiehFYmuYP/RM2SKJa24dMSQhjMQG77p06
    lujYuaHJbOhLMBePOknVFz2YecqAurpL/HgrK38i/qgnkxIisensbWU4RMpEBkNy
    JWxV7ulALV8kPIbj1/2ibmROBXyJ5AIC+Z3BeIpNbgLUWY/MA1fMwhj9E53yxzP2
    nNOSqDdUPUW/07Ii+R0bsWdA+D6l8X5X73JPKMJ1kP9Cao5MafFodNew1XJ5DO S7
    +LOZEuwBJ5NVTPEoh+7MSkoWVPJHdgcVl0doMrDmHvE5q5RBr8 j9Tu8e/rkrf5jK
    c/bIUMBTEnEfh0xvLeT93JbTA4o0eElZT/SBhKTmRWyJy3USRuh9mrjiWH1kAG1O
    8gS0qC6oXXDBbURB5yQVDt2PlrPOFJo/viX4gMwioLfFIQ22u8QuYUyZSZL8e6db
    WN4cGho02RekvKpMoQvJklrRdbzHkMC0zujCSSb7EZZvBusPhS O0c6av9e8na4gJ
    nM8LGm5KmGV+tQBtF4gs909CVOE2KU+OrrpSYp9cmtmB9rdDTJ 22CiERLcIbZUdx
    DTtDi/mdJ0V2MvcNnXljyfwZcvPW+fU2yZeesBMoi7Q/RFgdLI0JIzWI5IHdHOmU
    gpFSDvsKmDzcEeSN40cxALAXzg9jZZHxBEHwCW/SPDsSkai0o76UIP/JpH0GJEi5
    e/g2BIEPy9ThTLnhOGC3
    =3Jm2
    -----END PGP SIGNATURE-----


  7. Re: [PATCH 1/2] lockdep: implement full check without irq checking

    On Thu, 2008-10-30 at 11:36 +0100, Johannes Berg wrote:

    > > del_timer_sync():
    > >
    > > local_irq_save(flags);
    > > lock_aquire(my fake timer lock);
    > > lock_release(...);
    > > local_irq_restore(flags);
    > >
    > > and make that conditional CONFIG_PROVE_LOCKING and or wrap it up
    > > somewhere..

    >
    > Yeah, that is possible, but it seemed to me that would affect the
    > performance of del_timer_sync() quite a bit. Not sure it matters. And on
    > powerpc (which I care about) it won't actually affect performance much
    > because we lazily disable IRQs, but still. The >= 2 change also seemed
    > to generate smaller code?


    Its debug code, and I the >= 2 change makes the code much less obvious.

    So I prefer the slightly less performant but conceptually cleaner IRQ
    disable variant.


    --
    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/

  8. Re: [PATCH 1/2] lockdep: implement full check without irq checking

    On Thu, 2008-10-30 at 12:15 +0100, Peter Zijlstra wrote:
    > On Thu, 2008-10-30 at 11:36 +0100, Johannes Berg wrote:
    >
    > > > del_timer_sync():
    > > >
    > > > local_irq_save(flags);
    > > > lock_aquire(my fake timer lock);
    > > > lock_release(...);
    > > > local_irq_restore(flags);
    > > >
    > > > and make that conditional CONFIG_PROVE_LOCKING and or wrap it up
    > > > somewhere..

    > >
    > > Yeah, that is possible, but it seemed to me that would affect the
    > > performance of del_timer_sync() quite a bit. Not sure it matters. And on
    > > powerpc (which I care about) it won't actually affect performance much
    > > because we lazily disable IRQs, but still. The >= 2 change also seemed
    > > to generate smaller code?

    >
    > Its debug code, and I the >= 2 change makes the code much less obvious.
    >
    > So I prefer the slightly less performant but conceptually cleaner IRQ
    > disable variant.


    Alright. Thomas, shout if you want this code at all, then I'll clean it
    up and resend, I don't particularly care, just did it to see if it was
    possible.

    johannes

    -----BEGIN PGP SIGNATURE-----
    Comment: Johannes Berg (powerbook)

    iQIcBAABAgAGBQJJCZmNAAoJEKVg1VMiehFYSH4P/1UiVE7d+VhZQB+zVV2eNBQH
    kW08sR0tKyXqCmLJWfxy13L2sVJ3YnAmhcCTVOXRlu/q4Z4C3WylYBrpuF+GDY5T
    gJTRK2KatXoX6ze6OwmGKf6nmh6q8p2jpMqR8DZxwLh5lX98be 6MVi8SBFwL4XHi
    wGJ+H+ZvWf7q/QeC26OMEwaCgKuoLXjTRVTa2DwZR/NfjySOUHT6VW6+q9feAkvf
    l8PuaRehnl/WkgO2kxoe1scPjMFtxpeYi2Ganf3IjXjkWJU5CiP5bVsNvUc2l 0Wi
    +zHL5iLNg6w474HlQUjbAvjB0SAEEIr4AFsHPjD+e/IsOsBil3Avz8F1zECcy5zd
    buz5m5+eETeaBpKGbWqHAC/4cD2P/wxIgdcxGii/PJZvEVAcHdnpSP+K9HcTigte
    d9/Z3doHLK/DX49WA1rMx1LwgAHgh4asVLwzjleqTGkjuY86G8N5xIcR1eQK3 tnr
    Zt67TFKCeCDH+yURoqufUBEitA9C7bIdFbsKocNbTLDah/L+L5KbyqWsX/9KtOP4
    0YbOKgMu4+8xzx3lLL/sfrNQ+oz73LAAb9awGYjkeJ0i6vsOIgl/2Zc35thV/5iL
    eiAl0PeunVAUPxDD7e9cNfBbDtmufOXW9j0eUbo2K/st47XBn9W+Wwxg3vqQbUPh
    pESLCzQlpOtJgqrTRjNI
    =BQfu
    -----END PGP SIGNATURE-----


+ Reply to Thread