Whamcloud - gitweb
LU-11297 lnet: MR Routing Feature 83/34983/3
authorAmir Shehata <ashehata@whamcloud.com>
Fri, 7 Jun 2019 18:35:09 +0000 (14:35 -0400)
committerOleg Drokin <green@whamcloud.com>
Fri, 7 Jun 2019 18:38:06 +0000 (14:38 -0400)
This is a merge commit from the multi-rail branch. It brings in
the MR Routing feature. This feature aligns the LNET Multi-Rail
behavior with routing. A gateway now is viewed as a Multi-Rail
capable node. When a route is added only one entry per gateway
should be used. That route entry should use the primary-nid of
the gateway. The multi-rail selection algorithm is then run when
sending to the gateway to select the best interface to send to.

Furthermore the gateway aliveness is now kept via the health
mechanism. And the gateway pinger now uses discovery instead
of maintaining its own pinger handler.

Signed-off-by: Amir Shehata <ashehata@whamcloud.com>
Change-Id: Ie2d8c6449f84860511b322ff2db3ed656a163e74

1  2 
lnet/include/lnet/lib-lnet.h
lnet/klnds/socklnd/socklnd.c
lnet/lnet/router_proc.c
lustre/tests/sanity.sh

@@@ -92,16 -92,8 +92,8 @@@ extern struct lnet the_lnet;                 /* THE n
                kernel_getsockname(sock, addr, addrlen)
  #endif
  
- static inline int lnet_is_route_alive(struct lnet_route *route)
- {
-       if (!route->lr_gateway->lpni_alive)
-               return 0; /* gateway is down */
-       if ((route->lr_gateway->lpni_ping_feats &
-            LNET_PING_FEAT_NI_STATUS) == 0)
-               return 1; /* no NI status, assume it's alive */
-       /* has NI status, check # down NIs */
-       return route->lr_downis == 0;
- }
+ bool lnet_is_route_alive(struct lnet_route *route);
+ bool lnet_is_gateway_alive(struct lnet_peer *gw);
  
  static inline int lnet_is_wire_handle_none(struct lnet_handle_wire *wh)
  {
@@@ -448,9 -440,9 +440,9 @@@ lnet_peer_ni_decref_locked(struct lnet_
  }
  
  static inline int
- lnet_isrouter(struct lnet_peer_ni *lp)
+ lnet_isrouter(struct lnet_peer_ni *lpni)
  {
-       return lp->lpni_rtr_refcount != 0;
+       return lpni->lpni_peer_net->lpn_peer->lp_rtr_refcount != 0;
  }
  
  static inline void
@@@ -574,19 -566,23 +566,23 @@@ extern unsigned int lnet_health_sensiti
  extern unsigned int lnet_recovery_interval;
  extern unsigned int lnet_peer_discovery_disabled;
  extern unsigned int lnet_drop_asym_route;
+ extern unsigned int router_sensitivity_percentage;
+ extern int alive_router_check_interval;
  extern int portal_rotor;
  
- int lnet_notify(struct lnet_ni *ni, lnet_nid_t peer, int alive,
+ void lnet_mt_event_handler(struct lnet_event *event);
+ int lnet_notify(struct lnet_ni *ni, lnet_nid_t peer, bool alive, bool reset,
                time64_t when);
  void lnet_notify_locked(struct lnet_peer_ni *lp, int notifylnd, int alive,
                        time64_t when);
  int lnet_add_route(__u32 net, __u32 hops, lnet_nid_t gateway_nid,
-                  unsigned int priority);
- int lnet_check_routes(void);
+                  __u32 priority, __u32 sensitivity);
  int lnet_del_route(__u32 net, lnet_nid_t gw_nid);
  void lnet_destroy_routes(void);
  int lnet_get_route(int idx, __u32 *net, __u32 *hops,
-                  lnet_nid_t *gateway, __u32 *alive, __u32 *priority);
+                  lnet_nid_t *gateway, __u32 *alive, __u32 *priority,
+                  __u32 *sensitivity);
  int lnet_get_rtr_pool_cfg(int idx, struct lnet_ioctl_pool_cfg *pool_cfg);
  struct lnet_ni *lnet_get_next_ni_locked(struct lnet_net *mynet,
                                        struct lnet_ni *prev);
@@@ -607,6 -603,8 +603,8 @@@ int  lnet_rtrpools_adjust(int tiny, in
  int lnet_rtrpools_enable(void);
  void lnet_rtrpools_disable(void);
  void lnet_rtrpools_free(int keep_pools);
+ void lnet_rtr_transfer_to_peer(struct lnet_peer *src,
+                              struct lnet_peer *target);
  struct lnet_remotenet *lnet_find_rnet_locked(__u32 net);
  int lnet_dyn_add_net(struct lnet_ioctl_config_data *conf);
  int lnet_dyn_del_net(__u32 net);
@@@ -617,6 -615,7 +615,7 @@@ struct lnet_net *lnet_get_net_locked(__
  
  int lnet_islocalnid(lnet_nid_t nid);
  int lnet_islocalnet(__u32 net);
+ int lnet_islocalnet_locked(__u32 net);
  
  void lnet_msg_attach_md(struct lnet_msg *msg, struct lnet_libmd *md,
                        unsigned int offset, unsigned int mlen);
@@@ -734,7 -733,8 +733,8 @@@ int lnet_fault_ctl(int cmd, struct libc
  int lnet_fault_init(void);
  void lnet_fault_fini(void);
  
- bool lnet_drop_rule_match(struct lnet_hdr *hdr, enum lnet_msg_hstatus *hstatus);
+ bool lnet_drop_rule_match(struct lnet_hdr *hdr, lnet_nid_t local_nid,
+                         enum lnet_msg_hstatus *hstatus);
  
  int lnet_delay_rule_add(struct lnet_fault_attr *attr);
  int lnet_delay_rule_del(lnet_nid_t src, lnet_nid_t dst, bool shutdown);
@@@ -840,6 -840,9 +840,6 @@@ int lnet_acceptor_port(void)
  int lnet_acceptor_start(void);
  void lnet_acceptor_stop(void);
  
 -int lnet_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask);
 -int lnet_ipif_enumerate(char ***names);
 -void lnet_ipif_free_enumeration(char **names, int n);
  int lnet_sock_setbuf(struct socket *socket, int txbufsize, int rxbufsize);
  int lnet_sock_getbuf(struct socket *socket, int *txbufsize, int *rxbufsize);
  int lnet_sock_getaddr(struct socket *socket, bool remote, __u32 *ip, int *port);
@@@ -854,17 -857,16 +854,16 @@@ int lnet_sock_connect(struct socket **s
  
  int lnet_peers_start_down(void);
  int lnet_peer_buffer_credits(struct lnet_net *net);
+ void lnet_consolidate_routes_locked(struct lnet_peer *orig_lp,
+                                   struct lnet_peer *new_lp);
+ void lnet_router_discovery_complete(struct lnet_peer *lp);
  
  int lnet_monitor_thr_start(void);
  void lnet_monitor_thr_stop(void);
  
  bool lnet_router_checker_active(void);
  void lnet_check_routers(void);
- int lnet_router_pre_mt_start(void);
- void lnet_router_post_mt_start(void);
- void lnet_prune_rc_data(int wait_unlink);
- void lnet_router_cleanup(void);
- void lnet_router_ni_update_locked(struct lnet_peer_ni *gw, __u32 net);
+ void lnet_wait_router_start(void);
  void lnet_swap_pinginfo(struct lnet_ping_buffer *pbuf);
  
  int lnet_ping_info_validate(struct lnet_ping_info *pinfo);
@@@ -904,13 -906,18 +903,18 @@@ bool lnet_net_unique(__u32 net_id, stru
  bool lnet_ni_unique_net(struct list_head *nilist, char *iface);
  void lnet_incr_dlc_seq(void);
  __u32 lnet_get_dlc_seq_locked(void);
+ int lnet_get_net_count(void);
  
+ struct lnet_peer_net *lnet_get_next_peer_net_locked(struct lnet_peer *lp,
+                                                   __u32 prev_lpn_id);
  struct lnet_peer_ni *lnet_get_next_peer_ni_locked(struct lnet_peer *peer,
                                                  struct lnet_peer_net *peer_net,
                                                  struct lnet_peer_ni *prev);
  struct lnet_peer_ni *lnet_nid2peerni_locked(lnet_nid_t nid, lnet_nid_t pref,
                                        int cpt);
  struct lnet_peer_ni *lnet_nid2peerni_ex(lnet_nid_t nid, int cpt);
+ struct lnet_peer_ni *lnet_peer_get_ni_locked(struct lnet_peer *lp,
+                                            lnet_nid_t nid);
  struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid);
  struct lnet_peer *lnet_find_peer(lnet_nid_t nid);
  void lnet_peer_net_added(struct lnet_net *net);
@@@ -951,15 -958,6 +955,6 @@@ lnet_find_peer_net_locked(struct lnet_p
        return NULL;
  }
  
- static inline void
- lnet_peer_set_alive(struct lnet_peer_ni *lp)
- {
-       lp->lpni_last_alive = ktime_get_seconds();
-       lp->lpni_last_query = lp->lpni_last_alive;
-       if (!lp->lpni_alive)
-               lnet_notify_locked(lp, 0, 1, lp->lpni_last_alive);
- }
  static inline bool
  lnet_peer_is_multi_rail(struct lnet_peer *lp)
  {
@@@ -983,6 -981,8 +978,8 @@@ lnet_peer_ni_is_primary(struct lnet_pee
  }
  
  bool lnet_peer_is_uptodate(struct lnet_peer *lp);
+ bool lnet_is_discovery_disabled(struct lnet_peer *lp);
+ bool lnet_peer_gw_discovery(struct lnet_peer *lp);
  
  static inline bool
  lnet_peer_needs_push(struct lnet_peer *lp)
                return true;
        if (lp->lp_state & LNET_PEER_NO_DISCOVERY)
                return false;
+       /* if discovery is not enabled then no need to push */
+       if (lnet_peer_discovery_disabled)
+               return false;
        if (lp->lp_node_seqno < atomic_read(&the_lnet.ln_ping_target_seqno))
                return true;
        return false;
  }
  
+ /*
+  * A peer is alive if it satisfies the following two conditions:
+  *  1. peer health >= LNET_MAX_HEALTH_VALUE * router_sensitivity_percentage
+  *  2. the cached NI status received when we discover the peer is UP
+  */
+ static inline bool
+ lnet_is_peer_ni_alive(struct lnet_peer_ni *lpni)
+ {
+       bool halive = false;
+       halive = (atomic_read(&lpni->lpni_healthv) >=
+                (LNET_MAX_HEALTH_VALUE * router_sensitivity_percentage / 100));
+       return halive && lpni->lpni_ns_status == LNET_NI_STATUS_UP;
+ }
+ static inline void
+ lnet_set_healthv(atomic_t *healthv, int value)
+ {
+       atomic_set(healthv, value);
+ }
  static inline void
  lnet_inc_healthv(atomic_t *healthv)
  {
@@@ -1521,8 -1521,8 +1521,8 @@@ ksocknal_peer_failed(struct ksock_peer_
        read_unlock(&ksocknal_data.ksnd_global_lock);
  
        if (notify)
-               lnet_notify(peer_ni->ksnp_ni, peer_ni->ksnp_id.nid, 0,
-                           last_alive);
+               lnet_notify(peer_ni->ksnp_ni, peer_ni->ksnp_id.nid,
+                           false, false, last_alive);
  }
  
  void
@@@ -1781,7 -1781,7 +1781,7 @@@ ksocknal_close_matching_conns(struct ln
  }
  
  void
- ksocknal_notify(struct lnet_ni *ni, lnet_nid_t gw_nid, int alive)
+ ksocknal_notify_gw_down(lnet_nid_t gw_nid)
  {
        /* The router is telling me she's been notified of a change in
         * gateway state....
                .pid    = LNET_PID_ANY,
        };
  
-         CDEBUG (D_NET, "gw %s %s\n", libcfs_nid2str(gw_nid),
-                 alive ? "up" : "down");
+       CDEBUG(D_NET, "gw %s down\n", libcfs_nid2str(gw_nid));
  
-         if (!alive) {
-                 /* If the gateway crashed, close all open connections... */
-                 ksocknal_close_matching_conns (id, 0);
-                 return;
-         }
+       /* If the gateway crashed, close all open connections... */
+       ksocknal_close_matching_conns(id, 0);
+       return;
  
-         /* ...otherwise do nothing.  We can only establish new connections
-          * if we have autroutes, and these connect on demand. */
+       /* We can only establish new connections
+        * if we have autroutes, and these connect on demand. */
  }
  
  void
@@@ -2571,59 -2568,57 +2568,59 @@@ ksocknal_shutdown(struct lnet_ni *ni
  }
  
  static int
 -ksocknal_enumerate_interfaces(struct ksock_net *net)
 +ksocknal_enumerate_interfaces(struct ksock_net *net, char *iname)
  {
 -      int j = 0;
        struct net_device *dev;
  
        rtnl_lock();
        for_each_netdev(&init_net, dev) {
 -              const char *name = dev->name;
 +              /* The iname specified by an user land configuration can
 +               * map to an ifa_label so always treat iname as an ifa_label.
 +               * If iname is NULL then fall back to the net device name.
 +               */
 +              const char *name = iname ? iname : dev->name;
                struct in_device *in_dev;
 -              struct ksock_interface *ksi;
  
 -              if (strcmp(name, "lo") == 0) /* skip the loopback IF */
 +              if (strcmp(dev->name, "lo") == 0) /* skip the loopback IF */
                        continue;
  
                if (!(dev_get_flags(dev) & IFF_UP)) {
 -                      CWARN("Ignoring interface %s (down)\n", name);
 -                      continue;
 -              }
 -
 -              if (j == LNET_INTERFACES_NUM) {
 -                      CWARN("Ignoring interface %s (too many interfaces)\n",
 -                            name);
 +                      CWARN("Ignoring interface %s (down)\n", dev->name);
                        continue;
                }
  
                in_dev = __in_dev_get_rtnl(dev);
                if (!in_dev) {
 -                      CWARN("Interface %s has no IPv4 status.\n", name);
 +                      CWARN("Interface %s has no IPv4 status.\n", dev->name);
                        continue;
                }
  
 -              ksi = &net->ksnn_interfaces[j];
 +              for_ifa(in_dev)
 +                      if (strcmp(name, ifa->ifa_label) == 0) {
 +                              int idx = net->ksnn_ninterfaces;
 +                              struct ksock_interface *ksi;
  
 -              for_primary_ifa(in_dev)
 -                      if (strcmp(ifa->ifa_label, name) == 0) {
 +                              if (idx >= ARRAY_SIZE(net->ksnn_interfaces)) {
 +                                      rtnl_unlock();
 +                                      return -E2BIG;
 +                              }
 +
 +                              ksi = &net->ksnn_interfaces[idx];
                                ksi->ksni_ipaddr = ntohl(ifa->ifa_local);
                                ksi->ksni_netmask = ifa->ifa_mask;
                                strlcpy(ksi->ksni_name,
                                        name, sizeof(ksi->ksni_name));
 -                              j++;
 +                              net->ksnn_ninterfaces++;
                                break;
                        }
                endfor_ifa(in_dev);
          }
 -
        rtnl_unlock();
  
 -        if (j == 0)
 +      if (net->ksnn_ninterfaces == 0)
                  CERROR("Can't find any usable interfaces\n");
  
 -        return j;
 +      return net->ksnn_ninterfaces > 0 ? 0 : -ENOENT;
  }
  
  static int
@@@ -2788,45 -2783,41 +2785,45 @@@ ksocknal_startup(struct lnet_ni *ni
                net_tunables->lct_peer_rtr_credits =
                        *ksocknal_tunables.ksnd_peerrtrcredits;
  
 -      if (ni->ni_interfaces[0] == NULL) {
 -              rc = ksocknal_enumerate_interfaces(net);
 -              if (rc <= 0)
 +      if (!ni->ni_interfaces[0]) {
 +              rc = ksocknal_enumerate_interfaces(net, NULL);
 +              if (rc < 0)
                        goto fail_1;
 -
 -              net->ksnn_ninterfaces = 1;
        } else {
 +              /* Before Multi-Rail ksocklnd would manage
 +               * multiple interfaces with its own tcp bonding.
 +               * If we encounter an old configuration using
 +               * this tcp bonding approach then we need to
 +               * handle more than one ni_interfaces.
 +               *
 +               * In Multi-Rail configuration only ONE ni_interface
 +               * should exist. Each IP alias should be mapped to
 +               * each 'struct net_ni'.
 +               */
                for (i = 0; i < LNET_INTERFACES_NUM; i++) {
 -                      int up;
 +                      int j;
  
 -                      if (ni->ni_interfaces[i] == NULL)
 +                      if (!ni->ni_interfaces[i])
                                break;
  
 -                      rc = lnet_ipif_query(ni->ni_interfaces[i], &up,
 -                              &net->ksnn_interfaces[i].ksni_ipaddr,
 -                              &net->ksnn_interfaces[i].ksni_netmask);
 +                      for (j = 0; j < net->ksnn_ninterfaces;  j++) {
 +                              struct ksock_interface *ksi;
  
 -                      if (rc != 0) {
 -                              CERROR("Can't get interface %s info: %d\n",
 -                                     ni->ni_interfaces[i], rc);
 -                              goto fail_1;
 -                      }
 +                              ksi = &net->ksnn_interfaces[j];
  
 -                      if (!up) {
 -                              CERROR("Interface %s is down\n",
 -                                     ni->ni_interfaces[i]);
 -                              goto fail_1;
 +                              if (strcmp(ni->ni_interfaces[i],
 +                                         ksi->ksni_name) == 0) {
 +                                      CERROR("found duplicate %s\n",
 +                                             ksi->ksni_name);
 +                                      rc = -EEXIST;
 +                                      goto fail_1;
 +                              }
                        }
  
 -                      strlcpy(net->ksnn_interfaces[i].ksni_name,
 -                              ni->ni_interfaces[i],
 -                              sizeof(net->ksnn_interfaces[i].ksni_name));
 -
 +                      rc = ksocknal_enumerate_interfaces(net, ni->ni_interfaces[i]);
 +                      if (rc < 0)
 +                              goto fail_1;
                }
 -              net->ksnn_ninterfaces = i;
        }
  
        net_dev = dev_get_by_name(&init_net,
@@@ -2882,7 -2873,7 +2879,7 @@@ static int __init ksocklnd_init(void
        the_ksocklnd.lnd_ctl      = ksocknal_ctl;
        the_ksocklnd.lnd_send     = ksocknal_send;
        the_ksocklnd.lnd_recv     = ksocknal_recv;
-       the_ksocklnd.lnd_notify   = ksocknal_notify;
+       the_ksocklnd.lnd_notify_peer_down   = ksocknal_notify_gw_down;
        the_ksocklnd.lnd_query    = ksocknal_query;
        the_ksocklnd.lnd_accept   = ksocknal_accept;
  
diff --combined lnet/lnet/router_proc.c
@@@ -224,18 -224,17 +224,17 @@@ proc_lnet_routes(struct ctl_table *tabl
                }
  
                if (route != NULL) {
-                       __u32        net        = rnet->lrn_net;
-                       __u32 hops              = route->lr_hops;
-                       unsigned int priority   = route->lr_priority;
-                       lnet_nid_t   nid        = route->lr_gateway->lpni_nid;
-                       int          alive      = lnet_is_route_alive(route);
+                       __u32 net = rnet->lrn_net;
+                       __u32 hops = route->lr_hops;
+                       unsigned int priority = route->lr_priority;
+                       int alive = lnet_is_route_alive(route);
  
                        s += snprintf(s, tmpstr + tmpsiz - s,
                                      "%-8s %4d %8u %7s %s\n",
                                      libcfs_net2str(net), hops,
                                      priority,
                                      alive ? "up" : "down",
-                                     libcfs_nid2str(nid));
+                                     libcfs_nid2str(route->lr_nid));
                        LASSERT(tmpstr + tmpsiz - s > 0);
                }
  
@@@ -291,10 -290,8 +290,8 @@@ proc_lnet_routers(struct ctl_table *tab
  
        if (*ppos == 0) {
                s += snprintf(s, tmpstr + tmpsiz - s,
-                             "%-4s %7s %9s %6s %12s %9s %8s %7s %s\n",
-                             "ref", "rtr_ref", "alive_cnt", "state",
-                             "last_ping", "ping_sent", "deadline",
-                             "down_ni", "router");
+                             "%-4s %7s %5s %s\n",
+                             "ref", "rtr_ref", "alive", "router");
                LASSERT(tmpstr + tmpsiz - s > 0);
  
                lnet_net_lock(0);
                *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
        } else {
                struct list_head *r;
-               struct lnet_peer_ni *peer = NULL;
+               struct lnet_peer *peer = NULL;
                int               skip = off - 1;
  
                lnet_net_lock(0);
                r = the_lnet.ln_routers.next;
  
                while (r != &the_lnet.ln_routers) {
-                       struct lnet_peer_ni *lp =
-                         list_entry(r, struct lnet_peer_ni,
-                                    lpni_rtr_list);
+                       struct lnet_peer *lp =
+                         list_entry(r, struct lnet_peer,
+                                    lp_rtr_list);
  
                        if (skip == 0) {
                                peer = lp;
                }
  
                if (peer != NULL) {
-                       lnet_nid_t nid = peer->lpni_nid;
-                       time64_t now = ktime_get_seconds();
-                       time64_t deadline = peer->lpni_ping_deadline;
-                       int nrefs     = atomic_read(&peer->lpni_refcount);
-                       int nrtrrefs  = peer->lpni_rtr_refcount;
-                       int alive_cnt = peer->lpni_alive_count;
-                       int alive     = peer->lpni_alive;
-                       int pingsent  = !peer->lpni_ping_notsent;
-                       time64_t last_ping = now - peer->lpni_ping_timestamp;
-                       int down_ni   = 0;
-                       struct lnet_route *rtr;
-                       if ((peer->lpni_ping_feats &
-                            LNET_PING_FEAT_NI_STATUS) != 0) {
-                               list_for_each_entry(rtr, &peer->lpni_routes,
-                                                   lr_gwlist) {
-                                       /* downis on any route should be the
-                                        * number of downis on the gateway */
-                                       if (rtr->lr_downis != 0) {
-                                               down_ni = rtr->lr_downis;
-                                               break;
-                                       }
-                               }
-                       }
+                       lnet_nid_t nid = peer->lp_primary_nid;
+                       int nrefs     = atomic_read(&peer->lp_refcount);
+                       int nrtrrefs  = peer->lp_rtr_refcount;
+                       int alive     = lnet_is_gateway_alive(peer);
  
-                       if (deadline == 0)
-                               s += snprintf(s, tmpstr + tmpsiz - s,
-                                             "%-4d %7d %9d %6s %12llu %9d %8s %7d %s\n",
-                                             nrefs, nrtrrefs, alive_cnt,
-                                             alive ? "up" : "down", last_ping,
-                                             pingsent, "NA", down_ni,
-                                             libcfs_nid2str(nid));
-                       else
-                               s += snprintf(s, tmpstr + tmpsiz - s,
-                                             "%-4d %7d %9d %6s %12llu %9d %8llu %7d %s\n",
-                                             nrefs, nrtrrefs, alive_cnt,
-                                             alive ? "up" : "down", last_ping,
-                                             pingsent,
-                                             deadline - now,
-                                             down_ni, libcfs_nid2str(nid));
-                       LASSERT(tmpstr + tmpsiz - s > 0);
+                       s += snprintf(s, tmpstr + tmpsiz - s,
+                                     "%-4d %7d %5s %s\n",
+                                     nrefs, nrtrrefs,
+                                     alive ? "up" : "down",
+                                     libcfs_nid2str(nid));
                }
  
                lnet_net_unlock(0);
@@@ -535,20 -501,8 +501,8 @@@ proc_lnet_peers(struct ctl_table *table
  
                        if (lnet_isrouter(peer) ||
                            lnet_peer_aliveness_enabled(peer))
-                               aliveness = peer->lpni_alive ? "up" : "down";
-                       if (lnet_peer_aliveness_enabled(peer)) {
-                               time64_t now = ktime_get_seconds();
-                               lastalive = now - peer->lpni_last_alive;
-                               /* No need to mess up peers contents with
-                                * arbitrarily long integers - it suffices to
-                                * know that lastalive is more than 10000s old
-                                */
-                               if (lastalive >= 10000)
-                                       lastalive = 9999;
-                       }
+                               aliveness = lnet_is_peer_ni_alive(peer) ?
+                                       "up" : "down";
  
                        lnet_net_unlock(cpt);
  
@@@ -735,20 -689,18 +689,20 @@@ proc_lnet_nis(struct ctl_table *table, 
                        int j;
  
                        if (the_lnet.ln_routing)
-                               last_alive = now - ni->ni_last_alive;
+                               last_alive = now - ni->ni_net->net_last_alive;
  
 -                      /* @lo forever alive */
 -                      if (ni->ni_net->net_lnd->lnd_type == LOLND)
 -                              last_alive = 0;
 -
                        lnet_ni_lock(ni);
                        LASSERT(ni->ni_status != NULL);
                        stat = (ni->ni_status->ns_status ==
                                LNET_NI_STATUS_UP) ? "up" : "down";
                        lnet_ni_unlock(ni);
  
 +                      /* @lo forever alive */
 +                      if (ni->ni_net->net_lnd->lnd_type == LOLND) {
 +                              last_alive = 0;
 +                              stat = "up";
 +                      }
 +
                        /* we actually output credits information for
                         * TX queue of each partition */
                        cfs_percpt_for_each(tq, i, ni->ni_tx_queues) {
diff --combined lustre/tests/sanity.sh
@@@ -1533,112 -1533,6 +1533,112 @@@ test_27b() 
  }
  run_test 27b "create and write to two stripe file"
  
 +# 27c family tests specific striping, setstripe -o
 +test_27ca() {
 +      [[ $OSTCOUNT -lt 2 ]] && skip_env "skipping 2-stripe test"
 +      test_mkdir -p $DIR/$tdir
 +      local osts="1"
 +
 +      $LFS setstripe -o $osts $DIR/$tdir/$tfile  || error "setstripe failed"
 +      $LFS getstripe -i $DIR/$tdir/$tfile
 +      [ $($LFS getstripe -i $DIR/$tdir/$tfile ) -eq $osts ] ||
 +              error "stripe not on specified OST"
 +
 +      dd if=/dev/zero of=$DIR/$tdir/$tfile  bs=1M count=4 || error "dd failed"
 +}
 +run_test 27ca "one stripe on specified OST"
 +
 +test_27cb() {
 +      [[ $OSTCOUNT -lt 2 ]] && skip_env "skipping 2-stripe test"
 +      test_mkdir -p $DIR/$tdir
 +      local osts="1,0"
 +      $LFS setstripe -o $osts $DIR/$tdir/$tfile || error "setstripe failed"
 +      local getstripe=$($LFS getstripe $DIR/$tdir/$tfile)
 +      echo "$getstripe"
 +
 +      # Strip getstripe output to a space separated list of OSTs
 +      local getstripe_osts=$(echo "$getstripe" | sed -e '1,/obdidx/d' |\
 +              awk '{print $1}' | tr '\n' '\ ' | sed -e 's/[[:space:]]*$//')
 +      [ "$getstripe_osts" = "${osts//,/ }" ] ||
 +              error "stripes not on specified OSTs"
 +
 +      dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=4 || error "dd failed"
 +}
 +run_test 27cb "two stripes on specified OSTs"
 +
 +test_27cc() {
 +      [[ $OSTCOUNT -lt 2 ]] && skip_env "skipping 2-stripe test"
 +      [[ $($LCTL get_param mdc.*.import) =~ connect_flags.*overstriping ]] ||
 +              skip "server does not support overstriping"
 +
 +      test_mkdir -p $DIR/$tdir
 +      local osts="0,0"
 +      $LFS setstripe -o $osts $DIR/$tdir/$tfile || error "setstripe failed"
 +      local getstripe=$($LFS getstripe $DIR/$tdir/$tfile)
 +      echo "$getstripe"
 +
 +      # Strip getstripe output to a space separated list of OSTs
 +      local getstripe_osts=$(echo "$getstripe" | sed -e '1,/obdidx/d' |\
 +              awk '{print $1}' | tr '\n' '\ ' | sed -e 's/[[:space:]]*$//')
 +      [ "$getstripe_osts" = "${osts//,/ }" ] ||
 +              error "stripes not on specified OSTs"
 +
 +      dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=4 || error "dd failed"
 +}
 +run_test 27cc "two stripes on the same OST"
 +
 +test_27cd() {
 +      [[ $OSTCOUNT -lt 2 ]] && skip_env "skipping 2-stripe test"
 +      [[ $($LCTL get_param mdc.*.import) =~ connect_flags.*overstriping ]] ||
 +              skip "server does not support overstriping"
 +      test_mkdir -p $DIR/$tdir
 +      local osts="0,1,1,0"
 +      $LFS setstripe -o $osts $DIR/$tdir/$tfile || error "setstripe failed"
 +      local getstripe=$($LFS getstripe $DIR/$tdir/$tfile)
 +      echo "$getstripe"
 +
 +      # Strip getstripe output to a space separated list of OSTs
 +      local getstripe_osts=$(echo "$getstripe" | sed -e '1,/obdidx/d' |\
 +              awk '{print $1}' | tr '\n' '\ ' | sed -e 's/[[:space:]]*$//')
 +      [ "$getstripe_osts" = "${osts//,/ }" ] ||
 +              error "stripes not on specified OSTs"
 +
 +      dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=4 || error "dd failed"
 +}
 +run_test 27cd "four stripes on two OSTs"
 +
 +test_27ce() {
 +      [[ $OSTCOUNT -ge $(($LOV_MAX_STRIPE_COUNT / 2)) ]] &&
 +              skip_env "too many osts, skipping"
 +      [[ $($LCTL get_param mdc.*.import) =~ connect_flags.*overstriping ]] ||
 +              skip "server does not support overstriping"
 +      # We do one more stripe than we have OSTs
 +      [ $OSTCOUNT -ge 159 ] || large_xattr_enabled ||
 +              skip_env "ea_inode feature disabled"
 +
 +      test_mkdir -p $DIR/$tdir
 +      local osts=""
 +      for i in $(seq 0 $OSTCOUNT);
 +      do
 +              osts=$osts"0"
 +              if [ $i -ne $OSTCOUNT ]; then
 +                      osts=$osts","
 +              fi
 +      done
 +      $LFS setstripe -o $osts $DIR/$tdir/$tfile || error "setstripe failed"
 +      local getstripe=$($LFS getstripe $DIR/$tdir/$tfile)
 +      echo "$getstripe"
 +
 +      # Strip getstripe output to a space separated list of OSTs
 +      local getstripe_osts=$(echo "$getstripe" | sed -e '1,/obdidx/d' |\
 +              awk '{print $1}' | tr '\n' '\ ' | sed -e 's/[[:space:]]*$//')
 +      [ "$getstripe_osts" = "${osts//,/ }" ] ||
 +              error "stripes not on specified OSTs"
 +
 +      dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=4 || error "dd failed"
 +}
 +run_test 27ce "more stripes than OSTs with -o"
 +
  test_27d() {
        test_mkdir $DIR/$tdir
        $LFS setstripe -c 0 -i -1 -S 0 $DIR/$tdir/$tfile ||
@@@ -2294,8 -2188,7 +2294,8 @@@ test_27B() { # LU-252
  }
  run_test 27B "call setstripe on open unlinked file/rename victim"
  
 -test_27C() { #LU-2871
 +# 27C family tests full striping and overstriping
 +test_27Ca() { #LU-2871
        [[ $OSTCOUNT -lt 2 ]] && skip_env "needs >= 2 OSTs"
  
        declare -a ost_idx
                done
        done
  }
 -run_test 27C "check full striping across all OSTs"
 +run_test 27Ca "check full striping across all OSTs"
 +
 +test_27Cb() {
 +      [[ $($LCTL get_param mdc.*.import) =~ connect_flags.*overstriping ]] ||
 +              skip "server does not support overstriping"
 +      [[ $OSTCOUNT -ge $(($LOV_MAX_STRIPE_COUNT / 2)) ]] &&
 +              skip_env "too many osts, skipping"
 +
 +      test_mkdir -p $DIR/$tdir
 +      local setcount=$(($OSTCOUNT * 2))
 +      [ $setcount -ge 160 ] || large_xattr_enabled ||
 +              skip_env "ea_inode feature disabled"
 +
 +      $LFS setstripe -C $setcount $DIR/$tdir/$tfile ||
 +              error "setstripe failed"
 +
 +      local count=$($LFS getstripe -c $DIR/$tdir/$tfile)
 +      [ $count -eq $setcount ] ||
 +              error "stripe count $count, should be $setcount"
 +
 +      $LFS getstripe $DIR/$tdir/$tfile 2>&1 | grep "overstriped" ||
 +              error "overstriped should be set in pattern"
 +
 +      dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=4 conv=notrunc ||
 +              error "dd failed"
 +}
 +run_test 27Cb "more stripes than OSTs with -C"
 +
 +test_27Cc() {
 +      [[ $($LCTL get_param mdc.*.import) =~ connect_flags.*overstriping ]] ||
 +              skip "server does not support overstriping"
 +      [[ $OSTCOUNT -lt 2 ]] && skip_env "need > 1 OST"
 +
 +      test_mkdir -p $DIR/$tdir
 +      local setcount=$(($OSTCOUNT - 1))
 +
 +      [ $setcount -ge 160 ] || large_xattr_enabled ||
 +              skip_env "ea_inode feature disabled"
 +
 +      $LFS setstripe -C $setcount $DIR/$tdir/$tfile ||
 +              error "setstripe failed"
 +
 +      local count=$($LFS getstripe -c $DIR/$tdir/$tfile)
 +      [ $count -eq $setcount ] ||
 +              error "stripe count $count, should be $setcount"
 +
 +      $LFS getstripe $DIR/$tdir/$tfile 2>&1 | grep "overstriped" &&
 +              error "overstriped should not be set in pattern"
 +
 +      dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=4 conv=notrunc ||
 +              error "dd failed"
 +}
 +run_test 27Cc "fewer stripes than OSTs does not set overstriping"
 +
 +test_27Cd() {
 +      [[ $($LCTL get_param mdc.*.import) =~ connect_flags.*overstriping ]] ||
 +              skip "server does not support overstriping"
 +      [[ $OSTCOUNT -lt 2 ]] && skip_env "need > 1 OST"
 +      large_xattr_enabled || skip_env "ea_inode feature disabled"
 +
 +      test_mkdir -p $DIR/$tdir
 +      local setcount=$LOV_MAX_STRIPE_COUNT
 +
 +      $LFS setstripe -C $setcount $DIR/$tdir/$tfile ||
 +              error "setstripe failed"
 +
 +      local count=$($LFS getstripe -c $DIR/$tdir/$tfile)
 +      [ $count -eq $setcount ] ||
 +              error "stripe count $count, should be $setcount"
 +
 +      $LFS getstripe $DIR/$tdir/$tfile 2>&1 | grep "overstriped" ||
 +              error "overstriped should be set in pattern"
 +
 +      dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=4 conv=notrunc ||
 +              error "dd failed"
 +
 +      rm -f $DIR/$tdir/$tfile || error "Delete $tfile failed"
 +}
 +run_test 27Cd "test maximum stripe count"
 +
 +test_27Ce() {
 +      [[ $($LCTL get_param mdc.*.import) =~ connect_flags.*overstriping ]] ||
 +              skip "server does not support overstriping"
 +      test_mkdir -p $DIR/$tdir
 +
 +      pool_add $TESTNAME || error "Pool creation failed"
 +      pool_add_targets $TESTNAME 0 || error "pool_add_targets failed"
 +
 +      local setcount=8
 +
 +      $LFS setstripe  -C $setcount -p "$TESTNAME" $DIR/$tdir/$tfile ||
 +              error "setstripe failed"
 +
 +      local count=$($LFS getstripe -c $DIR/$tdir/$tfile)
 +      [ $count -eq $setcount ] ||
 +              error "stripe count $count, should be $setcount"
 +
 +      $LFS getstripe $DIR/$tdir/$tfile 2>&1 | grep "overstriped" ||
 +              error "overstriped should be set in pattern"
 +
 +      dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=4 conv=notrunc ||
 +              error "dd failed"
 +
 +      rm -f $DIR/$tdir/$tfile || error "Delete $tfile failed"
 +}
 +run_test 27Ce "test pool with overstriping"
 +
 +test_27Cf() {
 +      [[ $($LCTL get_param mdc.*.import) =~ connect_flags.*overstriping ]] ||
 +              skip "server does not support overstriping"
 +      [[ $OSTCOUNT -ge $(($LOV_MAX_STRIPE_COUNT / 2)) ]] &&
 +              skip_env "too many osts, skipping"
 +
 +      test_mkdir -p $DIR/$tdir
 +
 +      local setcount=$(($OSTCOUNT * 2))
 +      [ $setcount -ge 160 ] || large_xattr_enabled ||
 +              skip_env "ea_inode feature disabled"
 +
 +      $LFS setstripe  -C $setcount $DIR/$tdir/ ||
 +              error "setstripe failed"
 +
 +      echo 1 > $DIR/$tdir/$tfile
 +
 +      local count=$($LFS getstripe -c $DIR/$tdir/$tfile)
 +      [ $count -eq $setcount ] ||
 +              error "stripe count $count, should be $setcount"
 +
 +      $LFS getstripe $DIR/$tdir/$tfile 2>&1 | grep "overstriped" ||
 +              error "overstriped should be set in pattern"
 +
 +      dd if=/dev/zero of=$DIR/$tdir/$tfile bs=1M count=4 conv=notrunc ||
 +              error "dd failed"
 +
 +      rm -f $DIR/$tdir/$tfile || error "Delete $tfile failed"
 +}
 +run_test 27Cf "test default inheritance with overstriping"
  
  test_27D() {
        [ $OSTCOUNT -lt 2 ] && skip_env "needs >= 2 OSTs"
        [ $MDS1_VERSION -lt $(version_code 2.9.55) ] ||
                [ $CLIENT_VERSION -lt $(version_code 2.9.55) ] &&
                        skip27D+=" -s 30,31"
 +      [[ ! $($LCTL get_param mdc.*.import) =~ connect_flags.*overstriping ||
 +        $OSTCOUNT -ge $(($LOV_MAX_STRIPE_COUNT / 2)) ]] &&
 +              skip27D+=" -s 32,33"
        llapi_layout_test -d$DIR/$tdir -p$POOL -o$OSTCOUNT $skip27D ||
                error "llapi_layout_test failed"
  
@@@ -6948,39 -6702,6 +6948,39 @@@ test_60g() 
  }
  run_test 60g "transaction abort won't cause MDT hung"
  
 +test_60h() {
 +      [ $MDS1_VERSION -le $(version_code 2.12.52) ] ||
 +              skip "Need MDS version at least 2.12.52"
 +      [ $MDSCOUNT -le 2 ] || skip "Need >= 2 MDTs"
 +
 +      local f
 +
 +      #define OBD_FAIL_MDS_STRIPE_CREATE       0x188
 +      #define OBD_FAIL_MDS_STRIPE_FID          0x189
 +      for fail_loc in 0x80000188 0x80000189; do
 +              do_facet mds1 "$LCTL set_param fail_loc=$fail_loc"
 +              $LFS mkdir -c $MDSCOUNT -i 0 $DIR/$tdir-$fail_loc ||
 +                      error "mkdir $dir-$fail_loc failed"
 +              for i in {0..10}; do
 +                      # create may fail on missing stripe
 +                      echo $i > $DIR/$tdir-$fail_loc/$i
 +              done
 +              $LFS getdirstripe $DIR/$tdir-$fail_loc ||
 +                      error "getdirstripe $tdir-$fail_loc failed"
 +              $LFS migrate -m 1 $DIR/$tdir-$fail_loc ||
 +                      error "migrate $tdir-$fail_loc failed"
 +              $LFS getdirstripe $DIR/$tdir-$fail_loc ||
 +                      error "getdirstripe $tdir-$fail_loc failed"
 +              pushd $DIR/$tdir-$fail_loc
 +              for f in *; do
 +                      echo $f | cmp $f - || error "$f data mismatch"
 +              done
 +              popd
 +              rm -rf $DIR/$tdir-$fail_loc
 +      done
 +}
 +run_test 60h "striped directory with missing stripes can be accessed"
 +
  test_61a() {
        [ $PARALLEL == "yes" ] && skip "skip parallel run"
  
@@@ -7211,9 -6932,9 +7211,9 @@@ test_65d() 
  
        if [[ $STRIPECOUNT -le 0 ]]; then
                sc=1
 -      elif [[ $STRIPECOUNT -gt 2000 ]]; then
 -#LOV_MAX_STRIPE_COUNT is 2000
 -              [[ $OSTCOUNT -gt 2000 ]] && sc=2000 || sc=$(($OSTCOUNT - 1))
 +      elif [[ $STRIPECOUNT -gt $LOV_MAX_STRIPE_COUNT ]]; then
 +              [[ $OSTCOUNT -gt $LOV_MAX_STRIPE_COUNT ]] &&
 +                      sc=$LOV_MAX_STRIPE_COUNT || sc=$(($OSTCOUNT - 1))
        else
                sc=$(($STRIPECOUNT - 1))
        fi
@@@ -15038,8 -14759,8 +15038,8 @@@ test_215() { # for bugs 18102, 21079, 2
        # where ref > 0, rtr_ref > 0, alive_cnt >= 0, state is up/down,
        # last_ping >= 0, ping_sent is boolean (0/1), deadline and down_ni are
        # numeric (0 or >0 or <0), router is a string like 192.168.1.1@tcp2
-       L1="^ref +rtr_ref +alive_cnt +state +last_ping +ping_sent +deadline +down_ni +router$"
-       BR="^$P +$P +$N +(up|down) +$N +(0|1) +$I +$I +$NID$"
+       L1="^ref +rtr_ref +alive +router$"
+       BR="^$P +$P +(up|down) +$NID$"
        create_lnet_proc_files "routers"
        check_lnet_proc_entry "routers.sys" "lnet.routers" "$BR" "$L1"
        remove_lnet_proc_files "routers"
@@@ -18107,26 -17828,6 +18107,26 @@@ test_271f() 
  }
  run_test 271f "DoM: read on open (200K file and read tail)"
  
 +test_271g() {
 +      [[ $($LCTL get_param mdc.*.import) =~ async_discard ]] ||
 +              skip "Skipping due to old client or server version"
 +
 +      $LFS setstripe -E 1024K -L mdt -E EOF $DIR1/$tfile
 +      # to get layout
 +      $CHECKSTAT -t file $DIR1/$tfile
 +
 +      $MULTIOP $DIR1/$tfile Ow40960_w4096c &
 +      MULTIOP_PID=$!
 +      sleep 1
 +      #define OBD_FAIL_LDLM_CANCEL_BL_CB_RACE
 +      $LCTL set_param fail_loc=0x80000314
 +      rm $DIR1/$tfile || error "Unlink fails"
 +      RC=$?
 +      kill -USR1 $MULTIOP_PID && wait $MULTIOP_PID || error "multiop failure"
 +      [ $RC -eq 0 ] || error "Failed write to stale object"
 +}
 +run_test 271g "Discard DoM data vs client flush race"
 +
  test_272a() {
        [ $MDS1_VERSION -lt $(version_code 2.11.50) ] &&
                skip "Need MDS version at least 2.11.50"
@@@ -21163,15 -20864,6 +21163,15 @@@ test_813() 
  }
  run_test 813 "File heat verfication"
  
 +test_814()
 +{
 +      dd of=$DIR/$tfile seek=128 bs=1k < /dev/null
 +      echo -n y >> $DIR/$tfile
 +      cp --sparse=always $DIR/$tfile $DIR/${tfile}.cp || error "copy failed"
 +      diff $DIR/$tfile $DIR/${tfile}.cp || error "files should be same"
 +}
 +run_test 814 "sparse cp works as expected (LU-12361)"
 +
  #
  # tests that do cleanup/setup should be run at the end
  #