提交 21d91581 编写于 作者: Y Yu Kuai 提交者: Zheng Zengkai

blk-mq: fix divide by zero crash in tg_may_dispatch()

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

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

If blk-throttle is enabled and io is issued before
blk_throtl_register_queue() is done. Divide by zero crash will be
triggered in tg_may_dispatch() because 'throtl_slice' is uninitialized.

Thus introduce a new flag QUEUE_FLAG_THROTL_INIT_DONE. It will be set
after blk_throtl_register_queue() is done, and will be checked before
applying any config.
Signed-off-by: NYu Kuai <yukuai3@huawei.com>
Reviewed-by: NHou Tao <houtao1@huawei.com>
Signed-off-by: NChen Jun <chenjun102@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 a3e3ff2d
......@@ -910,6 +910,9 @@ int blk_register_queue(struct gendisk *disk)
blk_queue_flag_set(QUEUE_FLAG_REGISTERED, q);
wbt_enable_default(q);
blk_throtl_register_queue(q);
spin_lock_irq(&q->queue_lock);
blk_queue_flag_set(QUEUE_FLAG_THROTL_INIT_DONE, q);
spin_unlock_irq(&q->queue_lock);
/* Now everything is ready and send out KOBJ_ADD uevent */
kobject_uevent(&q->kobj, KOBJ_ADD);
......@@ -942,6 +945,10 @@ void blk_unregister_queue(struct gendisk *disk)
if (!blk_queue_registered(q))
return;
spin_lock_irq(&q->queue_lock);
blk_queue_flag_clear(QUEUE_FLAG_THROTL_INIT_DONE, q);
spin_unlock_irq(&q->queue_lock);
/*
* Since sysfs_remove_dir() prevents adding new directory entries
* before removal of existing entries starts, protect against
......
......@@ -11,6 +11,7 @@
#include <linux/bio.h>
#include <linux/blktrace_api.h>
#include <linux/blk-cgroup.h>
#include <linux/delay.h>
#include "blk.h"
#include "blk-cgroup-rwstat.h"
......@@ -1445,6 +1446,31 @@ static void tg_conf_updated(struct throtl_grp *tg, bool global)
}
}
static inline int throtl_check_init_done(struct request_queue *q)
{
if (test_bit(QUEUE_FLAG_THROTL_INIT_DONE, &q->queue_flags))
return 0;
return blk_queue_dying(q) ? -ENODEV : -EBUSY;
}
/*
* If throtl_check_init_done() return -EBUSY, we should retry after a short
* msleep(), since that throttle init will be completed in blk_register_queue()
* soon.
*/
static inline int throtl_restart_syscall_when_busy(int errno)
{
int ret = errno;
if (ret == -EBUSY) {
msleep(10);
ret = restart_syscall();
}
return ret;
}
static ssize_t tg_set_conf(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off, bool is_u64)
{
......@@ -1458,6 +1484,10 @@ static ssize_t tg_set_conf(struct kernfs_open_file *of,
if (ret)
return ret;
ret = throtl_check_init_done(ctx.disk->queue);
if (ret)
goto out_finish;
ret = -EINVAL;
if (sscanf(ctx.body, "%llu", &v) != 1)
goto out_finish;
......@@ -1475,6 +1505,7 @@ static ssize_t tg_set_conf(struct kernfs_open_file *of,
ret = 0;
out_finish:
blkg_conf_finish(&ctx);
ret = throtl_restart_syscall_when_busy(ret);
return ret ?: nbytes;
}
......@@ -1650,8 +1681,11 @@ static ssize_t tg_set_limit(struct kernfs_open_file *of,
if (ret)
return ret;
tg = blkg_to_tg(ctx.blkg);
ret = throtl_check_init_done(ctx.disk->queue);
if (ret)
goto out_finish;
tg = blkg_to_tg(ctx.blkg);
v[0] = tg->bps_conf[READ][index];
v[1] = tg->bps_conf[WRITE][index];
v[2] = tg->iops_conf[READ][index];
......@@ -1747,6 +1781,7 @@ static ssize_t tg_set_limit(struct kernfs_open_file *of,
ret = 0;
out_finish:
blkg_conf_finish(&ctx);
ret = throtl_restart_syscall_when_busy(ret);
return ret ?: nbytes;
}
......
......@@ -593,6 +593,7 @@ struct request_queue {
/* Keep blk_queue_flag_name[] in sync with the definitions below */
#define QUEUE_FLAG_STOPPED 0 /* queue is stopped */
#define QUEUE_FLAG_DYING 1 /* queue being torn down */
#define QUEUE_FLAG_THROTL_INIT_DONE 2 /* io throttle can be online */
#define QUEUE_FLAG_NOMERGES 3 /* disable merge attempts */
#define QUEUE_FLAG_SAME_COMP 4 /* complete on same CPU-group */
#define QUEUE_FLAG_FAIL_IO 5 /* fake timeout */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册