| From 7772855a996ec6e16944b120ab5ce21050279821 Mon Sep 17 00:00:00 2001 |
| From: Tony Battersby <tonyb@cybernetics.com> |
| Date: Fri, 13 Feb 2015 12:10:58 -0500 |
| Subject: sg: fix EWOULDBLOCK errors with scsi-mq |
| |
| From: Tony Battersby <tonyb@cybernetics.com> |
| |
| commit 7772855a996ec6e16944b120ab5ce21050279821 upstream. |
| |
| With scsi-mq enabled, userspace programs can get unexpected EWOULDBLOCK |
| (a.k.a. EAGAIN) errors when submitting commands to the SCSI generic |
| driver. Fix by calling blk_get_request() with GFP_KERNEL instead of |
| GFP_ATOMIC. |
| |
| Note: to avoid introducing a potential deadlock, this patch should be |
| applied after the patch titled "sg: fix unkillable I/O wait deadlock |
| with scsi-mq". |
| |
| Signed-off-by: Tony Battersby <tonyb@cybernetics.com> |
| Acked-by: Douglas Gilbert <dgilbert@interlog.com> |
| Tested-by: Douglas Gilbert <dgilbert@interlog.com> |
| Signed-off-by: James Bottomley <JBottomley@Parallels.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/scsi/sg.c | 17 ++++++++++++++++- |
| 1 file changed, 16 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/scsi/sg.c |
| +++ b/drivers/scsi/sg.c |
| @@ -1695,7 +1695,22 @@ sg_start_req(Sg_request *srp, unsigned c |
| return -ENOMEM; |
| } |
| |
| - rq = blk_get_request(q, rw, GFP_ATOMIC); |
| + /* |
| + * NOTE |
| + * |
| + * With scsi-mq enabled, there are a fixed number of preallocated |
| + * requests equal in number to shost->can_queue. If all of the |
| + * preallocated requests are already in use, then using GFP_ATOMIC with |
| + * blk_get_request() will return -EWOULDBLOCK, whereas using GFP_KERNEL |
| + * will cause blk_get_request() to sleep until an active command |
| + * completes, freeing up a request. Neither option is ideal, but |
| + * GFP_KERNEL is the better choice to prevent userspace from getting an |
| + * unexpected EWOULDBLOCK. |
| + * |
| + * With scsi-mq disabled, blk_get_request() with GFP_KERNEL usually |
| + * does not sleep except under memory pressure. |
| + */ |
| + rq = blk_get_request(q, rw, GFP_KERNEL); |
| if (IS_ERR(rq)) { |
| kfree(long_cmdp); |
| return PTR_ERR(rq); |