From: Jarek Poplawski <jarkao2@gmail.com>
To: Jay Vosburgh <fubar@us.ibm.com>
Cc: Jiri Bohac <jbohac@suse.cz>,
bonding-devel@lists.sourceforge.net, markine@google.com,
chavey@google.com, netdev@vger.kernel.org
Subject: Re: [RFC] bonding: fix workqueue re-arming races
Date: Wed, 1 Sep 2010 12:23:56 +0000 [thread overview]
Message-ID: <20100901122356.GB9468@ff.dom.local> (raw)
In-Reply-To: <20136.1283288063@death>
On 2010-08-31 22:54, Jay Vosburgh wrote:
> Jiri Bohac <jbohac@suse.cz> wrote:
>
>> Hi,
>>
>> this is another attempt to solve the bonding workqueue re-arming
>> races.
>>
>> The issue has been thoroughly discussed here:
>> http://article.gmane.org/gmane.linux.network/146949 "[PATCH]
>> bonding: cancel_delayed_work() -> cancel_delayed_work_sync()"
>> However, the only outcome was a proposal for an ugly hack with
>> busy-waiting on the rtnl.
>>
>> The problem:
>> Bonding uses delayed work that automatically re-arms itself,
>> e.g.: bond_mii_monitor().
>>
>> A dev->close() quickly followed by dev->open() on the bonding
>> master has a race condition. bond_close() sets kill_timers=1 and
>> calls cancel_delayed_work(), hoping that bond_mii_monitor() will
>> not re-arm again anymore. There are two problems with this:
>>
>> - bond->kill_timers is not re-checked after re-acquiring the
>> bond->lock (this would be easy to fix)
>>
>> - bond_open() resets bond->kill_timers to 0. If this happens
>> before bond_mii_monitor() notices the flag and exits, it will
>> re-arm itself. bond_open() then tries to schedule the delayed
>> work, which causes a BUG.
>>
>> The issue would be solved by calling cancel_delayed_work_sync(),
>> but this can not be done from bond_close() since it is called
>> under rtnl and the delayed work locks rtnl itself.
>>
>> My proposal is to move all the "commit" work that requires rtnl
>> to a separate work and schedule it on the bonding wq. Thus, the
>> re-arming work does not need rtnl and can be cancelled using
>> cancel_delayed_work_sync().
>>
>> Comments?
Looks mostly OK to me, but a bit more below...
>>
>> [note, this does not deal with bond_loadbalance_arp_mon(), where
>> rtnl is now taken as well in net-next; I'll do this if you think
>> the idea is good ]
>
> I don't believe the loadbalance_arp_mon acquires RTNL in
> net-next. I recall discussing this with Andy not too long ago, but I
> didn't think that change went in, and I don't see it in the tree.
>
>> Signed-off-by: Jiri Bohac <jbohac@suse.cz>
>>
>> diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
>> index 822f586..8015e12 100644
>> --- a/drivers/net/bonding/bond_3ad.c
>> +++ b/drivers/net/bonding/bond_3ad.c
>> @@ -2119,10 +2119,6 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
>>
>> read_lock(&bond->lock);
>>
>> - if (bond->kill_timers) {
>> - goto out;
>> - }
>> -
>> //check if there are any slaves
>> if (bond->slave_cnt == 0) {
>> goto re_arm;
>> @@ -2166,7 +2162,6 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
>>
>> re_arm:
>> queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
>> -out:
>> read_unlock(&bond->lock);
>> }
>>
>> diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
>> index c746b33..250d027 100644
>> --- a/drivers/net/bonding/bond_alb.c
>> +++ b/drivers/net/bonding/bond_alb.c
>> @@ -1397,6 +1397,23 @@ out:
>> return NETDEV_TX_OK;
>> }
>>
>> +void bond_alb_promisc_disable(struct work_struct *work)
>> +{
>> + struct bonding *bond = container_of(work, struct bonding,
>> + alb_promisc_disable_work);
>> + struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
>> +
>> + /*
>> + * dev_set_promiscuity requires rtnl and
>> + * nothing else.
>> + */
>> + rtnl_lock();
>> + dev_set_promiscuity(bond->curr_active_slave->dev, -1);
>> + bond_info->primary_is_promisc = 0;
>> + bond_info->rlb_promisc_timeout_counter = 0;
>> + rtnl_unlock();
>> +}
>
> What prevents this from deadlocking such that cpu A is in
> bond_close, holding RTNL and in cancel_delayed_work_sync, while cpu B is
> in the above function, trying to acquire RTNL?
I guess this one isn't cancelled in bond_close, so it should be safe.
>
> Also, assuming for the moment that the above isn't a problem,
> curr_active_slave may be NULL if the last slave is removed between the
> time bond_alb_promisc_disable is scheduled and when it runs. I'm not
> sure that the alb_bond_info can be guaranteed to be valid, either, if
> the mode changed.
Probably some or all of these work functions should test for closing
eg. with netif_running() or some other flag/variable under rtnl_lock().
....
>> static void bond_work_cancel_all(struct bonding *bond)
>> {
>> - write_lock_bh(&bond->lock);
>> - bond->kill_timers = 1;
>> - write_unlock_bh(&bond->lock);
>> -
>> if (bond->params.miimon && delayed_work_pending(&bond->mii_work))
I'd suggest to skip these delayed_work_pending() tests.
Thanks,
Jarek P.
>> - cancel_delayed_work(&bond->mii_work);
>> + cancel_delayed_work_sync(&bond->mii_work);
...
next prev parent reply other threads:[~2010-09-01 12:24 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-08-31 17:07 [RFC] bonding: fix workqueue re-arming races Jiri Bohac
2010-08-31 20:54 ` Jay Vosburgh
2010-09-01 12:23 ` Jarek Poplawski [this message]
2010-09-01 13:30 ` Jiri Bohac
2010-09-01 15:18 ` Jarek Poplawski
2010-09-01 15:37 ` Jarek Poplawski
2010-09-01 19:00 ` Jarek Poplawski
2010-09-01 19:11 ` Jiri Bohac
2010-09-01 19:20 ` Jarek Poplawski
2010-09-01 19:38 ` Jarek Poplawski
2010-09-01 19:46 ` Jay Vosburgh
2010-09-01 20:06 ` Jarek Poplawski
2010-09-01 13:16 ` Jiri Bohac
2010-09-01 17:14 ` Jay Vosburgh
2010-09-01 18:31 ` Jiri Bohac
2010-09-01 20:00 ` Jay Vosburgh
2010-09-01 20:56 ` Jiri Bohac
2010-09-02 0:54 ` Jay Vosburgh
2010-09-02 17:08 ` Jiri Bohac
2010-09-09 0:06 ` Jay Vosburgh
2010-09-16 22:44 ` Jay Vosburgh
2010-09-24 11:23 ` Narendra K
2010-10-01 18:22 ` Jiri Bohac
2010-10-05 15:03 ` Narendra_K
2010-10-06 7:36 ` Narendra_K
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=20100901122356.GB9468@ff.dom.local \
--to=jarkao2@gmail.com \
--cc=bonding-devel@lists.sourceforge.net \
--cc=chavey@google.com \
--cc=fubar@us.ibm.com \
--cc=jbohac@suse.cz \
--cc=markine@google.com \
--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).