* [PATCH] block,scsi: verify return pointer from blk_get_request
@ 2013-03-17 17:32 Joe Lawrence
2013-03-17 22:44 ` Jens Axboe
` (3 more replies)
0 siblings, 4 replies; 15+ messages in thread
From: Joe Lawrence @ 2013-03-17 17:32 UTC (permalink / raw)
To: linux-scsi; +Cc: Jens Axboe, Jiri Kosina, James E.J. Bottomley
Hello James / Jiri / Jens,
Stratus hit a NULL ptr deference bug when removing a USB CD-ROM while
burning a DVD. The stack trace below was produced on a RHEL 6.4-GA
kernel, however it looks like the bug still exists in 3.9.0-rc2: not all
callers of blk_get_request bother to verify the return pointer value
before using it.
There are other unsafe blk_get_request callers in the kernel, but they
live in the obsolete drivers/ide directory. Patches from the Linux
Driver Verification to harden those calls were rejected in Aug 2012 [1],
so I'll let them be.
[1] https://lkml.org/lkml/2012/8/9/561
Stack trace and notes:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000044
usb 3-1.6: USB disconnect, device number 4
usb 3-1.6.1: USB disconnect, device number 5
IP: [<ffffffff8126687b>] blk_send_start_stop+0x3b/0xa0
PGD 4034327067 PUD 4041356067 PMD 0
Oops: 0002 [#1] SMP
last sysfs file: /sys/devices/pci0000:00/0000:00:01.0/class
CPU 0
Modules linked in: nfs lockd fscache auth_rpcgss nfs_acl nls_utf8 fuse autofs4 sunrpc configfs bonding 8021q garp stp llc vhost_net macvtap macvlan tun uinput ipmi_devintf ftmod(P)(U) sg matroxfb(U) fosil(U) ext4 mbcache jbd2 sr_mod cdrom raid1 ixgbe(U) usb_storage mpt2sas(U) scsi_hbas(U) sd_mod(U) crc_t10dif scsi_transport_sas raid_class igb(U) dca ptp pps_core dm_mirror dm_region_hash dm_log dm_mod ipv6 cxgb4 cxgb3 mdio libiscsi_tcp libiscsi scsi_transport_iscsi [last unloaded: scsi_wait_scan]
Pid: 13461, comm: k3b Tainted: P --------------- 2.6.32-358.el6.x86_64 #1 Stratus ftServer 4700/G7LAY
RIP: 0010:[<ffffffff8126687b>] [<ffffffff8126687b>] blk_send_start_stop+0x3b/0xa0
RSP: 0018:ffff884050545b98 EFLAGS: 00010282
RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff88204e64c0f8
RBP: ffff884050545bb8 R08: 000000000297a798 R09: 0000000000000000
R10: 00000000000007e4 R11: 0000000000000001 R12: ffff88204e64c0f8
R13: ffff88204d1a3800 R14: 0000000000000002 R15: 000000000000005d
FS: 00007f480bfff700(0000) GS:ffff880040200000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000044 CR3: 00000040414ca000 CR4: 00000000000407f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process k3b (pid: 13461, threadinfo ffff884050544000, task ffff884046de1500)
Stack:
ffff88204e64c0f8 00000000fffffffa ffff88204d1a3800 000000000297a798
<d> ffff884050545cb8 ffffffff8126726a ffff880040236798 ffff880040236700
<d> ffff884050f7b538 ffff8840504ca0b8 ffff884050f7b500 0000000000000000
Call Trace:
[<ffffffff8126726a>] scsi_cmd_ioctl+0x18a/0x470
[<ffffffff8103392e>] ? physflat_send_IPI_mask+0xe/0x10
[<ffffffff8102dd89>] ? native_smp_send_reschedule+0x49/0x60
[<ffffffff81052258>] ? resched_task+0x68/0x80
[<ffffffff810570e0>] ? check_preempt_wakeup+0x1c0/0x260
[<ffffffff81054f13>] ? ftrace_raw_event_id_sched_wakeup_template+0xe3/0xf0
[<ffffffff812675a1>] scsi_cmd_blk_ioctl+0x51/0x70
[<ffffffffa01c1a1d>] cdrom_ioctl+0x4d/0xe60 [cdrom]
[<ffffffff812231f1>] ? avc_has_perm+0x71/0x90
[<ffffffffa0082440>] sr_block_ioctl+0x60/0xb0 [sr_mod]
[<ffffffff812642f7>] __blkdev_driver_ioctl+0x67/0x80
[<ffffffff8126477d>] blkdev_ioctl+0x1ed/0x6e0
[<ffffffff811bb76c>] block_ioctl+0x3c/0x40
[<ffffffff81194ed2>] vfs_ioctl+0x22/0xa0
[<ffffffff81195074>] do_vfs_ioctl+0x84/0x580
[<ffffffff811955f1>] sys_ioctl+0x81/0xa0
[<ffffffff8100b288>] tracesys+0xd9/0xde
Code: 08 4c 89 6c 24 10 4c 89 74 24 18 0f 1f 44 00 00 49 89 f5 41 89 d6 be 01 00 00 00 ba 10 00 00 00 49 89 fc e8 b8 82 ff ff 48 89 c3 <c7> 40 44 02 00 00 00 c7 80 38 01 00 00 60 ea 00 00 48 8b 80 00
RIP [<ffffffff8126687b>] blk_send_start_stop+0x3b/0xa0
RSP <ffff884050545b98>
CR2: 0000000000000044
What is blk_send_start_stop (inline __blk_send_generic) doing?
block/scsi_ioctl.c: 783
<blk_send_start_stop+0x33>: callq 0xffffffff8125eb30 <blk_get_request>
<blk_send_start_stop+0x38>: mov %rax,%rbx
block/scsi_ioctl.c: 784
<blk_send_start_stop+0x3b>: movl $0x2,0x44(%rax)
Where RAX: 0000000000000000
block/scsi_ioctl.c:
776 /* Send basic block requests */
777 static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_di
778 int cmd, int data)
779 {
780 struct request *rq;
781 int err;
782
783 rq = blk_get_request(q, WRITE, __GFP_WAIT);
784 rq->cmd_type = REQ_TYPE_BLOCK_PC; <<
785 rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
786 rq->cmd[0] = cmd;
787 rq->cmd[4] = data;
788 rq->cmd_len = 6;
789 err = blk_execute_rq(q, bd_disk, rq, 0);
790 blk_put_request(rq);
791
792 return err;
793 }
A quick verify of offset from "movl $0x2,0x44(%rax)":
crash> struct -o request | grep 0x44
[0x44] enum rq_cmd_type_bits cmd_type;
So blk_get_request returned a NULL struct request pointer, but
__blk_send_generic continued on without checking it first.
Regards,
-- Joe
>From 7450cd8ac7bc247439fe890e000c81e3653d2832 Mon Sep 17 00:00:00 2001
From: Joe Lawrence <joe.lawrence@stratus.com>
Date: Sat, 16 Mar 2013 19:45:04 -0400
Subject: [PATCH] block,scsi: verify return pointer from blk_get_request
The blk_get_request function may return NULL in low-memory conditions or
during device removal. Callers should verify the returned request
pointer before dereferencing.
Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Jiri Kosina <jkosina@suse.cz>
Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: linux-scsi@vger.kernel.org
---
block/scsi_ioctl.c | 4 ++++
drivers/block/pktcdvd.c | 2 ++
drivers/scsi/scsi_error.c | 2 ++
3 files changed, 8 insertions(+)
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 9a87daa..4d86eea 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -458,6 +458,8 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
}
rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);
+ if (!rq)
+ return -ENOMEM;
cmdlen = COMMAND_SIZE(opcode);
@@ -544,6 +546,8 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk,
int err;
rq = blk_get_request(q, WRITE, __GFP_WAIT);
+ if (!rq)
+ return -ENOMEM;
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
rq->cmd[0] = cmd;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 2e7de7a..3e2d662 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -711,6 +711,8 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
WRITE : READ, __GFP_WAIT);
+ if (!rq)
+ return -ENOMEM;
if (cgc->buflen) {
if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT))
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index c1b05a8..8f009c4 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1635,6 +1635,8 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
* request becomes available
*/
req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
req->cmd[0] = ALLOW_MEDIUM_REMOVAL;
req->cmd[1] = 0;
--
1.8.1.4
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH] block,scsi: verify return pointer from blk_get_request
2013-03-17 17:32 [PATCH] block,scsi: verify return pointer from blk_get_request Joe Lawrence
@ 2013-03-17 22:44 ` Jens Axboe
2013-05-23 20:40 ` James Bottomley
2013-03-19 13:55 ` Bart Van Assche
` (2 subsequent siblings)
3 siblings, 1 reply; 15+ messages in thread
From: Jens Axboe @ 2013-03-17 22:44 UTC (permalink / raw)
To: Joe Lawrence; +Cc: linux-scsi, Jiri Kosina, James E.J. Bottomley
On Sun, Mar 17 2013, Joe Lawrence wrote:
> Hello James / Jiri / Jens,
>
> Stratus hit a NULL ptr deference bug when removing a USB CD-ROM while
> burning a DVD. The stack trace below was produced on a RHEL 6.4-GA
> kernel, however it looks like the bug still exists in 3.9.0-rc2: not all
> callers of blk_get_request bother to verify the return pointer value
> before using it.
>
> There are other unsafe blk_get_request callers in the kernel, but they
> live in the obsolete drivers/ide directory. Patches from the Linux
> Driver Verification to harden those calls were rejected in Aug 2012 [1],
> so I'll let them be.
>
> [1] https://lkml.org/lkml/2012/8/9/561
>
> Stack trace and notes:
>
> BUG: unable to handle kernel NULL pointer dereference at 0000000000000044
> usb 3-1.6: USB disconnect, device number 4
> usb 3-1.6.1: USB disconnect, device number 5
> IP: [<ffffffff8126687b>] blk_send_start_stop+0x3b/0xa0
> PGD 4034327067 PUD 4041356067 PMD 0
> Oops: 0002 [#1] SMP
> last sysfs file: /sys/devices/pci0000:00/0000:00:01.0/class
> CPU 0
> Modules linked in: nfs lockd fscache auth_rpcgss nfs_acl nls_utf8 fuse autofs4 sunrpc configfs bonding 8021q garp stp llc vhost_net macvtap macvlan tun uinput ipmi_devintf ftmod(P)(U) sg matroxfb(U) fosil(U) ext4 mbcache jbd2 sr_mod cdrom raid1 ixgbe(U) usb_storage mpt2sas(U) scsi_hbas(U) sd_mod(U) crc_t10dif scsi_transport_sas raid_class igb(U) dca ptp pps_core dm_mirror dm_region_hash dm_log dm_mod ipv6 cxgb4 cxgb3 mdio libiscsi_tcp libiscsi scsi_transport_iscsi [last unloaded: scsi_wait_scan]
>
> Pid: 13461, comm: k3b Tainted: P --------------- 2.6.32-358.el6.x86_64 #1 Stratus ftServer 4700/G7LAY
> RIP: 0010:[<ffffffff8126687b>] [<ffffffff8126687b>] blk_send_start_stop+0x3b/0xa0
> RSP: 0018:ffff884050545b98 EFLAGS: 00010282
> RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
> RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff88204e64c0f8
> RBP: ffff884050545bb8 R08: 000000000297a798 R09: 0000000000000000
> R10: 00000000000007e4 R11: 0000000000000001 R12: ffff88204e64c0f8
> R13: ffff88204d1a3800 R14: 0000000000000002 R15: 000000000000005d
> FS: 00007f480bfff700(0000) GS:ffff880040200000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 0000000000000044 CR3: 00000040414ca000 CR4: 00000000000407f0
> DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> Process k3b (pid: 13461, threadinfo ffff884050544000, task ffff884046de1500)
> Stack:
> ffff88204e64c0f8 00000000fffffffa ffff88204d1a3800 000000000297a798
> <d> ffff884050545cb8 ffffffff8126726a ffff880040236798 ffff880040236700
> <d> ffff884050f7b538 ffff8840504ca0b8 ffff884050f7b500 0000000000000000
> Call Trace:
> [<ffffffff8126726a>] scsi_cmd_ioctl+0x18a/0x470
> [<ffffffff8103392e>] ? physflat_send_IPI_mask+0xe/0x10
> [<ffffffff8102dd89>] ? native_smp_send_reschedule+0x49/0x60
> [<ffffffff81052258>] ? resched_task+0x68/0x80
> [<ffffffff810570e0>] ? check_preempt_wakeup+0x1c0/0x260
> [<ffffffff81054f13>] ? ftrace_raw_event_id_sched_wakeup_template+0xe3/0xf0
> [<ffffffff812675a1>] scsi_cmd_blk_ioctl+0x51/0x70
> [<ffffffffa01c1a1d>] cdrom_ioctl+0x4d/0xe60 [cdrom]
> [<ffffffff812231f1>] ? avc_has_perm+0x71/0x90
> [<ffffffffa0082440>] sr_block_ioctl+0x60/0xb0 [sr_mod]
> [<ffffffff812642f7>] __blkdev_driver_ioctl+0x67/0x80
> [<ffffffff8126477d>] blkdev_ioctl+0x1ed/0x6e0
> [<ffffffff811bb76c>] block_ioctl+0x3c/0x40
> [<ffffffff81194ed2>] vfs_ioctl+0x22/0xa0
> [<ffffffff81195074>] do_vfs_ioctl+0x84/0x580
> [<ffffffff811955f1>] sys_ioctl+0x81/0xa0
> [<ffffffff8100b288>] tracesys+0xd9/0xde
> Code: 08 4c 89 6c 24 10 4c 89 74 24 18 0f 1f 44 00 00 49 89 f5 41 89 d6 be 01 00 00 00 ba 10 00 00 00 49 89 fc e8 b8 82 ff ff 48 89 c3 <c7> 40 44 02 00 00 00 c7 80 38 01 00 00 60 ea 00 00 48 8b 80 00
> RIP [<ffffffff8126687b>] blk_send_start_stop+0x3b/0xa0
> RSP <ffff884050545b98>
> CR2: 0000000000000044
>
> What is blk_send_start_stop (inline __blk_send_generic) doing?
>
> block/scsi_ioctl.c: 783
> <blk_send_start_stop+0x33>: callq 0xffffffff8125eb30 <blk_get_request>
> <blk_send_start_stop+0x38>: mov %rax,%rbx
> block/scsi_ioctl.c: 784
> <blk_send_start_stop+0x3b>: movl $0x2,0x44(%rax)
>
> Where RAX: 0000000000000000
>
> block/scsi_ioctl.c:
>
> 776 /* Send basic block requests */
> 777 static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_di
> 778 int cmd, int data)
> 779 {
> 780 struct request *rq;
> 781 int err;
> 782
> 783 rq = blk_get_request(q, WRITE, __GFP_WAIT);
> 784 rq->cmd_type = REQ_TYPE_BLOCK_PC; <<
> 785 rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
> 786 rq->cmd[0] = cmd;
> 787 rq->cmd[4] = data;
> 788 rq->cmd_len = 6;
> 789 err = blk_execute_rq(q, bd_disk, rq, 0);
> 790 blk_put_request(rq);
> 791
> 792 return err;
> 793 }
>
> A quick verify of offset from "movl $0x2,0x44(%rax)":
>
> crash> struct -o request | grep 0x44
> [0x44] enum rq_cmd_type_bits cmd_type;
>
> So blk_get_request returned a NULL struct request pointer, but
> __blk_send_generic continued on without checking it first.
The reason why the above code does not check for NULL return, is because
__GFP_WAIT is set. But since queue dead checks were added, we can
trigger this now. So with that in mind, ENOMEM is not the right error
code for this, as it has nothing to do with running out of memory.
Would probably be best to return the correct error pointer from
blk_get_request(), as you would otherwise have to assume this knowledge
in the callers.
--
Jens Axboe
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] block,scsi: verify return pointer from blk_get_request
2013-03-17 17:32 [PATCH] block,scsi: verify return pointer from blk_get_request Joe Lawrence
2013-03-17 22:44 ` Jens Axboe
@ 2013-03-19 13:55 ` Bart Van Assche
2013-03-26 19:06 ` [PATCH v2] block: handle pointer error " Joe Lawrence
2013-05-24 18:15 ` [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios Joe Lawrence
3 siblings, 0 replies; 15+ messages in thread
From: Bart Van Assche @ 2013-03-19 13:55 UTC (permalink / raw)
To: Joe Lawrence; +Cc: linux-scsi, Jens Axboe, Jiri Kosina, James E.J. Bottomley
On 03/17/13 18:32, Joe Lawrence wrote:
> diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
> index c1b05a8..8f009c4 100644
> --- a/drivers/scsi/scsi_error.c
> +++ b/drivers/scsi/scsi_error.c
> @@ -1635,6 +1635,8 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
> * request becomes available
> */
> req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
> + if (!req)
> + return -ENOMEM;
>
> req->cmd[0] = ALLOW_MEDIUM_REMOVAL;
> req->cmd[1] = 0;
scsi_eh_lock_door() doesn't return a value to it's caller so I think a
plain "return" statement is sufficient here.
Bart.
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2] block: handle pointer error from blk_get_request
2013-03-17 17:32 [PATCH] block,scsi: verify return pointer from blk_get_request Joe Lawrence
2013-03-17 22:44 ` Jens Axboe
2013-03-19 13:55 ` Bart Van Assche
@ 2013-03-26 19:06 ` Joe Lawrence
2013-03-26 22:34 ` [PATCH v3] " Joe Lawrence
2013-05-24 18:15 ` [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios Joe Lawrence
3 siblings, 1 reply; 15+ messages in thread
From: Joe Lawrence @ 2013-03-26 19:06 UTC (permalink / raw)
To: Joe Lawrence
Cc: linux-scsi, Jens Axboe, James E.J. Bottomley, Bart Van Assche
Updated to address comments from Jens and Bart.
Accounting for the first change (below) introduces modifications to a
bunch of files. If this patch should be formatted differently or copied
to additional people / lists, let me know. The patch is based on the
for-next branch from Jens' linux-block tree.
Changes from v1:
- Distinguish error conditions in __get_request using ERR_PTR instead
of NULL. (blk_queue_dying will return ERR_PTR(-ENODEV), but should
the other error paths all return ERR_PTR(-ENOMEM) ?)
- Propagate ERR_PTR out from __get_request through blk_get_request,
updating callers accordingly.
Thanks,
-- Joe
>From 7122dd3ba8c3b1e7edff42ff9c21247fcf4379c2 Mon Sep 17 00:00:00 2001
From: Joe Lawrence <joe.lawrence@stratus.com>
Date: Tue, 26 Mar 2013 14:30:28 -0400
Subject: [PATCH v2] block: handle pointer error from blk_get_request
The blk_get_request function may fail in low-memory conditions or during
device removal (even if __GFP_WAIT is set). To distinguish between these
errors, modify the blk_get_request call stack to return the appropriate
error pointer. Verify that all callers check the return status and
consider IS_ERR instead of a simple NULL pointer check.
Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: Bart Van Assche <bvanassche@acm.org>
Cc: linux-scsi@vger.kernel.org
---
block/blk-core.c | 30 ++++++++++++++---------------
block/bsg.c | 8 ++++----
block/scsi_ioctl.c | 8 ++++++--
drivers/block/paride/pd.c | 2 ++
drivers/block/pktcdvd.c | 3 ++-
drivers/block/sx8.c | 2 +-
drivers/cdrom/cdrom.c | 4 ++--
drivers/ide/ide-park.c | 2 +-
drivers/scsi/device_handler/scsi_dh_alua.c | 2 +-
drivers/scsi/device_handler/scsi_dh_emc.c | 2 +-
drivers/scsi/device_handler/scsi_dh_hp_sw.c | 4 ++--
drivers/scsi/device_handler/scsi_dh_rdac.c | 2 +-
drivers/scsi/osd/osd_initiator.c | 4 ++--
drivers/scsi/osst.c | 2 +-
drivers/scsi/scsi_error.c | 2 ++
drivers/scsi/scsi_lib.c | 2 +-
drivers/scsi/scsi_tgt_lib.c | 2 +-
drivers/scsi/sg.c | 4 ++--
drivers/scsi/st.c | 2 +-
drivers/target/target_core_pscsi.c | 4 ++--
20 files changed, 50 insertions(+), 41 deletions(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index f224d17..f6789b7 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -886,9 +886,9 @@ static struct io_context *rq_ioc(struct bio *bio)
* Get a free request from @q. This function may fail under memory
* pressure or if @q is dead.
*
- * Must be callled with @q->queue_lock held and,
- * Returns %NULL on failure, with @q->queue_lock held.
- * Returns !%NULL on success, with @q->queue_lock *not held*.
+ * Must be called with @q->queue_lock held and,
+ * Returns ERR_PTR on failure, with @q->queue_lock held.
+ * Returns request pointer on success, with @q->queue_lock *not held*.
*/
static struct request *__get_request(struct request_list *rl, int rw_flags,
struct bio *bio, gfp_t gfp_mask)
@@ -902,7 +902,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
int may_queue;
if (unlikely(blk_queue_dying(q)))
- return NULL;
+ return ERR_PTR(-ENODEV);
may_queue = elv_may_queue(q, rw_flags);
if (may_queue == ELV_MQUEUE_NO)
@@ -927,7 +927,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
* process is not a "batcher", and not
* exempted by the IO scheduler
*/
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
}
}
@@ -945,7 +945,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
* allocated with any setting of ->nr_requests
*/
if (rl->count[is_sync] >= (3 * q->nr_requests / 2))
- return NULL;
+ return ERR_PTR(-ENOMEM);
q->nr_rqs[is_sync]++;
rl->count[is_sync]++;
@@ -1050,7 +1050,7 @@ fail_alloc:
rq_starved:
if (unlikely(rl->count[is_sync] == 0))
rl->starved[is_sync] = 1;
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
/**
@@ -1063,9 +1063,9 @@ rq_starved:
* Get a free request from @q. If %__GFP_WAIT is set in @gfp_mask, this
* function keeps retrying under memory pressure and fails iff @q is dead.
*
- * Must be callled with @q->queue_lock held and,
- * Returns %NULL on failure, with @q->queue_lock held.
- * Returns !%NULL on success, with @q->queue_lock *not held*.
+ * Must be called with @q->queue_lock held and,
+ * Returns ERR_PTR on failure, with @q->queue_lock held.
+ * Returns request pointer on success, with @q->queue_lock *not held*.
*/
static struct request *get_request(struct request_queue *q, int rw_flags,
struct bio *bio, gfp_t gfp_mask)
@@ -1078,12 +1078,12 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
rl = blk_get_rl(q, bio); /* transferred to @rq on success */
retry:
rq = __get_request(rl, rw_flags, bio, gfp_mask);
- if (rq)
+ if (!IS_ERR(rq))
return rq;
if (!(gfp_mask & __GFP_WAIT) || unlikely(blk_queue_dying(q))) {
blk_put_rl(rl);
- return NULL;
+ return rq;
}
/* wait on @rl and retry */
@@ -1119,7 +1119,7 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
spin_lock_irq(q->queue_lock);
rq = get_request(q, rw, NULL, gfp_mask);
- if (!rq)
+ if (unlikely(IS_ERR(rq)))
spin_unlock_irq(q->queue_lock);
/* q->queue_lock is unlocked at this point */
@@ -1528,8 +1528,8 @@ get_rq:
* Returns with the queue unlocked.
*/
req = get_request(q, rw_flags, bio, GFP_NOIO);
- if (unlikely(!req)) {
- bio_endio(bio, -ENODEV); /* @q is dead */
+ if (unlikely(IS_ERR(req))) {
+ bio_endio(bio, PTR_ERR(req)); /* @q is dead */
goto out_unlock;
}
diff --git a/block/bsg.c b/block/bsg.c
index 420a5a9..2b1c322 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -271,8 +271,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
* map scatter-gather elements separately and string them to request
*/
rq = blk_get_request(q, rw, GFP_KERNEL);
- if (!rq)
- return ERR_PTR(-ENOMEM);
+ if (IS_ERR(rq))
+ return rq;
ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd, has_write_perm);
if (ret)
goto out;
@@ -284,8 +284,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
}
next_rq = blk_get_request(q, READ, GFP_KERNEL);
- if (!next_rq) {
- ret = -ENOMEM;
+ if (IS_ERR(next_rq)) {
+ ret = PTR_ERR(rq);
goto out;
}
rq->next_rq = next_rq;
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 9a87daa..014b92a 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -311,8 +311,8 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
}
rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL);
- if (!rq)
- return -ENOMEM;
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
if (blk_fill_sghdr_rq(q, rq, hdr, mode)) {
blk_put_request(rq);
@@ -458,6 +458,8 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
}
rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
cmdlen = COMMAND_SIZE(opcode);
@@ -544,6 +546,8 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk,
int err;
rq = blk_get_request(q, WRITE, __GFP_WAIT);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
rq->cmd[0] = cmd;
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 831e3ac..0d4e530 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -722,6 +722,8 @@ static int pd_special_command(struct pd_unit *disk,
int err = 0;
rq = blk_get_request(disk->gd->queue, READ, __GFP_WAIT);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
rq->cmd_type = REQ_TYPE_SPECIAL;
rq->special = func;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 1119042..25ab3bd 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -711,7 +711,8 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
WRITE : READ, __GFP_WAIT);
-
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
if (cgc->buflen) {
if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT))
goto out;
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 3fb6ab4..911b7fc 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -568,7 +568,7 @@ static struct carm_request *carm_get_special(struct carm_host *host)
return NULL;
rq = blk_get_request(host->oob_q, WRITE /* bogus */, GFP_KERNEL);
- if (!rq) {
+ if (IS_ERR(rq)) {
spin_lock_irqsave(&host->lock, flags);
carm_put_request(host, crq);
spin_unlock_irqrestore(&host->lock, flags);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index d620b44..999d852 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2161,8 +2161,8 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
len = nr * CD_FRAMESIZE_RAW;
rq = blk_get_request(q, READ, GFP_KERNEL);
- if (!rq) {
- ret = -ENOMEM;
+ if (IS_ERR(rq)) {
+ ret = PTR_ERR(rq);
break;
}
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
index 6ab9ab2..fd432de 100644
--- a/drivers/ide/ide-park.c
+++ b/drivers/ide/ide-park.c
@@ -46,7 +46,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
* timeout has expired, so power management will be reenabled.
*/
rq = blk_get_request(q, READ, GFP_NOWAIT);
- if (unlikely(!rq))
+ if (unlikely(IS_ERR(rq)))
goto out;
rq->cmd[0] = REQ_UNPARK_HEADS;
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6f4d8e6..f07f152 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -115,7 +115,7 @@ static struct request *get_alua_req(struct scsi_device *sdev,
rq = blk_get_request(q, rw, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev,
"%s: blk_get_request failed\n", __func__);
return NULL;
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index e1c8be0..2ec3261 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -275,7 +275,7 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,
rq = blk_get_request(sdev->request_queue,
(cmd != INQUIRY) ? WRITE : READ, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
return NULL;
}
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index 084062b..1cf4019 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -117,7 +117,7 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
retry:
req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
- if (!req)
+ if (IS_ERR(req))
return SCSI_DH_RES_TEMP_UNAVAIL;
req->cmd_type = REQ_TYPE_BLOCK_PC;
@@ -247,7 +247,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h)
struct request *req;
req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC);
- if (!req)
+ if (IS_ERR(req))
return SCSI_DH_RES_TEMP_UNAVAIL;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 69c915a..009bd8f 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -274,7 +274,7 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
rq = blk_get_request(q, rw, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev,
"get_rdac_req: blk_get_request failed.\n");
return NULL;
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index d8293f2..b4cd56b 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -1567,8 +1567,8 @@ static struct request *_make_request(struct request_queue *q, bool has_write,
struct request *req;
req = blk_get_request(q, has_write ? WRITE : READ, flags);
- if (unlikely(!req))
- return ERR_PTR(-ENOMEM);
+ if (unlikely(IS_ERR(req)))
+ return req;
return req;
}
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 21883a2..826cda9 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -362,7 +362,7 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
int write = (data_direction == DMA_TO_DEVICE);
req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL);
- if (!req)
+ if (IS_ERR(req))
return DRIVER_ERROR << 24;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index c1b05a8..7b248fb 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1635,6 +1635,8 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
* request becomes available
*/
req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
+ if (IS_ERR(req))
+ return;
req->cmd[0] = ALLOW_MEDIUM_REMOVAL;
req->cmd[1] = 0;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index c31187d..cad055b 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -236,7 +236,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int ret = DRIVER_ERROR << 24;
req = blk_get_request(sdev->request_queue, write, __GFP_WAIT);
- if (!req)
+ if (IS_ERR(req))
return ret;
if (bufflen && blk_rq_map_kern(sdev->request_queue, req,
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 84a1fdf..d300620 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -97,7 +97,7 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
* we are in target mode we want the opposite.
*/
rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask);
- if (!rq)
+ if (IS_ERR(rq))
goto free_tcmd;
cmd = __scsi_get_command(shost, gfp_mask);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 9f0c465..5d39fec 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1649,8 +1649,8 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
dxfer_len));
rq = blk_get_request(q, rw, GFP_ATOMIC);
- if (!rq)
- return -ENOMEM;
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
memcpy(rq->cmd, cmd, hp->cmd_len);
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 8697447..5fca9cb 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -481,7 +481,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
req = blk_get_request(SRpnt->stp->device->request_queue, write,
GFP_KERNEL);
- if (!req)
+ if (IS_ERR(req))
return DRIVER_ERROR << 24;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 82e78d7..8cd953a 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -1045,9 +1045,9 @@ pscsi_execute_cmd(struct se_cmd *cmd)
req = blk_get_request(pdv->pdv_sd->request_queue,
(data_direction == DMA_TO_DEVICE),
GFP_KERNEL);
- if (!req || IS_ERR(req)) {
+ if (IS_ERR(req)) {
pr_err("PSCSI: blk_get_request() failed: %ld\n",
- req ? IS_ERR(req) : -ENOMEM);
+ PTR_ERR(req));
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
goto fail;
}
--
1.8.1.4
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v3] block: handle pointer error from blk_get_request
2013-03-26 19:06 ` [PATCH v2] block: handle pointer error " Joe Lawrence
@ 2013-03-26 22:34 ` Joe Lawrence
2013-05-23 20:09 ` [PATCH v4] " Joe Lawrence
0 siblings, 1 reply; 15+ messages in thread
From: Joe Lawrence @ 2013-03-26 22:34 UTC (permalink / raw)
To: linux-scsi
Cc: Jens Axboe, James E.J. Bottomley, Bart Van Assche, Joe Lawrence
... one more caller to update (how did blk_make_request hide? :) ...
Changes from v2:
- Updated blk_make_request to check IS_ERR from blk_get_request
That should account for all the callers of blk_get_request, save for the
IDE drivers, which I left alone but for the lone caller in ide-park.c
that does bother to check the return pointer.
Regards,
-- Joe
>From 05646b66021df447207e327e3c7c8692a506cd4b Mon Sep 17 00:00:00 2001
From: Joe Lawrence <joe.lawrence@stratus.com>
Date: Tue, 26 Mar 2013 18:03:26 -0400
Subject: [PATCH v3] block: handle pointer error from blk_get_request
The blk_get_request function may fail in low-memory conditions or during
device removal (even if __GFP_WAIT is set). To distinguish between these
errors, modify the blk_get_request call stack to return the appropriate
error pointer. Verify that all callers check the return status and
consider IS_ERR instead of a simple NULL pointer check.
Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: Bart Van Assche <bvanassche@acm.org>
Cc: linux-scsi@vger.kernel.org
---
block/blk-core.c | 34 ++++++++++++++---------------
block/bsg.c | 8 +++----
block/scsi_ioctl.c | 8 +++++--
drivers/block/paride/pd.c | 2 ++
drivers/block/pktcdvd.c | 3 ++-
drivers/block/sx8.c | 2 +-
drivers/cdrom/cdrom.c | 4 ++--
drivers/ide/ide-park.c | 2 +-
drivers/scsi/device_handler/scsi_dh_alua.c | 2 +-
drivers/scsi/device_handler/scsi_dh_emc.c | 2 +-
drivers/scsi/device_handler/scsi_dh_hp_sw.c | 4 ++--
drivers/scsi/device_handler/scsi_dh_rdac.c | 2 +-
drivers/scsi/osd/osd_initiator.c | 4 ++--
drivers/scsi/osst.c | 2 +-
drivers/scsi/scsi_error.c | 2 ++
drivers/scsi/scsi_lib.c | 2 +-
drivers/scsi/scsi_tgt_lib.c | 2 +-
drivers/scsi/sg.c | 4 ++--
drivers/scsi/st.c | 2 +-
drivers/target/target_core_pscsi.c | 4 ++--
20 files changed, 52 insertions(+), 43 deletions(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index f224d17..9e254e4 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -886,9 +886,9 @@ static struct io_context *rq_ioc(struct bio *bio)
* Get a free request from @q. This function may fail under memory
* pressure or if @q is dead.
*
- * Must be callled with @q->queue_lock held and,
- * Returns %NULL on failure, with @q->queue_lock held.
- * Returns !%NULL on success, with @q->queue_lock *not held*.
+ * Must be called with @q->queue_lock held and,
+ * Returns ERR_PTR on failure, with @q->queue_lock held.
+ * Returns request pointer on success, with @q->queue_lock *not held*.
*/
static struct request *__get_request(struct request_list *rl, int rw_flags,
struct bio *bio, gfp_t gfp_mask)
@@ -902,7 +902,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
int may_queue;
if (unlikely(blk_queue_dying(q)))
- return NULL;
+ return ERR_PTR(-ENODEV);
may_queue = elv_may_queue(q, rw_flags);
if (may_queue == ELV_MQUEUE_NO)
@@ -927,7 +927,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
* process is not a "batcher", and not
* exempted by the IO scheduler
*/
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
}
}
@@ -945,7 +945,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
* allocated with any setting of ->nr_requests
*/
if (rl->count[is_sync] >= (3 * q->nr_requests / 2))
- return NULL;
+ return ERR_PTR(-ENOMEM);
q->nr_rqs[is_sync]++;
rl->count[is_sync]++;
@@ -1050,7 +1050,7 @@ fail_alloc:
rq_starved:
if (unlikely(rl->count[is_sync] == 0))
rl->starved[is_sync] = 1;
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
/**
@@ -1063,9 +1063,9 @@ rq_starved:
* Get a free request from @q. If %__GFP_WAIT is set in @gfp_mask, this
* function keeps retrying under memory pressure and fails iff @q is dead.
*
- * Must be callled with @q->queue_lock held and,
- * Returns %NULL on failure, with @q->queue_lock held.
- * Returns !%NULL on success, with @q->queue_lock *not held*.
+ * Must be called with @q->queue_lock held and,
+ * Returns ERR_PTR on failure, with @q->queue_lock held.
+ * Returns request pointer on success, with @q->queue_lock *not held*.
*/
static struct request *get_request(struct request_queue *q, int rw_flags,
struct bio *bio, gfp_t gfp_mask)
@@ -1078,12 +1078,12 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
rl = blk_get_rl(q, bio); /* transferred to @rq on success */
retry:
rq = __get_request(rl, rw_flags, bio, gfp_mask);
- if (rq)
+ if (!IS_ERR(rq))
return rq;
if (!(gfp_mask & __GFP_WAIT) || unlikely(blk_queue_dying(q))) {
blk_put_rl(rl);
- return NULL;
+ return rq;
}
/* wait on @rl and retry */
@@ -1119,7 +1119,7 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
spin_lock_irq(q->queue_lock);
rq = get_request(q, rw, NULL, gfp_mask);
- if (!rq)
+ if (unlikely(IS_ERR(rq)))
spin_unlock_irq(q->queue_lock);
/* q->queue_lock is unlocked at this point */
@@ -1163,8 +1163,8 @@ struct request *blk_make_request(struct request_queue *q, struct bio *bio,
{
struct request *rq = blk_get_request(q, bio_data_dir(bio), gfp_mask);
- if (unlikely(!rq))
- return ERR_PTR(-ENOMEM);
+ if (unlikely(IS_ERR(rq)))
+ return rq;
for_each_bio(bio) {
struct bio *bounce_bio = bio;
@@ -1528,8 +1528,8 @@ get_rq:
* Returns with the queue unlocked.
*/
req = get_request(q, rw_flags, bio, GFP_NOIO);
- if (unlikely(!req)) {
- bio_endio(bio, -ENODEV); /* @q is dead */
+ if (unlikely(IS_ERR(req))) {
+ bio_endio(bio, PTR_ERR(req)); /* @q is dead */
goto out_unlock;
}
diff --git a/block/bsg.c b/block/bsg.c
index 420a5a9..2b1c322 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -271,8 +271,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
* map scatter-gather elements separately and string them to request
*/
rq = blk_get_request(q, rw, GFP_KERNEL);
- if (!rq)
- return ERR_PTR(-ENOMEM);
+ if (IS_ERR(rq))
+ return rq;
ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd, has_write_perm);
if (ret)
goto out;
@@ -284,8 +284,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
}
next_rq = blk_get_request(q, READ, GFP_KERNEL);
- if (!next_rq) {
- ret = -ENOMEM;
+ if (IS_ERR(next_rq)) {
+ ret = PTR_ERR(rq);
goto out;
}
rq->next_rq = next_rq;
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 9a87daa..014b92a 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -311,8 +311,8 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
}
rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL);
- if (!rq)
- return -ENOMEM;
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
if (blk_fill_sghdr_rq(q, rq, hdr, mode)) {
blk_put_request(rq);
@@ -458,6 +458,8 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
}
rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
cmdlen = COMMAND_SIZE(opcode);
@@ -544,6 +546,8 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk,
int err;
rq = blk_get_request(q, WRITE, __GFP_WAIT);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
rq->cmd[0] = cmd;
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 831e3ac..0d4e530 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -722,6 +722,8 @@ static int pd_special_command(struct pd_unit *disk,
int err = 0;
rq = blk_get_request(disk->gd->queue, READ, __GFP_WAIT);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
rq->cmd_type = REQ_TYPE_SPECIAL;
rq->special = func;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 1119042..25ab3bd 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -711,7 +711,8 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
WRITE : READ, __GFP_WAIT);
-
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
if (cgc->buflen) {
if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT))
goto out;
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 3fb6ab4..911b7fc 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -568,7 +568,7 @@ static struct carm_request *carm_get_special(struct carm_host *host)
return NULL;
rq = blk_get_request(host->oob_q, WRITE /* bogus */, GFP_KERNEL);
- if (!rq) {
+ if (IS_ERR(rq)) {
spin_lock_irqsave(&host->lock, flags);
carm_put_request(host, crq);
spin_unlock_irqrestore(&host->lock, flags);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index d620b44..999d852 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2161,8 +2161,8 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
len = nr * CD_FRAMESIZE_RAW;
rq = blk_get_request(q, READ, GFP_KERNEL);
- if (!rq) {
- ret = -ENOMEM;
+ if (IS_ERR(rq)) {
+ ret = PTR_ERR(rq);
break;
}
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
index 6ab9ab2..fd432de 100644
--- a/drivers/ide/ide-park.c
+++ b/drivers/ide/ide-park.c
@@ -46,7 +46,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
* timeout has expired, so power management will be reenabled.
*/
rq = blk_get_request(q, READ, GFP_NOWAIT);
- if (unlikely(!rq))
+ if (unlikely(IS_ERR(rq)))
goto out;
rq->cmd[0] = REQ_UNPARK_HEADS;
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6f4d8e6..f07f152 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -115,7 +115,7 @@ static struct request *get_alua_req(struct scsi_device *sdev,
rq = blk_get_request(q, rw, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev,
"%s: blk_get_request failed\n", __func__);
return NULL;
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index e1c8be0..2ec3261 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -275,7 +275,7 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,
rq = blk_get_request(sdev->request_queue,
(cmd != INQUIRY) ? WRITE : READ, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
return NULL;
}
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index 084062b..1cf4019 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -117,7 +117,7 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
retry:
req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
- if (!req)
+ if (IS_ERR(req))
return SCSI_DH_RES_TEMP_UNAVAIL;
req->cmd_type = REQ_TYPE_BLOCK_PC;
@@ -247,7 +247,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h)
struct request *req;
req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC);
- if (!req)
+ if (IS_ERR(req))
return SCSI_DH_RES_TEMP_UNAVAIL;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 69c915a..009bd8f 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -274,7 +274,7 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
rq = blk_get_request(q, rw, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev,
"get_rdac_req: blk_get_request failed.\n");
return NULL;
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index d8293f2..b4cd56b 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -1567,8 +1567,8 @@ static struct request *_make_request(struct request_queue *q, bool has_write,
struct request *req;
req = blk_get_request(q, has_write ? WRITE : READ, flags);
- if (unlikely(!req))
- return ERR_PTR(-ENOMEM);
+ if (unlikely(IS_ERR(req)))
+ return req;
return req;
}
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 21883a2..826cda9 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -362,7 +362,7 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
int write = (data_direction == DMA_TO_DEVICE);
req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL);
- if (!req)
+ if (IS_ERR(req))
return DRIVER_ERROR << 24;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index c1b05a8..7b248fb 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1635,6 +1635,8 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
* request becomes available
*/
req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
+ if (IS_ERR(req))
+ return;
req->cmd[0] = ALLOW_MEDIUM_REMOVAL;
req->cmd[1] = 0;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index c31187d..cad055b 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -236,7 +236,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int ret = DRIVER_ERROR << 24;
req = blk_get_request(sdev->request_queue, write, __GFP_WAIT);
- if (!req)
+ if (IS_ERR(req))
return ret;
if (bufflen && blk_rq_map_kern(sdev->request_queue, req,
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 84a1fdf..d300620 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -97,7 +97,7 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
* we are in target mode we want the opposite.
*/
rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask);
- if (!rq)
+ if (IS_ERR(rq))
goto free_tcmd;
cmd = __scsi_get_command(shost, gfp_mask);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 9f0c465..5d39fec 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1649,8 +1649,8 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
dxfer_len));
rq = blk_get_request(q, rw, GFP_ATOMIC);
- if (!rq)
- return -ENOMEM;
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
memcpy(rq->cmd, cmd, hp->cmd_len);
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 8697447..5fca9cb 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -481,7 +481,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
req = blk_get_request(SRpnt->stp->device->request_queue, write,
GFP_KERNEL);
- if (!req)
+ if (IS_ERR(req))
return DRIVER_ERROR << 24;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index 82e78d7..8cd953a 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -1045,9 +1045,9 @@ pscsi_execute_cmd(struct se_cmd *cmd)
req = blk_get_request(pdv->pdv_sd->request_queue,
(data_direction == DMA_TO_DEVICE),
GFP_KERNEL);
- if (!req || IS_ERR(req)) {
+ if (IS_ERR(req)) {
pr_err("PSCSI: blk_get_request() failed: %ld\n",
- req ? IS_ERR(req) : -ENOMEM);
+ PTR_ERR(req));
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
goto fail;
}
--
1.8.1.4
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v4] block: handle pointer error from blk_get_request
2013-03-26 22:34 ` [PATCH v3] " Joe Lawrence
@ 2013-05-23 20:09 ` Joe Lawrence
2013-05-23 20:24 ` Boaz Harrosh
0 siblings, 1 reply; 15+ messages in thread
From: Joe Lawrence @ 2013-05-23 20:09 UTC (permalink / raw)
To: linux-scsi; +Cc: Jens Axboe, James E.J. Bottomley, Bart Van Assche
Hi Jens,
A small fix to this patch to properly cleanup sg_scsi_ioctl buffer when
blk_get_request fails (a return value check was introduced in patch
version 1). Since this is change emanates out of the block layer, I'm
assuming it should go through your tree, though I'm not sure which
branch it needs to be based on. It appears to apply cleanly to for-3.10
and for-3.11. Let me know what you prefer.
Changes from v3:
- Fix memory leak introduced in previous patch versions of
sg_scsi_ioctl error path
Regards,
-- Joe
>From 07293e4ce42dfc9a2688fac1ce62a32853348fc3 Mon Sep 17 00:00:00 2001
From: Joe Lawrence <joe.lawrence@stratus.com>
Date: Thu, 23 May 2013 15:05:08 -0400
Subject: [PATCH v4] block: handle pointer error from blk_get_request
The blk_get_request function may fail in low-memory conditions or during
device removal (even if __GFP_WAIT is set). To distinguish between these
errors, modify the blk_get_request call stack to return the appropriate
error pointer. Verify that all callers check the return status and
consider IS_ERR instead of a simple NULL pointer check.
Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: Bart Van Assche <bvanassche@acm.org>
Cc: linux-scsi@vger.kernel.org
---
block/blk-core.c | 34 ++++++++++++++---------------
block/bsg.c | 8 +++----
block/scsi_ioctl.c | 13 ++++++++---
drivers/block/paride/pd.c | 2 ++
drivers/block/pktcdvd.c | 3 ++-
drivers/block/sx8.c | 2 +-
drivers/cdrom/cdrom.c | 4 ++--
drivers/ide/ide-park.c | 2 +-
drivers/scsi/device_handler/scsi_dh_alua.c | 2 +-
drivers/scsi/device_handler/scsi_dh_emc.c | 2 +-
drivers/scsi/device_handler/scsi_dh_hp_sw.c | 4 ++--
drivers/scsi/device_handler/scsi_dh_rdac.c | 2 +-
drivers/scsi/osd/osd_initiator.c | 4 ++--
drivers/scsi/osst.c | 2 +-
drivers/scsi/scsi_error.c | 2 ++
drivers/scsi/scsi_lib.c | 2 +-
drivers/scsi/scsi_tgt_lib.c | 2 +-
drivers/scsi/sg.c | 4 ++--
drivers/scsi/st.c | 2 +-
drivers/target/target_core_pscsi.c | 4 ++--
20 files changed, 56 insertions(+), 44 deletions(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index f224d17..9e254e4 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -886,9 +886,9 @@ static struct io_context *rq_ioc(struct bio *bio)
* Get a free request from @q. This function may fail under memory
* pressure or if @q is dead.
*
- * Must be callled with @q->queue_lock held and,
- * Returns %NULL on failure, with @q->queue_lock held.
- * Returns !%NULL on success, with @q->queue_lock *not held*.
+ * Must be called with @q->queue_lock held and,
+ * Returns ERR_PTR on failure, with @q->queue_lock held.
+ * Returns request pointer on success, with @q->queue_lock *not held*.
*/
static struct request *__get_request(struct request_list *rl, int rw_flags,
struct bio *bio, gfp_t gfp_mask)
@@ -902,7 +902,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
int may_queue;
if (unlikely(blk_queue_dying(q)))
- return NULL;
+ return ERR_PTR(-ENODEV);
may_queue = elv_may_queue(q, rw_flags);
if (may_queue == ELV_MQUEUE_NO)
@@ -927,7 +927,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
* process is not a "batcher", and not
* exempted by the IO scheduler
*/
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
}
}
@@ -945,7 +945,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
* allocated with any setting of ->nr_requests
*/
if (rl->count[is_sync] >= (3 * q->nr_requests / 2))
- return NULL;
+ return ERR_PTR(-ENOMEM);
q->nr_rqs[is_sync]++;
rl->count[is_sync]++;
@@ -1050,7 +1050,7 @@ fail_alloc:
rq_starved:
if (unlikely(rl->count[is_sync] == 0))
rl->starved[is_sync] = 1;
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
/**
@@ -1063,9 +1063,9 @@ rq_starved:
* Get a free request from @q. If %__GFP_WAIT is set in @gfp_mask, this
* function keeps retrying under memory pressure and fails iff @q is dead.
*
- * Must be callled with @q->queue_lock held and,
- * Returns %NULL on failure, with @q->queue_lock held.
- * Returns !%NULL on success, with @q->queue_lock *not held*.
+ * Must be called with @q->queue_lock held and,
+ * Returns ERR_PTR on failure, with @q->queue_lock held.
+ * Returns request pointer on success, with @q->queue_lock *not held*.
*/
static struct request *get_request(struct request_queue *q, int rw_flags,
struct bio *bio, gfp_t gfp_mask)
@@ -1078,12 +1078,12 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
rl = blk_get_rl(q, bio); /* transferred to @rq on success */
retry:
rq = __get_request(rl, rw_flags, bio, gfp_mask);
- if (rq)
+ if (!IS_ERR(rq))
return rq;
if (!(gfp_mask & __GFP_WAIT) || unlikely(blk_queue_dying(q))) {
blk_put_rl(rl);
- return NULL;
+ return rq;
}
/* wait on @rl and retry */
@@ -1119,7 +1119,7 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
spin_lock_irq(q->queue_lock);
rq = get_request(q, rw, NULL, gfp_mask);
- if (!rq)
+ if (unlikely(IS_ERR(rq)))
spin_unlock_irq(q->queue_lock);
/* q->queue_lock is unlocked at this point */
@@ -1163,8 +1163,8 @@ struct request *blk_make_request(struct request_queue *q, struct bio *bio,
{
struct request *rq = blk_get_request(q, bio_data_dir(bio), gfp_mask);
- if (unlikely(!rq))
- return ERR_PTR(-ENOMEM);
+ if (unlikely(IS_ERR(rq)))
+ return rq;
for_each_bio(bio) {
struct bio *bounce_bio = bio;
@@ -1528,8 +1528,8 @@ get_rq:
* Returns with the queue unlocked.
*/
req = get_request(q, rw_flags, bio, GFP_NOIO);
- if (unlikely(!req)) {
- bio_endio(bio, -ENODEV); /* @q is dead */
+ if (unlikely(IS_ERR(req))) {
+ bio_endio(bio, PTR_ERR(req)); /* @q is dead */
goto out_unlock;
}
diff --git a/block/bsg.c b/block/bsg.c
index 420a5a9..2b1c322 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -271,8 +271,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
* map scatter-gather elements separately and string them to request
*/
rq = blk_get_request(q, rw, GFP_KERNEL);
- if (!rq)
- return ERR_PTR(-ENOMEM);
+ if (IS_ERR(rq))
+ return rq;
ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd, has_write_perm);
if (ret)
goto out;
@@ -284,8 +284,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
}
next_rq = blk_get_request(q, READ, GFP_KERNEL);
- if (!next_rq) {
- ret = -ENOMEM;
+ if (IS_ERR(next_rq)) {
+ ret = PTR_ERR(rq);
goto out;
}
rq->next_rq = next_rq;
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 9a87daa..69961fe 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -311,8 +311,8 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
}
rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL);
- if (!rq)
- return -ENOMEM;
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
if (blk_fill_sghdr_rq(q, rq, hdr, mode)) {
blk_put_request(rq);
@@ -458,6 +458,10 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
}
rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);
+ if (IS_ERR(rq)) {
+ err = PTR_ERR(rq);
+ goto error_free_buffer;
+ }
cmdlen = COMMAND_SIZE(opcode);
@@ -530,8 +534,9 @@ out:
}
error:
- kfree(buffer);
blk_put_request(rq);
+error_free_buffer:
+ kfree(buffer);
return err;
}
EXPORT_SYMBOL_GPL(sg_scsi_ioctl);
@@ -544,6 +549,8 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk,
int err;
rq = blk_get_request(q, WRITE, __GFP_WAIT);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
rq->cmd[0] = cmd;
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 831e3ac..0d4e530 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -722,6 +722,8 @@ static int pd_special_command(struct pd_unit *disk,
int err = 0;
rq = blk_get_request(disk->gd->queue, READ, __GFP_WAIT);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
rq->cmd_type = REQ_TYPE_SPECIAL;
rq->special = func;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 1119042..25ab3bd 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -711,7 +711,8 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
WRITE : READ, __GFP_WAIT);
-
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
if (cgc->buflen) {
if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT))
goto out;
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 3fb6ab4..911b7fc 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -568,7 +568,7 @@ static struct carm_request *carm_get_special(struct carm_host *host)
return NULL;
rq = blk_get_request(host->oob_q, WRITE /* bogus */, GFP_KERNEL);
- if (!rq) {
+ if (IS_ERR(rq)) {
spin_lock_irqsave(&host->lock, flags);
carm_put_request(host, crq);
spin_unlock_irqrestore(&host->lock, flags);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index d620b44..999d852 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2161,8 +2161,8 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
len = nr * CD_FRAMESIZE_RAW;
rq = blk_get_request(q, READ, GFP_KERNEL);
- if (!rq) {
- ret = -ENOMEM;
+ if (IS_ERR(rq)) {
+ ret = PTR_ERR(rq);
break;
}
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
index 6ab9ab2..fd432de 100644
--- a/drivers/ide/ide-park.c
+++ b/drivers/ide/ide-park.c
@@ -46,7 +46,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
* timeout has expired, so power management will be reenabled.
*/
rq = blk_get_request(q, READ, GFP_NOWAIT);
- if (unlikely(!rq))
+ if (unlikely(IS_ERR(rq)))
goto out;
rq->cmd[0] = REQ_UNPARK_HEADS;
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6f4d8e6..f07f152 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -115,7 +115,7 @@ static struct request *get_alua_req(struct scsi_device *sdev,
rq = blk_get_request(q, rw, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev,
"%s: blk_get_request failed\n", __func__);
return NULL;
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index e1c8be0..2ec3261 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -275,7 +275,7 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,
rq = blk_get_request(sdev->request_queue,
(cmd != INQUIRY) ? WRITE : READ, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
return NULL;
}
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index 084062b..1cf4019 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -117,7 +117,7 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
retry:
req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
- if (!req)
+ if (IS_ERR(req))
return SCSI_DH_RES_TEMP_UNAVAIL;
req->cmd_type = REQ_TYPE_BLOCK_PC;
@@ -247,7 +247,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h)
struct request *req;
req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC);
- if (!req)
+ if (IS_ERR(req))
return SCSI_DH_RES_TEMP_UNAVAIL;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 69c915a..009bd8f 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -274,7 +274,7 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
rq = blk_get_request(q, rw, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev,
"get_rdac_req: blk_get_request failed.\n");
return NULL;
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index d8293f2..b4cd56b 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -1567,8 +1567,8 @@ static struct request *_make_request(struct request_queue *q, bool has_write,
struct request *req;
req = blk_get_request(q, has_write ? WRITE : READ, flags);
- if (unlikely(!req))
- return ERR_PTR(-ENOMEM);
+ if (unlikely(IS_ERR(req)))
+ return req;
return req;
}
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 21883a2..826cda9 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -362,7 +362,7 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
int write = (data_direction == DMA_TO_DEVICE);
req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL);
- if (!req)
+ if (IS_ERR(req))
return DRIVER_ERROR << 24;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index c1b05a8..7b248fb 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1635,6 +1635,8 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
* request becomes available
*/
req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
+ if (IS_ERR(req))
+ return;
req->cmd[0] = ALLOW_MEDIUM_REMOVAL;
req->cmd[1] = 0;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index c31187d..cad055b 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -236,7 +236,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int ret = DRIVER_ERROR << 24;
req = blk_get_request(sdev->request_queue, write, __GFP_WAIT);
- if (!req)
+ if (IS_ERR(req))
return ret;
if (bufflen && blk_rq_map_kern(sdev->request_queue, req,
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 84a1fdf..d300620 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -97,7 +97,7 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
* we are in target mode we want the opposite.
*/
rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask);
- if (!rq)
+ if (IS_ERR(rq))
goto free_tcmd;
cmd = __scsi_get_command(shost, gfp_mask);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 9f0c465..5d39fec 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1649,8 +1649,8 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
dxfer_len));
rq = blk_get_request(q, rw, GFP_ATOMIC);
- if (!rq)
- return -ENOMEM;
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
memcpy(rq->cmd, cmd, hp->cmd_len);
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 8697447..5fca9cb 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -481,7 +481,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
req = blk_get_request(SRpnt->stp->device->request_queue, write,
GFP_KERNEL);
- if (!req)
+ if (IS_ERR(req))
return DRIVER_ERROR << 24;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index e992b27..bb5a811 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -1050,9 +1050,9 @@ pscsi_execute_cmd(struct se_cmd *cmd)
req = blk_get_request(pdv->pdv_sd->request_queue,
(data_direction == DMA_TO_DEVICE),
GFP_KERNEL);
- if (!req || IS_ERR(req)) {
+ if (IS_ERR(req)) {
pr_err("PSCSI: blk_get_request() failed: %ld\n",
- req ? IS_ERR(req) : -ENOMEM);
+ PTR_ERR(req));
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
goto fail;
}
--
1.8.1.4
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v4] block: handle pointer error from blk_get_request
2013-05-23 20:09 ` [PATCH v4] " Joe Lawrence
@ 2013-05-23 20:24 ` Boaz Harrosh
0 siblings, 0 replies; 15+ messages in thread
From: Boaz Harrosh @ 2013-05-23 20:24 UTC (permalink / raw)
To: Joe Lawrence
Cc: linux-scsi, Jens Axboe, James E.J. Bottomley, Bart Van Assche
On 23/05/13 23:09, Joe Lawrence wrote:
> Hi Jens,
>
> Subject: [PATCH v4] block: handle pointer error from blk_get_request
>
> The blk_get_request function may fail in low-memory conditions or during
> device removal (even if __GFP_WAIT is set). To distinguish between these
> errors, modify the blk_get_request call stack to return the appropriate
> error pointer. Verify that all callers check the return status and
> consider IS_ERR instead of a simple NULL pointer check.
>
> Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
> Cc: Jens Axboe <axboe@kernel.dk>
> Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
> Cc: Bart Van Assche <bvanassche@acm.org>
> Cc: linux-scsi@vger.kernel.org
ACK-by: Boaz Harrosh <bharrosh@panasas.com>
> ---
<>
> drivers/scsi/osd/osd_initiator.c | 4 ++--
<>
> diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
> index d8293f2..b4cd56b 100644
> --- a/drivers/scsi/osd/osd_initiator.c
> +++ b/drivers/scsi/osd/osd_initiator.c
> @@ -1567,8 +1567,8 @@ static struct request *_make_request(struct request_queue *q, bool has_write,
> struct request *req;
>
> req = blk_get_request(q, has_write ? WRITE : READ, flags);
> - if (unlikely(!req))
> - return ERR_PTR(-ENOMEM);
> + if (unlikely(IS_ERR(req)))
> + return req;
>
> return req;
> }
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] block,scsi: verify return pointer from blk_get_request
2013-03-17 22:44 ` Jens Axboe
@ 2013-05-23 20:40 ` James Bottomley
2013-05-23 21:37 ` Joe Lawrence
0 siblings, 1 reply; 15+ messages in thread
From: James Bottomley @ 2013-05-23 20:40 UTC (permalink / raw)
To: Jens Axboe; +Cc: Joe Lawrence, linux-scsi, Jiri Kosina
On Sun, 2013-03-17 at 16:44 -0600, Jens Axboe wrote:
> On Sun, Mar 17 2013, Joe Lawrence wrote:
> > Hello James / Jiri / Jens,
> >
> > Stratus hit a NULL ptr deference bug when removing a USB CD-ROM while
> > burning a DVD. The stack trace below was produced on a RHEL 6.4-GA
> > kernel, however it looks like the bug still exists in 3.9.0-rc2: not all
> > callers of blk_get_request bother to verify the return pointer value
> > before using it.
> >
> > There are other unsafe blk_get_request callers in the kernel, but they
> > live in the obsolete drivers/ide directory. Patches from the Linux
> > Driver Verification to harden those calls were rejected in Aug 2012 [1],
> > so I'll let them be.
> >
> > [1] https://lkml.org/lkml/2012/8/9/561
> >
> > Stack trace and notes:
> >
> > BUG: unable to handle kernel NULL pointer dereference at 0000000000000044
> > usb 3-1.6: USB disconnect, device number 4
> > usb 3-1.6.1: USB disconnect, device number 5
> > IP: [<ffffffff8126687b>] blk_send_start_stop+0x3b/0xa0
> > PGD 4034327067 PUD 4041356067 PMD 0
> > Oops: 0002 [#1] SMP
> > last sysfs file: /sys/devices/pci0000:00/0000:00:01.0/class
> > CPU 0
> > Modules linked in: nfs lockd fscache auth_rpcgss nfs_acl nls_utf8 fuse autofs4 sunrpc configfs bonding 8021q garp stp llc vhost_net macvtap macvlan tun uinput ipmi_devintf ftmod(P)(U) sg matroxfb(U) fosil(U) ext4 mbcache jbd2 sr_mod cdrom raid1 ixgbe(U) usb_storage mpt2sas(U) scsi_hbas(U) sd_mod(U) crc_t10dif scsi_transport_sas raid_class igb(U) dca ptp pps_core dm_mirror dm_region_hash dm_log dm_mod ipv6 cxgb4 cxgb3 mdio libiscsi_tcp libiscsi scsi_transport_iscsi [last unloaded: scsi_wait_scan]
> >
> > Pid: 13461, comm: k3b Tainted: P --------------- 2.6.32-358.el6.x86_64 #1 Stratus ftServer 4700/G7LAY
> > RIP: 0010:[<ffffffff8126687b>] [<ffffffff8126687b>] blk_send_start_stop+0x3b/0xa0
> > RSP: 0018:ffff884050545b98 EFLAGS: 00010282
> > RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
> > RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff88204e64c0f8
> > RBP: ffff884050545bb8 R08: 000000000297a798 R09: 0000000000000000
> > R10: 00000000000007e4 R11: 0000000000000001 R12: ffff88204e64c0f8
> > R13: ffff88204d1a3800 R14: 0000000000000002 R15: 000000000000005d
> > FS: 00007f480bfff700(0000) GS:ffff880040200000(0000) knlGS:0000000000000000
> > CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > CR2: 0000000000000044 CR3: 00000040414ca000 CR4: 00000000000407f0
> > DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> > DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> > Process k3b (pid: 13461, threadinfo ffff884050544000, task ffff884046de1500)
> > Stack:
> > ffff88204e64c0f8 00000000fffffffa ffff88204d1a3800 000000000297a798
> > <d> ffff884050545cb8 ffffffff8126726a ffff880040236798 ffff880040236700
> > <d> ffff884050f7b538 ffff8840504ca0b8 ffff884050f7b500 0000000000000000
> > Call Trace:
> > [<ffffffff8126726a>] scsi_cmd_ioctl+0x18a/0x470
> > [<ffffffff8103392e>] ? physflat_send_IPI_mask+0xe/0x10
> > [<ffffffff8102dd89>] ? native_smp_send_reschedule+0x49/0x60
> > [<ffffffff81052258>] ? resched_task+0x68/0x80
> > [<ffffffff810570e0>] ? check_preempt_wakeup+0x1c0/0x260
> > [<ffffffff81054f13>] ? ftrace_raw_event_id_sched_wakeup_template+0xe3/0xf0
> > [<ffffffff812675a1>] scsi_cmd_blk_ioctl+0x51/0x70
> > [<ffffffffa01c1a1d>] cdrom_ioctl+0x4d/0xe60 [cdrom]
> > [<ffffffff812231f1>] ? avc_has_perm+0x71/0x90
> > [<ffffffffa0082440>] sr_block_ioctl+0x60/0xb0 [sr_mod]
> > [<ffffffff812642f7>] __blkdev_driver_ioctl+0x67/0x80
> > [<ffffffff8126477d>] blkdev_ioctl+0x1ed/0x6e0
> > [<ffffffff811bb76c>] block_ioctl+0x3c/0x40
> > [<ffffffff81194ed2>] vfs_ioctl+0x22/0xa0
> > [<ffffffff81195074>] do_vfs_ioctl+0x84/0x580
> > [<ffffffff811955f1>] sys_ioctl+0x81/0xa0
> > [<ffffffff8100b288>] tracesys+0xd9/0xde
> > Code: 08 4c 89 6c 24 10 4c 89 74 24 18 0f 1f 44 00 00 49 89 f5 41 89 d6 be 01 00 00 00 ba 10 00 00 00 49 89 fc e8 b8 82 ff ff 48 89 c3 <c7> 40 44 02 00 00 00 c7 80 38 01 00 00 60 ea 00 00 48 8b 80 00
> > RIP [<ffffffff8126687b>] blk_send_start_stop+0x3b/0xa0
> > RSP <ffff884050545b98>
> > CR2: 0000000000000044
> >
> > What is blk_send_start_stop (inline __blk_send_generic) doing?
> >
> > block/scsi_ioctl.c: 783
> > <blk_send_start_stop+0x33>: callq 0xffffffff8125eb30 <blk_get_request>
> > <blk_send_start_stop+0x38>: mov %rax,%rbx
> > block/scsi_ioctl.c: 784
> > <blk_send_start_stop+0x3b>: movl $0x2,0x44(%rax)
> >
> > Where RAX: 0000000000000000
> >
> > block/scsi_ioctl.c:
> >
> > 776 /* Send basic block requests */
> > 777 static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_di
> > 778 int cmd, int data)
> > 779 {
> > 780 struct request *rq;
> > 781 int err;
> > 782
> > 783 rq = blk_get_request(q, WRITE, __GFP_WAIT);
> > 784 rq->cmd_type = REQ_TYPE_BLOCK_PC; <<
> > 785 rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
> > 786 rq->cmd[0] = cmd;
> > 787 rq->cmd[4] = data;
> > 788 rq->cmd_len = 6;
> > 789 err = blk_execute_rq(q, bd_disk, rq, 0);
> > 790 blk_put_request(rq);
> > 791
> > 792 return err;
> > 793 }
> >
> > A quick verify of offset from "movl $0x2,0x44(%rax)":
> >
> > crash> struct -o request | grep 0x44
> > [0x44] enum rq_cmd_type_bits cmd_type;
> >
> > So blk_get_request returned a NULL struct request pointer, but
> > __blk_send_generic continued on without checking it first.
>
> The reason why the above code does not check for NULL return, is because
> __GFP_WAIT is set. But since queue dead checks were added, we can
> trigger this now. So with that in mind, ENOMEM is not the right error
> code for this, as it has nothing to do with running out of memory.
>
> Would probably be best to return the correct error pointer from
> blk_get_request(), as you would otherwise have to assume this knowledge
> in the callers.
Now that we see the size of the patch diff between fixing the bug and
doing proper error returns, I'm really not convinced this should be done
as a single bug fix patch. The modify all error returns is big and if
we missed one, it will cause problems that will manifest as an oops, so
it makes a fairly compact fix a big error prone patch.
What about two patches: one to fix the actual bug (this patch), which
could go now and one to change the return type, which would go in the
normal merge window.
James
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH] block,scsi: verify return pointer from blk_get_request
2013-05-23 20:40 ` James Bottomley
@ 2013-05-23 21:37 ` Joe Lawrence
0 siblings, 0 replies; 15+ messages in thread
From: Joe Lawrence @ 2013-05-23 21:37 UTC (permalink / raw)
To: linux-scsi; +Cc: James Bottomley, Jens Axboe, Jiri Kosina
On Fri, 24 May 2013 00:40:11 +0400
James Bottomley <James.Bottomley@hansenpartnership.com> wrote:
> Now that we see the size of the patch diff between fixing the bug and
> doing proper error returns, I'm really not convinced this should be
> done as a single bug fix patch. The modify all error returns is big
> and if we missed one, it will cause problems that will manifest as an
> oops, so it makes a fairly compact fix a big error prone patch.
>
> What about two patches: one to fix the actual bug (this patch), which
> could go now and one to change the return type, which would go in the
> normal merge window.
That would certainly be safer (apologies for not getting to this before
the merge window).
I can split these modifications from the return type changes tomorrow.
This would include fixes to address new and previous patch comments:
- v1: If callers are passing in __GFP_WAIT, then blk_get_request
should only fail if the device queue is dead, so it would be
more appropriate to return -ENODEV. (Jens)
- v1: scsi_eh_lock_door is defined as void, don't return errno
(Bart)
- v1: drivers/block/paride/pd.c :: pd_special_command should check
blk_get_request return value
- v4: the error path introduced in sg_scsi_ioctl should free the
buffer
Thanks,
-- Joe
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios
2013-03-17 17:32 [PATCH] block,scsi: verify return pointer from blk_get_request Joe Lawrence
` (2 preceding siblings ...)
2013-03-26 19:06 ` [PATCH v2] block: handle pointer error " Joe Lawrence
@ 2013-05-24 18:15 ` Joe Lawrence
2013-05-24 18:16 ` [PATCH v5 1/2] block,scsi: verify return pointer from blk_get_request Joe Lawrence
` (2 more replies)
3 siblings, 3 replies; 15+ messages in thread
From: Joe Lawrence @ 2013-05-24 18:15 UTC (permalink / raw)
To: linux-scsi
Cc: Joe Lawrence, Jens Axboe, Jiri Kosina, James E.J. Bottomley,
Bart Van Assche
[PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios
Changes from v4:
- As per James' suggestion, split into two patches: the first adds
blk_get_request return value checking to avoid potential oops, the
second converts callers and friends to handle ERR_PTR differentiation
of -ENOMEM and -ENODEV.
Regards,
-- Joe
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v5 1/2] block,scsi: verify return pointer from blk_get_request
2013-05-24 18:15 ` [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios Joe Lawrence
@ 2013-05-24 18:16 ` Joe Lawrence
2013-05-27 14:42 ` Jiri Kosina
2013-05-24 18:17 ` [PATCH v5 2/2] block,scsi: convert and handle ERR_PTR " Joe Lawrence
2013-07-24 14:29 ` [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios Joe Lawrence
2 siblings, 1 reply; 15+ messages in thread
From: Joe Lawrence @ 2013-05-24 18:16 UTC (permalink / raw)
To: linux-scsi
Cc: Joe Lawrence, Jens Axboe, Jiri Kosina, James E.J. Bottomley,
Bart Van Assche
>From 22307be1bc6e404622b1f074094902e385a1bd30 Mon Sep 17 00:00:00 2001
From: Joe Lawrence <joe.lawrence@stratus.com>
Date: Fri, 24 May 2013 12:39:04 -0400
Subject: [PATCH v5 1/2] block,scsi: verify return pointer from blk_get_request
The blk-core dead queue checks introduced in commit 70460571 added an
error scenario to blk_get_request that returns NULL if the request queue
has been shutdown. This changed the behavior for __GFP_WAIT callers, who
should now verify the return value before dereferencing.
Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Jiri Kosina <jkosina@suse.cz>
Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: Bart Van Assche <bvanassche@acm.org>
Cc: linux-scsi@vger.kernel.org
---
block/scsi_ioctl.c | 9 ++++++++-
drivers/block/paride/pd.c | 2 ++
drivers/block/pktcdvd.c | 2 ++
drivers/scsi/scsi_error.c | 2 ++
4 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 9a87daa..6c87d4e 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -458,6 +458,10 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
}
rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);
+ if (!rq) {
+ err = -ENODEV;
+ goto error_free_buffer;
+ }
cmdlen = COMMAND_SIZE(opcode);
@@ -530,8 +534,9 @@ out:
}
error:
- kfree(buffer);
blk_put_request(rq);
+error_free_buffer:
+ kfree(buffer);
return err;
}
EXPORT_SYMBOL_GPL(sg_scsi_ioctl);
@@ -544,6 +549,8 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk,
int err;
rq = blk_get_request(q, WRITE, __GFP_WAIT);
+ if (!rq)
+ return -ENODEV;
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
rq->cmd[0] = cmd;
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 831e3ac..fc2ecff 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -722,6 +722,8 @@ static int pd_special_command(struct pd_unit *disk,
int err = 0;
rq = blk_get_request(disk->gd->queue, READ, __GFP_WAIT);
+ if (!rq)
+ return -ENODEV;
rq->cmd_type = REQ_TYPE_SPECIAL;
rq->special = func;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 1119042..4a8fb03f 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -711,6 +711,8 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
WRITE : READ, __GFP_WAIT);
+ if (!rq)
+ return -ENODEV;
if (cgc->buflen) {
if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT))
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index c1b05a8..aa6b83d 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1635,6 +1635,8 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
* request becomes available
*/
req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
+ if (!req)
+ return;
req->cmd[0] = ALLOW_MEDIUM_REMOVAL;
req->cmd[1] = 0;
--
1.8.1.4
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v5 2/2] block,scsi: convert and handle ERR_PTR from blk_get_request
2013-05-24 18:15 ` [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios Joe Lawrence
2013-05-24 18:16 ` [PATCH v5 1/2] block,scsi: verify return pointer from blk_get_request Joe Lawrence
@ 2013-05-24 18:17 ` Joe Lawrence
2013-05-27 14:42 ` Jiri Kosina
2013-07-24 14:29 ` [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios Joe Lawrence
2 siblings, 1 reply; 15+ messages in thread
From: Joe Lawrence @ 2013-05-24 18:17 UTC (permalink / raw)
To: linux-scsi
Cc: Joe Lawrence, Jens Axboe, Jiri Kosina, James E.J. Bottomley,
Bart Van Assche
>From 5b26d593807b30f60ed41f6fd5a16a56c3c9a43c Mon Sep 17 00:00:00 2001
From: Joe Lawrence <joe.lawrence@stratus.com>
Date: Fri, 24 May 2013 13:05:09 -0400
Subject: [PATCH v5 2/2] block,scsi: convert and handle ERR_PTR from blk_get_request
The blk_get_request function may fail in low-memory conditions or during
device removal (even if __GFP_WAIT is set). To distinguish between these
errors, modify the blk_get_request call stack to return the appropriate
ERR_PTR. Verify that all callers check the return status and consider
IS_ERR instead of a simple NULL pointer check.
Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Jiri Kosina <jkosina@suse.cz>
Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: Bart Van Assche <bvanassche@acm.org>
Cc: linux-scsi@vger.kernel.org
---
block/blk-core.c | 34 ++++++++++++++---------------
block/bsg.c | 8 +++----
block/scsi_ioctl.c | 12 +++++-----
drivers/block/paride/pd.c | 4 ++--
drivers/block/pktcdvd.c | 4 ++--
drivers/block/sx8.c | 2 +-
drivers/cdrom/cdrom.c | 4 ++--
drivers/ide/ide-park.c | 2 +-
drivers/scsi/device_handler/scsi_dh_alua.c | 2 +-
drivers/scsi/device_handler/scsi_dh_emc.c | 2 +-
drivers/scsi/device_handler/scsi_dh_hp_sw.c | 4 ++--
drivers/scsi/device_handler/scsi_dh_rdac.c | 2 +-
drivers/scsi/osd/osd_initiator.c | 4 ++--
drivers/scsi/osst.c | 2 +-
drivers/scsi/scsi_error.c | 2 +-
drivers/scsi/scsi_lib.c | 2 +-
drivers/scsi/scsi_tgt_lib.c | 2 +-
drivers/scsi/sg.c | 4 ++--
drivers/scsi/st.c | 2 +-
drivers/target/target_core_pscsi.c | 4 ++--
20 files changed, 51 insertions(+), 51 deletions(-)
diff --git a/block/blk-core.c b/block/blk-core.c
index f224d17..9e254e4 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -886,9 +886,9 @@ static struct io_context *rq_ioc(struct bio *bio)
* Get a free request from @q. This function may fail under memory
* pressure or if @q is dead.
*
- * Must be callled with @q->queue_lock held and,
- * Returns %NULL on failure, with @q->queue_lock held.
- * Returns !%NULL on success, with @q->queue_lock *not held*.
+ * Must be called with @q->queue_lock held and,
+ * Returns ERR_PTR on failure, with @q->queue_lock held.
+ * Returns request pointer on success, with @q->queue_lock *not held*.
*/
static struct request *__get_request(struct request_list *rl, int rw_flags,
struct bio *bio, gfp_t gfp_mask)
@@ -902,7 +902,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
int may_queue;
if (unlikely(blk_queue_dying(q)))
- return NULL;
+ return ERR_PTR(-ENODEV);
may_queue = elv_may_queue(q, rw_flags);
if (may_queue == ELV_MQUEUE_NO)
@@ -927,7 +927,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
* process is not a "batcher", and not
* exempted by the IO scheduler
*/
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
}
}
@@ -945,7 +945,7 @@ static struct request *__get_request(struct request_list *rl, int rw_flags,
* allocated with any setting of ->nr_requests
*/
if (rl->count[is_sync] >= (3 * q->nr_requests / 2))
- return NULL;
+ return ERR_PTR(-ENOMEM);
q->nr_rqs[is_sync]++;
rl->count[is_sync]++;
@@ -1050,7 +1050,7 @@ fail_alloc:
rq_starved:
if (unlikely(rl->count[is_sync] == 0))
rl->starved[is_sync] = 1;
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
/**
@@ -1063,9 +1063,9 @@ rq_starved:
* Get a free request from @q. If %__GFP_WAIT is set in @gfp_mask, this
* function keeps retrying under memory pressure and fails iff @q is dead.
*
- * Must be callled with @q->queue_lock held and,
- * Returns %NULL on failure, with @q->queue_lock held.
- * Returns !%NULL on success, with @q->queue_lock *not held*.
+ * Must be called with @q->queue_lock held and,
+ * Returns ERR_PTR on failure, with @q->queue_lock held.
+ * Returns request pointer on success, with @q->queue_lock *not held*.
*/
static struct request *get_request(struct request_queue *q, int rw_flags,
struct bio *bio, gfp_t gfp_mask)
@@ -1078,12 +1078,12 @@ static struct request *get_request(struct request_queue *q, int rw_flags,
rl = blk_get_rl(q, bio); /* transferred to @rq on success */
retry:
rq = __get_request(rl, rw_flags, bio, gfp_mask);
- if (rq)
+ if (!IS_ERR(rq))
return rq;
if (!(gfp_mask & __GFP_WAIT) || unlikely(blk_queue_dying(q))) {
blk_put_rl(rl);
- return NULL;
+ return rq;
}
/* wait on @rl and retry */
@@ -1119,7 +1119,7 @@ struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
spin_lock_irq(q->queue_lock);
rq = get_request(q, rw, NULL, gfp_mask);
- if (!rq)
+ if (unlikely(IS_ERR(rq)))
spin_unlock_irq(q->queue_lock);
/* q->queue_lock is unlocked at this point */
@@ -1163,8 +1163,8 @@ struct request *blk_make_request(struct request_queue *q, struct bio *bio,
{
struct request *rq = blk_get_request(q, bio_data_dir(bio), gfp_mask);
- if (unlikely(!rq))
- return ERR_PTR(-ENOMEM);
+ if (unlikely(IS_ERR(rq)))
+ return rq;
for_each_bio(bio) {
struct bio *bounce_bio = bio;
@@ -1528,8 +1528,8 @@ get_rq:
* Returns with the queue unlocked.
*/
req = get_request(q, rw_flags, bio, GFP_NOIO);
- if (unlikely(!req)) {
- bio_endio(bio, -ENODEV); /* @q is dead */
+ if (unlikely(IS_ERR(req))) {
+ bio_endio(bio, PTR_ERR(req)); /* @q is dead */
goto out_unlock;
}
diff --git a/block/bsg.c b/block/bsg.c
index 420a5a9..2b1c322 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -271,8 +271,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
* map scatter-gather elements separately and string them to request
*/
rq = blk_get_request(q, rw, GFP_KERNEL);
- if (!rq)
- return ERR_PTR(-ENOMEM);
+ if (IS_ERR(rq))
+ return rq;
ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd, has_write_perm);
if (ret)
goto out;
@@ -284,8 +284,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
}
next_rq = blk_get_request(q, READ, GFP_KERNEL);
- if (!next_rq) {
- ret = -ENOMEM;
+ if (IS_ERR(next_rq)) {
+ ret = PTR_ERR(rq);
goto out;
}
rq->next_rq = next_rq;
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 6c87d4e..69961fe 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -311,8 +311,8 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
}
rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL);
- if (!rq)
- return -ENOMEM;
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
if (blk_fill_sghdr_rq(q, rq, hdr, mode)) {
blk_put_request(rq);
@@ -458,8 +458,8 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
}
rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);
- if (!rq) {
- err = -ENODEV;
+ if (IS_ERR(rq)) {
+ err = PTR_ERR(rq);
goto error_free_buffer;
}
@@ -549,8 +549,8 @@ static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk,
int err;
rq = blk_get_request(q, WRITE, __GFP_WAIT);
- if (!rq)
- return -ENODEV;
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
rq->cmd[0] = cmd;
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index fc2ecff..0d4e530 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -722,8 +722,8 @@ static int pd_special_command(struct pd_unit *disk,
int err = 0;
rq = blk_get_request(disk->gd->queue, READ, __GFP_WAIT);
- if (!rq)
- return -ENODEV;
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
rq->cmd_type = REQ_TYPE_SPECIAL;
rq->special = func;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 4a8fb03f..67f3d87 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -711,8 +711,8 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
WRITE : READ, __GFP_WAIT);
- if (!rq)
- return -ENODEV;
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
if (cgc->buflen) {
if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT))
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 3fb6ab4..911b7fc 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -568,7 +568,7 @@ static struct carm_request *carm_get_special(struct carm_host *host)
return NULL;
rq = blk_get_request(host->oob_q, WRITE /* bogus */, GFP_KERNEL);
- if (!rq) {
+ if (IS_ERR(rq)) {
spin_lock_irqsave(&host->lock, flags);
carm_put_request(host, crq);
spin_unlock_irqrestore(&host->lock, flags);
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index d620b44..999d852 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2161,8 +2161,8 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
len = nr * CD_FRAMESIZE_RAW;
rq = blk_get_request(q, READ, GFP_KERNEL);
- if (!rq) {
- ret = -ENOMEM;
+ if (IS_ERR(rq)) {
+ ret = PTR_ERR(rq);
break;
}
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
index 6ab9ab2..fd432de 100644
--- a/drivers/ide/ide-park.c
+++ b/drivers/ide/ide-park.c
@@ -46,7 +46,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
* timeout has expired, so power management will be reenabled.
*/
rq = blk_get_request(q, READ, GFP_NOWAIT);
- if (unlikely(!rq))
+ if (unlikely(IS_ERR(rq)))
goto out;
rq->cmd[0] = REQ_UNPARK_HEADS;
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6f4d8e6..f07f152 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -115,7 +115,7 @@ static struct request *get_alua_req(struct scsi_device *sdev,
rq = blk_get_request(q, rw, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev,
"%s: blk_get_request failed\n", __func__);
return NULL;
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index e1c8be0..2ec3261 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -275,7 +275,7 @@ static struct request *get_req(struct scsi_device *sdev, int cmd,
rq = blk_get_request(sdev->request_queue,
(cmd != INQUIRY) ? WRITE : READ, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed");
return NULL;
}
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index 084062b..1cf4019 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -117,7 +117,7 @@ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
retry:
req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO);
- if (!req)
+ if (IS_ERR(req))
return SCSI_DH_RES_TEMP_UNAVAIL;
req->cmd_type = REQ_TYPE_BLOCK_PC;
@@ -247,7 +247,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h)
struct request *req;
req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC);
- if (!req)
+ if (IS_ERR(req))
return SCSI_DH_RES_TEMP_UNAVAIL;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 69c915a..009bd8f 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -274,7 +274,7 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
rq = blk_get_request(q, rw, GFP_NOIO);
- if (!rq) {
+ if (IS_ERR(rq)) {
sdev_printk(KERN_INFO, sdev,
"get_rdac_req: blk_get_request failed.\n");
return NULL;
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index d8293f2..b4cd56b 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -1567,8 +1567,8 @@ static struct request *_make_request(struct request_queue *q, bool has_write,
struct request *req;
req = blk_get_request(q, has_write ? WRITE : READ, flags);
- if (unlikely(!req))
- return ERR_PTR(-ENOMEM);
+ if (unlikely(IS_ERR(req)))
+ return req;
return req;
}
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 21883a2..826cda9 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -362,7 +362,7 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd,
int write = (data_direction == DMA_TO_DEVICE);
req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL);
- if (!req)
+ if (IS_ERR(req))
return DRIVER_ERROR << 24;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index aa6b83d..7b248fb 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1635,7 +1635,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev)
* request becomes available
*/
req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL);
- if (!req)
+ if (IS_ERR(req))
return;
req->cmd[0] = ALLOW_MEDIUM_REMOVAL;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index c31187d..cad055b 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -236,7 +236,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
int ret = DRIVER_ERROR << 24;
req = blk_get_request(sdev->request_queue, write, __GFP_WAIT);
- if (!req)
+ if (IS_ERR(req))
return ret;
if (bufflen && blk_rq_map_kern(sdev->request_queue, req,
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 84a1fdf..d300620 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -97,7 +97,7 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
* we are in target mode we want the opposite.
*/
rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask);
- if (!rq)
+ if (IS_ERR(rq))
goto free_tcmd;
cmd = __scsi_get_command(shost, gfp_mask);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 9f0c465..5d39fec 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1649,8 +1649,8 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
dxfer_len));
rq = blk_get_request(q, rw, GFP_ATOMIC);
- if (!rq)
- return -ENOMEM;
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
memcpy(rq->cmd, cmd, hp->cmd_len);
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 8697447..5fca9cb 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -481,7 +481,7 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
req = blk_get_request(SRpnt->stp->device->request_queue, write,
GFP_KERNEL);
- if (!req)
+ if (IS_ERR(req))
return DRIVER_ERROR << 24;
req->cmd_type = REQ_TYPE_BLOCK_PC;
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c
index e992b27..bb5a811 100644
--- a/drivers/target/target_core_pscsi.c
+++ b/drivers/target/target_core_pscsi.c
@@ -1050,9 +1050,9 @@ pscsi_execute_cmd(struct se_cmd *cmd)
req = blk_get_request(pdv->pdv_sd->request_queue,
(data_direction == DMA_TO_DEVICE),
GFP_KERNEL);
- if (!req || IS_ERR(req)) {
+ if (IS_ERR(req)) {
pr_err("PSCSI: blk_get_request() failed: %ld\n",
- req ? IS_ERR(req) : -ENOMEM);
+ PTR_ERR(req));
ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
goto fail;
}
--
1.8.1.4
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v5 1/2] block,scsi: verify return pointer from blk_get_request
2013-05-24 18:16 ` [PATCH v5 1/2] block,scsi: verify return pointer from blk_get_request Joe Lawrence
@ 2013-05-27 14:42 ` Jiri Kosina
0 siblings, 0 replies; 15+ messages in thread
From: Jiri Kosina @ 2013-05-27 14:42 UTC (permalink / raw)
To: Joe Lawrence
Cc: linux-scsi, Jens Axboe, James E.J. Bottomley, Bart Van Assche
On Fri, 24 May 2013, Joe Lawrence wrote:
> From 22307be1bc6e404622b1f074094902e385a1bd30 Mon Sep 17 00:00:00 2001
> From: Joe Lawrence <joe.lawrence@stratus.com>
> Date: Fri, 24 May 2013 12:39:04 -0400
> Subject: [PATCH v5 1/2] block,scsi: verify return pointer from blk_get_request
>
> The blk-core dead queue checks introduced in commit 70460571 added an
> error scenario to blk_get_request that returns NULL if the request queue
> has been shutdown. This changed the behavior for __GFP_WAIT callers, who
> should now verify the return value before dereferencing.
>
> Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
> Cc: Jens Axboe <axboe@kernel.dk>
> Cc: Jiri Kosina <jkosina@suse.cz>
> Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
> Cc: Bart Van Assche <bvanassche@acm.org>
> Cc: linux-scsi@vger.kernel.org
> ---
> block/scsi_ioctl.c | 9 ++++++++-
> drivers/block/paride/pd.c | 2 ++
> drivers/block/pktcdvd.c | 2 ++
Acked-by: Jiri Kosina <jkosina@suse.cz>
for the pktdvd.c change.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v5 2/2] block,scsi: convert and handle ERR_PTR from blk_get_request
2013-05-24 18:17 ` [PATCH v5 2/2] block,scsi: convert and handle ERR_PTR " Joe Lawrence
@ 2013-05-27 14:42 ` Jiri Kosina
0 siblings, 0 replies; 15+ messages in thread
From: Jiri Kosina @ 2013-05-27 14:42 UTC (permalink / raw)
To: Joe Lawrence
Cc: linux-scsi, Jens Axboe, James E.J. Bottomley, Bart Van Assche
On Fri, 24 May 2013, Joe Lawrence wrote:
> From 5b26d593807b30f60ed41f6fd5a16a56c3c9a43c Mon Sep 17 00:00:00 2001
> From: Joe Lawrence <joe.lawrence@stratus.com>
> Date: Fri, 24 May 2013 13:05:09 -0400
> Subject: [PATCH v5 2/2] block,scsi: convert and handle ERR_PTR from blk_get_request
>
> The blk_get_request function may fail in low-memory conditions or during
> device removal (even if __GFP_WAIT is set). To distinguish between these
> errors, modify the blk_get_request call stack to return the appropriate
> ERR_PTR. Verify that all callers check the return status and consider
> IS_ERR instead of a simple NULL pointer check.
>
> Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
> Cc: Jens Axboe <axboe@kernel.dk>
> Cc: Jiri Kosina <jkosina@suse.cz>
> Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
> Cc: Bart Van Assche <bvanassche@acm.org>
> Cc: linux-scsi@vger.kernel.org
> ---
> block/blk-core.c | 34 ++++++++++++++---------------
> block/bsg.c | 8 +++----
> block/scsi_ioctl.c | 12 +++++-----
> drivers/block/paride/pd.c | 4 ++--
> drivers/block/pktcdvd.c | 4 ++--
Acked-by: Jiri Kosina <jkosina@suse.cz>
for the pktdvd.c change.
Thanks Joe.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios
2013-05-24 18:15 ` [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios Joe Lawrence
2013-05-24 18:16 ` [PATCH v5 1/2] block,scsi: verify return pointer from blk_get_request Joe Lawrence
2013-05-24 18:17 ` [PATCH v5 2/2] block,scsi: convert and handle ERR_PTR " Joe Lawrence
@ 2013-07-24 14:29 ` Joe Lawrence
2 siblings, 0 replies; 15+ messages in thread
From: Joe Lawrence @ 2013-07-24 14:29 UTC (permalink / raw)
To: linux-scsi@vger.kernel.org; +Cc: Jens Axboe
On Fri, 24 May 2013 14:15:31 -0400
Joe Lawrence <joe.lawrence@stratus.com> wrote:
> [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios
>
> Changes from v4:
>
> - As per James' suggestion, split into two patches: the first adds
> blk_get_request return value checking to avoid potential oops, the
> second converts callers and friends to handle ERR_PTR differentiation
> of -ENOMEM and -ENODEV.
>
> Regards,
>
> -- Joe
Hello Jens,
I'm clearing out some of my old patches and was wondering about the
status of these two.
They apply cleanly to the tip of Linus's branch and it appears
that no new callers of blk_get_request have been introduced since v5 of
the patches.
link to thread:
http://thread.gmane.org/gmane.linux.scsi/80934/focus=82216
Regards,
-- Joe
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2013-07-24 14:29 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-17 17:32 [PATCH] block,scsi: verify return pointer from blk_get_request Joe Lawrence
2013-03-17 22:44 ` Jens Axboe
2013-05-23 20:40 ` James Bottomley
2013-05-23 21:37 ` Joe Lawrence
2013-03-19 13:55 ` Bart Van Assche
2013-03-26 19:06 ` [PATCH v2] block: handle pointer error " Joe Lawrence
2013-03-26 22:34 ` [PATCH v3] " Joe Lawrence
2013-05-23 20:09 ` [PATCH v4] " Joe Lawrence
2013-05-23 20:24 ` Boaz Harrosh
2013-05-24 18:15 ` [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios Joe Lawrence
2013-05-24 18:16 ` [PATCH v5 1/2] block,scsi: verify return pointer from blk_get_request Joe Lawrence
2013-05-27 14:42 ` Jiri Kosina
2013-05-24 18:17 ` [PATCH v5 2/2] block,scsi: convert and handle ERR_PTR " Joe Lawrence
2013-05-27 14:42 ` Jiri Kosina
2013-07-24 14:29 ` [PATCH v5 0/2] block,scsi: fixup blk_get_request dead queue scenarios Joe Lawrence
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).