+ the_lnet.ln_rc_state = LNET_RC_STATE_SHUTDOWN;
+ return;
+}
+
+#if defined(__KERNEL__) && defined(LNET_ROUTER)
+
+static void
+lnet_prune_zombie_rcd (int wait_unlink)
+{
+ lnet_rc_data_t *rcd;
+ lnet_rc_data_t *tmp;
+ cfs_list_t free_rcd;
+ int i;
+ __u64 version;
+
+ CFS_INIT_LIST_HEAD(&free_rcd);
+
+ LNET_LOCK();
+rescan:
+ version = the_lnet.ln_routers_version;
+ cfs_list_for_each_entry_safe (rcd, tmp, &the_lnet.ln_zombie_rcd,
+ rcd_list) {
+ if (LNetHandleIsInvalid(rcd->rcd_mdh)) {
+ cfs_list_del(&rcd->rcd_list);
+ cfs_list_add(&rcd->rcd_list, &free_rcd);
+ continue;
+ }
+
+ LNET_UNLOCK();
+
+ LNetMDUnlink(rcd->rcd_mdh);
+
+ LNET_LOCK();
+ if (version != the_lnet.ln_routers_version)
+ goto rescan;
+ }
+
+ i = 2;
+ while (wait_unlink && !cfs_list_empty(&the_lnet.ln_zombie_rcd)) {
+ rcd = cfs_list_entry(the_lnet.ln_zombie_rcd.next,
+ lnet_rc_data_t, rcd_list);
+ if (LNetHandleIsInvalid(rcd->rcd_mdh)) {
+ cfs_list_del(&rcd->rcd_list);
+ cfs_list_add(&rcd->rcd_list, &free_rcd);
+ continue;
+ }
+
+ LNET_UNLOCK();
+
+ LNetMDUnlink(rcd->rcd_mdh);
+
+ i++;
+ CDEBUG(((i & (-i)) == i) ? D_WARNING : D_NET,
+ "Waiting for rc buffers to unlink\n");
+ cfs_pause(cfs_time_seconds(1));
+
+ LNET_LOCK();
+ }
+
+ LNET_UNLOCK();
+
+ while (!cfs_list_empty(&free_rcd)) {
+ rcd = cfs_list_entry(free_rcd.next, lnet_rc_data_t, rcd_list);
+ cfs_list_del_init(&rcd->rcd_list);
+ lnet_destroy_rc_data(rcd);
+ }
+ return;
+}
+
+static int
+lnet_router_checker(void *arg)
+{
+ int rc;
+ lnet_peer_t *rtr;
+ cfs_list_t *entry;
+ lnet_process_id_t rtr_id;
+
+ cfs_daemonize("router_checker");
+ cfs_block_allsigs();
+
+ rtr_id.pid = LUSTRE_SRV_LNET_PID;
+
+ LASSERT (the_lnet.ln_rc_state == LNET_RC_STATE_RUNNING);
+
+ while (the_lnet.ln_rc_state == LNET_RC_STATE_RUNNING) {
+ __u64 version;
+
+ LNET_LOCK();
+rescan:
+ version = the_lnet.ln_routers_version;
+
+ cfs_list_for_each (entry, &the_lnet.ln_routers) {
+ rtr = cfs_list_entry(entry, lnet_peer_t, lp_rtr_list);
+ lnet_ping_router_locked(rtr);
+
+ /* NB dropped lock */
+ if (version != the_lnet.ln_routers_version) {
+ /* the routers list has changed */
+ goto rescan;
+ }
+ }
+
+ LNET_UNLOCK();
+
+ if (the_lnet.ln_routing)
+ lnet_update_ni_status();
+
+ lnet_prune_zombie_rcd(0); /* don't wait for UNLINK */
+
+ /* Call cfs_pause() here always adds 1 to load average
+ * because kernel counts # active tasks as nr_running
+ * + nr_uninterruptible. */
+ cfs_schedule_timeout_and_set_state(CFS_TASK_INTERRUPTIBLE,
+ cfs_time_seconds(1));
+ }
+
+ LNET_LOCK();
+
+ cfs_list_for_each (entry, &the_lnet.ln_routers) {
+ rtr = cfs_list_entry(entry, lnet_peer_t, lp_rtr_list);
+
+ if (rtr->lp_rcd == NULL)
+ continue;
+
+ LASSERT (cfs_list_empty(&rtr->lp_rcd->rcd_list));
+ cfs_list_add(&rtr->lp_rcd->rcd_list, &the_lnet.ln_zombie_rcd);
+ rtr->lp_rcd = NULL;
+ }
+
+ LNET_UNLOCK();
+
+ lnet_prune_zombie_rcd(1); /* wait for UNLINK */
+
+ LASSERT (the_lnet.ln_rc_state == LNET_RC_STATE_STOPTHREAD);
+ the_lnet.ln_rc_state = LNET_RC_STATE_UNLINKING;
+
+ rc = LNetMDUnlink(the_lnet.ln_rc_mdh);
+ LASSERT (rc == 0);
+
+ /* The unlink event callback will signal final completion */
+ return 0;