Whamcloud - gitweb
LU-13708 lnet: lnet_notify sets route aliveness incorrectly 60/39160/7
authorChris Horn <chris.horn@hpe.com>
Tue, 23 Jun 2020 18:02:51 +0000 (13:02 -0500)
committerOleg Drokin <green@whamcloud.com>
Wed, 10 Mar 2021 08:01:36 +0000 (08:01 +0000)
lnet_notify() modifies route aliveness in two ways:
1. By setting lp_alive field of the lnet_peer struct.
2. By setting lr_alive field of the lnet_route struct (via call to
   lnet_set_route_aliveness())

In both cases, the aliveness value assigned is determined by a call
to lnet_is_peer_ni_alive(), but that value only reflects the aliveness
of a particular peer NI. A gateway may have multiple peer NIs, so the
aliveness of a gateway peer (lp_alive) is not necessarily equivalent
to the aliveness of one of its NIs. Furthermore, the lr_alive field
is only used to determine route aliveness for path selection if
discovery is disabled locally or on the gateway (see
lnet_find_route_locked() and lnet_is_route_alive()).

In general, we should not set lp_alive based on an lnet_notify()
call, and we should only set lr_alive if discovery is disabled. For
lr_alive specifically, we should only set it for those routes that
have the peer NI as a next-hop.

An exception to the above exists when the reset argument to
lnet_notify() is set. The gnilnd uses this flag in its calls to
lnet_notify() because gnilnd receives out-of-band notifications of
node up and down events. Thus, when gnilnd calls lnet_notify() we
actually know whether the gateway peer is up or down and we can set
lp_alive appropriately.

net lock/EX is held by other callers of lnet_set_route_aliveness, so
we do the same in lnet_notify().

Fixes: e35be987da ("LU-12422 lnet: discovery off route state update")
Fixes: ebc9835a97 ("LU-12941 lnet: Add peer level aliveness information")
Test-Parameters: trivial
HPE-bug-id: LUS-9034
Signed-off-by: Chris Horn <chris.horn@hpe.com>
Change-Id: I2927e5f5ef849e45c233c92d2a6deca765e496eb
Reviewed-on: https://review.whamcloud.com/39160
Reviewed-by: Serguei Smirnov <ssmirnov@whamcloud.com>
Reviewed-by: James Simmons <jsimmons@infradead.org>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lnet/lnet/router.c

index acddc75..3d06b45 100644 (file)
@@ -401,6 +401,7 @@ lnet_set_route_hop_type(struct lnet_peer *gw, struct lnet_route *route)
        lnet_check_route_inconsistency(route);
 }
 
+/* Must hold net_lock/EX */
 static inline void
 lnet_set_route_aliveness(struct lnet_route *route, bool alive)
 {
@@ -415,6 +416,7 @@ lnet_set_route_aliveness(struct lnet_route *route, bool alive)
        }
 }
 
+/* Must hold net_lock/EX */
 void
 lnet_router_discovery_ping_reply(struct lnet_peer *lp)
 {
@@ -1770,6 +1772,37 @@ lnet_notify(struct lnet_ni *ni, lnet_nid_t nid, bool alive, bool reset,
 
        /* recalculate aliveness */
        alive = lnet_is_peer_ni_alive(lpni);
+
+       lp = lpni->lpni_peer_net->lpn_peer;
+       /* If this is an LNet router then update route aliveness */
+       if (lp->lp_rtr_refcount) {
+               if (reset)
+                       /* reset flag indicates gateway peer went up or down */
+                       lp->lp_alive = alive;
+
+               /* If discovery is disabled, locally or on the gateway, then
+                * any routes using lpni as next-hop need to be updated
+                *
+                * NB: We can get many notifications while a route is down, so
+                * we try and avoid the expensive net_lock/EX here for the
+                * common case of receiving duplicate lnet_notify() calls (i.e.
+                * only grab EX lock when we actually need to update the route
+                * aliveness).
+                */
+               if (lnet_is_discovery_disabled(lp)) {
+                       list_for_each_entry(route, &lp->lp_routes, lr_gwlist) {
+                               if (route->lr_nid == lpni->lpni_nid &&
+                                   route->lr_alive != alive) {
+                                       lnet_net_unlock(0);
+                                       lnet_net_lock(LNET_LOCK_EX);
+                                       lnet_set_route_aliveness(route, alive);
+                                       lnet_net_unlock(LNET_LOCK_EX);
+                                       lnet_net_lock(0);
+                               }
+                       }
+               }
+       }
+
        lnet_net_unlock(0);
 
        if (ni != NULL && !alive)
@@ -1778,12 +1811,6 @@ lnet_notify(struct lnet_ni *ni, lnet_nid_t nid, bool alive, bool reset,
        cpt = lpni->lpni_cpt;
        lnet_net_lock(cpt);
        lnet_peer_ni_decref_locked(lpni);
-       if (lpni && lpni->lpni_peer_net && lpni->lpni_peer_net->lpn_peer) {
-               lp = lpni->lpni_peer_net->lpn_peer;
-               lp->lp_alive = alive;
-               list_for_each_entry(route, &lp->lp_routes, lr_gwlist)
-                       lnet_set_route_aliveness(route, alive);
-       }
        lnet_net_unlock(cpt);
 
        return 0;