2003-03-29 22:22:19

by Shawn Starr

[permalink] [raw]
Subject: Re: [OOPS][2.5.66bk3+] run_timer_softirq - IRQ Mishandlings

Perhaps adding this to the kernel as a config option might be handy for
people looking for not freed timers?

Shawn.

----- Original Message -----
From: "Andrew Morton" <[email protected]>
To: "Shawn Starr" <[email protected]>
Cc: <[email protected]>; <[email protected]>
Sent: Saturday, March 29, 2003 5:28 PM
Subject: Re: [OOPS][2.5.66bk3+] run_timer_softirq - IRQ Mishandlings


> "Shawn Starr" <[email protected]> wrote:
> >
> > How can I go about debugging this? How can I find the path causing the
> > problem?
> >
>
> Someone did
>
> kfree(foo);
>
> insead of
>
> del_timer_sync(&foo->timer);
> kfree(foo);
>
> so you have a freed-but-pending timer.
>
>
> This is a horrid bug. One way to find it would be to change
> cache_free_debugcheck() to walk the just-freed-up memory looking for an
> instance of TIMER_MAGIC. If that is found and timer_pending() is true
then
> drop a backtrace and print out timer->function.
>
> err.... Here you go, this may find it.
>
>
>
> fs/open.c | 33 +++++++++++++++++++++++++++++++++
> include/linux/timer.h | 3 ++-
> mm/slab.c | 30 ++++++++++++++++++++++++++++++
> 3 files changed, 65 insertions(+), 1 deletion(-)
>
> diff -puN include/linux/timer.h~freed-timer-finder include/linux/timer.h
> --- 25/include/linux/timer.h~freed-timer-finder 2003-03-29
14:10:15.000000000 -0800
> +++ 25-akpm/include/linux/timer.h 2003-03-29 14:10:26.000000000 -0800
> @@ -8,11 +8,12 @@
> struct tvec_t_base_s;
>
> struct timer_list {
> + unsigned long magic;
> +
> struct list_head entry;
> unsigned long expires;
>
> spinlock_t lock;
> - unsigned long magic;
>
> void (*function)(unsigned long);
> unsigned long data;
> diff -puN mm/slab.c~freed-timer-finder mm/slab.c
> --- 25/mm/slab.c~freed-timer-finder 2003-03-29 14:10:30.000000000 -0800
> +++ 25-akpm/mm/slab.c 2003-03-29 14:16:23.000000000 -0800
> @@ -800,6 +800,35 @@ static void poison_obj(kmem_cache_t *cac
> *(unsigned char *)(addr+size-1) = POISON_END;
> }
>
> +static void timer_hunt(kmem_cache_t *cachep, void *addr)
> +{
> + int size = cachep->objsize;
> + void *p;
> +
> + if (cachep->flags & SLAB_RED_ZONE) {
> + addr += BYTES_PER_WORD;
> + size -= 2*BYTES_PER_WORD;
> + }
> + if (cachep->flags & SLAB_STORE_USER) {
> + size -= BYTES_PER_WORD;
> + }
> +
> + for (p = addr; p < addr + size; p += sizeof(unsigned long)) {
> + unsigned long *laddr = p;
> +
> + if (*laddr == TIMER_MAGIC) {
> + struct timer_list *timer;
> +
> + timer = (struct timer_list *)laddr;
> + if (timer_pending(timer)) {
> + printk("free of pending timer at %p\n", timer);
> + printk("function=%p\n", timer->function);
> + dump_stack();
> + }
> + }
> + }
> +}
> +
> static void *fprob(unsigned char* addr, unsigned int size)
> {
> unsigned char *end;
> @@ -1603,6 +1632,7 @@ static inline void *cache_free_debugchec
> else
> cachep->dtor(objp, cachep, 0);
> }
> + timer_hunt(cachep, objp);
> if (cachep->flags & SLAB_POISON)
> poison_obj(cachep, objp, POISON_AFTER);
> #endif
> diff -puN fs/open.c~freed-timer-finder fs/open.c
> --- 25/fs/open.c~freed-timer-finder 2003-03-29 14:17:32.000000000 -0800
> +++ 25-akpm/fs/open.c 2003-03-29 14:21:20.000000000 -0800
> @@ -793,11 +793,44 @@ void fd_install(unsigned int fd, struct
> write_unlock(&files->file_lock);
> }
>
> +#include <linux/timer.h>
> +
> +struct foo_thing {
> + int a;
> + struct timer_list t;
> + int b;
> +};
> +
> +static void my_foo(unsigned long data)
> +{
> + printk("the handler\n");
> +}
> +
> +static void timer_thing(void)
> +{
> + static int did_it;
> + struct foo_thing *f;
> +
> + if (did_it)
> + return;
> + did_it = 1;
> +
> + f = kmalloc(sizeof(*f), GFP_KERNEL);
> + init_timer(&f->t);
> + f->t.expires = jiffies + HZ;
> + f->t.function = my_foo;
> + add_timer(&f->t);
> + kfree(f);
> +}
> +
> asmlinkage long sys_open(const char * filename, int flags, int mode)
> {
> char * tmp;
> int fd, error;
>
> + if (current->uid == 9999)
> + timer_thing();
> +
> #if BITS_PER_LONG != 32
> flags |= O_LARGEFILE;
> #endif
>
> _
>
>