diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-21 19:16:42 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-21 19:16:42 -0800 |
commit | c8c6c9ba39e3fe65cf3497d692bf6fe808ff222b (patch) | |
tree | 4358c44f57f9ce1bfb5886aea8bea3b137ecb551 /drivers/scsi/sg.c | |
parent | 93aaa830fc173560505c3411806509299d8871ce (diff) | |
parent | 7772855a996ec6e16944b120ab5ce21050279821 (diff) |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull misc SCSI patches from James Bottomley:
"This is a short patch set representing a couple of left overs from the
merge window (debug removal and MAINTAINER changes).
Plus one merge window regression (the local workqueue for hpsa) and a
set of bug fixes for several issues (two for scsi-mq and the rest an
assortment of long standing stuff, all cc'd to stable)"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi:
sg: fix EWOULDBLOCK errors with scsi-mq
sg: fix unkillable I/O wait deadlock with scsi-mq
sg: fix read() error reporting
wd719x: add missing .module to wd719x_template
hpsa: correct compiler warnings introduced by hpsa-add-local-workqueue patch
fixed invalid assignment of 64bit mask to host dma_boundary for scatter gather segment boundary limit.
fcoe: Transition maintainership to Vasu
am53c974: remove left-over debugging code
Diffstat (limited to 'drivers/scsi/sg.c')
-rw-r--r-- | drivers/scsi/sg.c | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 0cbc1fb45f10..2270bd51f9c2 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -546,7 +546,7 @@ static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp) { sg_io_hdr_t *hp = &srp->header; - int err = 0; + int err = 0, err2; int len; if (count < SZ_SG_IO_HDR) { @@ -575,8 +575,8 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp) goto err_out; } err_out: - err = sg_finish_rem_req(srp); - return (0 == err) ? count : err; + err2 = sg_finish_rem_req(srp); + return err ? : err2 ? : count; } static ssize_t @@ -1335,6 +1335,17 @@ sg_rq_end_io(struct request *rq, int uptodate) } /* Rely on write phase to clean out srp status values, so no "else" */ + /* + * Free the request as soon as it is complete so that its resources + * can be reused without waiting for userspace to read() the + * result. But keep the associated bio (if any) around until + * blk_rq_unmap_user() can be called from user context. + */ + srp->rq = NULL; + if (rq->cmd != rq->__cmd) + kfree(rq->cmd); + __blk_put_request(rq->q, rq); + write_lock_irqsave(&sfp->rq_list_lock, iflags); if (unlikely(srp->orphan)) { if (sfp->keep_orphan) @@ -1669,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); @@ -1759,10 +1785,10 @@ sg_finish_rem_req(Sg_request *srp) SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp, "sg_finish_rem_req: res_used=%d\n", (int) srp->res_used)); - if (srp->rq) { - if (srp->bio) - ret = blk_rq_unmap_user(srp->bio); + if (srp->bio) + ret = blk_rq_unmap_user(srp->bio); + if (srp->rq) { if (srp->rq->cmd != srp->rq->__cmd) kfree(srp->rq->cmd); blk_put_request(srp->rq); |