Exemplo n.º 1
0
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);
	}
}
Exemplo n.º 2
0
/*
 * 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);
	}
}
Exemplo n.º 3
0
/*
 * 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)));
}
Exemplo n.º 4
0
/*
 * 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);
}
Exemplo n.º 5
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();
}
Exemplo n.º 6
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;

	/*                                                               */
	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();
}
Exemplo n.º 7
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_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);
}