mei: fix memory leak of pending write cb objects
Write callbacks are released on the write completed path but
when file handler is closed before the writes are
completed those are left dangling on write and write_waiting queues.
We add mei_io_list_free function to perform this task
Also move static functions to client.c form client.h
Cc: stable <stable@vger.kernel.org> # 3.11+
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 7536081..8c078b8 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -71,20 +71,66 @@
/**
+ * mei_cl_cmp_id - tells if the clients are the same
+ *
+ * @cl1: host client 1
+ * @cl2: host client 2
+ *
+ * returns true - if the clients has same host and me ids
+ * false - otherwise
+ */
+static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
+ const struct mei_cl *cl2)
+{
+ return cl1 && cl2 &&
+ (cl1->host_client_id == cl2->host_client_id) &&
+ (cl1->me_client_id == cl2->me_client_id);
+}
+
+/**
+ * mei_io_list_flush - removes cbs belonging to cl.
+ *
+ * @list: an instance of our list structure
+ * @cl: host client, can be NULL for flushing the whole list
+ * @free: whether to free the cbs
+ */
+static void __mei_io_list_flush(struct mei_cl_cb *list,
+ struct mei_cl *cl, bool free)
+{
+ struct mei_cl_cb *cb;
+ struct mei_cl_cb *next;
+
+ /* enable removing everything if no cl is specified */
+ list_for_each_entry_safe(cb, next, &list->list, list) {
+ if (!cl || (cb->cl && mei_cl_cmp_id(cl, cb->cl))) {
+ list_del(&cb->list);
+ if (free)
+ mei_io_cb_free(cb);
+ }
+ }
+}
+
+/**
* mei_io_list_flush - removes list entry belonging to cl.
*
* @list: An instance of our list structure
* @cl: host client
*/
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
+static inline void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl)
{
- struct mei_cl_cb *cb;
- struct mei_cl_cb *next;
+ __mei_io_list_flush(list, cl, false);
+}
- list_for_each_entry_safe(cb, next, &list->list, list) {
- if (cb->cl && mei_cl_cmp_id(cl, cb->cl))
- list_del(&cb->list);
- }
+
+/**
+ * mei_io_list_free - removes cb belonging to cl and free them
+ *
+ * @list: An instance of our list structure
+ * @cl: host client
+ */
+static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
+{
+ __mei_io_list_flush(list, cl, true);
}
/**
@@ -193,8 +239,8 @@
cl_dbg(dev, cl, "remove list entry belonging to cl\n");
mei_io_list_flush(&cl->dev->read_list, cl);
- mei_io_list_flush(&cl->dev->write_list, cl);
- mei_io_list_flush(&cl->dev->write_waiting_list, cl);
+ mei_io_list_free(&cl->dev->write_list, cl);
+ mei_io_list_free(&cl->dev->write_waiting_list, cl);
mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
mei_io_list_flush(&cl->dev->amthif_cmd_list, cl);
@@ -956,20 +1002,8 @@
*/
void mei_cl_all_write_clear(struct mei_device *dev)
{
- struct mei_cl_cb *cb, *next;
- struct list_head *list;
-
- list = &dev->write_list.list;
- list_for_each_entry_safe(cb, next, list, list) {
- list_del(&cb->list);
- mei_io_cb_free(cb);
- }
-
- list = &dev->write_waiting_list.list;
- list_for_each_entry_safe(cb, next, list, list) {
- list_del(&cb->list);
- mei_io_cb_free(cb);
- }
+ mei_io_list_free(&dev->write_list, NULL);
+ mei_io_list_free(&dev->write_waiting_list, NULL);
}
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index c11b663..8139393 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -45,8 +45,6 @@
{
INIT_LIST_HEAD(&list->list);
}
-void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl);
-
/*
* MEI Host Client Functions
*/
@@ -61,22 +59,6 @@
int mei_cl_flush_queues(struct mei_cl *cl);
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl);
-/**
- * mei_cl_cmp_id - tells if file private data have same id
- *
- * @fe1: private data of 1. file object
- * @fe2: private data of 2. file object
- *
- * returns true - if ids are the same and not NULL
- */
-static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
- const struct mei_cl *cl2)
-{
- return cl1 && cl2 &&
- (cl1->host_client_id == cl2->host_client_id) &&
- (cl1->me_client_id == cl2->me_client_id);
-}
-
int mei_cl_flow_ctrl_creds(struct mei_cl *cl);