Whamcloud - gitweb
LU-4423 lnet: check for null pointer at line 1569 of router.c
[fs/lustre-release.git] / lnet / lnet / router.c
index edfa384..6699245 100644 (file)
@@ -3,8 +3,7 @@
  *
  * Copyright (c) 2011, 2014, Intel Corporation.
  *
- *   This file is part of Portals
- *   http://sourceforge.net/projects/sandiaportals/
+ *   This file is part of Lustre, https://wiki.hpdd.intel.com/
  *
  *   Portals is free software; you can redistribute it and/or
  *   modify it under the terms of version 2 of the GNU General Public
@@ -24,8 +23,6 @@
 #define DEBUG_SUBSYSTEM S_LNET
 #include <lnet/lib-lnet.h>
 
-#if defined(__KERNEL__) && defined(LNET_ROUTER)
-
 #define LNET_NRB_TINY_MIN      512     /* min value for each CPT */
 #define LNET_NRB_TINY          (LNET_NRB_TINY_MIN * 4)
 #define LNET_NRB_SMALL_MIN     4096    /* min value for each CPT */
@@ -73,15 +70,6 @@ lnet_peer_buffer_credits(lnet_ni_t *ni)
 
 /* forward ref's */
 static int lnet_router_checker(void *);
-#else
-
-int
-lnet_peer_buffer_credits(lnet_ni_t *ni)
-{
-        return 0;
-}
-
-#endif
 
 static int check_routers_before_use = 0;
 CFS_MODULE_PARM(check_routers_before_use, "i", int, 0444,
@@ -148,7 +136,7 @@ lnet_ni_notify_locked(lnet_ni_t *ni, lnet_peer_t *lp)
          * NB individual events can be missed; the only guarantee is that you
          * always get the most recent news */
 
-       if (lp->lp_notifying)
+       if (lp->lp_notifying || ni == NULL)
                 return;
 
         lp->lp_notifying = 1;
@@ -248,10 +236,11 @@ lnet_find_net_locked (__u32 net)
 
 static void lnet_shuffle_seed(void)
 {
-        static int seeded = 0;
-        int lnd_type, seed[2];
-        struct timeval tv;
-        lnet_ni_t *ni;
+       static int seeded;
+       __u32 lnd_type;
+       __u32 seed[2];
+       struct timeval tv;
+       lnet_ni_t *ni;
        struct list_head *tmp;
 
         if (seeded)
@@ -416,6 +405,9 @@ lnet_add_route(__u32 net, unsigned int hops, lnet_nid_t gateway,
        if (rnet != rnet2)
                LIBCFS_FREE(rnet, sizeof(*rnet));
 
+       /* indicate to startup the router checker if configured */
+       wake_up(&the_lnet.ln_rc_waitq);
+
        return rc;
 }
 
@@ -735,6 +727,11 @@ lnet_parse_rc_info(lnet_rc_data_t *rcd)
                        rte->lr_downis = 0;
                        continue;
                }
+               /* if @down is zero and this route is single-hop, it means
+                * we can't find NI for target network */
+               if (down == 0 && rte->lr_hops == 1)
+                       down = 1;
+
                rte->lr_downis = down;
        }
 }
@@ -819,11 +816,9 @@ lnet_wait_known_routerstate(void)
                if (all_known)
                         return;
 
-#ifndef __KERNEL__
-                lnet_router_checker();
-#endif
-                cfs_pause(cfs_time_seconds(1));
-        }
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(cfs_time_seconds(1));
+       }
 }
 
 void
@@ -1061,67 +1056,10 @@ int
 lnet_router_checker_start(void)
 {
        int                     rc;
-       int                     eqsz;
-#ifdef __KERNEL__
+       int                     eqsz = 0;
        struct task_struct     *task;
-#else /* __KERNEL__ */
-       lnet_peer_t            *rtr;
-       __u64                   version;
-       int                     nrtr = 0;
-       int                     router_checker_max_eqsize = 10240;
-
-        LASSERT (check_routers_before_use);
-        LASSERT (dead_router_check_interval > 0);
-
-       lnet_net_lock(0);
-
-        /* As an approximation, allow each router the same number of
-         * outstanding events as it is allowed outstanding sends */
-        eqsz = 0;
-        version = the_lnet.ln_routers_version;
-       list_for_each_entry(rtr, &the_lnet.ln_routers, lp_rtr_list) {
-                lnet_ni_t         *ni = rtr->lp_ni;
-                lnet_process_id_t  id;
-
-                nrtr++;
-                eqsz += ni->ni_peertxcredits;
-
-                /* one async ping reply per router */
-                id.nid = rtr->lp_nid;
-               id.pid = LNET_PID_LUSTRE;
-
-               lnet_net_unlock(0);
-
-                rc = LNetSetAsync(id, 1);
-                if (rc != 0) {
-                        CWARN("LNetSetAsync %s failed: %d\n",
-                              libcfs_id2str(id), rc);
-                        return rc;
-                }
-
-               lnet_net_lock(0);
-               /* NB router list doesn't change in userspace */
-               LASSERT(version == the_lnet.ln_routers_version);
-       }
-
-       lnet_net_unlock(0);
-
-        if (nrtr == 0) {
-                CDEBUG(D_NET,
-                       "No router found, not starting router checker\n");
-                return 0;
-        }
 
-        /* at least allow a SENT and a REPLY per router */
-        if (router_checker_max_eqsize < 2 * nrtr)
-                router_checker_max_eqsize = 2 * nrtr;
-
-        LASSERT (eqsz > 0);
-        if (eqsz > router_checker_max_eqsize)
-                eqsz = router_checker_max_eqsize;
-#endif
-
-        LASSERT (the_lnet.ln_rc_state == LNET_RC_STATE_SHUTDOWN);
+       LASSERT(the_lnet.ln_rc_state == LNET_RC_STATE_SHUTDOWN);
 
         if (check_routers_before_use &&
             dead_router_check_interval <= 0) {
@@ -1131,29 +1069,15 @@ lnet_router_checker_start(void)
                 return -EINVAL;
         }
 
-        if (!the_lnet.ln_routing &&
-            live_router_check_interval <= 0 &&
-            dead_router_check_interval <= 0)
-                return 0;
-
-#ifdef __KERNEL__
        sema_init(&the_lnet.ln_rc_signal, 0);
-        /* EQ size doesn't matter; the callback is guaranteed to get every
-         * event */
-       eqsz = 0;
-        rc = LNetEQAlloc(eqsz, lnet_router_checker_event,
-                         &the_lnet.ln_rc_eqh);
-#else
-        rc = LNetEQAlloc(eqsz, LNET_EQ_HANDLER_NONE,
-                         &the_lnet.ln_rc_eqh);
-#endif
-        if (rc != 0) {
-                CERROR("Can't allocate EQ(%d): %d\n", eqsz, rc);
-                return -ENOMEM;
-        }
 
-        the_lnet.ln_rc_state = LNET_RC_STATE_RUNNING;
-#ifdef __KERNEL__
+       rc = LNetEQAlloc(0, lnet_router_checker_event, &the_lnet.ln_rc_eqh);
+       if (rc != 0) {
+               CERROR("Can't allocate EQ(%d): %d\n", eqsz, rc);
+               return -ENOMEM;
+       }
+
+       the_lnet.ln_rc_state = LNET_RC_STATE_RUNNING;
        task = kthread_run(lnet_router_checker, NULL, "router_checker");
        if (IS_ERR(task)) {
                rc = PTR_ERR(task);
@@ -1165,7 +1089,6 @@ lnet_router_checker_start(void)
                the_lnet.ln_rc_state = LNET_RC_STATE_SHUTDOWN;
                return -ENOMEM;
        }
-#endif
 
         if (check_routers_before_use) {
                 /* Note that a helpful side-effect of pinging all known routers
@@ -1180,20 +1103,18 @@ lnet_router_checker_start(void)
 void
 lnet_router_checker_stop (void)
 {
-        int rc;
+       int rc;
 
-        if (the_lnet.ln_rc_state == LNET_RC_STATE_SHUTDOWN)
-                return;
+       if (the_lnet.ln_rc_state == LNET_RC_STATE_SHUTDOWN)
+               return;
 
-        LASSERT (the_lnet.ln_rc_state == LNET_RC_STATE_RUNNING);
+       LASSERT (the_lnet.ln_rc_state == LNET_RC_STATE_RUNNING);
        the_lnet.ln_rc_state = LNET_RC_STATE_STOPPING;
+       /* wakeup the RC thread if it's sleeping */
+       wake_up(&the_lnet.ln_rc_waitq);
 
-#ifdef __KERNEL__
        /* block until event callback signals exit */
        down(&the_lnet.ln_rc_signal);
-#else
-       lnet_router_checker();
-#endif
        LASSERT(the_lnet.ln_rc_state == LNET_RC_STATE_SHUTDOWN);
 
         rc = LNetEQFree(the_lnet.ln_rc_eqh);
@@ -1273,7 +1194,8 @@ lnet_prune_rc_data(int wait_unlink)
                i++;
                CDEBUG(((i & (-i)) == i) ? D_WARNING : D_NET,
                       "Waiting for rc buffers to unlink\n");
-               cfs_pause(cfs_time_seconds(1) / 4);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(cfs_time_seconds(1) / 4);
 
                lnet_net_lock(LNET_LOCK_EX);
        }
@@ -1281,20 +1203,42 @@ lnet_prune_rc_data(int wait_unlink)
        lnet_net_unlock(LNET_LOCK_EX);
 }
 
+/*
+ * This function is called to check if the RC should block indefinitely.
+ * It's called from lnet_router_checker() as well as being passed to
+ * wait_event_interruptible() to avoid the lost wake_up problem.
+ *
+ * When it's called from wait_event_interruptible() it is necessary to
+ * also not sleep if the rc state is not running to avoid a deadlock
+ * when the system is shutting down
+ */
+static inline bool
+lnet_router_checker_active(void)
+{
+       if (the_lnet.ln_rc_state != LNET_RC_STATE_RUNNING)
+               return true;
 
-#if defined(__KERNEL__) && defined(LNET_ROUTER)
+       /* Router Checker thread needs to run when routing is enabled in
+        * order to call lnet_update_ni_status_locked() */
+       if (the_lnet.ln_routing)
+               return true;
+
+       return !list_empty(&the_lnet.ln_routers) &&
+               (live_router_check_interval > 0 ||
+                dead_router_check_interval > 0);
+}
 
 static int
 lnet_router_checker(void *arg)
 {
-        lnet_peer_t       *rtr;
+       lnet_peer_t       *rtr;
        struct list_head  *entry;
 
-        cfs_block_allsigs();
+       cfs_block_allsigs();
 
-        LASSERT (the_lnet.ln_rc_state == LNET_RC_STATE_RUNNING);
+       LASSERT (the_lnet.ln_rc_state == LNET_RC_STATE_RUNNING);
 
-        while (the_lnet.ln_rc_state == LNET_RC_STATE_RUNNING) {
+       while (the_lnet.ln_rc_state == LNET_RC_STATE_RUNNING) {
                __u64   version;
                int     cpt;
                int     cpt2;
@@ -1316,14 +1260,14 @@ rescan:
                                        goto rescan;
                        }
 
-                        lnet_ping_router_locked(rtr);
+                       lnet_ping_router_locked(rtr);
 
-                        /* NB dropped lock */
-                        if (version != the_lnet.ln_routers_version) {
-                                /* the routers list has changed */
-                                goto rescan;
-                        }
-                }
+                       /* NB dropped lock */
+                       if (version != the_lnet.ln_routers_version) {
+                               /* the routers list has changed */
+                               goto rescan;
+                       }
+               }
 
                if (the_lnet.ln_routing)
                        lnet_update_ni_status_locked();
@@ -1332,11 +1276,19 @@ rescan:
 
                lnet_prune_rc_data(0); /* don't wait for UNLINK */
 
-               /* Call cfs_pause() here always adds 1 to load average
+               /* Call schedule_timeout() here always adds 1 to load average
                 * because kernel counts # active tasks as nr_running
                 * + nr_uninterruptible. */
-               schedule_timeout_and_set_state(TASK_INTERRUPTIBLE,
-                                                  cfs_time_seconds(1));
+               /* if there are any routes then wakeup every second.  If
+                * there are no routes then sleep indefinitely until woken
+                * up by a user adding a route */
+               if (!lnet_router_checker_active())
+                       wait_event_interruptible(the_lnet.ln_rc_waitq,
+                                                lnet_router_checker_active());
+               else
+                       wait_event_interruptible_timeout(the_lnet.ln_rc_waitq,
+                                                        false,
+                                                        cfs_time_seconds(1));
        }
 
        LASSERT(the_lnet.ln_rc_state == LNET_RC_STATE_STOPPING);
@@ -1828,133 +1780,3 @@ lnet_notify(lnet_ni_t *ni, lnet_nid_t nid, int alive, cfs_time_t when)
        return 0;
 }
 EXPORT_SYMBOL(lnet_notify);
-
-void
-lnet_get_tunables (void)
-{
-        return;
-}
-
-#else
-
-int
-lnet_notify (lnet_ni_t *ni, lnet_nid_t nid, int alive, cfs_time_t when)
-{
-        return -EOPNOTSUPP;
-}
-
-void
-lnet_router_checker (void)
-{
-        static time_t last = 0;
-        static int    running = 0;
-
-        time_t            now = cfs_time_current_sec();
-        int               interval = now - last;
-        int               rc;
-        __u64             version;
-        lnet_peer_t      *rtr;
-
-        /* It's no use to call me again within a sec - all intervals and
-         * timeouts are measured in seconds */
-        if (last != 0 && interval < 2)
-                return;
-
-        if (last != 0 &&
-            interval > MAX(live_router_check_interval,
-                           dead_router_check_interval))
-                CNETERR("Checker(%d/%d) not called for %d seconds\n",
-                        live_router_check_interval, dead_router_check_interval,
-                        interval);
-
-       LASSERT(LNET_CPT_NUMBER == 1);
-
-       lnet_net_lock(0);
-       LASSERT(!running); /* recursion check */
-       running = 1;
-       lnet_net_unlock(0);
-
-       last = now;
-
-       if (the_lnet.ln_rc_state == LNET_RC_STATE_STOPPING)
-               lnet_prune_rc_data(0); /* unlink all rcd and nowait */
-
-        /* consume all pending events */
-        while (1) {
-                int          i;
-                lnet_event_t ev;
-
-                /* NB ln_rc_eqh must be the 1st in 'eventqs' otherwise the
-                 * recursion breaker in LNetEQPoll would fail */
-                rc = LNetEQPoll(&the_lnet.ln_rc_eqh, 1, 0, &ev, &i);
-                if (rc == 0)   /* no event pending */
-                        break;
-
-                /* NB a lost SENT prevents me from pinging a router again */
-                if (rc == -EOVERFLOW) {
-                        CERROR("Dropped an event!!!\n");
-                        abort();
-                }
-
-                LASSERT (rc == 1);
-
-                lnet_router_checker_event(&ev);
-        }
-
-       if (the_lnet.ln_rc_state == LNET_RC_STATE_STOPPING) {
-               lnet_prune_rc_data(1); /* release rcd */
-               the_lnet.ln_rc_state = LNET_RC_STATE_SHUTDOWN;
-                running = 0;
-                return;
-        }
-
-        LASSERT (the_lnet.ln_rc_state == LNET_RC_STATE_RUNNING);
-
-       lnet_net_lock(0);
-
-       version = the_lnet.ln_routers_version;
-       list_for_each_entry(rtr, &the_lnet.ln_routers, lp_rtr_list) {
-               lnet_ping_router_locked(rtr);
-               LASSERT(version == the_lnet.ln_routers_version);
-       }
-
-       lnet_net_unlock(0);
-
-       running = 0; /* lock only needed for the recursion check */
-       return;
-}
-
-/* NB lnet_peers_start_down depends on me,
- * so must be called before any peer creation */
-void
-lnet_get_tunables (void)
-{
-        char *s;
-
-        s = getenv("LNET_ROUTER_PING_TIMEOUT");
-        if (s != NULL) router_ping_timeout = atoi(s);
-
-        s = getenv("LNET_LIVE_ROUTER_CHECK_INTERVAL");
-        if (s != NULL) live_router_check_interval = atoi(s);
-
-        s = getenv("LNET_DEAD_ROUTER_CHECK_INTERVAL");
-        if (s != NULL) dead_router_check_interval = atoi(s);
-
-        /* This replaces old lnd_notify mechanism */
-        check_routers_before_use = 1;
-        if (dead_router_check_interval <= 0)
-                dead_router_check_interval = 30;
-}
-
-void
-lnet_rtrpools_free(int keep_pools)
-{
-}
-
-int
-lnet_rtrpools_alloc(int im_a_arouter)
-{
-        return 0;
-}
-
-#endif