net: ipc_router: Reference count routing table entries and remote ports

Everytime a routing table entry or a remote port is searched and then
accessed, a global lock is used to protect the access for its entire
duration.

Define a reference element in the concerned structure. Get a reference
to the entry everytime it is searched and accessed. Put the reference back
once the access is complete. Release the data structure when the reference
count is zero.

Change-Id: I95312e4903167dda50c83ecf2e2a409b9dcbf6bd
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
This commit is contained in:
Karthikeyan Ramasubramanian 2014-05-12 18:15:09 -06:00
parent 763e35c98f
commit 6b7e004d0e
1 changed files with 259 additions and 210 deletions

View File

@ -142,10 +142,11 @@ struct msm_ipc_resume_tx_port {
#define RP_HASH_SIZE 32
struct msm_ipc_router_remote_port {
struct list_head list;
struct kref ref;
struct mutex rport_lock_lhb2;
uint32_t node_id;
uint32_t port_id;
uint32_t tx_quota_cnt;
struct mutex quota_lock_lhb2;
struct list_head resume_tx_port_list;
void *sec_rule;
struct msm_ipc_server *server;
@ -169,6 +170,7 @@ struct msm_ipc_router_xprt_info {
#define RT_HASH_SIZE 4
struct msm_ipc_routing_table_entry {
struct list_head list;
struct kref ref;
uint32_t node_id;
uint32_t neighbor_node_id;
struct list_head remote_port_list[RP_HASH_SIZE];
@ -208,43 +210,6 @@ static void init_routing_table(void)
INIT_LIST_HEAD(&routing_table[i]);
}
static struct msm_ipc_routing_table_entry *alloc_routing_table_entry(
uint32_t node_id)
{
int i;
struct msm_ipc_routing_table_entry *rt_entry;
rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
GFP_KERNEL);
if (!rt_entry) {
IPC_RTR_ERR("%s: rt_entry allocation failed for %d\n",
__func__, node_id);
return NULL;
}
for (i = 0; i < RP_HASH_SIZE; i++)
INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
init_rwsem(&rt_entry->lock_lha4);
rt_entry->node_id = node_id;
rt_entry->xprt_info = NULL;
return rt_entry;
}
/* Must be called with routing_table_lock_lha3 locked. */
static int add_routing_table_entry(
struct msm_ipc_routing_table_entry *rt_entry)
{
uint32_t key;
if (!rt_entry)
return -EINVAL;
key = (rt_entry->node_id % RT_HASH_SIZE);
list_add_tail(&rt_entry->list, &routing_table[key]);
return 0;
}
/* Must be called with routing_table_lock_lha3 locked. */
static struct msm_ipc_routing_table_entry *lookup_routing_table(
uint32_t node_id)
@ -259,6 +224,93 @@ static struct msm_ipc_routing_table_entry *lookup_routing_table(
return NULL;
}
/**
* create_routing_table_entry() - Lookup and create a routing table entry
* @node_id: Node ID of the routing table entry to be created.
* @xprt_info: XPRT through which the node ID is reachable.
*
* @return: a reference to the routing table entry on success, NULL on failure.
*/
static struct msm_ipc_routing_table_entry *create_routing_table_entry(
uint32_t node_id, struct msm_ipc_router_xprt_info *xprt_info)
{
int i;
struct msm_ipc_routing_table_entry *rt_entry;
uint32_t key;
down_write(&routing_table_lock_lha3);
rt_entry = lookup_routing_table(node_id);
if (rt_entry)
goto out_create_rtentry1;
rt_entry = kmalloc(sizeof(struct msm_ipc_routing_table_entry),
GFP_KERNEL);
if (!rt_entry) {
IPC_RTR_ERR("%s: rt_entry allocation failed for %d\n",
__func__, node_id);
goto out_create_rtentry2;
}
for (i = 0; i < RP_HASH_SIZE; i++)
INIT_LIST_HEAD(&rt_entry->remote_port_list[i]);
init_rwsem(&rt_entry->lock_lha4);
kref_init(&rt_entry->ref);
rt_entry->node_id = node_id;
rt_entry->xprt_info = xprt_info;
if (xprt_info)
rt_entry->neighbor_node_id = xprt_info->remote_node_id;
key = (node_id % RT_HASH_SIZE);
list_add_tail(&rt_entry->list, &routing_table[key]);
out_create_rtentry1:
kref_get(&rt_entry->ref);
out_create_rtentry2:
up_write(&routing_table_lock_lha3);
return rt_entry;
}
/**
* ipc_router_get_rtentry_ref() - Get a reference to the routing table entry
* @node_id: Node ID of the routing table entry.
*
* @return: a reference to the routing table entry on success, NULL on failure.
*
* This function is used to obtain a reference to the rounting table entry
* corresponding to a node id.
*/
static struct msm_ipc_routing_table_entry *ipc_router_get_rtentry_ref(
uint32_t node_id)
{
struct msm_ipc_routing_table_entry *rt_entry;
down_read(&routing_table_lock_lha3);
rt_entry = lookup_routing_table(node_id);
if (rt_entry)
kref_get(&rt_entry->ref);
up_read(&routing_table_lock_lha3);
return rt_entry;
}
/**
* ipc_router_release_rtentry() - Cleanup and release the routing table entry
* @ref: Reference to the entry.
*
* This function is called when all references to the routing table entry are
* released.
*/
void ipc_router_release_rtentry(struct kref *ref)
{
struct msm_ipc_routing_table_entry *rt_entry =
container_of(ref, struct msm_ipc_routing_table_entry, ref);
/*
* All references to a routing entry will be put only under SSR.
* As part of SSR, all the internals of the routing table entry
* are cleaned. So just free the routing table entry.
*/
kfree(rt_entry);
}
struct rr_packet *rr_read(struct msm_ipc_router_xprt_info *xprt_info)
{
struct rr_packet *temp_pkt;
@ -599,7 +651,6 @@ static int calc_tx_header_size(struct rr_packet *pkt,
{
int hdr_size = 0;
int xprt_version = 0;
struct msm_ipc_routing_table_entry *rt_entry;
struct msm_ipc_router_xprt_info *xprt_info = dst_xprt_info;
if (!pkt) {
@ -607,16 +658,6 @@ static int calc_tx_header_size(struct rr_packet *pkt,
return -EINVAL;
}
if (!xprt_info) {
rt_entry = lookup_routing_table(pkt->hdr.dst_node_id);
if (!rt_entry || !(rt_entry->xprt_info)) {
IPC_RTR_ERR("%s: Node %d is not up\n",
__func__, pkt->hdr.dst_node_id);
return -ENODEV;
}
xprt_info = rt_entry->xprt_info;
}
if (xprt_info)
xprt_version = xprt_info->xprt->get_version(xprt_info->xprt);
@ -1030,16 +1071,21 @@ static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
return NULL;
}
/* Must be called with routing_table_lock_lha3 locked. */
static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
uint32_t node_id,
uint32_t port_id)
/**
* ipc_router_get_rport_ref()- Get reference to the remote port
* @node_id: Node ID corresponding to the remote port.
* @port_id: Port ID corresponding to the remote port.
*
* @return: a reference to the remote port on success, NULL on failure.
*/
static struct msm_ipc_router_remote_port *ipc_router_get_rport_ref(
uint32_t node_id, uint32_t port_id)
{
struct msm_ipc_router_remote_port *rport_ptr;
struct msm_ipc_routing_table_entry *rt_entry;
int key = (port_id & (RP_HASH_SIZE - 1));
rt_entry = lookup_routing_table(node_id);
rt_entry = ipc_router_get_rtentry_ref(node_id);
if (!rt_entry) {
IPC_RTR_ERR("%s: Node is not up\n", __func__);
return NULL;
@ -1049,46 +1095,67 @@ static struct msm_ipc_router_remote_port *msm_ipc_router_lookup_remote_port(
list_for_each_entry(rport_ptr,
&rt_entry->remote_port_list[key], list) {
if (rport_ptr->port_id == port_id) {
up_read(&rt_entry->lock_lha4);
return rport_ptr;
kref_get(&rport_ptr->ref);
goto out_lookup_rmt_port1;
}
}
rport_ptr = NULL;
out_lookup_rmt_port1:
up_read(&rt_entry->lock_lha4);
return NULL;
kref_put(&rt_entry->ref, ipc_router_release_rtentry);
return rport_ptr;
}
/* Must be called with routing_table_lock_lha3 locked. */
static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
uint32_t node_id,
uint32_t port_id)
/**
* ipc_router_create_rport() - Create a remote port
* @node_id: Node ID corresponding to the remote port.
* @port_id: Port ID corresponding to the remote port.
* @xprt_info: XPRT through which the concerned node is reachable.
*
* @return: a reference to the remote port on success, NULL on failure.
*/
static struct msm_ipc_router_remote_port *ipc_router_create_rport(
uint32_t node_id, uint32_t port_id,
struct msm_ipc_router_xprt_info *xprt_info)
{
struct msm_ipc_router_remote_port *rport_ptr;
struct msm_ipc_routing_table_entry *rt_entry;
int key = (port_id & (RP_HASH_SIZE - 1));
rt_entry = lookup_routing_table(node_id);
rt_entry = create_routing_table_entry(node_id, xprt_info);
if (!rt_entry) {
IPC_RTR_ERR("%s: Node is not up\n", __func__);
IPC_RTR_ERR("%s: Node cannot be created\n", __func__);
return NULL;
}
down_write(&rt_entry->lock_lha4);
list_for_each_entry(rport_ptr,
&rt_entry->remote_port_list[key], list) {
if (rport_ptr->port_id == port_id)
goto out_create_rmt_port1;
}
rport_ptr = kmalloc(sizeof(struct msm_ipc_router_remote_port),
GFP_KERNEL);
if (!rport_ptr) {
IPC_RTR_ERR("%s: Remote port alloc failed\n", __func__);
return NULL;
goto out_create_rmt_port2;
}
rport_ptr->port_id = port_id;
rport_ptr->node_id = node_id;
rport_ptr->sec_rule = NULL;
rport_ptr->server = NULL;
rport_ptr->tx_quota_cnt = 0;
mutex_init(&rport_ptr->quota_lock_lhb2);
kref_init(&rport_ptr->ref);
mutex_init(&rport_ptr->rport_lock_lhb2);
INIT_LIST_HEAD(&rport_ptr->resume_tx_port_list);
down_write(&rt_entry->lock_lha4);
list_add_tail(&rport_ptr->list,
&rt_entry->remote_port_list[key]);
out_create_rmt_port1:
kref_get(&rport_ptr->ref);
out_create_rmt_port2:
up_write(&rt_entry->lock_lha4);
kref_put(&rt_entry->ref, ipc_router_release_rtentry);
return rport_ptr;
}
@ -1099,7 +1166,7 @@ static struct msm_ipc_router_remote_port *msm_ipc_router_create_remote_port(
* This function deletes all the resume_tx ports associated with a remote port
* and frees the memory allocated to each resume_tx port.
*
* Must be called with rport_ptr->quota_lock_lhb2 locked.
* Must be called with rport_ptr->rport_lock_lhb2 locked.
*/
static void msm_ipc_router_free_resume_tx_port(
struct msm_ipc_router_remote_port *rport_ptr)
@ -1124,7 +1191,7 @@ static void msm_ipc_router_free_resume_tx_port(
* remote port's resume_tx list. This function is used to ensure that
* the same port is not added to the remote_port's resume_tx list repeatedly.
*
* Must be called with rport_ptr->quota_lock_lhb2 locked.
* Must be called with rport_ptr->rport_lock_lhb2 locked.
*/
static int msm_ipc_router_lookup_resume_tx_port(
struct msm_ipc_router_remote_port *rport_ptr, uint32_t port_id)
@ -1150,7 +1217,7 @@ static int msm_ipc_router_lookup_resume_tx_port(
* function sequentially deletes each entry in the resume_tx_port_list of the
* remote port.
*
* Must be called with rport_ptr->quota_lock_lhb2 locked.
* Must be called with rport_ptr->rport_lock_lhb2 locked.
*/
static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
struct rr_packet *pkt, union rr_control_msg *msg)
@ -1175,8 +1242,28 @@ static void post_resume_tx(struct msm_ipc_router_remote_port *rport_ptr,
}
}
/* Must be called with routing_table_lock_lha3 locked. */
static void msm_ipc_router_destroy_remote_port(
/**
* ipc_router_release_rport() - Cleanup and release the remote port
* @ref: Reference to the remote port.
*
* This function is called when all references to the remote port are released.
*/
static void ipc_router_release_rport(struct kref *ref)
{
struct msm_ipc_router_remote_port *rport_ptr =
container_of(ref, struct msm_ipc_router_remote_port, ref);
mutex_lock(&rport_ptr->rport_lock_lhb2);
msm_ipc_router_free_resume_tx_port(rport_ptr);
mutex_unlock(&rport_ptr->rport_lock_lhb2);
kfree(rport_ptr);
}
/**
* ipc_router_destroy_rport() - Destroy the remote port
* @rport_ptr: Pointer to the remote port to be destroyed.
*/
static void ipc_router_destroy_rport(
struct msm_ipc_router_remote_port *rport_ptr)
{
uint32_t node_id;
@ -1186,7 +1273,7 @@ static void msm_ipc_router_destroy_remote_port(
return;
node_id = rport_ptr->node_id;
rt_entry = lookup_routing_table(node_id);
rt_entry = ipc_router_get_rtentry_ref(node_id);
if (!rt_entry) {
IPC_RTR_ERR("%s: Node %d is not up\n", __func__, node_id);
return;
@ -1194,10 +1281,8 @@ static void msm_ipc_router_destroy_remote_port(
down_write(&rt_entry->lock_lha4);
list_del(&rport_ptr->list);
up_write(&rt_entry->lock_lha4);
mutex_lock(&rport_ptr->quota_lock_lhb2);
msm_ipc_router_free_resume_tx_port(rport_ptr);
mutex_unlock(&rport_ptr->quota_lock_lhb2);
kfree(rport_ptr);
kref_put(&rport_ptr->ref, ipc_router_release_rport);
kref_put(&rt_entry->ref, ipc_router_release_rtentry);
return;
}
@ -1534,8 +1619,7 @@ static int forward_msg(struct msm_ipc_router_xprt_info *xprt_info,
return -EINVAL;
hdr = &(pkt->hdr);
down_read(&routing_table_lock_lha3);
rt_entry = lookup_routing_table(hdr->dst_node_id);
rt_entry = ipc_router_get_rtentry_ref(hdr->dst_node_id);
if (!(rt_entry) || !(rt_entry->xprt_info)) {
IPC_RTR_ERR("%s: Routing table not initialized\n", __func__);
ret = -ENODEV;
@ -1575,8 +1659,8 @@ fm_error3:
fm_error2:
up_read(&rt_entry->lock_lha4);
fm_error1:
up_read(&routing_table_lock_lha3);
if (rt_entry)
kref_put(&rt_entry->ref, ipc_router_release_rtentry);
return ret;
}
@ -1643,11 +1727,17 @@ static void update_comm_mode_info(struct comm_mode_info *mode_info,
return;
}
/**
* cleanup_rmt_server() - Cleanup server hosted in the remote port
* @xprt_info: XPRT through which this cleanup event is handled.
* @rport_ptr: Remote port that is being cleaned up.
* @server: Server that is hosted in the remote port.
*/
static void cleanup_rmt_server(struct msm_ipc_router_xprt_info *xprt_info,
struct msm_ipc_router_remote_port *rport_ptr)
struct msm_ipc_router_remote_port *rport_ptr,
struct msm_ipc_server *server)
{
union rr_control_msg ctl;
struct msm_ipc_server *server = rport_ptr->server;
D("Remove server %08x:%08x - %08x:%08x",
server->name.service, server->name.instance,
@ -1669,6 +1759,7 @@ static void cleanup_rmt_ports(struct msm_ipc_router_xprt_info *xprt_info,
struct msm_ipc_routing_table_entry *rt_entry)
{
struct msm_ipc_router_remote_port *rport_ptr, *tmp_rport_ptr;
struct msm_ipc_server *server;
union rr_control_msg ctl;
int j;
@ -1677,19 +1768,23 @@ static void cleanup_rmt_ports(struct msm_ipc_router_xprt_info *xprt_info,
list_for_each_entry_safe(rport_ptr, tmp_rport_ptr,
&rt_entry->remote_port_list[j], list) {
list_del(&rport_ptr->list);
mutex_lock(&rport_ptr->quota_lock_lhb2);
msm_ipc_router_free_resume_tx_port(rport_ptr);
mutex_unlock(&rport_ptr->quota_lock_lhb2);
if (rport_ptr->server)
cleanup_rmt_server(xprt_info, rport_ptr);
mutex_lock(&rport_ptr->rport_lock_lhb2);
server = rport_ptr->server;
rport_ptr->server = NULL;
mutex_unlock(&rport_ptr->rport_lock_lhb2);
if (server) {
cleanup_rmt_server(xprt_info, rport_ptr,
server);
server = NULL;
}
ctl.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_CLIENT;
ctl.cli.node_id = rport_ptr->node_id;
ctl.cli.port_id = rport_ptr->port_id;
kref_put(&rport_ptr->ref, ipc_router_release_rport);
relay_ctl_msg(xprt_info, &ctl);
broadcast_ctl_msg_locally(&ctl);
kfree(rport_ptr);
}
}
}
@ -1719,7 +1814,7 @@ static void msm_ipc_cleanup_routing_table(
rt_entry->xprt_info = NULL;
up_write(&rt_entry->lock_lha4);
list_del(&rt_entry->list);
kfree(rt_entry);
kref_put(&rt_entry->ref, ipc_router_release_rtentry);
}
}
up_write(&routing_table_lock_lha3);
@ -1739,16 +1834,15 @@ static void sync_sec_rule(struct msm_ipc_server *server, void *rule)
struct msm_ipc_server_port *server_port;
struct msm_ipc_router_remote_port *rport_ptr = NULL;
down_read(&routing_table_lock_lha3);
list_for_each_entry(server_port, &server->server_port_list, list) {
rport_ptr = msm_ipc_router_lookup_remote_port(
rport_ptr = ipc_router_get_rport_ref(
server_port->server_addr.node_id,
server_port->server_addr.port_id);
if (!rport_ptr)
continue;
rport_ptr->sec_rule = rule;
kref_put(&rport_ptr->ref, ipc_router_release_rport);
}
up_read(&routing_table_lock_lha3);
server->synced_sec_rule = 1;
}
@ -1829,30 +1923,12 @@ static int process_hello_msg(struct msm_ipc_router_xprt_info *xprt_info,
RR("o HELLO NID %d\n", hdr->src_node_id);
xprt_info->remote_node_id = hdr->src_node_id;
/*
* Find the entry from Routing Table corresponding to Node ID.
* Under SSR, an entry will be found. When the system boots up
* for the 1st time, an entry will not be found and hence allocate
* an entry. Update the entry with the Node ID that it corresponds
* to and the XPRT through which it can be reached.
*/
down_write(&routing_table_lock_lha3);
rt_entry = lookup_routing_table(hdr->src_node_id);
rt_entry = create_routing_table_entry(hdr->src_node_id, xprt_info);
if (!rt_entry) {
rt_entry = alloc_routing_table_entry(hdr->src_node_id);
if (!rt_entry) {
up_write(&routing_table_lock_lha3);
IPC_RTR_ERR("%s: rt_entry allocation failed\n",
__func__);
return -ENOMEM;
}
add_routing_table_entry(rt_entry);
IPC_RTR_ERR("%s: rt_entry allocation failed\n", __func__);
return -ENOMEM;
}
down_write(&rt_entry->lock_lha4);
rt_entry->neighbor_node_id = xprt_info->remote_node_id;
rt_entry->xprt_info = xprt_info;
up_write(&rt_entry->lock_lha4);
up_write(&routing_table_lock_lha3);
kref_put(&rt_entry->ref, ipc_router_release_rtentry);
/* Send a reply HELLO message */
memset(&ctl, 0, sizeof(ctl));
@ -1897,25 +1973,22 @@ static int process_resume_tx_msg(union rr_control_msg *msg,
struct rr_packet *pkt)
{
struct msm_ipc_router_remote_port *rport_ptr;
int ret = 0;
RR("o RESUME_TX id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
down_read(&local_ports_lock_lha2);
down_read(&routing_table_lock_lha3);
rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
msg->cli.port_id);
rport_ptr = ipc_router_get_rport_ref(msg->cli.node_id,
msg->cli.port_id);
if (!rport_ptr) {
up_read(&local_ports_lock_lha2);
IPC_RTR_ERR("%s: Unable to resume client\n", __func__);
ret = -ENODEV;
goto prtm_out;
return -ENODEV;
}
mutex_lock(&rport_ptr->quota_lock_lhb2);
mutex_lock(&rport_ptr->rport_lock_lhb2);
rport_ptr->tx_quota_cnt = 0;
post_resume_tx(rport_ptr, pkt, msg);
mutex_unlock(&rport_ptr->quota_lock_lhb2);
prtm_out:
up_read(&routing_table_lock_lha3);
mutex_unlock(&rport_ptr->rport_lock_lhb2);
kref_put(&rport_ptr->ref, ipc_router_release_rport);
up_read(&local_ports_lock_lha2);
return 0;
}
@ -1935,30 +2008,17 @@ static int process_new_server_msg(struct msm_ipc_router_xprt_info *xprt_info,
RR("o NEW_SERVER id=%d:%08x service=%08x:%08x\n", msg->srv.node_id,
msg->srv.port_id, msg->srv.service, msg->srv.instance);
/*
* Find the entry from Routing Table corresponding to Node ID.
* Under SSR, an entry will be found. When the subsystem hosting
* service is not adjacent, an entry will not be found and hence
* allocate an entry. Update the entry with the Node ID that it
* corresponds to and the XPRT through which it can be reached.
*/
down_write(&routing_table_lock_lha3);
rt_entry = lookup_routing_table(msg->srv.node_id);
rt_entry = ipc_router_get_rtentry_ref(msg->srv.node_id);
if (!rt_entry) {
rt_entry = alloc_routing_table_entry(msg->srv.node_id);
rt_entry = create_routing_table_entry(msg->srv.node_id,
xprt_info);
if (!rt_entry) {
up_write(&routing_table_lock_lha3);
IPC_RTR_ERR("%s: rt_entry allocation failed\n",
__func__);
return -ENOMEM;
}
down_write(&rt_entry->lock_lha4);
rt_entry->neighbor_node_id = xprt_info->remote_node_id;
rt_entry->xprt_info = xprt_info;
up_write(&rt_entry->lock_lha4);
add_routing_table_entry(rt_entry);
}
up_write(&routing_table_lock_lha3);
kref_put(&rt_entry->ref, ipc_router_release_rtentry);
/* If the service does not exist already in the database, create and
* store the service info. Create a remote port structure in which
@ -1978,22 +2038,18 @@ static int process_new_server_msg(struct msm_ipc_router_xprt_info *xprt_info,
return -ENOMEM;
}
down_read(&routing_table_lock_lha3);
if (!msm_ipc_router_lookup_remote_port(
msg->srv.node_id, msg->srv.port_id)) {
rport_ptr = msm_ipc_router_create_remote_port(
msg->srv.node_id, msg->srv.port_id);
if (!rport_ptr) {
up_read(&routing_table_lock_lha3);
up_write(&server_list_lock_lha2);
return -ENOMEM;
}
rport_ptr->server = server;
rport_ptr->sec_rule = msm_ipc_get_security_rule(
msg->srv.service,
msg->srv.instance);
rport_ptr = ipc_router_create_rport(msg->srv.node_id,
msg->srv.port_id, xprt_info);
if (!rport_ptr) {
up_write(&server_list_lock_lha2);
return -ENOMEM;
}
up_read(&routing_table_lock_lha3);
mutex_lock(&rport_ptr->rport_lock_lhb2);
rport_ptr->server = server;
mutex_unlock(&rport_ptr->rport_lock_lhb2);
rport_ptr->sec_rule = msm_ipc_get_security_rule(
msg->srv.service, msg->srv.instance);
kref_put(&rport_ptr->ref, ipc_router_release_rport);
}
up_write(&server_list_lock_lha2);
@ -2017,13 +2073,15 @@ static int process_rmv_server_msg(struct msm_ipc_router_xprt_info *xprt_info,
down_write(&server_list_lock_lha2);
server = msm_ipc_router_lookup_server(msg->srv.service,
msg->srv.instance, msg->srv.node_id, msg->srv.port_id);
down_write(&routing_table_lock_lha3);
rport_ptr = msm_ipc_router_lookup_remote_port(msg->srv.node_id,
msg->srv.port_id);
if (rport_ptr && rport_ptr->server == server)
rport_ptr->server = NULL;
up_write(&routing_table_lock_lha3);
rport_ptr = ipc_router_get_rport_ref(msg->srv.node_id,
msg->srv.port_id);
if (rport_ptr) {
mutex_lock(&rport_ptr->rport_lock_lhb2);
if (rport_ptr->server == server)
rport_ptr->server = NULL;
mutex_unlock(&rport_ptr->rport_lock_lhb2);
kref_put(&rport_ptr->ref, ipc_router_release_rport);
}
if (server) {
msm_ipc_router_destroy_server(server, msg->srv.node_id,
@ -2044,18 +2102,22 @@ static int process_rmv_client_msg(struct msm_ipc_router_xprt_info *xprt_info,
union rr_control_msg *msg, struct rr_packet *pkt)
{
struct msm_ipc_router_remote_port *rport_ptr;
struct msm_ipc_server *server;
RR("o REMOVE_CLIENT id=%d:%08x\n", msg->cli.node_id, msg->cli.port_id);
down_write(&server_list_lock_lha2);
down_write(&routing_table_lock_lha3);
rport_ptr = msm_ipc_router_lookup_remote_port(msg->cli.node_id,
msg->cli.port_id);
rport_ptr = ipc_router_get_rport_ref(msg->cli.node_id,
msg->cli.port_id);
if (rport_ptr) {
if (rport_ptr->server)
cleanup_rmt_server(NULL, rport_ptr);
msm_ipc_router_destroy_remote_port(rport_ptr);
mutex_lock(&rport_ptr->rport_lock_lhb2);
server = rport_ptr->server;
rport_ptr->server = NULL;
mutex_unlock(&rport_ptr->rport_lock_lhb2);
if (server)
cleanup_rmt_server(NULL, rport_ptr, server);
kref_put(&rport_ptr->ref, ipc_router_release_rport);
ipc_router_destroy_rport(rport_ptr);
}
up_write(&routing_table_lock_lha3);
up_write(&server_list_lock_lha2);
relay_ctl_msg(xprt_info, msg);
@ -2169,26 +2231,22 @@ static void do_read_data(struct work_struct *work)
goto read_next_pkt2;
}
down_read(&routing_table_lock_lha3);
rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
hdr->src_port_id);
rport_ptr = ipc_router_get_rport_ref(hdr->src_node_id,
hdr->src_port_id);
if (!rport_ptr) {
rport_ptr = msm_ipc_router_create_remote_port(
hdr->src_node_id,
hdr->src_port_id);
rport_ptr = ipc_router_create_rport(hdr->src_node_id,
hdr->src_port_id, xprt_info);
if (!rport_ptr) {
IPC_RTR_ERR(
"%s: Rmt Prt %08x:%08x create failed\n",
__func__, hdr->src_node_id, hdr->src_port_id);
goto read_next_pkt3;
goto read_next_pkt2;
}
}
up_read(&routing_table_lock_lha3);
kref_put(&rport_ptr->ref, ipc_router_release_rport);
post_pkt_to_port(port_ptr, pkt, 0);
up_read(&local_ports_lock_lha2);
continue;
read_next_pkt3:
up_read(&routing_table_lock_lha3);
read_next_pkt2:
up_read(&local_ports_lock_lha2);
read_next_pkt1:
@ -2375,11 +2433,11 @@ static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
hdr->dst_node_id = rport_ptr->node_id;
hdr->dst_port_id = rport_ptr->port_id;
mutex_lock(&rport_ptr->quota_lock_lhb2);
mutex_lock(&rport_ptr->rport_lock_lhb2);
if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA) {
if (msm_ipc_router_lookup_resume_tx_port(
rport_ptr, src->this_port.port_id)) {
mutex_unlock(&rport_ptr->quota_lock_lhb2);
mutex_unlock(&rport_ptr->rport_lock_lhb2);
return -EAGAIN;
}
resume_tx_port =
@ -2388,7 +2446,7 @@ static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
if (!resume_tx_port) {
IPC_RTR_ERR("%s: Resume_Tx port allocation failed\n",
__func__);
mutex_unlock(&rport_ptr->quota_lock_lhb2);
mutex_unlock(&rport_ptr->rport_lock_lhb2);
return -ENOMEM;
}
INIT_LIST_HEAD(&resume_tx_port->list);
@ -2396,16 +2454,16 @@ static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
resume_tx_port->node_id = src->this_port.node_id;
list_add_tail(&resume_tx_port->list,
&rport_ptr->resume_tx_port_list);
mutex_unlock(&rport_ptr->quota_lock_lhb2);
mutex_unlock(&rport_ptr->rport_lock_lhb2);
return -EAGAIN;
}
rport_ptr->tx_quota_cnt++;
if (rport_ptr->tx_quota_cnt == IPC_ROUTER_DEFAULT_RX_QUOTA)
hdr->control_flag |= CONTROL_FLAG_CONFIRM_RX;
mutex_unlock(&rport_ptr->quota_lock_lhb2);
mutex_unlock(&rport_ptr->rport_lock_lhb2);
rt_entry = lookup_routing_table(hdr->dst_node_id);
if (!rt_entry || !rt_entry->xprt_info) {
rt_entry = ipc_router_get_rtentry_ref(hdr->dst_node_id);
if (!rt_entry) {
IPC_RTR_ERR("%s: Remote node %d not up\n",
__func__, hdr->dst_node_id);
return -ENODEV;
@ -2414,17 +2472,14 @@ static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
xprt_info = rt_entry->xprt_info;
ret = prepend_header(pkt, xprt_info);
if (ret < 0) {
up_read(&rt_entry->lock_lha4);
IPC_RTR_ERR("%s: Prepend Header failed\n", __func__);
return ret;
goto out_write_pkt;
}
xprt_option = xprt_info->xprt->get_option(xprt_info->xprt);
if (!(xprt_option & FRAG_PKT_WRITE_ENABLE)) {
ret = defragment_pkt(pkt);
if (ret < 0) {
up_read(&rt_entry->lock_lha4);
return ret;
}
if (ret < 0)
goto out_write_pkt;
}
temp_skb = skb_peek_tail(pkt->pkt_fragment_q);
@ -2434,7 +2489,9 @@ static int msm_ipc_router_write_pkt(struct msm_ipc_port *src,
mutex_lock(&xprt_info->tx_lock_lhb2);
ret = xprt_info->xprt->write(pkt, pkt->length, xprt_info->xprt);
mutex_unlock(&xprt_info->tx_lock_lhb2);
out_write_pkt:
up_read(&rt_entry->lock_lha4);
kref_put(&rt_entry->ref, ipc_router_release_rtentry);
if (ret < 0) {
IPC_RTR_ERR("%s: Write on XPRT failed\n", __func__);
@ -2508,11 +2565,8 @@ int msm_ipc_router_send_to(struct msm_ipc_port *src,
return ret;
}
down_read(&routing_table_lock_lha3);
rport_ptr = msm_ipc_router_lookup_remote_port(dst_node_id,
dst_port_id);
rport_ptr = ipc_router_get_rport_ref(dst_node_id, dst_port_id);
if (!rport_ptr) {
up_read(&routing_table_lock_lha3);
IPC_RTR_ERR("%s: Remote port not found\n", __func__);
return -ENODEV;
}
@ -2520,7 +2574,7 @@ int msm_ipc_router_send_to(struct msm_ipc_port *src,
if (src->check_send_permissions) {
ret = src->check_send_permissions(rport_ptr->sec_rule);
if (ret <= 0) {
up_read(&routing_table_lock_lha3);
kref_put(&rport_ptr->ref, ipc_router_release_rport);
IPC_RTR_ERR("%s: permission failure for %s\n",
__func__, current->comm);
return -EPERM;
@ -2529,13 +2583,13 @@ int msm_ipc_router_send_to(struct msm_ipc_port *src,
pkt = create_pkt(data);
if (!pkt) {
up_read(&routing_table_lock_lha3);
kref_put(&rport_ptr->ref, ipc_router_release_rport);
IPC_RTR_ERR("%s: Pkt creation failed\n", __func__);
return -ENOMEM;
}
ret = msm_ipc_router_write_pkt(src, rport_ptr, pkt);
up_read(&routing_table_lock_lha3);
kref_put(&rport_ptr->ref, ipc_router_release_rport);
if (ret < 0)
pkt->pkt_fragment_q = NULL;
release_pkt(pkt);
@ -2591,19 +2645,17 @@ static int msm_ipc_router_send_resume_tx(void *data)
msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
msg.cli.node_id = hdr->dst_node_id;
msg.cli.port_id = hdr->dst_port_id;
down_read(&routing_table_lock_lha3);
rt_entry = lookup_routing_table(hdr->src_node_id);
rt_entry = ipc_router_get_rtentry_ref(hdr->src_node_id);
if (!rt_entry) {
IPC_RTR_ERR("%s: %d Node is not present",
__func__, hdr->src_node_id);
up_read(&routing_table_lock_lha3);
return -ENODEV;
}
RR("x RESUME_TX id=%d:%08x\n",
msg.cli.node_id, msg.cli.port_id);
ret = ipc_router_send_ctl_msg(rt_entry->xprt_info, &msg,
hdr->src_node_id);
up_read(&routing_table_lock_lha3);
kref_put(&rt_entry->ref, ipc_router_release_rtentry);
if (ret < 0)
IPC_RTR_ERR(
"%s: Send Resume_Tx Failed SRC_NODE: %d SRC_PORT: %d DEST_NODE: %d",
@ -3209,7 +3261,6 @@ static void debugfs_init(void) {}
static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
{
struct msm_ipc_router_xprt_info *xprt_info;
struct msm_ipc_routing_table_entry *rt_entry;
xprt_info = kmalloc(sizeof(struct msm_ipc_router_xprt_info),
GFP_KERNEL);
@ -3246,8 +3297,6 @@ static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
down_write(&routing_table_lock_lha3);
if (!routing_table_inited) {
init_routing_table();
rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
add_routing_table_entry(rt_entry);
routing_table_inited = 1;
}
up_write(&routing_table_lock_lha3);
@ -3404,11 +3453,11 @@ static int msm_ipc_router_init(void)
down_write(&routing_table_lock_lha3);
if (!routing_table_inited) {
init_routing_table();
rt_entry = alloc_routing_table_entry(IPC_ROUTER_NID_LOCAL);
add_routing_table_entry(rt_entry);
routing_table_inited = 1;
}
up_write(&routing_table_lock_lha3);
rt_entry = create_routing_table_entry(IPC_ROUTER_NID_LOCAL, NULL);
kref_put(&rt_entry->ref, ipc_router_release_rtentry);
ret = msm_ipc_router_init_sockets();
if (ret < 0)