From 52bda664e51ed36f883a60153e69d5ece0a50aa6 Mon Sep 17 00:00:00 2001 From: Dhoat Harpal Date: Thu, 8 Dec 2016 20:40:54 +0530 Subject: [PATCH] soc: qcom: glink: Fix queue intent after glink close Glink pkt client is calling glink_queue_rx_intent even after calling glink_close, this result in calling with invalid handle. glink_queue_rx_intent is called with mutex lock and dev handle is set to NULL right after call to glink_close. CRs-Fixed: 1098097 Change-Id: I6fc8e7d91a6d27fe6602e8aabcffcdbfb1316c97 Signed-off-by: Dhoat Harpal --- drivers/soc/qcom/msm_glink_pkt.c | 39 ++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c index 490faf89ab76..9c20343abdaa 100644 --- a/drivers/soc/qcom/msm_glink_pkt.c +++ b/drivers/soc/qcom/msm_glink_pkt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -502,13 +502,21 @@ static void glink_pkt_queue_rx_intent_worker(struct work_struct *work) struct queue_rx_intent_work, work); struct glink_pkt_dev *devp = work_item->devp; - if (!devp || !devp->handle) { + if (!devp) { + GLINK_PKT_ERR("%s: Invalid device\n", __func__); + kfree(work_item); + return; + } + mutex_lock(&devp->ch_lock); + if (!devp->handle) { GLINK_PKT_ERR("%s: Invalid device Handle\n", __func__); + mutex_unlock(&devp->ch_lock); kfree(work_item); return; } ret = glink_queue_rx_intent(devp->handle, devp, work_item->intent_size); + mutex_unlock(&devp->ch_lock); GLINK_PKT_INFO("%s: Triggered with size[%zu] ret[%d]\n", __func__, work_item->intent_size, ret); if (ret) @@ -1035,6 +1043,27 @@ error: return ret; } +/** + * pop_rx_pkt() - return first pkt from rx pkt_list + * devp: pointer to G-Link packet device. + * + * This function return first item from rx pkt_list and NULL if list is empty. + */ +struct glink_rx_pkt *pop_rx_pkt(struct glink_pkt_dev *devp) +{ + unsigned long flags; + struct glink_rx_pkt *pkt = NULL; + + spin_lock_irqsave(&devp->pkt_list_lock, flags); + if (!list_empty(&devp->pkt_list)) { + pkt = list_first_entry(&devp->pkt_list, + struct glink_rx_pkt, list); + list_del(&pkt->list); + } + spin_unlock_irqrestore(&devp->pkt_list_lock, flags); + return pkt; +} + /** * glink_pkt_release() - release operation on glink_pkt device * inode: Pointer to the inode structure. @@ -1049,6 +1078,7 @@ int glink_pkt_release(struct inode *inode, struct file *file) int ret = 0; struct glink_pkt_dev *devp = file->private_data; unsigned long flags; + struct glink_rx_pkt *pkt; GLINK_PKT_INFO("%s() on dev id:%d by [%s] ref_cnt[%d]\n", __func__, devp->i, current->comm, devp->ref_cnt); @@ -1057,9 +1087,14 @@ int glink_pkt_release(struct inode *inode, struct file *file) devp->ref_cnt--; if (devp->handle && devp->ref_cnt == 0) { + while ((pkt = pop_rx_pkt(devp))) { + glink_rx_done(devp->handle, pkt->data, false); + kfree(pkt); + } wake_up(&devp->ch_read_wait_queue); wake_up_interruptible(&devp->ch_opened_wait_queue); ret = glink_close(devp->handle); + devp->handle = NULL; if (ret) { GLINK_PKT_ERR("%s: close failed ret[%d]\n", __func__, ret);