summaryrefslogtreecommitdiffstats
path: root/queue-3.16/scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch
diff options
context:
space:
mode:
Diffstat (limited to 'queue-3.16/scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch')
-rw-r--r--queue-3.16/scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch45
1 files changed, 45 insertions, 0 deletions
diff --git a/queue-3.16/scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch b/queue-3.16/scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch
new file mode 100644
index 00000000..d40b3a94
--- /dev/null
+++ b/queue-3.16/scsi-sg-recheck-mmap_io-request-length-with-lock-held.patch
@@ -0,0 +1,45 @@
+From: Todd Poynor <toddpoynor@google.com>
+Date: Tue, 15 Aug 2017 21:48:43 -0700
+Subject: scsi: sg: recheck MMAP_IO request length with lock held
+
+commit 8d26f491116feaa0b16de370b6a7ba40a40fa0b4 upstream.
+
+Commit 1bc0eb044615 ("scsi: sg: protect accesses to 'reserved' page
+array") adds needed concurrency protection for the "reserve" buffer.
+Some checks that are initially made outside the lock are replicated once
+the lock is taken to ensure the checks and resulting decisions are made
+using consistent state.
+
+The check that a request with flag SG_FLAG_MMAP_IO set fits in the
+reserve buffer also needs to be performed again under the lock to ensure
+the reserve buffer length compared against matches the value in effect
+when the request is linked to the reserve buffer. An -ENOMEM should be
+returned in this case, instead of switching over to an indirect buffer
+as for non-MMAP_IO requests.
+
+Signed-off-by: Todd Poynor <toddpoynor@google.com>
+Acked-by: Douglas Gilbert <dgilbert@interlog.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+---
+ drivers/scsi/sg.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -1772,9 +1772,12 @@ sg_start_req(Sg_request *srp, unsigned c
+ !sfp->res_in_use) {
+ sfp->res_in_use = 1;
+ sg_link_reserve(sfp, srp, dxfer_len);
+- } else if ((hp->flags & SG_FLAG_MMAP_IO) && sfp->res_in_use) {
++ } else if (hp->flags & SG_FLAG_MMAP_IO) {
++ res = -EBUSY; /* sfp->res_in_use == 1 */
++ if (dxfer_len > rsv_schp->bufflen)
++ res = -ENOMEM;
+ mutex_unlock(&sfp->f_mutex);
+- return -EBUSY;
++ return res;
+ } else {
+ res = sg_build_indirect(req_schp, sfp, dxfer_len);
+ if (res) {