From: Marcelo Ricardo Leitner <mleitner@redhat.com>
To: Neil Horman <nhorman@tuxdriver.com>
Cc: netdev@vger.kernel.org, linux-sctp@vger.kernel.org,
Daniel Borkmann <daniel@iogearbox.net>,
Vlad Yasevich <vyasevich@gmail.com>,
Michio Honda <micchie@sfc.wide.ad.jp>
Subject: Re: [PATCH v2 1/2] sctp: rcu-ify addr_waitq
Date: Fri, 05 Jun 2015 14:18:30 +0000 [thread overview]
Message-ID: <20150605141830.GM3387@localhost.localdomain> (raw)
In-Reply-To: <20150604142710.GD24585@hmsreliant.think-freely.org>
On Thu, Jun 04, 2015 at 10:27:10AM -0400, Neil Horman wrote:
> On Wed, Jun 03, 2015 at 01:54:01PM -0300, mleitner@redhat.com wrote:
> > From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
> >
> > That's needed for the next patch, so we break the lock inversion between
> > netns_sctp->addr_wq_lock and socket lock on
> > sctp_addr_wq_timeout_handler(). With this, we can traverse addr_waitq
> > without taking addr_wq_lock, taking it just for the write operations.
> >
> > Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
> > ---
> >
> > Notes:
> > v1->v2:
> > As asked by Neil, this now reuses addr_wq_lock. And for that, also
> > rcu-ifyies addr_waitq.
> >
> > include/net/netns/sctp.h | 2 +-
> > net/sctp/protocol.c | 81 +++++++++++++++++++++++++++++-------------------
> > 2 files changed, 50 insertions(+), 33 deletions(-)
> >
> > diff --git a/include/net/netns/sctp.h b/include/net/netns/sctp.h
> > index 3573a81815ad9e0efb6ceb721eb066d3726419f0..9e53412c4ed829e8e45777a6d95406d490dbaa75 100644
> > --- a/include/net/netns/sctp.h
> > +++ b/include/net/netns/sctp.h
> > @@ -28,7 +28,7 @@ struct netns_sctp {
> > * It is a list of sctp_sockaddr_entry.
> > */
> > struct list_head local_addr_list;
> > - struct list_head addr_waitq;
> > + struct list_head __rcu addr_waitq;
> > struct timer_list addr_wq_timer;
> > struct list_head auto_asconf_splist;
> > spinlock_t addr_wq_lock;
> > diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
> > index 53b7acde9aa37bf3d4029c459421564d5270f4c0..a5089883b28195f3aef69ef35b5397322a01126f 100644
> > --- a/net/sctp/protocol.c
> > +++ b/net/sctp/protocol.c
> > @@ -593,15 +593,46 @@ static void sctp_v4_ecn_capable(struct sock *sk)
> > INET_ECN_xmit(sk);
> > }
> >
> > +static void sctp_free_addr_wq(struct net *net)
> > +{
> > + struct sctp_sockaddr_entry *addrw;
> > +
> > + spin_lock_bh(&net->sctp.addr_wq_lock);
> > + del_timer(&net->sctp.addr_wq_timer);
> > + list_for_each_entry_rcu(addrw, &net->sctp.addr_waitq, list) {
> > + list_del_rcu(&addrw->list);
> > + kfree_rcu(addrw, rcu);
> > + }
> > + spin_unlock_bh(&net->sctp.addr_wq_lock);
> > +}
> > +
> > +/* As there is no refcnt on sctp_sockaddr_entry, we must check inside
> > + * the lock if it wasn't removed from addr_waitq already, otherwise we
> > + * could double-free it.
> > + */
> > +static void sctp_free_addr_wq_entry(struct net *net,
> > + struct sctp_sockaddr_entry *addrw)
> > +{
> > + struct sctp_sockaddr_entry *temp;
> > +
> > + spin_lock_bh(&net->sctp.addr_wq_lock);
> > + list_for_each_entry_rcu(temp, &net->sctp.addr_waitq, list) {
> > + if (temp = addrw) {
> > + list_del_rcu(&addrw->list);
> > + kfree_rcu(addrw, rcu);
> > + }
> > + }
> > + spin_unlock_bh(&net->sctp.addr_wq_lock);
> > +}
> > +
> > static void sctp_addr_wq_timeout_handler(unsigned long arg)
> > {
> > struct net *net = (struct net *)arg;
> > - struct sctp_sockaddr_entry *addrw, *temp;
> > + struct sctp_sockaddr_entry *addrw;
> > struct sctp_sock *sp;
> >
> > - spin_lock_bh(&net->sctp.addr_wq_lock);
> > -
> > - list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
> > + rcu_read_lock_bh();
> > + list_for_each_entry_rcu(addrw, &net->sctp.addr_waitq, list) {
> > pr_debug("%s: the first ent in wq:%p is addr:%pISc for cmd:%d at "
> > "entry:%p\n", __func__, &net->sctp.addr_waitq, &addrw->a.sa,
> > addrw->state, addrw);
> > @@ -627,7 +658,9 @@ static void sctp_addr_wq_timeout_handler(unsigned long arg)
> >
> > timeo_val = jiffies;
> > timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
> > + spin_lock_bh(&net->sctp.addr_wq_lock);
> > mod_timer(&net->sctp.addr_wq_timer, timeo_val);
> > + spin_unlock_bh(&net->sctp.addr_wq_lock);
> Do we actually need to lock the addr_wq_lock here? mod_timer has its own
> internal locking.
No, we don't. I'll remove these.
> > break;
> > }
> > }
> > @@ -647,35 +680,20 @@ static void sctp_addr_wq_timeout_handler(unsigned long arg)
> > #if IS_ENABLED(CONFIG_IPV6)
> > free_next:
> > #endif
> > - list_del(&addrw->list);
> > - kfree(addrw);
> > - }
> > - spin_unlock_bh(&net->sctp.addr_wq_lock);
> > -}
> > -
> > -static void sctp_free_addr_wq(struct net *net)
> > -{
> > - struct sctp_sockaddr_entry *addrw;
> > - struct sctp_sockaddr_entry *temp;
> > -
> > - spin_lock_bh(&net->sctp.addr_wq_lock);
> > - del_timer(&net->sctp.addr_wq_timer);
> > - list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
> > - list_del(&addrw->list);
> > - kfree(addrw);
> > + sctp_free_addr_wq_entry(net, addrw);
> > }
> > - spin_unlock_bh(&net->sctp.addr_wq_lock);
> > + rcu_read_unlock_bh();
> > }
> >
> > /* lookup the entry for the same address in the addr_waitq
> > - * sctp_addr_wq MUST be locked
> > + * rcu read MUST be locked
> > */
> > static struct sctp_sockaddr_entry *sctp_addr_wq_lookup(struct net *net,
> > struct sctp_sockaddr_entry *addr)
> > {
> > struct sctp_sockaddr_entry *addrw;
> >
> > - list_for_each_entry(addrw, &net->sctp.addr_waitq, list) {
> > + list_for_each_entry_rcu(addrw, &net->sctp.addr_waitq, list) {
> > if (addrw->a.sa.sa_family != addr->a.sa.sa_family)
> > continue;
> > if (addrw->a.sa.sa_family = AF_INET) {
> > @@ -702,7 +720,7 @@ void sctp_addr_wq_mgmt(struct net *net, struct sctp_sockaddr_entry *addr, int cm
> > * new address after a couple of addition and deletion of that address
> > */
> >
> > - spin_lock_bh(&net->sctp.addr_wq_lock);
> > + rcu_read_lock_bh();
> > /* Offsets existing events in addr_wq */
> > addrw = sctp_addr_wq_lookup(net, addr);
> > if (addrw) {
> > @@ -710,22 +728,21 @@ void sctp_addr_wq_mgmt(struct net *net, struct sctp_sockaddr_entry *addr, int cm
> > pr_debug("%s: offsets existing entry for %d, addr:%pISc "
> > "in wq:%p\n", __func__, addrw->state, &addrw->a.sa,
> > &net->sctp.addr_waitq);
> > -
> > - list_del(&addrw->list);
> > - kfree(addrw);
> > + sctp_free_addr_wq_entry(net, addrw);
> > }
> > - spin_unlock_bh(&net->sctp.addr_wq_lock);
> > + rcu_read_unlock_bh();
> > return;
> > }
> > + rcu_read_unlock_bh();
> >
> > /* OK, we have to add the new address to the wait queue */
> > addrw = kmemdup(addr, sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
> > - if (addrw = NULL) {
> > - spin_unlock_bh(&net->sctp.addr_wq_lock);
> > + if (!addrw)
> > return;
> > - }
> > addrw->state = cmd;
> > - list_add_tail(&addrw->list, &net->sctp.addr_waitq);
> > +
> > + spin_lock_bh(&net->sctp.addr_wq_lock);
> > + list_add_tail_rcu(&addrw->list, &net->sctp.addr_waitq);
> >
> > pr_debug("%s: add new entry for cmd:%d, addr:%pISc in wq:%p\n",
> > __func__, addrw->state, &addrw->a.sa, &net->sctp.addr_waitq);
>
> Other than the comment above, and the break you need to insert, I think this
> looks good, thanks for taking the extra time on it!
> Best
> Neil
Cool, thx! v3 in a few.
Marcelo
WARNING: multiple messages have this Message-ID (diff)
From: Marcelo Ricardo Leitner <mleitner@redhat.com>
To: Neil Horman <nhorman@tuxdriver.com>
Cc: netdev@vger.kernel.org, linux-sctp@vger.kernel.org,
Daniel Borkmann <daniel@iogearbox.net>,
Vlad Yasevich <vyasevich@gmail.com>,
Michio Honda <micchie@sfc.wide.ad.jp>
Subject: Re: [PATCH v2 1/2] sctp: rcu-ify addr_waitq
Date: Fri, 5 Jun 2015 11:18:30 -0300 [thread overview]
Message-ID: <20150605141830.GM3387@localhost.localdomain> (raw)
In-Reply-To: <20150604142710.GD24585@hmsreliant.think-freely.org>
On Thu, Jun 04, 2015 at 10:27:10AM -0400, Neil Horman wrote:
> On Wed, Jun 03, 2015 at 01:54:01PM -0300, mleitner@redhat.com wrote:
> > From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
> >
> > That's needed for the next patch, so we break the lock inversion between
> > netns_sctp->addr_wq_lock and socket lock on
> > sctp_addr_wq_timeout_handler(). With this, we can traverse addr_waitq
> > without taking addr_wq_lock, taking it just for the write operations.
> >
> > Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
> > ---
> >
> > Notes:
> > v1->v2:
> > As asked by Neil, this now reuses addr_wq_lock. And for that, also
> > rcu-ifyies addr_waitq.
> >
> > include/net/netns/sctp.h | 2 +-
> > net/sctp/protocol.c | 81 +++++++++++++++++++++++++++++-------------------
> > 2 files changed, 50 insertions(+), 33 deletions(-)
> >
> > diff --git a/include/net/netns/sctp.h b/include/net/netns/sctp.h
> > index 3573a81815ad9e0efb6ceb721eb066d3726419f0..9e53412c4ed829e8e45777a6d95406d490dbaa75 100644
> > --- a/include/net/netns/sctp.h
> > +++ b/include/net/netns/sctp.h
> > @@ -28,7 +28,7 @@ struct netns_sctp {
> > * It is a list of sctp_sockaddr_entry.
> > */
> > struct list_head local_addr_list;
> > - struct list_head addr_waitq;
> > + struct list_head __rcu addr_waitq;
> > struct timer_list addr_wq_timer;
> > struct list_head auto_asconf_splist;
> > spinlock_t addr_wq_lock;
> > diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
> > index 53b7acde9aa37bf3d4029c459421564d5270f4c0..a5089883b28195f3aef69ef35b5397322a01126f 100644
> > --- a/net/sctp/protocol.c
> > +++ b/net/sctp/protocol.c
> > @@ -593,15 +593,46 @@ static void sctp_v4_ecn_capable(struct sock *sk)
> > INET_ECN_xmit(sk);
> > }
> >
> > +static void sctp_free_addr_wq(struct net *net)
> > +{
> > + struct sctp_sockaddr_entry *addrw;
> > +
> > + spin_lock_bh(&net->sctp.addr_wq_lock);
> > + del_timer(&net->sctp.addr_wq_timer);
> > + list_for_each_entry_rcu(addrw, &net->sctp.addr_waitq, list) {
> > + list_del_rcu(&addrw->list);
> > + kfree_rcu(addrw, rcu);
> > + }
> > + spin_unlock_bh(&net->sctp.addr_wq_lock);
> > +}
> > +
> > +/* As there is no refcnt on sctp_sockaddr_entry, we must check inside
> > + * the lock if it wasn't removed from addr_waitq already, otherwise we
> > + * could double-free it.
> > + */
> > +static void sctp_free_addr_wq_entry(struct net *net,
> > + struct sctp_sockaddr_entry *addrw)
> > +{
> > + struct sctp_sockaddr_entry *temp;
> > +
> > + spin_lock_bh(&net->sctp.addr_wq_lock);
> > + list_for_each_entry_rcu(temp, &net->sctp.addr_waitq, list) {
> > + if (temp == addrw) {
> > + list_del_rcu(&addrw->list);
> > + kfree_rcu(addrw, rcu);
> > + }
> > + }
> > + spin_unlock_bh(&net->sctp.addr_wq_lock);
> > +}
> > +
> > static void sctp_addr_wq_timeout_handler(unsigned long arg)
> > {
> > struct net *net = (struct net *)arg;
> > - struct sctp_sockaddr_entry *addrw, *temp;
> > + struct sctp_sockaddr_entry *addrw;
> > struct sctp_sock *sp;
> >
> > - spin_lock_bh(&net->sctp.addr_wq_lock);
> > -
> > - list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
> > + rcu_read_lock_bh();
> > + list_for_each_entry_rcu(addrw, &net->sctp.addr_waitq, list) {
> > pr_debug("%s: the first ent in wq:%p is addr:%pISc for cmd:%d at "
> > "entry:%p\n", __func__, &net->sctp.addr_waitq, &addrw->a.sa,
> > addrw->state, addrw);
> > @@ -627,7 +658,9 @@ static void sctp_addr_wq_timeout_handler(unsigned long arg)
> >
> > timeo_val = jiffies;
> > timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
> > + spin_lock_bh(&net->sctp.addr_wq_lock);
> > mod_timer(&net->sctp.addr_wq_timer, timeo_val);
> > + spin_unlock_bh(&net->sctp.addr_wq_lock);
> Do we actually need to lock the addr_wq_lock here? mod_timer has its own
> internal locking.
No, we don't. I'll remove these.
> > break;
> > }
> > }
> > @@ -647,35 +680,20 @@ static void sctp_addr_wq_timeout_handler(unsigned long arg)
> > #if IS_ENABLED(CONFIG_IPV6)
> > free_next:
> > #endif
> > - list_del(&addrw->list);
> > - kfree(addrw);
> > - }
> > - spin_unlock_bh(&net->sctp.addr_wq_lock);
> > -}
> > -
> > -static void sctp_free_addr_wq(struct net *net)
> > -{
> > - struct sctp_sockaddr_entry *addrw;
> > - struct sctp_sockaddr_entry *temp;
> > -
> > - spin_lock_bh(&net->sctp.addr_wq_lock);
> > - del_timer(&net->sctp.addr_wq_timer);
> > - list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
> > - list_del(&addrw->list);
> > - kfree(addrw);
> > + sctp_free_addr_wq_entry(net, addrw);
> > }
> > - spin_unlock_bh(&net->sctp.addr_wq_lock);
> > + rcu_read_unlock_bh();
> > }
> >
> > /* lookup the entry for the same address in the addr_waitq
> > - * sctp_addr_wq MUST be locked
> > + * rcu read MUST be locked
> > */
> > static struct sctp_sockaddr_entry *sctp_addr_wq_lookup(struct net *net,
> > struct sctp_sockaddr_entry *addr)
> > {
> > struct sctp_sockaddr_entry *addrw;
> >
> > - list_for_each_entry(addrw, &net->sctp.addr_waitq, list) {
> > + list_for_each_entry_rcu(addrw, &net->sctp.addr_waitq, list) {
> > if (addrw->a.sa.sa_family != addr->a.sa.sa_family)
> > continue;
> > if (addrw->a.sa.sa_family == AF_INET) {
> > @@ -702,7 +720,7 @@ void sctp_addr_wq_mgmt(struct net *net, struct sctp_sockaddr_entry *addr, int cm
> > * new address after a couple of addition and deletion of that address
> > */
> >
> > - spin_lock_bh(&net->sctp.addr_wq_lock);
> > + rcu_read_lock_bh();
> > /* Offsets existing events in addr_wq */
> > addrw = sctp_addr_wq_lookup(net, addr);
> > if (addrw) {
> > @@ -710,22 +728,21 @@ void sctp_addr_wq_mgmt(struct net *net, struct sctp_sockaddr_entry *addr, int cm
> > pr_debug("%s: offsets existing entry for %d, addr:%pISc "
> > "in wq:%p\n", __func__, addrw->state, &addrw->a.sa,
> > &net->sctp.addr_waitq);
> > -
> > - list_del(&addrw->list);
> > - kfree(addrw);
> > + sctp_free_addr_wq_entry(net, addrw);
> > }
> > - spin_unlock_bh(&net->sctp.addr_wq_lock);
> > + rcu_read_unlock_bh();
> > return;
> > }
> > + rcu_read_unlock_bh();
> >
> > /* OK, we have to add the new address to the wait queue */
> > addrw = kmemdup(addr, sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
> > - if (addrw == NULL) {
> > - spin_unlock_bh(&net->sctp.addr_wq_lock);
> > + if (!addrw)
> > return;
> > - }
> > addrw->state = cmd;
> > - list_add_tail(&addrw->list, &net->sctp.addr_waitq);
> > +
> > + spin_lock_bh(&net->sctp.addr_wq_lock);
> > + list_add_tail_rcu(&addrw->list, &net->sctp.addr_waitq);
> >
> > pr_debug("%s: add new entry for cmd:%d, addr:%pISc in wq:%p\n",
> > __func__, addrw->state, &addrw->a.sa, &net->sctp.addr_waitq);
>
> Other than the comment above, and the break you need to insert, I think this
> looks good, thanks for taking the extra time on it!
> Best
> Neil
Cool, thx! v3 in a few.
Marcelo
next prev parent reply other threads:[~2015-06-05 14:18 UTC|newest]
Thread overview: 68+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-28 0:52 [PATCH] sctp: fix ASCONF list handling mleitner
2015-05-28 0:52 ` mleitner
2015-05-28 10:15 ` Neil Horman
2015-05-28 10:15 ` Neil Horman
2015-05-28 11:17 ` Marcelo Ricardo Leitner
2015-05-28 11:17 ` Marcelo Ricardo Leitner
2015-05-28 13:27 ` Marcelo Ricardo Leitner
2015-05-28 13:27 ` Marcelo Ricardo Leitner
2015-05-28 14:31 ` Neil Horman
2015-05-28 14:31 ` Neil Horman
2015-05-28 14:46 ` Marcelo Ricardo Leitner
2015-05-28 14:46 ` Marcelo Ricardo Leitner
2015-05-29 13:17 ` Neil Horman
2015-05-29 13:17 ` Neil Horman
2015-05-29 16:50 ` Marcelo Ricardo Leitner
2015-05-29 16:50 ` Marcelo Ricardo Leitner
2015-06-01 14:00 ` Neil Horman
2015-06-01 14:00 ` Neil Horman
2015-06-01 22:28 ` Marcelo Ricardo Leitner
2015-06-01 22:28 ` Marcelo Ricardo Leitner
2015-06-02 13:48 ` Neil Horman
2015-06-02 13:48 ` Neil Horman
2015-06-03 16:54 ` [PATCH v2 1/2] sctp: rcu-ify addr_waitq mleitner
2015-06-03 16:54 ` mleitner
2015-06-03 17:19 ` Marcelo Ricardo Leitner
2015-06-03 17:19 ` Marcelo Ricardo Leitner
2015-06-04 14:27 ` Neil Horman
2015-06-04 14:27 ` Neil Horman
2015-06-05 14:18 ` Marcelo Ricardo Leitner [this message]
2015-06-05 14:18 ` Marcelo Ricardo Leitner
2015-06-05 17:08 ` [PATCH v3 " mleitner
2015-06-05 17:08 ` mleitner
2015-06-08 13:58 ` Neil Horman
2015-06-08 13:58 ` Neil Horman
2015-06-08 14:46 ` Hannes Frederic Sowa
2015-06-08 14:46 ` Hannes Frederic Sowa
2015-06-08 14:59 ` Hannes Frederic Sowa
2015-06-08 14:59 ` Hannes Frederic Sowa
2015-06-08 15:19 ` Neil Horman
2015-06-08 15:19 ` Neil Horman
2015-06-08 15:37 ` Hannes Frederic Sowa
2015-06-08 15:37 ` Hannes Frederic Sowa
2015-06-09 11:36 ` Neil Horman
2015-06-09 11:36 ` Neil Horman
2015-06-09 19:32 ` Marcelo Ricardo Leitner
2015-06-09 19:32 ` Marcelo Ricardo Leitner
2015-06-10 13:31 ` Marcelo Ricardo Leitner
2015-06-10 13:31 ` Marcelo Ricardo Leitner
2015-06-10 19:14 ` Neil Horman
2015-06-10 19:14 ` Neil Horman
2015-06-11 14:30 ` [PATCH v4] sctp: fix ASCONF list handling mleitner
2015-06-11 14:30 ` mleitner
2015-06-11 23:31 ` David Miller
2015-06-11 23:31 ` David Miller
2015-06-12 13:16 ` [PATCH v5] " marcelo.leitner
2015-06-12 13:16 ` marcelo.leitner
2015-06-14 19:56 ` David Miller
2015-06-14 19:56 ` David Miller
2015-06-05 17:08 ` [PATCH v3 2/2] " mleitner
2015-06-05 17:08 ` mleitner
2015-06-08 20:09 ` Hannes Frederic Sowa
2015-06-08 20:09 ` Hannes Frederic Sowa
2015-06-09 15:37 ` Marcelo Ricardo Leitner
2015-06-09 15:37 ` Marcelo Ricardo Leitner
2015-06-09 17:04 ` Neil Horman
2015-06-09 17:04 ` Neil Horman
2015-06-03 16:54 ` [PATCH v2 " mleitner
2015-06-03 16:54 ` mleitner
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=20150605141830.GM3387@localhost.localdomain \
--to=mleitner@redhat.com \
--cc=daniel@iogearbox.net \
--cc=linux-sctp@vger.kernel.org \
--cc=micchie@sfc.wide.ad.jp \
--cc=netdev@vger.kernel.org \
--cc=nhorman@tuxdriver.com \
--cc=vyasevich@gmail.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.