diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index fd1fed3381a0..50b37f38e6e8 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -130,6 +130,7 @@ struct mmc_blk_data { struct device_attribute force_ro; struct device_attribute power_ro_lock; struct device_attribute num_wr_reqs_to_start_packing; + struct device_attribute no_pack_for_random; int area_type; }; @@ -348,6 +349,55 @@ exit: return ret; } +static ssize_t +no_pack_for_random_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); + int ret; + + ret = snprintf(buf, PAGE_SIZE, "%d\n", md->queue.no_pack_for_random); + + mmc_blk_put(md); + return ret; +} + +static ssize_t +no_pack_for_random_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int value; + struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); + struct mmc_card *card = md->queue.card; + int ret = count; + + if (!card) { + ret = -EINVAL; + goto exit; + } + + sscanf(buf, "%d", &value); + + if (value < 0) { + pr_err("%s: value %d is not valid. old value remains = %d", + mmc_hostname(card->host), value, + md->queue.no_pack_for_random); + ret = -EINVAL; + goto exit; + } + + md->queue.no_pack_for_random = (value > 0) ? true : false; + + pr_debug("%s: no_pack_for_random: new value = %d", + mmc_hostname(card->host), + md->queue.no_pack_for_random); + +exit: + mmc_blk_put(md); + return ret; +} + static int mmc_blk_open(struct block_device *bdev, fmode_t mode) { struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk); @@ -1870,6 +1920,15 @@ static u8 mmc_blk_prep_packed_list(struct mmc_queue *mq, struct request *req) break; } + if (mq->no_pack_for_random) { + if ((blk_rq_pos(cur) + blk_rq_sectors(cur)) != + blk_rq_pos(next)) { + MMC_BLK_UPDATE_STOP_REASON(stats, RANDOM); + put_back = 1; + break; + } + } + if (rq_data_dir(next) == WRITE) mq->num_of_potential_packed_wr_reqs++; list_add_tail(&next->queuelist, &mqrq->packed->list); @@ -2653,8 +2712,21 @@ static int mmc_add_disk(struct mmc_blk_data *md) if (ret) goto num_wr_reqs_to_start_packing_fail; + md->no_pack_for_random.show = no_pack_for_random_show; + md->no_pack_for_random.store = no_pack_for_random_store; + sysfs_attr_init(&md->no_pack_for_random.attr); + md->no_pack_for_random.attr.name = "no_pack_for_random"; + md->no_pack_for_random.attr.mode = S_IRUGO | S_IWUSR; + ret = device_create_file(disk_to_dev(md->disk), + &md->no_pack_for_random); + if (ret) + goto no_pack_for_random_fails; + return ret; +no_pack_for_random_fails: + device_remove_file(disk_to_dev(md->disk), + &md->num_wr_reqs_to_start_packing); num_wr_reqs_to_start_packing_fail: device_remove_file(disk_to_dev(md->disk), &md->power_ro_lock); power_ro_lock_fail: diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h index 656de4677cbd..900137715ceb 100644 --- a/drivers/mmc/card/queue.h +++ b/drivers/mmc/card/queue.h @@ -61,6 +61,7 @@ struct mmc_queue { bool wr_packing_enabled; int num_of_potential_packed_wr_reqs; int num_wr_reqs_to_start_packing; + bool no_pack_for_random; int (*err_check_fn) (struct mmc_card *, struct mmc_async_req *); void (*packed_test_fn) (struct request_queue *, struct mmc_queue_req *); }; diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 46bb040cd335..98930066d952 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -524,6 +524,13 @@ static ssize_t mmc_wr_pack_stats_read(struct file *filp, char __user *ubuf, pack_stats->pack_stop_reason[LARGE_SEC_ALIGN]); strlcat(ubuf, temp_buf, 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); + } spin_unlock(&pack_stats->lock); diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 8c70e624325b..01fe9263d2f2 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -227,6 +227,7 @@ enum mmc_packed_stop_reasons { REL_WRITE, THRESHOLD, LARGE_SEC_ALIGN, + RANDOM, MAX_REASONS, };