connection.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 777 行 · 第 1/2 页

C
777
字号
	/* sanity check */	if (atomic_read(&conn->usage) <= 0)		BUG();	if (likely(!atomic_dec_and_test(&conn->usage))) {		spin_unlock(&peer->conn_gylock);		_leave("");		return;	}	/* move to graveyard queue */	_debug("burying connection: {%08x}", ntohl(conn->conn_id));	list_del(&conn->link);	list_add_tail(&conn->link, &peer->conn_graveyard);	rxrpc_krxtimod_add_timer(&conn->timeout, rxrpc_conn_timeout * HZ);	spin_unlock(&peer->conn_gylock);	rxrpc_put_peer(conn->peer);	_leave(" [killed]");} /* end rxrpc_put_connection() *//*****************************************************************************//* * free a connection record */void rxrpc_conn_do_timeout(struct rxrpc_connection *conn){	struct rxrpc_peer *peer;	_enter("%p{u=%d p=%hu}",	       conn, atomic_read(&conn->usage), ntohs(conn->addr.sin_port));	peer = conn->peer;	if (atomic_read(&conn->usage) < 0)		BUG();	/* remove from graveyard if still dead */	spin_lock(&peer->conn_gylock);	if (atomic_read(&conn->usage) == 0) {		list_del_init(&conn->link);	}	else {		conn = NULL;	}	spin_unlock(&peer->conn_gylock);	if (!conn) {		_leave("");		return; /* resurrected */	}	_debug("--- Destroying Connection %p{%08x} ---",	       conn, ntohl(conn->conn_id));	down_write(&rxrpc_conns_sem);	list_del(&conn->proc_link);	up_write(&rxrpc_conns_sem);	write_lock(&peer->conn_idlock);	list_del(&conn->id_link);	write_unlock(&peer->conn_idlock);	__RXACCT(atomic_dec(&rxrpc_connection_count));	kfree(conn);	/* if the graveyard is now empty, wake up anyone waiting for that */	if (atomic_dec_and_test(&peer->conn_count))		wake_up(&peer->conn_gy_waitq);	_leave(" [destroyed]");} /* end rxrpc_conn_do_timeout() *//*****************************************************************************//* * clear all connection records from a peer endpoint */void rxrpc_conn_clearall(struct rxrpc_peer *peer){	DECLARE_WAITQUEUE(myself, current);	struct rxrpc_connection *conn;	int err;	_enter("%p", peer);	/* there shouldn't be any active conns remaining */	if (!list_empty(&peer->conn_active))		BUG();	/* manually timeout all conns in the graveyard */	spin_lock(&peer->conn_gylock);	while (!list_empty(&peer->conn_graveyard)) {		conn = list_entry(peer->conn_graveyard.next,				  struct rxrpc_connection, link);		err = rxrpc_krxtimod_del_timer(&conn->timeout);		spin_unlock(&peer->conn_gylock);		if (err == 0)			rxrpc_conn_do_timeout(conn);		spin_lock(&peer->conn_gylock);	}	spin_unlock(&peer->conn_gylock);	/* wait for the the conn graveyard to be completely cleared */	set_current_state(TASK_UNINTERRUPTIBLE);	add_wait_queue(&peer->conn_gy_waitq, &myself);	while (atomic_read(&peer->conn_count) != 0) {		schedule();		set_current_state(TASK_UNINTERRUPTIBLE);	}	remove_wait_queue(&peer->conn_gy_waitq, &myself);	set_current_state(TASK_RUNNING);	_leave("");} /* end rxrpc_conn_clearall() *//*****************************************************************************//* * allocate and prepare a message for sending out through the transport * endpoint */int rxrpc_conn_newmsg(struct rxrpc_connection *conn,		      struct rxrpc_call *call,		      uint8_t type,		      int dcount,		      struct kvec diov[],		      int alloc_flags,		      struct rxrpc_message **_msg){	struct rxrpc_message *msg;	int loop;	_enter("%p{%d},%p,%u", conn, ntohs(conn->addr.sin_port), call, type);	if (dcount > 3) {		_leave(" = -EINVAL");		return -EINVAL;	}	msg = kmalloc(sizeof(struct rxrpc_message), alloc_flags);	if (!msg) {		_leave(" = -ENOMEM");		return -ENOMEM;	}	memset(msg, 0, sizeof(*msg));	atomic_set(&msg->usage, 1);	INIT_LIST_HEAD(&msg->link);	msg->state = RXRPC_MSG_PREPARED;	msg->hdr.epoch		= conn->out_epoch;	msg->hdr.cid		= conn->conn_id | (call ? call->chan_ix : 0);	msg->hdr.callNumber	= call ? call->call_id : 0;	msg->hdr.type		= type;	msg->hdr.flags		= conn->out_clientflag;	msg->hdr.securityIndex	= conn->security_ix;	msg->hdr.serviceId	= conn->service_id;	/* generate sequence numbers for data packets */	if (call) {		switch (type) {		case RXRPC_PACKET_TYPE_DATA:			msg->seq = ++call->snd_seq_count;			msg->hdr.seq = htonl(msg->seq);			break;		case RXRPC_PACKET_TYPE_ACK:			/* ACK sequence numbers are complicated. The following			 * may be wrong:			 * - jumbo packet ACKs should have a seq number			 * - normal ACKs should not			 */		default:			break;		}	}	msg->dcount = dcount + 1;	msg->dsize = sizeof(msg->hdr);	msg->data[0].iov_len = sizeof(msg->hdr);	msg->data[0].iov_base = &msg->hdr;	for (loop=0; loop < dcount; loop++) {		msg->dsize += diov[loop].iov_len;		msg->data[loop+1].iov_len  = diov[loop].iov_len;		msg->data[loop+1].iov_base = diov[loop].iov_base;	}	__RXACCT(atomic_inc(&rxrpc_message_count));	*_msg = msg;	_leave(" = 0 (%p) #%d", msg, atomic_read(&rxrpc_message_count));	return 0;} /* end rxrpc_conn_newmsg() *//*****************************************************************************//* * free a message */void __rxrpc_put_message(struct rxrpc_message *msg){	int loop;	_enter("%p #%d", msg, atomic_read(&rxrpc_message_count));	if (msg->pkt)		kfree_skb(msg->pkt);	rxrpc_put_connection(msg->conn);	for (loop = 0; loop < 8; loop++)		if (test_bit(loop, &msg->dfree))			kfree(msg->data[loop].iov_base);	__RXACCT(atomic_dec(&rxrpc_message_count));	kfree(msg);	_leave("");} /* end __rxrpc_put_message() *//*****************************************************************************//* * send a message out through the transport endpoint */int rxrpc_conn_sendmsg(struct rxrpc_connection *conn,		       struct rxrpc_message *msg){	struct msghdr msghdr;	int ret;	_enter("%p{%d}", conn, ntohs(conn->addr.sin_port));	/* fill in some fields in the header */	spin_lock(&conn->lock);	msg->hdr.serial = htonl(++conn->serial_counter);	msg->rttdone = 0;	spin_unlock(&conn->lock);	/* set up the message to be transmitted */	msghdr.msg_name		= &conn->addr;	msghdr.msg_namelen	= sizeof(conn->addr);	msghdr.msg_control	= NULL;	msghdr.msg_controllen	= 0;	msghdr.msg_flags	= MSG_CONFIRM | MSG_DONTWAIT;	_net("Sending message type %d of %Zd bytes to %08x:%d",	     msg->hdr.type,	     msg->dsize,	     ntohl(conn->addr.sin_addr.s_addr),	     ntohs(conn->addr.sin_port));	/* send the message */	ret = kernel_sendmsg(conn->trans->socket, &msghdr,			     msg->data, msg->dcount, msg->dsize);	if (ret < 0) {		msg->state = RXRPC_MSG_ERROR;	} else {		msg->state = RXRPC_MSG_SENT;		ret = 0;		spin_lock(&conn->lock);		do_gettimeofday(&conn->atime);		msg->stamp = conn->atime;		spin_unlock(&conn->lock);	}	_leave(" = %d", ret);	return ret;} /* end rxrpc_conn_sendmsg() *//*****************************************************************************//* * deal with a subsequent call packet */int rxrpc_conn_receive_call_packet(struct rxrpc_connection *conn,				   struct rxrpc_call *call,				   struct rxrpc_message *msg){	struct rxrpc_message *pmsg;	struct list_head *_p;	unsigned cix, seq;	int ret = 0;	_enter("%p,%p,%p", conn, call, msg);	if (!call) {		cix = ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK;		spin_lock(&conn->lock);		call = conn->channels[cix];		if (!call || call->call_id != msg->hdr.callNumber) {			spin_unlock(&conn->lock);			rxrpc_trans_immediate_abort(conn->trans, msg, -ENOENT);			goto out;		}		else {			rxrpc_get_call(call);			spin_unlock(&conn->lock);		}	}	else {		rxrpc_get_call(call);	}	_proto("Received packet %%%u [%u] on call %hu:%u:%u",	       ntohl(msg->hdr.serial),	       ntohl(msg->hdr.seq),	       ntohs(msg->hdr.serviceId),	       ntohl(conn->conn_id),	       ntohl(call->call_id));	call->pkt_rcv_count++;	if (msg->pkt->dst && msg->pkt->dst->dev)		conn->peer->if_mtu =			msg->pkt->dst->dev->mtu -			msg->pkt->dst->dev->hard_header_len;	/* queue on the call in seq order */	rxrpc_get_message(msg);	seq = msg->seq;	spin_lock(&call->lock);	list_for_each(_p, &call->rcv_receiveq) {		pmsg = list_entry(_p, struct rxrpc_message, link);		if (pmsg->seq > seq)			break;	}	list_add_tail(&msg->link, _p);	/* reset the activity timeout */	call->flags |= RXRPC_CALL_RCV_PKT;	mod_timer(&call->rcv_timeout,jiffies + rxrpc_call_rcv_timeout * HZ);	spin_unlock(&call->lock);	rxrpc_krxiod_queue_call(call);	rxrpc_put_call(call); out:	_leave(" = %d", ret);	return ret;} /* end rxrpc_conn_receive_call_packet() *//*****************************************************************************//* * handle an ICMP error being applied to a connection */void rxrpc_conn_handle_error(struct rxrpc_connection *conn,			     int local, int errno){	struct rxrpc_call *calls[4];	int loop;	_enter("%p{%d},%d", conn, ntohs(conn->addr.sin_port), errno);	/* get a ref to all my calls in one go */	memset(calls, 0, sizeof(calls));	spin_lock(&conn->lock);	for (loop = 3; loop >= 0; loop--) {		if (conn->channels[loop]) {			calls[loop] = conn->channels[loop];			rxrpc_get_call(calls[loop]);		}	}	spin_unlock(&conn->lock);	/* now kick them all */	for (loop = 3; loop >= 0; loop--) {		if (calls[loop]) {			rxrpc_call_handle_error(calls[loop], local, errno);			rxrpc_put_call(calls[loop]);		}	}	_leave("");} /* end rxrpc_conn_handle_error() */

⌨️ 快捷键说明

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