diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 72bfdd835178..26fa4a4d96b0 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -591,9 +591,10 @@ static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf, { struct mmc_card *card = filp->private_data; struct mmc_wr_pack_stats *pack_stats; - int i; + int i, ret = 0; int max_num_of_packed_reqs = 0; - char *temp_buf; + char *temp_buf, *temp_ubuf; + size_t tubuf_cnt = 0; if (!card) return cnt; @@ -619,15 +620,24 @@ static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf, max_num_of_packed_reqs = card->ext_csd.max_packed_writes; - temp_buf = kmalloc(TEMP_BUF_SIZE, GFP_KERNEL); + if (cnt <= (strlen_user(ubuf) + 1)) + goto exit; + + temp_buf = kzalloc(TEMP_BUF_SIZE, GFP_KERNEL); if (!temp_buf) goto exit; + tubuf_cnt = cnt - strlen_user(ubuf) - 1; + + temp_ubuf = kzalloc(tubuf_cnt, GFP_KERNEL); + if (!temp_ubuf) + goto cleanup; + spin_lock(&pack_stats->lock); snprintf(temp_buf, TEMP_BUF_SIZE, "%s: write packing statistics:\n", mmc_hostname(card->host)); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); for (i = 1 ; i <= max_num_of_packed_reqs ; ++i) { if (pack_stats->packing_events[i]) { @@ -635,63 +645,63 @@ static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf, "%s: Packed %d reqs - %d times\n", mmc_hostname(card->host), i, pack_stats->packing_events[i]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } } snprintf(temp_buf, TEMP_BUF_SIZE, "%s: stopped packing due to the following reasons:\n", mmc_hostname(card->host)); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); if (pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: exceed max num of segments\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[EXCEEDS_SEGMENTS]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[EXCEEDS_SECTORS]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: exceed max num of sectors\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[EXCEEDS_SECTORS]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[WRONG_DATA_DIR]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: wrong data direction\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[WRONG_DATA_DIR]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: flush or discard\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[FLUSH_OR_DISCARD]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[EMPTY_QUEUE]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: empty queue\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[EMPTY_QUEUE]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[REL_WRITE]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: rel write\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[REL_WRITE]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[THRESHOLD]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: Threshold\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[THRESHOLD]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[LARGE_SEC_ALIGN]) { @@ -699,25 +709,36 @@ static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf, "%s: %d times: Large sector alignment\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[LARGE_SEC_ALIGN]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[RANDOM]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: random request\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[RANDOM]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } if (pack_stats->pack_stop_reason[FUA]) { snprintf(temp_buf, TEMP_BUF_SIZE, "%s: %d times: fua request\n", mmc_hostname(card->host), pack_stats->pack_stop_reason[FUA]); - strlcat(ubuf, temp_buf, cnt); + strlcat(temp_ubuf, temp_buf, tubuf_cnt); } + if (strlen_user(ubuf) < cnt - strlen(temp_ubuf)) + ret = copy_to_user((ubuf + strlen_user(ubuf)), + temp_ubuf, tubuf_cnt); + else + ret = -EFAULT; + if (ret) + pr_err("%s: %s: Copy to userspace failed: %s\n", + mmc_hostname(card->host), __func__, ubuf); spin_unlock(&pack_stats->lock); + kfree(temp_ubuf); + +cleanup: kfree(temp_buf); pr_info("%s", ubuf);