On 15/06/16(Wed) 11:38, David Gwynne wrote:
> this tweaks art_walk in preparation for a world where the table may
> be updated on another cpu.
> 
> at the moment we're relying on the big lock to serialise updates,
> so this adds big lock calls in the right place.

I don't understand.  rtable_walk() is always called with the
KERNEL_LOCK() held, is this going to change?

>                                                 jmatthew@ has a
> diff to serialise changes with a mutex, so those kernel lock calls
> can be replaced with the mutex ones.

Why?  I assume the mutex will be used to serialize changes with the
input path...  But taking/releasing the lock for each node doesn't
sound clever to me.  When rtable_walk() is called you generally want
the operation to complete on the whole table before allowing any other
change.

The whole idea behind moving the EAGAIN check inside rtable_walk() is
that we can grab the lock around art_walk() which would make sure the
table has been completely updated before continuing.

> the idea is that art walk will traverse the tables under the lock.
> that allows us to bump the refcount on tables, which means they'll
> still be there when we unwined after descending into them. it gives
> up the lock when it calls the per route callback. this is so the
> callback can decide to update the table while looking at it. that
> route reference is done via the srp api.

That said, I like where this is going :)

> Index: art.c
> ===================================================================
> RCS file: /cvs/src/sys/net/art.c,v
> retrieving revision 1.19
> diff -u -p -r1.19 art.c
> --- art.c     14 Jun 2016 04:42:02 -0000      1.19
> +++ art.c     14 Jun 2016 12:36:25 -0000
> @@ -78,10 +78,13 @@ struct art_node           *art_table_insert(struc
>                            int, struct art_node *);
>  struct art_node              *art_table_delete(struct art_root *, struct 
> art_table *,
>                            int, struct art_node *);
> -void                  art_table_ref(struct art_root *, struct art_table *);
> +struct art_table     *art_table_ref(struct art_root *, struct art_table *);
>  int                   art_table_free(struct art_root *, struct art_table *);
>  int                   art_table_walk(struct art_root *, struct art_table *,
>                            int (*f)(struct art_node *, void *), void *);
> +int                   art_walk_apply(struct art_root *,
> +                          struct art_node *, struct art_node *,
> +                          int (*f)(struct art_node *, void *), void *);
>  void                  art_table_gc(void *);
>  void                  art_gc(void *);
>  
> @@ -565,10 +568,11 @@ art_table_delete(struct art_root *ar, st
>       return (an);
>  }
>  
> -void
> +struct art_table *
>  art_table_ref(struct art_root *ar, struct art_table *at)
>  {
>       at->at_refcnt++;
> +     return (at);
>  }
>  
>  static inline int
> @@ -604,42 +608,44 @@ art_table_free(struct art_root *ar, stru
>  int
>  art_walk(struct art_root *ar, int (*f)(struct art_node *, void *), void *arg)
>  {
> +     struct srp_ref           sr;
>       struct art_table        *at;
>       struct art_node         *node;
> -     int                      error;
> -
> -     KERNEL_ASSERT_LOCKED();
> +     int                      error = 0;
>  
> +     KERNEL_LOCK();
>       at = srp_get_locked(&ar->ar_root);
> -     if (at == NULL)
> -             return (0);
> +     if (at != NULL) {
> +             art_table_ref(ar, at);
>  
> -     /*
> -      * The default route should be processed here because the root
> -      * table does not have a parent.
> -      */
> -     node = srp_get_locked(&at->at_default);
> -     if (node != NULL) {
> -             error = (*f)(node, arg);
> -             if (error)
> -                     return (error);
> +             /*
> +              * The default route should be processed here because the root
> +              * table does not have a parent.
> +              */
> +             node = srp_enter(&sr, &at->at_default);
> +             error = art_walk_apply(ar, node, NULL, f, arg);
> +             srp_leave(&sr);
> +
> +             if (error == 0)
> +                     error = art_table_walk(ar, at, f, arg);
> +
> +             art_table_free(ar, at);
>       }
> +     KERNEL_UNLOCK();
>  
> -     return (art_table_walk(ar, at, f, arg));
> +     return (error);
>  }
>  
>  int
>  art_table_walk(struct art_root *ar, struct art_table *at,
>      int (*f)(struct art_node *, void *), void *arg)
>  {
> -     struct art_node         *next, *an = NULL;
> -     struct art_node         *node;
> +     struct srp_ref           sr;
> +     struct art_node         *node, *next;
> +     struct art_table        *nat;
>       int                      i, j, error = 0;
>       uint32_t                 maxfringe = (at->at_minfringe << 1);
>  
> -     /* Prevent this table to be freed while we're manipulating it. */
> -     art_table_ref(ar, at);
> -
>       /*
>        * Iterate non-fringe nodes in ``natural'' order.
>        */
> @@ -651,12 +657,13 @@ art_table_walk(struct art_root *ar, stru
>                */
>               for (i = max(j, 2); i < at->at_minfringe; i <<= 1) {
>                       next = srp_get_locked(&at->at_heap[i >> 1].node);
> -                     an = srp_get_locked(&at->at_heap[i].node);
> -                     if ((an != NULL) && (an != next)) {
> -                             error = (*f)(an, arg);
> -                             if (error)
> -                                     goto out;
> -                     }
> +
> +                     node = srp_enter(&sr, &at->at_heap[i].node);
> +                     error = art_walk_apply(ar, node, next, f, arg);
> +                     srp_leave(&sr);
> +
> +                     if (error != 0)
> +                             return (error);
>               }
>       }
>  
> @@ -665,28 +672,47 @@ art_table_walk(struct art_root *ar, stru
>        */
>       for (i = at->at_minfringe; i < maxfringe; i++) {
>               next = srp_get_locked(&at->at_heap[i >> 1].node);
> -             node = srp_get_locked(&at->at_heap[i].node);
> -             if (!ISLEAF(node))
> -                     an = srp_get_locked(&SUBTABLE(node)->at_default);
> -             else
> -                     an = node;
>  
> -             if ((an != NULL) && (an != next)) {
> -                     error = (*f)(an, arg);
> -                     if (error)
> -                             goto out;
> +             node = srp_enter(&sr, &at->at_heap[i].node);
> +             if (!ISLEAF(node)) {
> +                     nat = art_table_ref(ar, SUBTABLE(node));
> +                     node = srp_follow(&sr, &nat->at_default);
> +             } else
> +                     nat = NULL;
> +
> +             error = art_walk_apply(ar, node, next, f, arg);
> +             srp_leave(&sr);
> +
> +             if (error != 0) {
> +                     art_table_free(ar, nat);
> +                     return (error);
>               }
>  
> -             if (ISLEAF(node))
> -                     continue;
> +             if (nat != NULL) {
> +                     error = art_table_walk(ar, nat, f, arg);
> +                     art_table_free(ar, nat);
> +                     if (error != 0)
> +                             return (error);
> +             }
> +     }
>  
> -             error = art_table_walk(ar, SUBTABLE(node), f, arg);
> -             if (error)
> -                     break;
> +     return (0);
> +}
> +
> +int
> +art_walk_apply(struct art_root *ar,
> +    struct art_node *an, struct art_node *next,
> +    int (*f)(struct art_node *, void *), void *arg)
> +{
> +     int error = 0;
> +
> +     if ((an != NULL) && (an != next)) {
> +             /* this assumes an->an_dst is not used by f */
> +             KERNEL_UNLOCK();
> +             error = (*f)(an, arg);
> +             KERNEL_LOCK();
>       }
>  
> -out:
> -     art_table_free(ar, at);
>       return (error);
>  }
>  
> Index: rtable.c
> ===================================================================
> RCS file: /cvs/src/sys/net/rtable.c,v
> retrieving revision 1.47
> diff -u -p -r1.47 rtable.c
> --- rtable.c  14 Jun 2016 04:42:02 -0000      1.47
> +++ rtable.c  14 Jun 2016 12:36:25 -0000
> @@ -853,16 +853,16 @@ struct rtable_walk_cookie {
>  int
>  rtable_walk_helper(struct art_node *an, void *xrwc)
>  {
> +     struct srp_ref                   sr;
>       struct rtable_walk_cookie       *rwc = xrwc;
> -     struct rtentry                  *rt, *nrt;
> +     struct rtentry                  *rt;
>       int                              error = 0;
>  
> -     KERNEL_ASSERT_LOCKED();
> -
> -     SRPL_FOREACH_SAFE_LOCKED(rt, &an->an_rtlist, rt_next, nrt) {
> +     SRPL_FOREACH(rt, &sr, &an->an_rtlist, rt_next) {
>               if ((error = (*rwc->rwc_func)(rt, rwc->rwc_arg, rwc->rwc_rid)))
>                       break;
>       }
> +     SRPL_LEAVE(&sr);
>  
>       return (error);
>  }
> 

Reply via email to