Commit e2848c93 authored by Yu Kuai's avatar Yu Kuai Committed by Zheng Zengkai
Browse files

block: fix crash on cmpxchg for request_wrapper

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I65K8D


CVE: NA

--------------------------------

Now that address of request_wrapper is caculated by address of request
plus cmd_size, if cmd_size is not aligned to 8 bytes, request_wrapper
will end up not aligned to 8 bytes as well, which will crash in arm64
because assembly instruction casal requires that operand address is
aligned to 8 bytes:

Internal error: Oops: 96000021 [#1] SMP
pc : blk_account_io_latency+0x54/0x134
Call trace:
 blk_account_io_latency+0x54/0x134
 blk_account_io_done+0x3c/0x4c
 __blk_mq_end_request+0x78/0x134
 scsi_end_request+0xcc/0x1f0
 scsi_io_completion+0x88/0x240
 scsi_finish_command+0x104/0x140
 scsi_softirq_done+0x90/0x180
 blk_mq_complete_request+0x5c/0x70
 scsi_mq_done+0x4c/0x100

Fix the problem by declaring request_wrapper as aligned to cachline, and
placing it before request.

Fixes: 82327165 ("blk-mq: don't access request_wrapper if request is not allocated from block layer")
Signed-off-by: default avatarYu Kuai <yukuai3@huawei.com>
Reviewed-by: default avatarHou Tao <houtao1@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent b9187984
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -470,6 +470,7 @@ struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
					      gfp_t flags)
{
	struct blk_flush_queue *fq;
	struct request_wrapper *wrapper;
	int rq_sz = sizeof(struct request) + sizeof(struct request_wrapper);

	fq = kzalloc_node(sizeof(*fq), flags, node);
@@ -479,10 +480,11 @@ struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
	spin_lock_init(&fq->mq_flush_lock);

	rq_sz = round_up(rq_sz + cmd_size, cache_line_size());
	fq->flush_rq = kzalloc_node(rq_sz, flags, node);
	if (!fq->flush_rq)
	wrapper = kzalloc_node(rq_sz, flags, node);
	if (!wrapper)
		goto fail_rq;

	fq->flush_rq = (struct request *)(wrapper + 1);
	INIT_LIST_HEAD(&fq->flush_queue[0]);
	INIT_LIST_HEAD(&fq->flush_queue[1]);
	INIT_LIST_HEAD(&fq->flush_data_in_flight);
@@ -501,7 +503,7 @@ void blk_free_flush_queue(struct blk_flush_queue *fq)
	if (!fq)
		return;

	kfree(fq->flush_rq);
	kfree(request_to_wrapper(fq->flush_rq));
	kfree(fq);
}

+1 −1
Original line number Diff line number Diff line
@@ -2642,7 +2642,7 @@ static int blk_mq_alloc_rqs(struct blk_mq_tag_set *set,
		to_do = min(entries_per_page, depth - i);
		left -= to_do * rq_size;
		for (j = 0; j < to_do; j++) {
			struct request *rq = p;
			struct request *rq = p + sizeof(struct request_wrapper);

			tags->static_rqs[i] = rq;
			if (blk_mq_init_request(set, rq, hctx_idx, node)) {
+3 −6
Original line number Diff line number Diff line
@@ -40,14 +40,11 @@ struct blk_mq_ctx {
struct request_wrapper {
	/* Time that I/O was counted in part_get_stat_info(). */
	u64 stat_time_ns;
};
} ____cacheline_aligned_in_smp;

static inline struct request_wrapper *request_to_wrapper(struct request *rq)
static inline struct request_wrapper *request_to_wrapper(void *rq)
{
	unsigned long addr = (unsigned long)rq;

	addr += sizeof(*rq) + rq->q->tag_set->cmd_size;
	return (struct request_wrapper *)addr;
	return rq - sizeof(struct request_wrapper);
}

void blk_mq_exit_queue(struct request_queue *q);