FAILED: patch "[PATCH] mmc: sdhci: fix dma memory leak in sdhci_pre_req()" failed to apply to 4.1-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 4.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
d31911b9374a76560d2c8ea4aa6ce5781621e81dMon Sep 17 00:00:00 2001
From: Haibo Chen <[email protected]>
Date: Tue, 25 Aug 2015 10:02:11 +0800
Subject: [PATCH] mmc: sdhci: fix dma memory leak in sdhci_pre_req()
Currently one mrq->data maybe execute dma_map_sg() twice when mmc subsystem prepare over one new request, and the following log show up:
sdhci[sdhci_pre_dma_transfer] invalid cookie: 24, next-cookie 25
In this condition, mrq->date map a dma-memory(1) in sdhci_pre_req for the first time, and map another dma-memory(2) in sdhci_prepare_data for the second time. But driver only unmap the dma-memory(2), and dma-memory(1) never unmapped, which cause the dma memory leak issue.
This patch use another method to map the dma memory for the mrq->data which can fix this dma memory leak issue.
drivers/mmc/host/sdhci.c +25 -42
@@ -54,8 +54,7 @@ static void sdhci_finish_command(struct sdhci_host *);static int sdhci_execute_tuning (struct mmc_host *mmc,u32 opcode);static void sdhci_enable_preset_value (struct sdhci_host *host,bool enable);static int sdhci_pre_dma_transfer (struct sdhci_host *host, -struct mmc_data *data, -struct sdhci_host_next *next); +struct mmc_data *data);static int sdhci_do_get_cd (struct sdhci_host *host);#ifdef CONFIG_PM
@@ -495,7 +494,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, goto fail;BUG_ON (host->align_addr & host->align_mask); - host->sg_count =sdhci_pre_dma_transfer (host, data,NULL ); + host->sg_count =sdhci_pre_dma_transfer (host, data);if (host->sg_count <0 ) goto unmap_align;
@@ -634,9 +633,11 @@ static void sdhci_adma_table_post(struct sdhci_host *host, } } -if (!data->host_cookie) +if (data->host_cookie ==COOKIE_MAPPED ) {dma_unmap_sg (mmc_dev (host->mmc), data->sg, data->sg_len, direction); + data->host_cookie =COOKIE_UNMAPPED ; + } }static u8 sdhci_calc_timeout (struct sdhci_host *host,struct mmc_command *cmd)
@@ -832,7 +833,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) }else {int sg_cnt; - sg_cnt =sdhci_pre_dma_transfer (host, data,NULL ); + sg_cnt =sdhci_pre_dma_transfer (host, data);if (sg_cnt <=0 ) {/* * This only happens when someone fed
@@ -948,11 +949,13 @@ static void sdhci_finish_data(struct sdhci_host *host)if (host->flags &SDHCI_USE_ADMA )sdhci_adma_table_post (host, data);else { -if (!data->host_cookie) +if (data->host_cookie ==COOKIE_MAPPED ) {dma_unmap_sg (mmc_dev (host->mmc), data->sg, data->sg_len, (data->flags &MMC_DATA_READ ) ?DMA_FROM_DEVICE :DMA_TO_DEVICE ); + data->host_cookie =COOKIE_UNMAPPED ; + } } }
@@ -2116,49 +2119,36 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,struct mmc_data *data = mrq->data;if (host->flags &SDHCI_REQ_USE_DMA ) { -if (data->host_cookie) +if (data->host_cookie ==COOKIE_GIVEN || + data->host_cookie ==COOKIE_MAPPED )dma_unmap_sg (mmc_dev (host->mmc), data->sg, data->sg_len, data->flags &MMC_DATA_WRITE ?DMA_TO_DEVICE :DMA_FROM_DEVICE ); - mrq->data->host_cookie =0 ; + data->host_cookie =COOKIE_UNMAPPED ; } }static int sdhci_pre_dma_transfer (struct sdhci_host *host, -struct mmc_data *data, -struct sdhci_host_next *next) +struct mmc_data *data) {int sg_count; -if (!next && data->host_cookie && - data->host_cookie != host->next_data.cookie) { -pr_debug (DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n" , - __func__, data->host_cookie, host->next_data.cookie); - data->host_cookie =0 ; +if (data->host_cookie ==COOKIE_MAPPED ) { + data->host_cookie =COOKIE_GIVEN ; +return data->sg_count; } -/* Check if next job is already prepared */ -if (next || - (!next && data->host_cookie != host->next_data.cookie)) { - sg_count =dma_map_sg (mmc_dev (host->mmc), data->sg, - data->sg_len, - data->flags &MMC_DATA_WRITE ? -DMA_TO_DEVICE :DMA_FROM_DEVICE ); - - }else { - sg_count = host->next_data.sg_count; - host->next_data.sg_count =0 ; - } +WARN_ON (data->host_cookie ==COOKIE_GIVEN ); + sg_count =dma_map_sg (mmc_dev (host->mmc), data->sg, data->sg_len, + data->flags &MMC_DATA_WRITE ? +DMA_TO_DEVICE :DMA_FROM_DEVICE );if (sg_count ==0 ) -return -EINVAL ; +return -ENOSPC ; -if (next) { - next->sg_count = sg_count; - data->host_cookie = ++next->cookie <0 ?1 : next->cookie; - }else - host->sg_count = sg_count; + data->sg_count = sg_count; + data->host_cookie =COOKIE_MAPPED ;return sg_count; }
@@ -2168,16 +2158,10 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, {struct sdhci_host *host =mmc_priv (mmc); -if (mrq->data->host_cookie) { - mrq->data->host_cookie =0 ; -return ; - } + mrq->data->host_cookie =COOKIE_UNMAPPED ;if (host->flags &SDHCI_REQ_USE_DMA ) -if (sdhci_pre_dma_transfer (host, - mrq->data, - &host->next_data) <0 ) - mrq->data->host_cookie =0 ; +sdhci_pre_dma_transfer (host, mrq->data); }static void sdhci_card_event (struct mmc_host *mmc)
@@ -3049,7 +3033,6 @@ int sdhci_add_host(struct sdhci_host *host) host->max_clk = host->ops->get_max_clock (host); } - host->next_data.cookie =1 ;/* * In case of Host Controller v3.00, find out whether clock * multiplier is supported.
drivers/mmc/host/sdhci.h +4 -4
@@ -309,9 +309,10 @@ struct sdhci_adma2_64_desc {*/ #define SDHCI_MAX_SEGS 128 -struct sdhci_host_next { -unsigned int sg_count; -s32 cookie; +enum sdhci_cookie { +COOKIE_UNMAPPED , +COOKIE_MAPPED , +COOKIE_GIVEN , };struct sdhci_host {
@@ -505,7 +506,6 @@ struct sdhci_host {unsigned int tuning_mode;/* Re-tuning mode supported by host */ #define SDHCI_TUNING_MODE_1 0 -struct sdhci_host_next next_data;unsigned long private[0 ]____cacheline_aligned ; };
PATCH 1/1 mmc: sdhci: fix dma memory leak in sdhci_pre_req()
From: Haibo Chen <[email protected]>
commit d31911b9374a76560d2c8ea4aa6ce5781621e81d upstream.
Currently one mrq->data maybe execute dma_map_sg() twice when mmc subsystem prepare over one new request, and the following log show up:
sdhci[sdhci_pre_dma_transfer] invalid cookie: 24, next-cookie 25
In this condition, mrq->date map a dma-memory(1) in sdhci_pre_req for the first time, and map another dma-memory(2) in sdhci_prepare_data for the second time. But driver only unmap the dma-memory(2), and dma-memory(1) never unmapped, which cause the dma memory leak issue.
This patch use another method to map the dma memory for the mrq->data which can fix this dma memory leak issue.
[js] add sg_count to mmc_data as happenned in 208489032bdd8d (mmc:
mediatek: Add Mediatek MMC driver).
--- drivers/mmc/host/sdhci.c | 67 ++++++++++++++++++------------------------------ drivers/mmc/host/sdhci.h | 8 +++--- include/linux/mmc/core.h | 1 + 3 files changed, 30 insertions(+), 46 deletions(-)
drivers/mmc/host/sdhci.c +25 -42
@@ -55,8 +55,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);static void sdhci_tuning_timer (unsigned long data);static void sdhci_enable_preset_value (struct sdhci_host *host,bool enable);static int sdhci_pre_dma_transfer (struct sdhci_host *host, -struct mmc_data *data, -struct sdhci_host_next *next); +struct mmc_data *data);static int sdhci_do_get_cd (struct sdhci_host *host);#ifdef CONFIG_PM
@@ -510,7 +509,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, goto fail;BUG_ON (host->align_addr & host->align_mask); - host->sg_count =sdhci_pre_dma_transfer (host, data,NULL ); + host->sg_count =sdhci_pre_dma_transfer (host, data);if (host->sg_count <0 ) goto unmap_align;
@@ -649,9 +648,11 @@ static void sdhci_adma_table_post(struct sdhci_host *host, } } -if (!data->host_cookie) +if (data->host_cookie ==COOKIE_MAPPED ) {dma_unmap_sg (mmc_dev (host->mmc), data->sg, data->sg_len, direction); + data->host_cookie =COOKIE_UNMAPPED ; + } }static u8 sdhci_calc_timeout (struct sdhci_host *host,struct mmc_command *cmd)
@@ -847,7 +848,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) }else {int sg_cnt; - sg_cnt =sdhci_pre_dma_transfer (host, data,NULL ); + sg_cnt =sdhci_pre_dma_transfer (host, data);if (sg_cnt <=0 ) {/* * This only happens when someone fed
@@ -963,11 +964,13 @@ static void sdhci_finish_data(struct sdhci_host *host)if (host->flags &SDHCI_USE_ADMA )sdhci_adma_table_post (host, data);else { -if (!data->host_cookie) +if (data->host_cookie ==COOKIE_MAPPED ) {dma_unmap_sg (mmc_dev (host->mmc), data->sg, data->sg_len, (data->flags &MMC_DATA_READ ) ?DMA_FROM_DEVICE :DMA_TO_DEVICE ); + data->host_cookie =COOKIE_UNMAPPED ; + } } }
@@ -2129,49 +2132,36 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,struct mmc_data *data = mrq->data;if (host->flags &SDHCI_REQ_USE_DMA ) { -if (data->host_cookie) +if (data->host_cookie ==COOKIE_GIVEN || + data->host_cookie ==COOKIE_MAPPED )dma_unmap_sg (mmc_dev (host->mmc), data->sg, data->sg_len, data->flags &MMC_DATA_WRITE ?DMA_TO_DEVICE :DMA_FROM_DEVICE ); - mrq->data->host_cookie =0 ; + data->host_cookie =COOKIE_UNMAPPED ; } }static int sdhci_pre_dma_transfer (struct sdhci_host *host, -struct mmc_data *data, -struct sdhci_host_next *next) +struct mmc_data *data) {int sg_count; -if (!next && data->host_cookie && - data->host_cookie != host->next_data.cookie) { -pr_debug (DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n" , - __func__, data->host_cookie, host->next_data.cookie); - data->host_cookie =0 ; +if (data->host_cookie ==COOKIE_MAPPED ) { + data->host_cookie =COOKIE_GIVEN ; +return data->sg_count; } -/* Check if next job is already prepared */ -if (next || - (!next && data->host_cookie != host->next_data.cookie)) { - sg_count =dma_map_sg (mmc_dev (host->mmc), data->sg, - data->sg_len, - data->flags &MMC_DATA_WRITE ? -DMA_TO_DEVICE :DMA_FROM_DEVICE ); - - }else { - sg_count = host->next_data.sg_count; - host->next_data.sg_count =0 ; - } +WARN_ON (data->host_cookie ==COOKIE_GIVEN ); + sg_count =dma_map_sg (mmc_dev (host->mmc), data->sg, data->sg_len, + data->flags &MMC_DATA_WRITE ? +DMA_TO_DEVICE :DMA_FROM_DEVICE );if (sg_count ==0 ) -return -EINVAL ; +return -ENOSPC ; -if (next) { - next->sg_count = sg_count; - data->host_cookie = ++next->cookie <0 ?1 : next->cookie; - }else - host->sg_count = sg_count; + data->sg_count = sg_count; + data->host_cookie =COOKIE_MAPPED ;return sg_count; }
@@ -2181,16 +2171,10 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, {struct sdhci_host *host =mmc_priv (mmc); -if (mrq->data->host_cookie) { - mrq->data->host_cookie =0 ; -return ; - } + mrq->data->host_cookie =COOKIE_UNMAPPED ;if (host->flags &SDHCI_REQ_USE_DMA ) -if (sdhci_pre_dma_transfer (host, - mrq->data, - &host->next_data) <0 ) - mrq->data->host_cookie =0 ; +sdhci_pre_dma_transfer (host, mrq->data); }static void sdhci_card_event (struct mmc_host *mmc)
@@ -3088,7 +3072,6 @@ int sdhci_add_host(struct sdhci_host *host) host->max_clk = host->ops->get_max_clock (host); } - host->next_data.cookie =1 ;/* * In case of Host Controller v3.00, find out whether clock * multiplier is supported.
drivers/mmc/host/sdhci.h +4 -4
@@ -309,9 +309,10 @@ struct sdhci_adma2_64_desc {*/ #define SDHCI_MAX_SEGS 128 -struct sdhci_host_next { -unsigned int sg_count; -s32 cookie; +enum sdhci_cookie { +COOKIE_UNMAPPED , +COOKIE_MAPPED , +COOKIE_GIVEN , };struct sdhci_host {
@@ -506,7 +507,6 @@ struct sdhci_host {#define SDHCI_TUNING_MODE_1 0struct timer_list tuning_timer;/* Timer for tuning */ -struct sdhci_host_next next_data;unsigned long private[0 ]____cacheline_aligned ; };
include/linux/mmc/core.h +1 -0
@@ -121,6 +121,7 @@ struct mmc_data {struct mmc_request *mrq;/* associated request */ unsigned int sg_len;/* size of scatter list */ +int sg_count;/* mapped sg entries */ struct scatterlist *sg;/* I/O scatter list */ s32 host_cookie;/* host private data */ };
Signature · 1 line
2.6.0
Re: [PATCH 4.1] mmc: sdhci: fix dma memory leak in sdhci_pre_req()
Quoted 2 lines · Jiri Slaby
[js] add
sg_counttommc_dataas happenned in208489032bdd8d(mmc:
mediatek: Add Mediatek MMC driver).
I don't know if this is justifiable or how otherwise to solve this... The prereq 208489032bdd8d is way too big for stable, I suppose.
include/linux/mmc/core.h struct mmc_data { · line 127
Quoted 11 lines
include/linux/mmc/core.h +1
-0@@ -121,6 +121,7 @@ struct mmc_data {struct mmc_request *mrq;/* associated request */ unsigned int sg_len;/* size of scatter list */ +int sg_count;/* mapped sg entries */ struct scatterlist *sg;/* I/O scatter list */ s32 host_cookie;/* host private data */ };
thanks,
Signature · 2 lines
js suse labs
Greg KH
maintainerRe: [PATCH 4.1] mmc: sdhci: fix dma memory leak in sdhci_pre_req()
Quoted 6 lines · Jiri Slaby
Quoted 2 lines · Jiri Slaby
[js] add
sg_counttommc_dataas happenned in208489032bdd8d(mmc:
mediatek: Add Mediatek MMC driver).I don't know if this is justifiable or how otherwise to solve this... The prereq
208489032bdd8dis way too big for stable, I suppose.
Yeah, that doesn't make sense to add, I'll just take your backport, it's better.
thanks,
greg k-h