static void xpc_channel_mgr(struct xpc_partition *part) { while (part->act_state != XPC_P_AS_DEACTIVATING || atomic_read(&part->nchannels_active) > 0 || !xpc_partition_disengaged(part)) { xpc_process_sent_chctl_flags(part); /* */ atomic_dec(&part->channel_mgr_requests); (void)wait_event_interruptible(part->channel_mgr_wq, (atomic_read(&part->channel_mgr_requests) > 0 || part->chctl.all_flags != 0 || (part->act_state == XPC_P_AS_DEACTIVATING && atomic_read(&part->nchannels_active) == 0 && xpc_partition_disengaged(part)))); atomic_set(&part->channel_mgr_requests, 1); } }
/* * The first kthread assigned to a newly activated partition is the one * created by XPC HB with which it calls xpc_activating(). XPC hangs on to * that kthread until the partition is brought down, at which time that kthread * returns back to XPC HB. (The return of that kthread will signify to XPC HB * that XPC has dismantled all communication infrastructure for the associated * partition.) This kthread becomes the channel manager for that partition. * * Each active partition has a channel manager, who, besides connecting and * disconnecting channels, will ensure that each of the partition's connected * channels has the required number of assigned kthreads to get the work done. */ static void xpc_channel_mgr(struct xpc_partition *part) { while (part->act_state != XPC_P_AS_DEACTIVATING || atomic_read(&part->nchannels_active) > 0 || !xpc_partition_disengaged(part)) { xpc_process_sent_chctl_flags(part); /* * Wait until we've been requested to activate kthreads or * all of the channel's message queues have been torn down or * a signal is pending. * * The channel_mgr_requests is set to 1 after being awakened, * This is done to prevent the channel mgr from making one pass * through the loop for each request, since he will * be servicing all the requests in one pass. The reason it's * set to 1 instead of 0 is so that other kthreads will know * that the channel mgr is running and won't bother trying to * wake him up. */ atomic_dec(&part->channel_mgr_requests); (void)wait_event_interruptible(part->channel_mgr_wq, (atomic_read(&part->channel_mgr_requests) > 0 || part->chctl.all_flags != 0 || (part->act_state == XPC_P_AS_DEACTIVATING && atomic_read(&part->nchannels_active) == 0 && xpc_partition_disengaged(part)))); atomic_set(&part->channel_mgr_requests, 1); } }
/* * Timer function to enforce the timelimit on the partition disengage. */ static void xpc_timeout_partition_disengage(unsigned long data) { struct xpc_partition *part = (struct xpc_partition *)data; DBUG_ON(time_is_after_jiffies(part->disengage_timeout)); (void)xpc_partition_disengaged(part); DBUG_ON(part->disengage_timeout != 0); DBUG_ON(xpc_partition_engaged(XPC_PARTID(part))); }
/* * Timer function to enforce the timelimit on the partition disengage request. */ static void xpc_timeout_partition_disengage_request(unsigned long data) { struct xpc_partition *part = (struct xpc_partition *)data; DBUG_ON(time_before(jiffies, part->disengage_request_timeout)); (void)xpc_partition_disengaged(part); DBUG_ON(part->disengage_request_timeout != 0); DBUG_ON(xpc_partition_engaged(1UL << XPC_PARTID(part)) != 0); }
static void xpc_do_exit(enum xp_retval reason) { short partid; int active_part_count, printed_waiting_msg = 0; struct xpc_partition *part; unsigned long printmsg_time, disengage_timeout = 0; /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */ DBUG_ON(xpc_exiting == 1); /* * Let the heartbeat checker thread and the discovery thread * (if one is running) know that they should exit. Also wake up * the heartbeat checker thread in case it's sleeping. */ xpc_exiting = 1; wake_up_interruptible(&xpc_activate_IRQ_wq); /* wait for the discovery thread to exit */ wait_for_completion(&xpc_discovery_exited); /* wait for the heartbeat checker thread to exit */ wait_for_completion(&xpc_hb_checker_exited); /* sleep for a 1/3 of a second or so */ (void)msleep_interruptible(300); /* wait for all partitions to become inactive */ printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); xpc_disengage_timedout = 0; do { active_part_count = 0; for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; if (xpc_partition_disengaged(part) && part->act_state == XPC_P_AS_INACTIVE) { continue; } active_part_count++; XPC_DEACTIVATE_PARTITION(part, reason); if (part->disengage_timeout > disengage_timeout) disengage_timeout = part->disengage_timeout; } if (xpc_any_partition_engaged()) { if (time_is_before_jiffies(printmsg_time)) { dev_info(xpc_part, "waiting for remote " "partitions to deactivate, timeout in " "%ld seconds\n", (disengage_timeout - jiffies) / HZ); printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); printed_waiting_msg = 1; } } else if (active_part_count > 0) { if (printed_waiting_msg) { dev_info(xpc_part, "waiting for local partition" " to deactivate\n"); printed_waiting_msg = 0; } } else { if (!xpc_disengage_timedout) { dev_info(xpc_part, "all partitions have " "deactivated\n"); } break; } /* sleep for a 1/3 of a second or so */ (void)msleep_interruptible(300); } while (1); DBUG_ON(xpc_any_partition_engaged()); DBUG_ON(xpc_any_hbs_allowed() != 0); xpc_teardown_rsvd_page(); if (reason == xpUnloading) { (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); } /* clear the interface to XPC's functions */ xpc_clear_interface(); if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); xpc_teardown_partitions(); if (is_shub()) xpc_exit_sn2(); else if (is_uv()) xpc_exit_uv(); }
static void xpc_do_exit(enum xp_retval reason) { short partid; int active_part_count, printed_waiting_msg = 0; struct xpc_partition *part; unsigned long printmsg_time, disengage_timeout = 0; /* */ DBUG_ON(xpc_exiting == 1); /* */ xpc_exiting = 1; wake_up_interruptible(&xpc_activate_IRQ_wq); /* */ wait_for_completion(&xpc_discovery_exited); /* */ wait_for_completion(&xpc_hb_checker_exited); /* */ (void)msleep_interruptible(300); /* */ printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); xpc_disengage_timedout = 0; do { active_part_count = 0; for (partid = 0; partid < xp_max_npartitions; partid++) { part = &xpc_partitions[partid]; if (xpc_partition_disengaged(part) && part->act_state == XPC_P_AS_INACTIVE) { continue; } active_part_count++; XPC_DEACTIVATE_PARTITION(part, reason); if (part->disengage_timeout > disengage_timeout) disengage_timeout = part->disengage_timeout; } if (xpc_arch_ops.any_partition_engaged()) { if (time_is_before_jiffies(printmsg_time)) { dev_info(xpc_part, "waiting for remote " "partitions to deactivate, timeout in " "%ld seconds\n", (disengage_timeout - jiffies) / HZ); printmsg_time = jiffies + (XPC_DEACTIVATE_PRINTMSG_INTERVAL * HZ); printed_waiting_msg = 1; } } else if (active_part_count > 0) { if (printed_waiting_msg) { dev_info(xpc_part, "waiting for local partition" " to deactivate\n"); printed_waiting_msg = 0; } } else { if (!xpc_disengage_timedout) { dev_info(xpc_part, "all partitions have " "deactivated\n"); } break; } /* */ (void)msleep_interruptible(300); } while (1); DBUG_ON(xpc_arch_ops.any_partition_engaged()); xpc_teardown_rsvd_page(); if (reason == xpUnloading) { (void)unregister_die_notifier(&xpc_die_notifier); (void)unregister_reboot_notifier(&xpc_reboot_notifier); } /* */ xpc_clear_interface(); if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); xpc_teardown_partitions(); if (is_shub()) xpc_exit_sn2(); else if (is_uv()) xpc_exit_uv(); }
static void xpc_do_exit(enum xp_retval reason) { short partid; int active_part_count, printed_waiting_msg = 0; struct xpc_partition *part; unsigned long printmsg_time, disengage_request_timeout = 0; /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */ DBUG_ON(xpc_exiting == 1); /* * Let the heartbeat checker thread and the discovery thread * (if one is running) know that they should exit. Also wake up * the heartbeat checker thread in case it's sleeping. */ xpc_exiting = 1; wake_up_interruptible(&xpc_act_IRQ_wq); /* ignore all incoming interrupts */ free_irq(SGI_XPC_ACTIVATE, NULL); /* wait for the discovery thread to exit */ wait_for_completion(&xpc_discovery_exited); /* wait for the heartbeat checker thread to exit */ wait_for_completion(&xpc_hb_checker_exited); /* sleep for a 1/3 of a second or so */ (void)msleep_interruptible(300); /* wait for all partitions to become inactive */ printmsg_time = jiffies + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); xpc_disengage_request_timedout = 0; do { active_part_count = 0; for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) { part = &xpc_partitions[partid]; if (xpc_partition_disengaged(part) && part->act_state == XPC_P_INACTIVE) { continue; } active_part_count++; XPC_DEACTIVATE_PARTITION(part, reason); if (part->disengage_request_timeout > disengage_request_timeout) { disengage_request_timeout = part->disengage_request_timeout; } } if (xpc_partition_engaged(-1UL)) { if (time_after(jiffies, printmsg_time)) { dev_info(xpc_part, "waiting for remote " "partitions to disengage, timeout in " "%ld seconds\n", (disengage_request_timeout - jiffies) / HZ); printmsg_time = jiffies + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ); printed_waiting_msg = 1; } } else if (active_part_count > 0) { if (printed_waiting_msg) { dev_info(xpc_part, "waiting for local partition" " to disengage\n"); printed_waiting_msg = 0; } } else { if (!xpc_disengage_request_timedout) { dev_info(xpc_part, "all partitions have " "disengaged\n"); } break; } /* sleep for a 1/3 of a second or so */ (void)msleep_interruptible(300); } while (1); DBUG_ON(xpc_partition_engaged(-1UL)); /* indicate to others that our reserved page is uninitialized */ xpc_rsvd_page->vars_pa = 0; /* now it's time to eliminate our heartbeat */ del_timer_sync(&xpc_hb_timer); DBUG_ON(xpc_vars->heartbeating_to_mask != 0); if (reason == xpUnloading) { /* take ourselves off of the reboot_notifier_list */ (void)unregister_reboot_notifier(&xpc_reboot_notifier); /* take ourselves off of the die_notifier list */ (void)unregister_die_notifier(&xpc_die_notifier); } /* close down protections for IPI operations */ xpc_restrict_IPI_ops(); /* clear the interface to XPC's functions */ xpc_clear_interface(); if (xpc_sysctl) unregister_sysctl_table(xpc_sysctl); kfree(xpc_remote_copy_buffer_base); }