diff mbox series

[v3] nullb: Prevent use of legacy request queue mode

Message ID 20190211234716.18816-1-damien.lemoal@wdc.com (mailing list archive)
State New, archived
Headers show
Series [v3] nullb: Prevent use of legacy request queue mode | expand

Commit Message

Damien Le Moal Feb. 11, 2019, 11:47 p.m. UTC
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
the power attribute of configfs.

Finally, remove the "1=rq" value from the list of possible values of
the queue_mode module argument to make it clear that this is no longer
a valid setting.

Fixes: e50b1e327aeb ("null_blk: remove legacy IO path")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---

Changes from v2:
* Fixed "Fixes" tag
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(-)

Comments

Jens Axboe Feb. 12, 2019, 2:55 a.m. UTC | #1
On 2/11/19 4:47 PM, 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
> the power attribute of configfs.
> 
> Finally, remove the "1=rq" value from the list of possible values of
> the queue_mode module argument to make it clear that this is no longer
> a valid setting.

I actually left that in there on purpose, to avoid breaking test
scripts. It's not the perfect solution, but I viewed it as the
lesser of two evils. Maybe we're fine now, I think blktests has
been fixed a while back?
Damien Le Moal Feb. 12, 2019, 3:01 a.m. UTC | #2
On 2019/02/12 11:55, Jens Axboe wrote:
> On 2/11/19 4:47 PM, 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
>> the power attribute of configfs.
>>
>> Finally, remove the "1=rq" value from the list of possible values of
>> the queue_mode module argument to make it clear that this is no longer
>> a valid setting.
> 
> I actually left that in there on purpose, to avoid breaking test
> scripts. It's not the perfect solution, but I viewed it as the
> lesser of two evils. Maybe we're fine now, I think blktests has
> been fixed a while back?
> 

Yes, blktests is fine right now and not triggering the problem with a default
config. Internally, blktests never tries to enable the rq=1 mode. I discovered
this problem doing tests manually.
diff mbox series

Patch

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);