]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.18-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 22 Sep 2017 11:18:17 +0000 (13:18 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 22 Sep 2017 11:18:17 +0000 (13:18 +0200)
added patches:
scsi-qla2xxx-fix-an-integer-overflow-in-sysfs-code.patch
scsi-sg-factor-out-sg_fill_request_table.patch
scsi-sg-fixup-infoleak-when-using-sg_get_request_table.patch
scsi-sg-off-by-one-in-sg_ioctl.patch
scsi-sg-remove-save_scat_len.patch
scsi-sg-use-standard-lists-for-sg_requests.patch

queue-3.18/scsi-qla2xxx-fix-an-integer-overflow-in-sysfs-code.patch [new file with mode: 0644]
queue-3.18/scsi-sg-factor-out-sg_fill_request_table.patch [new file with mode: 0644]
queue-3.18/scsi-sg-fixup-infoleak-when-using-sg_get_request_table.patch [new file with mode: 0644]
queue-3.18/scsi-sg-off-by-one-in-sg_ioctl.patch [new file with mode: 0644]
queue-3.18/scsi-sg-remove-save_scat_len.patch [new file with mode: 0644]
queue-3.18/scsi-sg-use-standard-lists-for-sg_requests.patch [new file with mode: 0644]
queue-3.18/series

diff --git a/queue-3.18/scsi-qla2xxx-fix-an-integer-overflow-in-sysfs-code.patch b/queue-3.18/scsi-qla2xxx-fix-an-integer-overflow-in-sysfs-code.patch
new file mode 100644 (file)
index 0000000..d896f21
--- /dev/null
@@ -0,0 +1,62 @@
+From e6f77540c067b48dee10f1e33678415bfcc89017 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Wed, 30 Aug 2017 16:30:35 +0300
+Subject: scsi: qla2xxx: Fix an integer overflow in sysfs code
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit e6f77540c067b48dee10f1e33678415bfcc89017 upstream.
+
+The value of "size" comes from the user.  When we add "start + size" it
+could lead to an integer overflow bug.
+
+It means we vmalloc() a lot more memory than we had intended.  I believe
+that on 64 bit systems vmalloc() can succeed even if we ask it to
+allocate huge 4GB buffers.  So we would get memory corruption and likely
+a crash when we call ha->isp_ops->write_optrom() and ->read_optrom().
+
+Only root can trigger this bug.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=194061
+
+Fixes: b7cc176c9eb3 ("[SCSI] qla2xxx: Allow region-based flash-part accesses.")
+Reported-by: shqking <shqking@gmail.com>
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/qla2xxx/qla_attr.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/scsi/qla2xxx/qla_attr.c
++++ b/drivers/scsi/qla2xxx/qla_attr.c
+@@ -404,6 +404,8 @@ qla2x00_sysfs_write_optrom_ctl(struct fi
+               return -EINVAL;
+       if (start > ha->optrom_size)
+               return -EINVAL;
++      if (size > ha->optrom_size - start)
++              size = ha->optrom_size - start;
+       mutex_lock(&ha->optrom_mutex);
+       switch (val) {
+@@ -429,8 +431,7 @@ qla2x00_sysfs_write_optrom_ctl(struct fi
+               }
+               ha->optrom_region_start = start;
+-              ha->optrom_region_size = start + size > ha->optrom_size ?
+-                  ha->optrom_size - start : size;
++              ha->optrom_region_size = start + size;
+               ha->optrom_state = QLA_SREADING;
+               ha->optrom_buffer = vmalloc(ha->optrom_region_size);
+@@ -503,8 +504,7 @@ qla2x00_sysfs_write_optrom_ctl(struct fi
+               }
+               ha->optrom_region_start = start;
+-              ha->optrom_region_size = start + size > ha->optrom_size ?
+-                  ha->optrom_size - start : size;
++              ha->optrom_region_size = start + size;
+               ha->optrom_state = QLA_SWRITING;
+               ha->optrom_buffer = vmalloc(ha->optrom_region_size);
diff --git a/queue-3.18/scsi-sg-factor-out-sg_fill_request_table.patch b/queue-3.18/scsi-sg-factor-out-sg_fill_request_table.patch
new file mode 100644 (file)
index 0000000..b4475fb
--- /dev/null
@@ -0,0 +1,106 @@
+From 4759df905a474d245752c9dc94288e779b8734dd Mon Sep 17 00:00:00 2001
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 15 Sep 2017 14:05:15 +0200
+Subject: scsi: sg: factor out sg_fill_request_table()
+
+From: Hannes Reinecke <hare@suse.de>
+
+commit 4759df905a474d245752c9dc94288e779b8734dd upstream.
+
+Factor out sg_fill_request_table() for better readability.
+
+[mkp: typos, applied by hand]
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/sg.c |   61 ++++++++++++++++++++++++++++++------------------------
+ 1 file changed, 35 insertions(+), 26 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -854,6 +854,40 @@ static int max_sectors_bytes(struct requ
+       return max_sectors << 9;
+ }
++static void
++sg_fill_request_table(Sg_fd *sfp, sg_req_info_t *rinfo)
++{
++      Sg_request *srp;
++      int val;
++      unsigned int ms;
++
++      val = 0;
++      list_for_each_entry(srp, &sfp->rq_list, entry) {
++              if (val > SG_MAX_QUEUE)
++                      break;
++              memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
++              rinfo[val].req_state = srp->done + 1;
++              rinfo[val].problem =
++                      srp->header.masked_status &
++                      srp->header.host_status &
++                      srp->header.driver_status;
++              if (srp->done)
++                      rinfo[val].duration =
++                              srp->header.duration;
++              else {
++                      ms = jiffies_to_msecs(jiffies);
++                      rinfo[val].duration =
++                              (ms > srp->header.duration) ?
++                              (ms - srp->header.duration) : 0;
++              }
++              rinfo[val].orphan = srp->orphan;
++              rinfo[val].sg_io_owned = srp->sg_io_owned;
++              rinfo[val].pack_id = srp->header.pack_id;
++              rinfo[val].usr_ptr = srp->header.usr_ptr;
++              val++;
++      }
++}
++
+ static long
+ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
+ {
+@@ -1047,38 +1081,13 @@ sg_ioctl(struct file *filp, unsigned int
+                       return -EFAULT;
+               else {
+                       sg_req_info_t *rinfo;
+-                      unsigned int ms;
+                       rinfo = kmalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
+                                                               GFP_KERNEL);
+                       if (!rinfo)
+                               return -ENOMEM;
+                       read_lock_irqsave(&sfp->rq_list_lock, iflags);
+-                      val = 0;
+-                      list_for_each_entry(srp, &sfp->rq_list, entry) {
+-                              if (val >= SG_MAX_QUEUE)
+-                                      break;
+-                              memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
+-                              rinfo[val].req_state = srp->done + 1;
+-                              rinfo[val].problem =
+-                                      srp->header.masked_status &
+-                                      srp->header.host_status &
+-                                      srp->header.driver_status;
+-                              if (srp->done)
+-                                      rinfo[val].duration =
+-                                              srp->header.duration;
+-                              else {
+-                                      ms = jiffies_to_msecs(jiffies);
+-                                      rinfo[val].duration =
+-                                              (ms > srp->header.duration) ?
+-                                              (ms - srp->header.duration) : 0;
+-                              }
+-                              rinfo[val].orphan = srp->orphan;
+-                              rinfo[val].sg_io_owned = srp->sg_io_owned;
+-                              rinfo[val].pack_id = srp->header.pack_id;
+-                              rinfo[val].usr_ptr = srp->header.usr_ptr;
+-                              val++;
+-                      }
++                      sg_fill_request_table(sfp, rinfo);
+                       read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+                       result = __copy_to_user(p, rinfo,
+                                               SZ_SG_REQ_INFO * SG_MAX_QUEUE);
diff --git a/queue-3.18/scsi-sg-fixup-infoleak-when-using-sg_get_request_table.patch b/queue-3.18/scsi-sg-fixup-infoleak-when-using-sg_get_request_table.patch
new file mode 100644 (file)
index 0000000..bf3ff6f
--- /dev/null
@@ -0,0 +1,46 @@
+From 3e0097499839e0fe3af380410eababe5a47c4cf9 Mon Sep 17 00:00:00 2001
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 15 Sep 2017 14:05:16 +0200
+Subject: scsi: sg: fixup infoleak when using SG_GET_REQUEST_TABLE
+
+From: Hannes Reinecke <hare@suse.de>
+
+commit 3e0097499839e0fe3af380410eababe5a47c4cf9 upstream.
+
+When calling SG_GET_REQUEST_TABLE ioctl only a half-filled table is
+returned; the remaining part will then contain stale kernel memory
+information.  This patch zeroes out the entire table to avoid this
+issue.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Bart Van Assche <bart.vanassche@wdc.com>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/sg.c |    5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -865,7 +865,6 @@ sg_fill_request_table(Sg_fd *sfp, sg_req
+       list_for_each_entry(srp, &sfp->rq_list, entry) {
+               if (val > SG_MAX_QUEUE)
+                       break;
+-              memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
+               rinfo[val].req_state = srp->done + 1;
+               rinfo[val].problem =
+                       srp->header.masked_status &
+@@ -1082,8 +1081,8 @@ sg_ioctl(struct file *filp, unsigned int
+               else {
+                       sg_req_info_t *rinfo;
+-                      rinfo = kmalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
+-                                                              GFP_KERNEL);
++                      rinfo = kzalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE,
++                                      GFP_KERNEL);
+                       if (!rinfo)
+                               return -ENOMEM;
+                       read_lock_irqsave(&sfp->rq_list_lock, iflags);
diff --git a/queue-3.18/scsi-sg-off-by-one-in-sg_ioctl.patch b/queue-3.18/scsi-sg-off-by-one-in-sg_ioctl.patch
new file mode 100644 (file)
index 0000000..5642c64
--- /dev/null
@@ -0,0 +1,33 @@
+From bd46fc406b30d1db1aff8dabaff8d18bb423fdcf Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Thu, 17 Aug 2017 10:09:54 +0300
+Subject: scsi: sg: off by one in sg_ioctl()
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit bd46fc406b30d1db1aff8dabaff8d18bb423fdcf upstream.
+
+If "val" is SG_MAX_QUEUE then we are one element beyond the end of the
+"rinfo" array so the > should be >=.
+
+Fixes: 109bade9c625 ("scsi: sg: use standard lists for sg_requests")
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.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>
+
+---
+ drivers/scsi/sg.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -1056,7 +1056,7 @@ sg_ioctl(struct file *filp, unsigned int
+                       read_lock_irqsave(&sfp->rq_list_lock, iflags);
+                       val = 0;
+                       list_for_each_entry(srp, &sfp->rq_list, entry) {
+-                              if (val > SG_MAX_QUEUE)
++                              if (val >= SG_MAX_QUEUE)
+                                       break;
+                               memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
+                               rinfo[val].req_state = srp->done + 1;
diff --git a/queue-3.18/scsi-sg-remove-save_scat_len.patch b/queue-3.18/scsi-sg-remove-save_scat_len.patch
new file mode 100644 (file)
index 0000000..e6b6376
--- /dev/null
@@ -0,0 +1,40 @@
+From 136e57bf43dc4babbfb8783abbf707d483cacbe3 Mon Sep 17 00:00:00 2001
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 7 Apr 2017 09:34:13 +0200
+Subject: scsi: sg: remove 'save_scat_len'
+
+From: Hannes Reinecke <hare@suse.de>
+
+commit 136e57bf43dc4babbfb8783abbf707d483cacbe3 upstream.
+
+Unused.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Tested-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/sg.c |    2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -157,7 +157,6 @@ typedef struct sg_fd {             /* holds the sta
+       int timeout;            /* defaults to SG_DEFAULT_TIMEOUT      */
+       int timeout_user;       /* defaults to SG_DEFAULT_TIMEOUT_USER */
+       Sg_scatter_hold reserve;        /* buffer held for this file descriptor */
+-      unsigned save_scat_len; /* original length of trunc. scat. element */
+       Sg_request *headrp;     /* head of request slist, NULL->empty */
+       struct fasync_struct *async_qp; /* used by asynchronous notification */
+       Sg_request req_arr[SG_MAX_QUEUE];       /* used as singly-linked list */
+@@ -2105,7 +2104,6 @@ sg_unlink_reserve(Sg_fd * sfp, Sg_reques
+       req_schp->pages = NULL;
+       req_schp->page_order = 0;
+       req_schp->sglist_len = 0;
+-      sfp->save_scat_len = 0;
+       srp->res_used = 0;
+       /* Called without mutex lock to avoid deadlock */
+       sfp->res_in_use = 0;
diff --git a/queue-3.18/scsi-sg-use-standard-lists-for-sg_requests.patch b/queue-3.18/scsi-sg-use-standard-lists-for-sg_requests.patch
new file mode 100644 (file)
index 0000000..fe1b418
--- /dev/null
@@ -0,0 +1,290 @@
+From 109bade9c625c89bb5ea753aaa1a0a97e6fbb548 Mon Sep 17 00:00:00 2001
+From: Hannes Reinecke <hare@suse.de>
+Date: Fri, 7 Apr 2017 09:34:16 +0200
+Subject: scsi: sg: use standard lists for sg_requests
+
+From: Hannes Reinecke <hare@suse.de>
+
+commit 109bade9c625c89bb5ea753aaa1a0a97e6fbb548 upstream.
+
+'Sg_request' is using a private list implementation; convert it to
+standard lists.
+
+Signed-off-by: Hannes Reinecke <hare@suse.com>
+Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
+Tested-by: Johannes Thumshirn <jthumshirn@suse.de>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/sg.c |  147 ++++++++++++++++++++++--------------------------------
+ 1 file changed, 61 insertions(+), 86 deletions(-)
+
+--- a/drivers/scsi/sg.c
++++ b/drivers/scsi/sg.c
+@@ -133,7 +133,7 @@ struct sg_device;          /* forward declaratio
+ struct sg_fd;
+ typedef struct sg_request {   /* SG_MAX_QUEUE requests outstanding per file */
+-      struct sg_request *nextrp;      /* NULL -> tail request (slist) */
++      struct list_head entry; /* list entry */
+       struct sg_fd *parentfp; /* NULL -> not in use */
+       Sg_scatter_hold data;   /* hold buffer, perhaps scatter list */
+       sg_io_hdr_t header;     /* scsi command+info, see <scsi/sg.h> */
+@@ -157,7 +157,7 @@ typedef struct sg_fd {             /* holds the sta
+       int timeout;            /* defaults to SG_DEFAULT_TIMEOUT      */
+       int timeout_user;       /* defaults to SG_DEFAULT_TIMEOUT_USER */
+       Sg_scatter_hold reserve;        /* buffer held for this file descriptor */
+-      Sg_request *headrp;     /* head of request slist, NULL->empty */
++      struct list_head rq_list; /* head of request list */
+       struct fasync_struct *async_qp; /* used by asynchronous notification */
+       Sg_request req_arr[SG_MAX_QUEUE];       /* used as singly-linked list */
+       char low_dma;           /* as in parent but possibly overridden to 1 */
+@@ -965,7 +965,7 @@ sg_ioctl(struct file *filp, unsigned int
+               if (!access_ok(VERIFY_WRITE, ip, sizeof (int)))
+                       return -EFAULT;
+               read_lock_irqsave(&sfp->rq_list_lock, iflags);
+-              for (srp = sfp->headrp; srp; srp = srp->nextrp) {
++              list_for_each_entry(srp, &sfp->rq_list, entry) {
+                       if ((1 == srp->done) && (!srp->sg_io_owned)) {
+                               read_unlock_irqrestore(&sfp->rq_list_lock,
+                                                      iflags);
+@@ -978,7 +978,8 @@ sg_ioctl(struct file *filp, unsigned int
+               return 0;
+       case SG_GET_NUM_WAITING:
+               read_lock_irqsave(&sfp->rq_list_lock, iflags);
+-              for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) {
++              val = 0;
++              list_for_each_entry(srp, &sfp->rq_list, entry) {
+                       if ((1 == srp->done) && (!srp->sg_io_owned))
+                               ++val;
+               }
+@@ -1053,35 +1054,33 @@ sg_ioctl(struct file *filp, unsigned int
+                       if (!rinfo)
+                               return -ENOMEM;
+                       read_lock_irqsave(&sfp->rq_list_lock, iflags);
+-                      for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
+-                           ++val, srp = srp ? srp->nextrp : srp) {
++                      val = 0;
++                      list_for_each_entry(srp, &sfp->rq_list, entry) {
++                              if (val > SG_MAX_QUEUE)
++                                      break;
+                               memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
+-                              if (srp) {
+-                                      rinfo[val].req_state = srp->done + 1;
+-                                      rinfo[val].problem =
+-                                          srp->header.masked_status & 
+-                                          srp->header.host_status & 
+-                                          srp->header.driver_status;
+-                                      if (srp->done)
+-                                              rinfo[val].duration =
+-                                                      srp->header.duration;
+-                                      else {
+-                                              ms = jiffies_to_msecs(jiffies);
+-                                              rinfo[val].duration =
+-                                                  (ms > srp->header.duration) ?
+-                                                  (ms - srp->header.duration) : 0;
+-                                      }
+-                                      rinfo[val].orphan = srp->orphan;
+-                                      rinfo[val].sg_io_owned =
+-                                                      srp->sg_io_owned;
+-                                      rinfo[val].pack_id =
+-                                                      srp->header.pack_id;
+-                                      rinfo[val].usr_ptr =
+-                                                      srp->header.usr_ptr;
++                              rinfo[val].req_state = srp->done + 1;
++                              rinfo[val].problem =
++                                      srp->header.masked_status &
++                                      srp->header.host_status &
++                                      srp->header.driver_status;
++                              if (srp->done)
++                                      rinfo[val].duration =
++                                              srp->header.duration;
++                              else {
++                                      ms = jiffies_to_msecs(jiffies);
++                                      rinfo[val].duration =
++                                              (ms > srp->header.duration) ?
++                                              (ms - srp->header.duration) : 0;
+                               }
++                              rinfo[val].orphan = srp->orphan;
++                              rinfo[val].sg_io_owned = srp->sg_io_owned;
++                              rinfo[val].pack_id = srp->header.pack_id;
++                              rinfo[val].usr_ptr = srp->header.usr_ptr;
++                              val++;
+                       }
+                       read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+-                      result = __copy_to_user(p, rinfo, 
++                      result = __copy_to_user(p, rinfo,
+                                               SZ_SG_REQ_INFO * SG_MAX_QUEUE);
+                       result = result ? -EFAULT : 0;
+                       kfree(rinfo);
+@@ -1213,7 +1212,7 @@ sg_poll(struct file *filp, poll_table *
+               return POLLERR;
+       poll_wait(filp, &sfp->read_wait, wait);
+       read_lock_irqsave(&sfp->rq_list_lock, iflags);
+-      for (srp = sfp->headrp; srp; srp = srp->nextrp) {
++      list_for_each_entry(srp, &sfp->rq_list, entry) {
+               /* if any read waiting, flag it */
+               if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned))
+                       res = POLLIN | POLLRDNORM;
+@@ -2116,7 +2115,7 @@ sg_get_rq_mark(Sg_fd * sfp, int pack_id)
+       unsigned long iflags;
+       write_lock_irqsave(&sfp->rq_list_lock, iflags);
+-      for (resp = sfp->headrp; resp; resp = resp->nextrp) {
++      list_for_each_entry(resp, &sfp->rq_list, entry) {
+               /* look for requests that are ready + not SG_IO owned */
+               if ((1 == resp->done) && (!resp->sg_io_owned) &&
+                   ((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
+@@ -2134,70 +2133,45 @@ sg_add_request(Sg_fd * sfp)
+ {
+       int k;
+       unsigned long iflags;
+-      Sg_request *resp;
+       Sg_request *rp = sfp->req_arr;
+       write_lock_irqsave(&sfp->rq_list_lock, iflags);
+-      resp = sfp->headrp;
+-      if (!resp) {
+-              memset(rp, 0, sizeof (Sg_request));
+-              rp->parentfp = sfp;
+-              resp = rp;
+-              sfp->headrp = resp;
+-      } else {
+-              if (0 == sfp->cmd_q)
+-                      resp = NULL;    /* command queuing disallowed */
+-              else {
+-                      for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
+-                              if (!rp->parentfp)
+-                                      break;
+-                      }
+-                      if (k < SG_MAX_QUEUE) {
+-                              memset(rp, 0, sizeof (Sg_request));
+-                              rp->parentfp = sfp;
+-                              while (resp->nextrp)
+-                                      resp = resp->nextrp;
+-                              resp->nextrp = rp;
+-                              resp = rp;
+-                      } else
+-                              resp = NULL;
++      if (!list_empty(&sfp->rq_list)) {
++              if (!sfp->cmd_q)
++                      goto out_unlock;
++
++              for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
++                      if (!rp->parentfp)
++                              break;
+               }
++              if (k >= SG_MAX_QUEUE)
++                      goto out_unlock;
+       }
+-      if (resp) {
+-              resp->nextrp = NULL;
+-              resp->header.duration = jiffies_to_msecs(jiffies);
+-      }
++      memset(rp, 0, sizeof (Sg_request));
++      rp->parentfp = sfp;
++      rp->header.duration = jiffies_to_msecs(jiffies);
++      list_add_tail(&rp->entry, &sfp->rq_list);
+       write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+-      return resp;
++      return rp;
++out_unlock:
++      write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
++      return NULL;
+ }
+ /* Return of 1 for found; 0 for not found */
+ static int
+ sg_remove_request(Sg_fd * sfp, Sg_request * srp)
+ {
+-      Sg_request *prev_rp;
+-      Sg_request *rp;
+       unsigned long iflags;
+       int res = 0;
+-      if ((!sfp) || (!srp) || (!sfp->headrp))
++      if (!sfp || !srp || list_empty(&sfp->rq_list))
+               return res;
+       write_lock_irqsave(&sfp->rq_list_lock, iflags);
+-      prev_rp = sfp->headrp;
+-      if (srp == prev_rp) {
+-              sfp->headrp = prev_rp->nextrp;
+-              prev_rp->parentfp = NULL;
++      if (!list_empty(&srp->entry)) {
++              list_del(&srp->entry);
++              srp->parentfp = NULL;
+               res = 1;
+-      } else {
+-              while ((rp = prev_rp->nextrp)) {
+-                      if (srp == rp) {
+-                              prev_rp->nextrp = rp->nextrp;
+-                              rp->parentfp = NULL;
+-                              res = 1;
+-                              break;
+-                      }
+-                      prev_rp = rp;
+-              }
+       }
+       write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+       return res;
+@@ -2216,7 +2190,7 @@ sg_add_sfp(Sg_device * sdp)
+       init_waitqueue_head(&sfp->read_wait);
+       rwlock_init(&sfp->rq_list_lock);
+-
++      INIT_LIST_HEAD(&sfp->rq_list);
+       kref_init(&sfp->f_ref);
+       mutex_init(&sfp->f_mutex);
+       sfp->timeout = SG_DEFAULT_TIMEOUT;
+@@ -2257,10 +2231,13 @@ sg_remove_sfp_usercontext(struct work_st
+ {
+       struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work);
+       struct sg_device *sdp = sfp->parentdp;
++      Sg_request *srp;
+       /* Cleanup any responses which were never read(). */
+-      while (sfp->headrp)
+-              sg_finish_rem_req(sfp->headrp);
++      while (!list_empty(&sfp->rq_list)) {
++              srp = list_first_entry(&sfp->rq_list, Sg_request, entry);
++              sg_finish_rem_req(srp);
++      }
+       if (sfp->reserve.bufflen > 0) {
+               SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp,
+@@ -2663,7 +2640,7 @@ static int sg_proc_seq_show_devstrs(stru
+ /* must be called while holding sg_index_lock */
+ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
+ {
+-      int k, m, new_interface, blen, usg;
++      int k, new_interface, blen, usg;
+       Sg_request *srp;
+       Sg_fd *fp;
+       const sg_io_hdr_t *hp;
+@@ -2683,13 +2660,11 @@ static void sg_proc_debug_helper(struct
+               seq_printf(s, "   cmd_q=%d f_packid=%d k_orphan=%d closed=0\n",
+                          (int) fp->cmd_q, (int) fp->force_packid,
+                          (int) fp->keep_orphan);
+-              for (m = 0, srp = fp->headrp;
+-                              srp != NULL;
+-                              ++m, srp = srp->nextrp) {
++              list_for_each_entry(srp, &fp->rq_list, entry) {
+                       hp = &srp->header;
+                       new_interface = (hp->interface_id == '\0') ? 0 : 1;
+                       if (srp->res_used) {
+-                              if (new_interface && 
++                              if (new_interface &&
+                                   (SG_FLAG_MMAP_IO & hp->flags))
+                                       cp = "     mmap>> ";
+                               else
+@@ -2720,7 +2695,7 @@ static void sg_proc_debug_helper(struct
+                       seq_printf(s, "ms sgat=%d op=0x%02x\n", usg,
+                                  (int) srp->data.cmd_opcode);
+               }
+-              if (0 == m)
++              if (list_empty(&fp->rq_list))
+                       seq_puts(s, "     No requests active\n");
+               read_unlock(&fp->rq_list_lock);
+       }
index a981176b34ed2a47de34891e903979d69b65a0ca..0e9ac4d0cd1ccf30afc965df5250d361e1cdd655 100644 (file)
@@ -21,3 +21,9 @@ scsi-zfcp-fix-missing-trace-records-for-early-returns-in-tmf-eh-handlers.patch
 scsi-zfcp-fix-payload-with-full-fcp_rsp-iu-in-scsi-trace-records.patch
 scsi-zfcp-trace-hba-fsf-response-by-default-on-dismiss-or-timedout-late-response.patch
 scsi-zfcp-trace-high-part-of-new-64-bit-scsi-lun.patch
+scsi-sg-remove-save_scat_len.patch
+scsi-sg-use-standard-lists-for-sg_requests.patch
+scsi-sg-off-by-one-in-sg_ioctl.patch
+scsi-sg-factor-out-sg_fill_request_table.patch
+scsi-sg-fixup-infoleak-when-using-sg_get_request_table.patch
+scsi-qla2xxx-fix-an-integer-overflow-in-sysfs-code.patch