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

📄 xpc_channel.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		return xpcSuccess;	}	dev_dbg(xpc_chan, "can't get memory for local message queue and notify "		"queue, partid=%d, channel=%d\n", ch->partid, ch->number);	return xpcNoMemory;}/* * Allocate the cached remote message queue. */static enum xpc_retvalxpc_allocate_remote_msgqueue(struct xpc_channel *ch){	unsigned long irq_flags;	int nentries;	size_t nbytes;	DBUG_ON(ch->remote_nentries <= 0);	// >>> may want to check for ch->flags & XPC_C_DISCONNECTING between	// >>> iterations of the for-loop, bail if set?	// >>> should we impose a minumum #of entries? like 4 or 8?	for (nentries = ch->remote_nentries; nentries > 0; nentries--) {		nbytes = nentries * ch->msg_size;		ch->remote_msgqueue = xpc_kmalloc_cacheline_aligned(nbytes,						(GFP_KERNEL | GFP_DMA),						&ch->remote_msgqueue_base);		if (ch->remote_msgqueue == NULL) {			continue;		}		memset(ch->remote_msgqueue, 0, nbytes);		spin_lock_irqsave(&ch->lock, irq_flags);		if (nentries < ch->remote_nentries) {			dev_dbg(xpc_chan, "nentries=%d remote_nentries=%d, "				"partid=%d, channel=%d\n", nentries,				ch->remote_nentries, ch->partid, ch->number);			ch->remote_nentries = nentries;		}		spin_unlock_irqrestore(&ch->lock, irq_flags);		return xpcSuccess;	}	dev_dbg(xpc_chan, "can't get memory for cached remote message queue, "		"partid=%d, channel=%d\n", ch->partid, ch->number);	return xpcNoMemory;}/* * Allocate message queues and other stuff associated with a channel. * * Note: Assumes all of the channel sizes are filled in. */static enum xpc_retvalxpc_allocate_msgqueues(struct xpc_channel *ch){	unsigned long irq_flags;	int i;	enum xpc_retval ret;	DBUG_ON(ch->flags & XPC_C_SETUP);	if ((ret = xpc_allocate_local_msgqueue(ch)) != xpcSuccess) {		return ret;	}	if ((ret = xpc_allocate_remote_msgqueue(ch)) != xpcSuccess) {		kfree(ch->local_msgqueue_base);		ch->local_msgqueue = NULL;		kfree(ch->notify_queue);		ch->notify_queue = NULL;		return ret;	}	for (i = 0; i < ch->local_nentries; i++) {		/* use a semaphore as an event wait queue */		sema_init(&ch->notify_queue[i].sema, 0);	}	spin_lock_irqsave(&ch->lock, irq_flags);	ch->flags |= XPC_C_SETUP;	spin_unlock_irqrestore(&ch->lock, irq_flags);	return xpcSuccess;}/* * Process a connect message from a remote partition. * * Note: xpc_process_connect() is expecting to be called with the * spin_lock_irqsave held and will leave it locked upon return. */static voidxpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags){	enum xpc_retval ret;	DBUG_ON(!spin_is_locked(&ch->lock));	if (!(ch->flags & XPC_C_OPENREQUEST) ||				!(ch->flags & XPC_C_ROPENREQUEST)) {		/* nothing more to do for now */		return;	}	DBUG_ON(!(ch->flags & XPC_C_CONNECTING));	if (!(ch->flags & XPC_C_SETUP)) {		spin_unlock_irqrestore(&ch->lock, *irq_flags);		ret = xpc_allocate_msgqueues(ch);		spin_lock_irqsave(&ch->lock, *irq_flags);		if (ret != xpcSuccess) {			XPC_DISCONNECT_CHANNEL(ch, ret, irq_flags);		}		if (ch->flags & (XPC_C_CONNECTED | XPC_C_DISCONNECTING)) {			return;		}		DBUG_ON(!(ch->flags & XPC_C_SETUP));		DBUG_ON(ch->local_msgqueue == NULL);		DBUG_ON(ch->remote_msgqueue == NULL);	}	if (!(ch->flags & XPC_C_OPENREPLY)) {		ch->flags |= XPC_C_OPENREPLY;		xpc_IPI_send_openreply(ch, irq_flags);	}	if (!(ch->flags & XPC_C_ROPENREPLY)) {		return;	}	DBUG_ON(ch->remote_msgqueue_pa == 0);	ch->flags = (XPC_C_CONNECTED | XPC_C_SETUP);	/* clear all else */	dev_info(xpc_chan, "channel %d to partition %d connected\n",		ch->number, ch->partid);	spin_unlock_irqrestore(&ch->lock, *irq_flags);	xpc_create_kthreads(ch, 1);	spin_lock_irqsave(&ch->lock, *irq_flags);}/* * Notify those who wanted to be notified upon delivery of their message. */static voidxpc_notify_senders(struct xpc_channel *ch, enum xpc_retval reason, s64 put){	struct xpc_notify *notify;	u8 notify_type;	s64 get = ch->w_remote_GP.get - 1;	while (++get < put && atomic_read(&ch->n_to_notify) > 0) {		notify = &ch->notify_queue[get % ch->local_nentries];		/*		 * See if the notify entry indicates it was associated with		 * a message who's sender wants to be notified. It is possible		 * that it is, but someone else is doing or has done the		 * notification.		 */		notify_type = notify->type;		if (notify_type == 0 ||				cmpxchg(&notify->type, notify_type, 0) !=								notify_type) {			continue;		}		DBUG_ON(notify_type != XPC_N_CALL);		atomic_dec(&ch->n_to_notify);		if (notify->func != NULL) {			dev_dbg(xpc_chan, "notify->func() called, notify=0x%p, "				"msg_number=%ld, partid=%d, channel=%d\n",				(void *) notify, get, ch->partid, ch->number);			notify->func(reason, ch->partid, ch->number,								notify->key);			dev_dbg(xpc_chan, "notify->func() returned, "				"notify=0x%p, msg_number=%ld, partid=%d, "				"channel=%d\n", (void *) notify, get,				ch->partid, ch->number);		}	}}/* * Free up message queues and other stuff that were allocated for the specified * channel. * * Note: ch->reason and ch->reason_line are left set for debugging purposes, * they're cleared when XPC_C_DISCONNECTED is cleared. */static voidxpc_free_msgqueues(struct xpc_channel *ch){	DBUG_ON(!spin_is_locked(&ch->lock));	DBUG_ON(atomic_read(&ch->n_to_notify) != 0);	ch->remote_msgqueue_pa = 0;	ch->func = NULL;	ch->key = NULL;	ch->msg_size = 0;	ch->local_nentries = 0;	ch->remote_nentries = 0;	ch->kthreads_assigned_limit = 0;	ch->kthreads_idle_limit = 0;	ch->local_GP->get = 0;	ch->local_GP->put = 0;	ch->remote_GP.get = 0;	ch->remote_GP.put = 0;	ch->w_local_GP.get = 0;	ch->w_local_GP.put = 0;	ch->w_remote_GP.get = 0;	ch->w_remote_GP.put = 0;	ch->next_msg_to_pull = 0;	if (ch->flags & XPC_C_SETUP) {		ch->flags &= ~XPC_C_SETUP;		dev_dbg(xpc_chan, "ch->flags=0x%x, partid=%d, channel=%d\n",			ch->flags, ch->partid, ch->number);		kfree(ch->local_msgqueue_base);		ch->local_msgqueue = NULL;		kfree(ch->remote_msgqueue_base);		ch->remote_msgqueue = NULL;		kfree(ch->notify_queue);		ch->notify_queue = NULL;	}}/* * spin_lock_irqsave() is expected to be held on entry. */static voidxpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags){	struct xpc_partition *part = &xpc_partitions[ch->partid];	u32 channel_was_connected = (ch->flags & XPC_C_WASCONNECTED);	DBUG_ON(!spin_is_locked(&ch->lock));	if (!(ch->flags & XPC_C_DISCONNECTING)) {		return;	}	DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST));	/* make sure all activity has settled down first */	if (atomic_read(&ch->references) > 0) {		return;	}	DBUG_ON(atomic_read(&ch->kthreads_assigned) != 0);	if (part->act_state == XPC_P_DEACTIVATING) {		/* can't proceed until the other side disengages from us */		if (xpc_partition_engaged(1UL << ch->partid)) {			return;		}	} else {		/* as long as the other side is up do the full protocol */		if (!(ch->flags & XPC_C_RCLOSEREQUEST)) {			return;		}		if (!(ch->flags & XPC_C_CLOSEREPLY)) {			ch->flags |= XPC_C_CLOSEREPLY;			xpc_IPI_send_closereply(ch, irq_flags);		}		if (!(ch->flags & XPC_C_RCLOSEREPLY)) {			return;		}	}	/* wake those waiting for notify completion */	if (atomic_read(&ch->n_to_notify) > 0) {		/* >>> we do callout while holding ch->lock */		xpc_notify_senders(ch, ch->reason, ch->w_local_GP.put);	}	/* both sides are disconnected now */	/* it's now safe to free the channel's message queues */	xpc_free_msgqueues(ch);	/* mark disconnected, clear all other flags except XPC_C_WDISCONNECT */	ch->flags = (XPC_C_DISCONNECTED | (ch->flags & XPC_C_WDISCONNECT));	atomic_dec(&part->nchannels_active);	if (channel_was_connected) {		dev_info(xpc_chan, "channel %d to partition %d disconnected, "			"reason=%d\n", ch->number, ch->partid, ch->reason);	}	if (ch->flags & XPC_C_WDISCONNECT) {		spin_unlock_irqrestore(&ch->lock, *irq_flags);		up(&ch->wdisconnect_sema);		spin_lock_irqsave(&ch->lock, *irq_flags);	} else if (ch->delayed_IPI_flags) {		if (part->act_state != XPC_P_DEACTIVATING) {			/* time to take action on any delayed IPI flags */			spin_lock(&part->IPI_lock);			XPC_SET_IPI_FLAGS(part->local_IPI_amo, ch->number,							ch->delayed_IPI_flags);			spin_unlock(&part->IPI_lock);		}		ch->delayed_IPI_flags = 0;	}}/* * Process a change in the channel's remote connection state. */static voidxpc_process_openclose_IPI(struct xpc_partition *part, int ch_number,				u8 IPI_flags){	unsigned long irq_flags;	struct xpc_openclose_args *args =				&part->remote_openclose_args[ch_number];	struct xpc_channel *ch = &part->channels[ch_number];	enum xpc_retval reason;	spin_lock_irqsave(&ch->lock, irq_flags);again:	if ((ch->flags & XPC_C_DISCONNECTED) &&					(ch->flags & XPC_C_WDISCONNECT)) {		/*		 * Delay processing IPI flags until thread waiting disconnect		 * has had a chance to see that the channel is disconnected.		 */		ch->delayed_IPI_flags |= IPI_flags;		spin_unlock_irqrestore(&ch->lock, irq_flags);		return;	}	if (IPI_flags & XPC_IPI_CLOSEREQUEST) {		dev_dbg(xpc_chan, "XPC_IPI_CLOSEREQUEST (reason=%d) received "			"from partid=%d, channel=%d\n", args->reason,			ch->partid, ch->number);		/*		 * If RCLOSEREQUEST is set, we're probably waiting for		 * RCLOSEREPLY. We should find it and a ROPENREQUEST packed		 * with this RCLOSEREQUEST in the IPI_flags.		 */		if (ch->flags & XPC_C_RCLOSEREQUEST) {			DBUG_ON(!(ch->flags & XPC_C_DISCONNECTING));			DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST));			DBUG_ON(!(ch->flags & XPC_C_CLOSEREPLY));			DBUG_ON(ch->flags & XPC_C_RCLOSEREPLY);			DBUG_ON(!(IPI_flags & XPC_IPI_CLOSEREPLY));			IPI_flags &= ~XPC_IPI_CLOSEREPLY;			ch->flags |= XPC_C_RCLOSEREPLY;			/* both sides have finished disconnecting */			xpc_process_disconnect(ch, &irq_flags);			DBUG_ON(!(ch->flags & XPC_C_DISCONNECTED));			goto again;		}		if (ch->flags & XPC_C_DISCONNECTED) {			if (!(IPI_flags & XPC_IPI_OPENREQUEST)) {				if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo,					 ch_number) & XPC_IPI_OPENREQUEST)) {					DBUG_ON(ch->delayed_IPI_flags != 0);					spin_lock(&part->IPI_lock);					XPC_SET_IPI_FLAGS(part->local_IPI_amo,							ch_number,							XPC_IPI_CLOSEREQUEST);					spin_unlock(&part->IPI_lock);				}				spin_unlock_irqrestore(&ch->lock, irq_flags);				return;			}			XPC_SET_REASON(ch, 0, 0);			ch->flags &= ~XPC_C_DISCONNECTED;			atomic_inc(&part->nchannels_active);			ch->flags |= (XPC_C_CONNECTING | XPC_C_ROPENREQUEST);		}		IPI_flags &= ~(XPC_IPI_OPENREQUEST | XPC_IPI_OPENREPLY);		/*		 * The meaningful CLOSEREQUEST connection state fields are:		 *      reason = reason connection is to be closed		 */		ch->flags |= XPC_C_RCLOSEREQUEST;		if (!(ch->flags & XPC_C_DISCONNECTING)) {			reason = args->reason;			if (reason <= xpcSuccess || reason > xpcUnknownReason) {				reason = xpcUnknownReason;			} else if (reason == xpcUnregistering) {				reason = xpcOtherUnregistering;			}			XPC_DISCONNECT_CHANNEL(ch, reason, &irq_flags);			DBUG_ON(IPI_flags & XPC_IPI_CLOSEREPLY);			spin_unlock_irqrestore(&ch->lock, irq_flags);			return;		}		xpc_process_disconnect(ch, &irq_flags);	}	if (IPI_flags & XPC_IPI_CLOSEREPLY) {		dev_dbg(xpc_chan, "XPC_IPI_CLOSEREPLY received from partid=%d,"			" channel=%d\n", ch->partid, ch->number);		if (ch->flags & XPC_C_DISCONNECTED) {			DBUG_ON(part->act_state != XPC_P_DEACTIVATING);			spin_unlock_irqrestore(&ch->lock, irq_flags);			return;		}		DBUG_ON(!(ch->flags & XPC_C_CLOSEREQUEST));		if (!(ch->flags & XPC_C_RCLOSEREQUEST)) {			if ((XPC_GET_IPI_FLAGS(part->local_IPI_amo, ch_number)						& XPC_IPI_CLOSEREQUEST)) {				DBUG_ON(ch->delayed_IPI_flags != 0);				spin_lock(&part->IPI_lock);				XPC_SET_IPI_FLAGS(part->local_IPI_amo,						ch_number, XPC_IPI_CLOSEREPLY);				spin_unlock(&part->IPI_lock);

⌨️ 快捷键说明

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