diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c index f3c98f09477f..183213506222 100644 --- a/net/ipc_router/ipc_router_core.c +++ b/net/ipc_router/ipc_router_core.c @@ -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)