sg: fix EWOULDBLOCK errors with scsi-mq
authorTony Battersby <tonyb@cybernetics.com>
Fri, 13 Feb 2015 17:10:58 +0000 (12:10 -0500)
committerJames Bottomley <JBottomley@Parallels.com>
Tue, 17 Feb 2015 14:57:54 +0000 (06:57 -0800)
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".

Cc: <stable@vger.kernel.org> # 3.17+
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>
drivers/scsi/sg.c

index 208bf3c8a16cb5f84d06d780a7f3e747783d7503..5cb2a5e80b2bb056ad5c979c1bad42feb35cce70 100644 (file)
@@ -1680,7 +1680,22 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
                        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);
This page took 0.03451 seconds and 5 git commands to generate.