On Wed, 2007-09-12 at 15:33 -0700, Paul E. McKenney wrote:
> On Wed, Sep 12, 2007 at 05:03:42PM -0400, Vlad Yasevich wrote:
> > [... and here is the updated version as promissed ...]
> > 
> > Since the sctp_sockaddr_entry is now RCU enabled as part of
> > the patch to synchronize sctp_localaddr_list, it makes sense to
> > change all handling of these entries to RCU.  This includes the
> > sctp_bind_addrs structure and it's list of bound addresses.
> > 
> > This list is currently protected by an external rw_lock and that
> > looks like an overkill.  There are only 2 writers to the list:
> > bind()/bindx() calls, and BH processing of ASCONF-ACK chunks.
> > These are already seriealized via the socket lock, so they will
> > not step on each other.  These are also relatively rare, so we
> > should be good with RCU.
> > 
> > The readers are varied and they are easily converted to RCU.
> 
> Looks good from an RCU viewpoint -- I must defer to others on
> the networking aspects.
> 
> Acked-by: Paul E. McKenney <[EMAIL PROTECTED]>

looks good to me too. some minor typos and some comments on
RCU usage comments inline.

Also, I guess we can remove the sctp_[read/write]_[un]lock macros
from sctp.h now that you removed the all the users of rwlocks
in SCTP

Thanks
Sridhar
> 
> > Signed-off-by: Vlad Yasevich <[EMAIL PROTECTED]>
> > ---
> >  include/net/sctp/structs.h |    7 +--
> >  net/sctp/associola.c       |   14 +-----
> >  net/sctp/bind_addr.c       |   68 ++++++++++++++++++++----------
> >  net/sctp/endpointola.c     |   27 +++---------
> >  net/sctp/ipv6.c            |   12 ++---
> >  net/sctp/protocol.c        |   25 ++++-------
> >  net/sctp/sm_make_chunk.c   |   18 +++-----
> >  net/sctp/socket.c          |   98 
> > ++++++++++++-------------------------------
> >  8 files changed, 106 insertions(+), 163 deletions(-)
> > 
> > diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> > index a89e361..c2fe2dc 100644
> > --- a/include/net/sctp/structs.h
> > +++ b/include/net/sctp/structs.h
> > @@ -1155,7 +1155,9 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
> >                     int flags);
> >  int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
> >                    __u8 use_as_src, gfp_t gfp);
> > -int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
> > +int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
> > +                   void (*rcu_call)(struct rcu_head *,
> > +                                     void (*func)(struct rcu_head *)));
> >  int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
> >                      struct sctp_sock *);
> >  union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr      *bp,
> > @@ -1226,9 +1228,6 @@ struct sctp_ep_common {
> >      * bind_addr.address_list is our set of local IP addresses.
> >      */
> >     struct sctp_bind_addr bind_addr;
> > -
> > -   /* Protection during address list comparisons. */
> > -   rwlock_t   addr_lock;
> >  };
> > 
> > 
> > diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> > index 2ad1caf..9bad8ba 100644
> > --- a/net/sctp/associola.c
> > +++ b/net/sctp/associola.c
> > @@ -99,7 +99,6 @@ static struct sctp_association 
> > *sctp_association_init(struct sctp_association *a
> > 
> >     /* Initialize the bind addr area.  */
> >     sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port);
> > -   rwlock_init(&asoc->base.addr_lock);
> > 
> >     asoc->state = SCTP_STATE_CLOSED;
> > 
> > @@ -937,8 +936,6 @@ struct sctp_transport *sctp_assoc_is_match(struct 
> > sctp_association *asoc,
> >  {
> >     struct sctp_transport *transport;
> > 
> > -   sctp_read_lock(&asoc->base.addr_lock);
> > -
> >     if ((htons(asoc->base.bind_addr.port) == laddr->v4.sin_port) &&
> >         (htons(asoc->peer.port) == paddr->v4.sin_port)) {
> >             transport = sctp_assoc_lookup_paddr(asoc, paddr);
> > @@ -952,7 +949,6 @@ struct sctp_transport *sctp_assoc_is_match(struct 
> > sctp_association *asoc,
> >     transport = NULL;
> > 
> >  out:
> > -   sctp_read_unlock(&asoc->base.addr_lock);
> >     return transport;
> >  }
> > 
> > @@ -1376,19 +1372,13 @@ int sctp_assoc_set_bind_addr_from_cookie(struct 
> > sctp_association *asoc,
> >  int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
> >                         const union sctp_addr *laddr)
> >  {
> > -   int found;
> > +   int found = 0;
> > 
> > -   sctp_read_lock(&asoc->base.addr_lock);
> >     if ((asoc->base.bind_addr.port == ntohs(laddr->v4.sin_port)) &&
> >         sctp_bind_addr_match(&asoc->base.bind_addr, laddr,
> > -                            sctp_sk(asoc->base.sk))) {
> > +                            sctp_sk(asoc->base.sk)))
> >             found = 1;
> > -           goto out;
> > -   }
> > 
> > -   found = 0;
> > -out:
> > -   sctp_read_unlock(&asoc->base.addr_lock);
> >     return found;
> >  }
> > 
> > diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
> > index 7fc369f..d16055f 100644
> > --- a/net/sctp/bind_addr.c
> > +++ b/net/sctp/bind_addr.c
> > @@ -167,7 +167,11 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, 
> > union sctp_addr *new,
> > 
> >     INIT_LIST_HEAD(&addr->list);
> >     INIT_RCU_HEAD(&addr->rcu);
> > -   list_add_tail(&addr->list, &bp->address_list);
> > +
> > +   /* We always hold a socket lock when calling this function,
> > +    * so rcu_read_lock is not needed.
> > +    */
> > +   list_add_tail_rcu(&addr->list, &bp->address_list);

I am little confused with the comment above.
Isn't this an update-side of RCU. If so, this should be protected
by a spin-lock or a mutex rather than rcu_read_lock().

> >     SCTP_DBG_OBJCNT_INC(addr);
> > 
> >     return 0;
> > @@ -176,23 +180,35 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, 
> > union sctp_addr *new,
> >  /* Delete an address from the bind address list in the SCTP_bind_addr
> >   * structure.
> >   */
> > -int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr 
> > *del_addr)
> > +int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr 
> > *del_addr,
> > +                   void (*rcu_call)(struct rcu_head *head,
> > +                                    void (*func)(struct rcu_head *head)))
> >  {
> > -   struct list_head *pos, *temp;
> > -   struct sctp_sockaddr_entry *addr;
> > +   struct sctp_sockaddr_entry *addr, *temp;
> > 
> > -   list_for_each_safe(pos, temp, &bp->address_list) {
> > -           addr = list_entry(pos, struct sctp_sockaddr_entry, list);
> > +   /* We hold the socket lock when calling this function, so
> > +    * rcu_read_lock is not needed.
> > +    */

Same as above. This is also an update-side of RCU protected 
by socket lock.

> > +   list_for_each_entry_safe(addr, temp, &bp->address_list, list) {
> >             if (sctp_cmp_addr_exact(&addr->a, del_addr)) {
> >                     /* Found the exact match. */
> > -                   list_del(pos);
> > -                   kfree(addr);
> > -                   SCTP_DBG_OBJCNT_DEC(addr);
> > -
> > -                   return 0;
> > +                   addr->valid = 0;
> > +                   list_del_rcu(&addr->list);
> > +                   break;
> >             }
> >     }
> > 
> > +   /* Call the rcu callback provided in the args.  This function is
> > +    * called by both BH packet processing and user side socket option
> > +    * processing, but it works on different lists in those 2 contexts.
> > +    * Each context provides it's own callback, whether call_rc_bh()
s/call_rc_bh/call_rcu_bh

> > +    * or call_rcu(), to make sure that we wait an for appropriate time.
s/an for/for an

> > +    */
> > +   if (addr && !addr->valid) {
> > +           rcu_call(&addr->rcu, sctp_local_addr_free);
> > +           SCTP_DBG_OBJCNT_DEC(addr);
> > +   }
> > +
> >     return -EINVAL;
> >  }
> > 
> > @@ -302,15 +318,20 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp,
> >                      struct sctp_sock *opt)
> >  {
> >     struct sctp_sockaddr_entry *laddr;
> > -   struct list_head *pos;
> > -
> > -   list_for_each(pos, &bp->address_list) {
> > -           laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
> > -           if (opt->pf->cmp_addr(&laddr->a, addr, opt))
> > -                   return 1;
> > +   int match = 0;
> > +
> > +   rcu_read_lock();
> > +   list_for_each_entry_rcu(laddr, &bp->address_list, list) {
> > +           if (!laddr->valid)
> > +                   continue;
> > +           if (opt->pf->cmp_addr(&laddr->a, addr, opt)) {
> > +                   match = 1;
> > +                   break;
> > +           }
> >     }
> > +   rcu_read_unlock();
> > 
> > -   return 0;
> > +   return match;
> >  }
> > 
> >  /* Find the first address in the bind address list that is not present in
> > @@ -325,18 +346,19 @@ union sctp_addr *sctp_find_unmatch_addr(struct 
> > sctp_bind_addr *bp,
> >     union sctp_addr                 *addr;
> >     void                            *addr_buf;
> >     struct sctp_af                  *af;
> > -   struct list_head                *pos;
> >     int                             i;
> > 
> > -   list_for_each(pos, &bp->address_list) {
> > -           laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
> > -
> > +   /* This is only called sctp_send_asconf_del_ip() and we hold
> > +    * the socket lock in that code patch, so that address list
> > +    * can't change.
> > +    */
> > +   list_for_each_entry(laddr, &bp->address_list, list) {
> >             addr_buf = (union sctp_addr *)addrs;
> >             for (i = 0; i < addrcnt; i++) {
> >                     addr = (union sctp_addr *)addr_buf;
> >                     af = sctp_get_af_specific(addr->v4.sin_family);
> >                     if (!af)
> > -                           return NULL;
> > +                           break;
> > 
> >                     if (opt->pf->cmp_addr(&laddr->a, addr, opt))
> >                             break;
> > diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
> > index 1404a9e..110d912 100644
> > --- a/net/sctp/endpointola.c
> > +++ b/net/sctp/endpointola.c
> > @@ -92,7 +92,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct 
> > sctp_endpoint *ep,
> > 
> >     /* Initialize the bind addr area */
> >     sctp_bind_addr_init(&ep->base.bind_addr, 0);
> > -   rwlock_init(&ep->base.addr_lock);
> > 
> >     /* Remember who we are attached to.  */
> >     ep->base.sk = sk;
> > @@ -225,21 +224,14 @@ void sctp_endpoint_put(struct sctp_endpoint *ep)
> >  struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
> >                                            const union sctp_addr *laddr)
> >  {
> > -   struct sctp_endpoint *retval;
> > +   struct sctp_endpoint *retval = NULL;
> > 
> > -   sctp_read_lock(&ep->base.addr_lock);
> >     if (htons(ep->base.bind_addr.port) == laddr->v4.sin_port) {
> >             if (sctp_bind_addr_match(&ep->base.bind_addr, laddr,
> > -                                    sctp_sk(ep->base.sk))) {
> > +                                    sctp_sk(ep->base.sk)))
> >                     retval = ep;
> > -                   goto out;
> > -           }
> >     }
> > 
> > -   retval = NULL;
> > -
> > -out:
> > -   sctp_read_unlock(&ep->base.addr_lock);
> >     return retval;
> >  }
> > 
> > @@ -261,9 +253,7 @@ static struct sctp_association 
> > *__sctp_endpoint_lookup_assoc(
> >     list_for_each(pos, &ep->asocs) {
> >             asoc = list_entry(pos, struct sctp_association, asocs);
> >             if (rport == asoc->peer.port) {
> > -                   sctp_read_lock(&asoc->base.addr_lock);
> >                     *transport = sctp_assoc_lookup_paddr(asoc, paddr);
> > -                   sctp_read_unlock(&asoc->base.addr_lock);
> > 
> >                     if (*transport)
> >                             return asoc;
> > @@ -295,20 +285,17 @@ struct sctp_association *sctp_endpoint_lookup_assoc(
> >  int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
> >                             const union sctp_addr *paddr)
> >  {
> > -   struct list_head *pos;
> >     struct sctp_sockaddr_entry *addr;
> >     struct sctp_bind_addr *bp;
> > 
> > -   sctp_read_lock(&ep->base.addr_lock);
> >     bp = &ep->base.bind_addr;
> > -   list_for_each(pos, &bp->address_list) {
> > -           addr = list_entry(pos, struct sctp_sockaddr_entry, list);
> > -           if (sctp_has_association(&addr->a, paddr)) {
> > -                   sctp_read_unlock(&ep->base.addr_lock);
> > +   /* This function is called whith the socket lock held,
s/whith/with

> > +    * so the address_list can not change.
> > +    */
> > +   list_for_each_entry(addr, &bp->address_list, list) {
> > +           if (sctp_has_association(&addr->a, paddr))
> >                     return 1;
> > -           }
> >     }
> > -   sctp_read_unlock(&ep->base.addr_lock);
> > 
> >     return 0;
> >  }

<snip>
deleted the rest of the patch as it looks good and i have no
comments.

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to