Message ID | 20190128075634.25748-1-damien.lemoal@wdc.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v2] nullb: Prevent use of legacy request queue mode | expand |
Jens, Any comment on this patch ? Note: I tagged the patch with Fixes: 49f6613632f9 ("nullb: remove leftover legacy request code") but it the correct tag should probably be: Fixes: e50b1e327aeb ("null_blk: remove legacy IO path") On 2019/01/28 8:56, Damien Le Moal wrote: > When null_blk queue mode is specified together with modprobe/insmod, a > check to prevent setting the nullb device queue mode to 1 (NULL_Q_RQ) is > done. However, the same check is not performed when setting up a nullb > device through configfs, resulting in a oops (NULL pointer dereference > for the device request queue). > > Fix this problem by checking for an invalid queue mode value in > null_validate_conf(), propagating -EINVAL to null_add_dev() if the queue > mode is NULL_Q_RQ. While at it, also fix the propagation to user space > of null_add_dev() return value when a nullb device is created through > configfs power attribute. > > Finally, remove the "1=rq" value from the list of possible values for > the queue_mode attribute/module argument to make it clear that this is > no longer a valid setting. > > Fixes: 49f6613632f9 ("nullb: remove leftover legacy request code") > Cc: stable@vger.kernel.org > Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> > --- > > Changes from v1: > * Removed reference to rq mode from queue_mode description > > drivers/block/null_blk_main.c | 24 ++++++++++++++++++------ > 1 file changed, 18 insertions(+), 6 deletions(-) > > diff --git a/drivers/block/null_blk_main.c b/drivers/block/null_blk_main.c > index 62c9654b9ce8..155dcef3b21a 100644 > --- a/drivers/block/null_blk_main.c > +++ b/drivers/block/null_blk_main.c > @@ -130,7 +130,7 @@ static const struct kernel_param_ops null_queue_mode_param_ops = { > }; > > device_param_cb(queue_mode, &null_queue_mode_param_ops, &g_queue_mode, 0444); > -MODULE_PARM_DESC(queue_mode, "Block interface to use (0=bio,1=rq,2=multiqueue)"); > +MODULE_PARM_DESC(queue_mode, "Block interface to use (0=bio,2=multiqueue)"); > > static int g_gb = 250; > module_param_named(gb, g_gb, int, 0444); > @@ -318,9 +318,10 @@ static ssize_t nullb_device_power_store(struct config_item *item, > if (!dev->power && newp) { > if (test_and_set_bit(NULLB_DEV_FL_UP, &dev->flags)) > return count; > - if (null_add_dev(dev)) { > + ret = null_add_dev(dev); > + if (ret) { > clear_bit(NULLB_DEV_FL_UP, &dev->flags); > - return -ENOMEM; > + return ret; > } > > set_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags); > @@ -1561,8 +1562,13 @@ static int null_init_tag_set(struct nullb *nullb, struct blk_mq_tag_set *set) > return blk_mq_alloc_tag_set(set); > } > > -static void null_validate_conf(struct nullb_device *dev) > +static int null_validate_conf(struct nullb_device *dev) > { > + if (dev->queue_mode == NULL_Q_RQ) { > + pr_err("null_blk: legacy IO path no longer available\n"); > + return -EINVAL; > + } > + > dev->blocksize = round_down(dev->blocksize, 512); > dev->blocksize = clamp_t(unsigned int, dev->blocksize, 512, 4096); > > @@ -1588,6 +1594,8 @@ static void null_validate_conf(struct nullb_device *dev) > /* can not stop a queue */ > if (dev->queue_mode == NULL_Q_BIO) > dev->mbps = 0; > + > + return 0; > } > > #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION > @@ -1620,7 +1628,9 @@ static int null_add_dev(struct nullb_device *dev) > struct nullb *nullb; > int rv; > > - null_validate_conf(dev); > + rv = null_validate_conf(dev); > + if (rv) > + goto out; > > nullb = kzalloc_node(sizeof(*nullb), GFP_KERNEL, dev->home_node); > if (!nullb) { > @@ -1648,8 +1658,10 @@ static int null_add_dev(struct nullb_device *dev) > if (rv) > goto out_cleanup_queues; > > - if (!null_setup_fault()) > + if (!null_setup_fault()) { > + rv = -EINVAL; > goto out_cleanup_queues; > + } > > nullb->tag_set->timeout = 5 * HZ; > nullb->q = blk_mq_init_queue(nullb->tag_set); >
diff --git a/drivers/block/null_blk_main.c b/drivers/block/null_blk_main.c index 62c9654b9ce8..155dcef3b21a 100644 --- a/drivers/block/null_blk_main.c +++ b/drivers/block/null_blk_main.c @@ -130,7 +130,7 @@ static const struct kernel_param_ops null_queue_mode_param_ops = { }; device_param_cb(queue_mode, &null_queue_mode_param_ops, &g_queue_mode, 0444); -MODULE_PARM_DESC(queue_mode, "Block interface to use (0=bio,1=rq,2=multiqueue)"); +MODULE_PARM_DESC(queue_mode, "Block interface to use (0=bio,2=multiqueue)"); static int g_gb = 250; module_param_named(gb, g_gb, int, 0444); @@ -318,9 +318,10 @@ static ssize_t nullb_device_power_store(struct config_item *item, if (!dev->power && newp) { if (test_and_set_bit(NULLB_DEV_FL_UP, &dev->flags)) return count; - if (null_add_dev(dev)) { + ret = null_add_dev(dev); + if (ret) { clear_bit(NULLB_DEV_FL_UP, &dev->flags); - return -ENOMEM; + return ret; } set_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags); @@ -1561,8 +1562,13 @@ static int null_init_tag_set(struct nullb *nullb, struct blk_mq_tag_set *set) return blk_mq_alloc_tag_set(set); } -static void null_validate_conf(struct nullb_device *dev) +static int null_validate_conf(struct nullb_device *dev) { + if (dev->queue_mode == NULL_Q_RQ) { + pr_err("null_blk: legacy IO path no longer available\n"); + return -EINVAL; + } + dev->blocksize = round_down(dev->blocksize, 512); dev->blocksize = clamp_t(unsigned int, dev->blocksize, 512, 4096); @@ -1588,6 +1594,8 @@ static void null_validate_conf(struct nullb_device *dev) /* can not stop a queue */ if (dev->queue_mode == NULL_Q_BIO) dev->mbps = 0; + + return 0; } #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION @@ -1620,7 +1628,9 @@ static int null_add_dev(struct nullb_device *dev) struct nullb *nullb; int rv; - null_validate_conf(dev); + rv = null_validate_conf(dev); + if (rv) + goto out; nullb = kzalloc_node(sizeof(*nullb), GFP_KERNEL, dev->home_node); if (!nullb) { @@ -1648,8 +1658,10 @@ static int null_add_dev(struct nullb_device *dev) if (rv) goto out_cleanup_queues; - if (!null_setup_fault()) + if (!null_setup_fault()) { + rv = -EINVAL; goto out_cleanup_queues; + } nullb->tag_set->timeout = 5 * HZ; nullb->q = blk_mq_init_queue(nullb->tag_set);
When null_blk queue mode is specified together with modprobe/insmod, a check to prevent setting the nullb device queue mode to 1 (NULL_Q_RQ) is done. However, the same check is not performed when setting up a nullb device through configfs, resulting in a oops (NULL pointer dereference for the device request queue). Fix this problem by checking for an invalid queue mode value in null_validate_conf(), propagating -EINVAL to null_add_dev() if the queue mode is NULL_Q_RQ. While at it, also fix the propagation to user space of null_add_dev() return value when a nullb device is created through configfs power attribute. Finally, remove the "1=rq" value from the list of possible values for the queue_mode attribute/module argument to make it clear that this is no longer a valid setting. Fixes: 49f6613632f9 ("nullb: remove leftover legacy request code") Cc: stable@vger.kernel.org Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> --- Changes from v1: * Removed reference to rq mode from queue_mode description drivers/block/null_blk_main.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-)