⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xpc_main.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	/*	 * 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 == xpcUnloading) {		/* 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);}/* * This function is called when the system is being rebooted. */static intxpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused){	enum xpc_retval reason;	switch (event) {	case SYS_RESTART:		reason = xpcSystemReboot;		break;	case SYS_HALT:		reason = xpcSystemHalt;		break;	case SYS_POWER_OFF:		reason = xpcSystemPoweroff;		break;	default:		reason = xpcSystemGoingDown;	}	xpc_do_exit(reason);	return NOTIFY_DONE;}/* * Notify other partitions to disengage from all references to our memory. */static voidxpc_die_disengage(void){	struct xpc_partition *part;	partid_t partid;	unsigned long engaged;	long time, printmsg_time, disengage_request_timeout;	/* keep xpc_hb_checker thread from doing anything (just in case) */	xpc_exiting = 1;	xpc_vars->heartbeating_to_mask = 0;  /* indicate we're deactivated */	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {		part = &xpc_partitions[partid];		if (!XPC_SUPPORTS_DISENGAGE_REQUEST(part->							remote_vars_version)) {			/* just in case it was left set by an earlier XPC */			xpc_clear_partition_engaged(1UL << partid);			continue;		}		if (xpc_partition_engaged(1UL << partid) ||					part->act_state != XPC_P_INACTIVE) {			xpc_request_partition_disengage(part);			xpc_mark_partition_disengaged(part);			xpc_IPI_send_disengage(part);		}	}	time = rtc_time();	printmsg_time = time +		(XPC_DISENGAGE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second);	disengage_request_timeout = time +		(xpc_disengage_request_timelimit * sn_rtc_cycles_per_second);	/* wait for all other partitions to disengage from us */	while (1) {		engaged = xpc_partition_engaged(-1UL);		if (!engaged) {			dev_info(xpc_part, "all partitions have disengaged\n");			break;		}		time = rtc_time();		if (time >= disengage_request_timeout) {			for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {				if (engaged & (1UL << partid)) {					dev_info(xpc_part, "disengage from "						"remote partition %d timed "						"out\n", partid);				}			}			break;		}		if (time >= printmsg_time) {			dev_info(xpc_part, "waiting for remote partitions to "				"disengage, timeout in %ld seconds\n",				(disengage_request_timeout - time) /						sn_rtc_cycles_per_second);			printmsg_time = time +					(XPC_DISENGAGE_PRINTMSG_INTERVAL *						sn_rtc_cycles_per_second);		}	}}/* * This function is called when the system is being restarted or halted due * to some sort of system failure. If this is the case we need to notify the * other partitions to disengage from all references to our memory. * This function can also be called when our heartbeater could be offlined * for a time. In this case we need to notify other partitions to not worry * about the lack of a heartbeat. */static intxpc_system_die(struct notifier_block *nb, unsigned long event, void *unused){	switch (event) {	case DIE_MACHINE_RESTART:	case DIE_MACHINE_HALT:		xpc_die_disengage();		break;	case DIE_KDEBUG_ENTER:		/* Should lack of heartbeat be ignored by other partitions? */		if (!xpc_kdebug_ignore) {			break;		}		/* fall through */	case DIE_MCA_MONARCH_ENTER:	case DIE_INIT_MONARCH_ENTER:		xpc_vars->heartbeat++;		xpc_vars->heartbeat_offline = 1;		break;	case DIE_KDEBUG_LEAVE:		/* Is lack of heartbeat being ignored by other partitions? */		if (!xpc_kdebug_ignore) {			break;		}		/* fall through */	case DIE_MCA_MONARCH_LEAVE:	case DIE_INIT_MONARCH_LEAVE:		xpc_vars->heartbeat++;		xpc_vars->heartbeat_offline = 0;		break;	}	return NOTIFY_DONE;}int __initxpc_init(void){	int ret;	partid_t partid;	struct xpc_partition *part;	pid_t pid;	size_t buf_size;	if (!ia64_platform_is("sn2")) {		return -ENODEV;	}	buf_size = max(XPC_RP_VARS_SIZE,				XPC_RP_HEADER_SIZE + XP_NASID_MASK_BYTES);	xpc_remote_copy_buffer = xpc_kmalloc_cacheline_aligned(buf_size,				     GFP_KERNEL, &xpc_remote_copy_buffer_base);	if (xpc_remote_copy_buffer == NULL)		return -ENOMEM;	snprintf(xpc_part->bus_id, BUS_ID_SIZE, "part");	snprintf(xpc_chan->bus_id, BUS_ID_SIZE, "chan");	xpc_sysctl = register_sysctl_table(xpc_sys_dir);	/*	 * The first few fields of each entry of xpc_partitions[] need to	 * be initialized now so that calls to xpc_connect() and	 * xpc_disconnect() can be made prior to the activation of any remote	 * partition. NOTE THAT NONE OF THE OTHER FIELDS BELONGING TO THESE	 * ENTRIES ARE MEANINGFUL UNTIL AFTER AN ENTRY'S CORRESPONDING	 * PARTITION HAS BEEN ACTIVATED.	 */	for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {		part = &xpc_partitions[partid];		DBUG_ON((u64) part != L1_CACHE_ALIGN((u64) part));		part->act_IRQ_rcvd = 0;		spin_lock_init(&part->act_lock);		part->act_state = XPC_P_INACTIVE;		XPC_SET_REASON(part, 0, 0);		init_timer(&part->disengage_request_timer);		part->disengage_request_timer.function =				xpc_timeout_partition_disengage_request;		part->disengage_request_timer.data = (unsigned long) part;		part->setup_state = XPC_P_UNSET;		init_waitqueue_head(&part->teardown_wq);		atomic_set(&part->references, 0);	}	/*	 * Open up protections for IPI operations (and AMO operations on	 * Shub 1.1 systems).	 */	xpc_allow_IPI_ops();	/*	 * Interrupts being processed will increment this atomic variable and	 * awaken the heartbeat thread which will process the interrupts.	 */	atomic_set(&xpc_act_IRQ_rcvd, 0);	/*	 * This is safe to do before the xpc_hb_checker thread has started	 * because the handler releases a wait queue.  If an interrupt is	 * received before the thread is waiting, it will not go to sleep,	 * but rather immediately process the interrupt.	 */	ret = request_irq(SGI_XPC_ACTIVATE, xpc_act_IRQ_handler, 0,							"xpc hb", NULL);	if (ret != 0) {		dev_err(xpc_part, "can't register ACTIVATE IRQ handler, "			"errno=%d\n", -ret);		xpc_restrict_IPI_ops();		if (xpc_sysctl) {			unregister_sysctl_table(xpc_sysctl);		}		kfree(xpc_remote_copy_buffer_base);		return -EBUSY;	}	/*	 * Fill the partition reserved page with the information needed by	 * other partitions to discover we are alive and establish initial	 * communications.	 */	xpc_rsvd_page = xpc_rsvd_page_init();	if (xpc_rsvd_page == NULL) {		dev_err(xpc_part, "could not setup our reserved page\n");		free_irq(SGI_XPC_ACTIVATE, NULL);		xpc_restrict_IPI_ops();		if (xpc_sysctl) {			unregister_sysctl_table(xpc_sysctl);		}		kfree(xpc_remote_copy_buffer_base);		return -EBUSY;	}	/* add ourselves to the reboot_notifier_list */	ret = register_reboot_notifier(&xpc_reboot_notifier);	if (ret != 0) {		dev_warn(xpc_part, "can't register reboot notifier\n");	}	/* add ourselves to the die_notifier list */	ret = register_die_notifier(&xpc_die_notifier);	if (ret != 0) {		dev_warn(xpc_part, "can't register die notifier\n");	}	init_timer(&xpc_hb_timer);	xpc_hb_timer.function = xpc_hb_beater;	/*	 * The real work-horse behind xpc.  This processes incoming	 * interrupts and monitors remote heartbeats.	 */	pid = kernel_thread(xpc_hb_checker, NULL, 0);	if (pid < 0) {		dev_err(xpc_part, "failed while forking hb check thread\n");		/* indicate to others that our reserved page is uninitialized */		xpc_rsvd_page->vars_pa = 0;		/* 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);		del_timer_sync(&xpc_hb_timer);		free_irq(SGI_XPC_ACTIVATE, NULL);		xpc_restrict_IPI_ops();		if (xpc_sysctl) {			unregister_sysctl_table(xpc_sysctl);		}		kfree(xpc_remote_copy_buffer_base);		return -EBUSY;	}	/*	 * Startup a thread that will attempt to discover other partitions to	 * activate based on info provided by SAL. This new thread is short	 * lived and will exit once discovery is complete.	 */	pid = kernel_thread(xpc_initiate_discovery, NULL, 0);	if (pid < 0) {		dev_err(xpc_part, "failed while forking discovery thread\n");		/* mark this new thread as a non-starter */		complete(&xpc_discovery_exited);		xpc_do_exit(xpcUnloading);		return -EBUSY;	}	/* set the interface to point at XPC's functions */	xpc_set_interface(xpc_initiate_connect, xpc_initiate_disconnect,			  xpc_initiate_allocate, xpc_initiate_send,			  xpc_initiate_send_notify, xpc_initiate_received,			  xpc_initiate_partid_to_nasids);	return 0;}module_init(xpc_init);void __exitxpc_exit(void){	xpc_do_exit(xpcUnloading);}module_exit(xpc_exit);MODULE_AUTHOR("Silicon Graphics, Inc.");MODULE_DESCRIPTION("Cross Partition Communication (XPC) support");MODULE_LICENSE("GPL");module_param(xpc_hb_interval, int, 0);MODULE_PARM_DESC(xpc_hb_interval, "Number of seconds between "		"heartbeat increments.");module_param(xpc_hb_check_interval, int, 0);MODULE_PARM_DESC(xpc_hb_check_interval, "Number of seconds between "		"heartbeat checks.");module_param(xpc_disengage_request_timelimit, int, 0);MODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait "		"for disengage request to complete.");module_param(xpc_kdebug_ignore, int, 0);MODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by "		"other partitions when dropping into kdebug.");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -