netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Benjamin Thery <benjamin.thery@bull.net>
To: Herbert Xu <herbert@gondor.apana.org.au>
Cc: davem@davemloft.net, netdev@vger.kernel.org, dlezcano@fr.ibm.com
Subject: Re: [PATCH] net: deadlock during net device unregistration
Date: Mon, 06 Oct 2008 17:19:13 +0200	[thread overview]
Message-ID: <48EA2C71.6070509@bull.net> (raw)
In-Reply-To: <E1KmLCH-0003E2-Ch@gondolin.me.apana.org.au>

Herbert Xu wrote:
> Benjamin Thery <benjamin.thery@bull.net> wrote:
>> 1. Unregister a device, the following routines are called:
>>
>> -> unregister_netdev
>>  -> rtnl_lock
>>  -> unregister_netdevice
>>  -> rtnl_unlock
>>    -> netdev_run_todo
>>      -> netdev_wait_allrefs
> 
> OK, this explains lots of dead-locks that people have been seeing.
> 
> But I think we can go a step further:
> 
> net: Fix netdev_run_todo dead-lock
> 
> Benjamin Thery tracked down a bug that explains many instances
> of the error
> 
> unregister_netdevice: waiting for %s to become free. Usage count = %d
> 
> It turns out that netdev_run_todo can dead-lock with itself if
> a second instance of it is run in a thread that will then free
> a reference to the device waited on by the first instance.
> 
> The problem is really quite silly.  We were trying to create
> parallelism where none was required.  As netdev_run_todo always
> follows a RTNL section, and that todo tasks can only be added
> with the RTNL held, by definition you should only need to wait
> for the very ones that you've added and be done with it.
> 
> There is no need for a second mutex or spinlock.
> 
> This is exactly what the following patch does.

Herbert, thank you for having looked at the issue too.

When I understood how the dead lock happened, I considered playing
with the locks in net_set_todo()/netdev_run_todo(), but as some comments
in the code in this area sounds a bit too cryptic for my brain, I didn't
dare to change them myself. :)

I guess you know a lot better than me the history behind this piece of
code and why it was done this way.

I tested your patch on my testbed during all the afternoon.
It fixes the dead lock I can easily reproduce here with net namespaces
and I didn't produce any regressions on my setup.

Benjamin

> 
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
> 
> diff --git a/net/core/dev.c b/net/core/dev.c
> index e8eb2b4..021f531 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -3808,14 +3808,11 @@ static int dev_new_index(struct net *net)
>  }
>  
>  /* Delayed registration/unregisteration */
> -static DEFINE_SPINLOCK(net_todo_list_lock);
>  static LIST_HEAD(net_todo_list);
>  
>  static void net_set_todo(struct net_device *dev)
>  {
> -	spin_lock(&net_todo_list_lock);
>  	list_add_tail(&dev->todo_list, &net_todo_list);
> -	spin_unlock(&net_todo_list_lock);
>  }
>  
>  static void rollback_registered(struct net_device *dev)
> @@ -4142,33 +4139,24 @@ static void netdev_wait_allrefs(struct net_device *dev)
>   *	free_netdev(y1);
>   *	free_netdev(y2);
>   *
> - * We are invoked by rtnl_unlock() after it drops the semaphore.
> + * We are invoked by rtnl_unlock().
>   * This allows us to deal with problems:
>   * 1) We can delete sysfs objects which invoke hotplug
>   *    without deadlocking with linkwatch via keventd.
>   * 2) Since we run with the RTNL semaphore not held, we can sleep
>   *    safely in order to wait for the netdev refcnt to drop to zero.
> + *
> + * We must not return until all unregister events added during
> + * the interval the lock was held have been completed.
>   */
> -static DEFINE_MUTEX(net_todo_run_mutex);
>  void netdev_run_todo(void)
>  {
>  	struct list_head list;
>  
> -	/* Need to guard against multiple cpu's getting out of order. */
> -	mutex_lock(&net_todo_run_mutex);
> -
> -	/* Not safe to do outside the semaphore.  We must not return
> -	 * until all unregister events invoked by the local processor
> -	 * have been completed (either by this todo run, or one on
> -	 * another cpu).
> -	 */
> -	if (list_empty(&net_todo_list))
> -		goto out;
> -
>  	/* Snapshot list, allow later requests */
> -	spin_lock(&net_todo_list_lock);
>  	list_replace_init(&net_todo_list, &list);
> -	spin_unlock(&net_todo_list_lock);
> +
> +	__rtnl_unlock();
>  
>  	while (!list_empty(&list)) {
>  		struct net_device *dev
> @@ -4200,9 +4188,6 @@ void netdev_run_todo(void)
>  		/* Free network device */
>  		kobject_put(&dev->dev.kobj);
>  	}
> -
> -out:
> -	mutex_unlock(&net_todo_run_mutex);
>  }
>  
>  static struct net_device_stats *internal_stats(struct net_device *dev)
> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
> index 71edb8b..d6381c2 100644
> --- a/net/core/rtnetlink.c
> +++ b/net/core/rtnetlink.c
> @@ -73,7 +73,7 @@ void __rtnl_unlock(void)
>  
>  void rtnl_unlock(void)
>  {
> -	mutex_unlock(&rtnl_mutex);
> +	/* This fellow will unlock it for us. */
>  	netdev_run_todo();
>  }
>  
> Cheers,


-- 
B e n j a m i n   T h e r y  - BULL/DT/Open Software R&D

    http://www.bull.com

  parent reply	other threads:[~2008-10-06 15:19 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20080929175412.866679567@theryb.frec.bull.fr>
2008-09-29 17:54 ` [PATCH] net: deadlock during net device unregistration Benjamin Thery
2008-09-30  6:32   ` Jarek Poplawski
2008-09-30 11:52     ` Benjamin Thery
2008-09-30 13:58       ` David Miller
2008-09-30 14:07         ` Benjamin Thery
2008-09-30 14:42       ` Jarek Poplawski
2008-09-30 14:57         ` Jarek Poplawski
2008-09-30 15:18           ` Benjamin Thery
2008-10-01  9:59             ` David Miller
2008-10-01 10:10               ` Daniel Lezcano
2008-10-01 10:12                 ` David Miller
2008-10-01 14:14                   ` [PATCH] net: deadlock during net device unregistration - V2 Benjamin Thery
2008-10-01 19:48                     ` Jarek Poplawski
2008-10-01 21:06                       ` Daniel Lezcano
2008-10-01 21:52                         ` Jarek Poplawski
2008-10-01 23:31                         ` Jarek Poplawski
2008-10-02 15:23                           ` Benjamin Thery
2008-10-02 18:38                             ` Jarek Poplawski
2008-10-02 19:55                               ` Benjamin Thery 
2008-10-02 20:34                                 ` Jarek Poplawski
2008-10-04  7:42                                   ` Jarek Poplawski
2008-10-04  7:52                                     ` Jarek Poplawski
2008-10-03  0:41   ` [PATCH] net: deadlock during net device unregistration Eric W. Biederman
2008-10-05  4:26   ` Herbert Xu
2008-10-05  6:55     ` Jarek Poplawski
2008-10-05  6:56       ` Herbert Xu
2008-10-05  7:12         ` Jarek Poplawski
2008-10-05  7:28           ` Stephen Hemminger
2008-10-05  7:38             ` Herbert Xu
2008-10-05  7:39           ` Herbert Xu
2008-10-06 15:19     ` Benjamin Thery [this message]
2008-10-07 22:46       ` David Miller
2008-10-07 22:50     ` David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=48EA2C71.6070509@bull.net \
    --to=benjamin.thery@bull.net \
    --cc=davem@davemloft.net \
    --cc=dlezcano@fr.ibm.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).