From: Greg Kroah-Hartman Date: Thu, 12 Mar 2015 14:16:18 +0000 (+0100) Subject: 3.14-stable patches X-Git-Tag: v3.10.72~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fa8ec4818a8e2fc9efa614725b2a83b41edbc106;p=thirdparty%2Fkernel%2Fstable-queue.git 3.14-stable patches added patches: ib-core-fix-deadlock-on-uverbs-modify_qp-error-flow.patch ib-core-when-marshaling-ucma-path-from-user-space-clear-unused-fields.patch ib-mlx4-fix-wrong-usage-of-ipv4-protocol-for-multicast-attach-detach.patch ib-qib-do-not-write-eeprom.patch sg-fix-read-error-reporting.patch --- diff --git a/queue-3.14/ib-core-fix-deadlock-on-uverbs-modify_qp-error-flow.patch b/queue-3.14/ib-core-fix-deadlock-on-uverbs-modify_qp-error-flow.patch new file mode 100644 index 00000000000..fbe2109c1c3 --- /dev/null +++ b/queue-3.14/ib-core-fix-deadlock-on-uverbs-modify_qp-error-flow.patch @@ -0,0 +1,51 @@ +From 0fb8bcf022f19a375d7c4bd79ac513da8ae6d78b Mon Sep 17 00:00:00 2001 +From: Moshe Lazer +Date: Thu, 5 Feb 2015 13:53:52 +0200 +Subject: IB/core: Fix deadlock on uverbs modify_qp error flow + +From: Moshe Lazer + +commit 0fb8bcf022f19a375d7c4bd79ac513da8ae6d78b upstream. + +The deadlock occurs in __uverbs_modify_qp: we take a lock (idr_read_qp) +and in case of failure in ib_resolve_eth_l2_attrs we don't release +it (put_qp_read). Fix that. + +Fixes: ed4c54e5b4ba ("IB/core: Resolve Ethernet L2 addresses when modifying QP") +Signed-off-by: Moshe Lazer +Signed-off-by: Or Gerlitz +Signed-off-by: Roland Dreier +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/infiniband/core/uverbs_cmd.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -1964,20 +1964,21 @@ ssize_t ib_uverbs_modify_qp(struct ib_uv + if (qp->real_qp == qp) { + ret = ib_resolve_eth_l2_attrs(qp, attr, &cmd.attr_mask); + if (ret) +- goto out; ++ goto release_qp; + ret = qp->device->modify_qp(qp, attr, + modify_qp_mask(qp->qp_type, cmd.attr_mask), &udata); + } else { + ret = ib_modify_qp(qp, attr, modify_qp_mask(qp->qp_type, cmd.attr_mask)); + } + +- put_qp_read(qp); +- + if (ret) +- goto out; ++ goto release_qp; + + ret = in_len; + ++release_qp: ++ put_qp_read(qp); ++ + out: + kfree(attr); + diff --git a/queue-3.14/ib-core-when-marshaling-ucma-path-from-user-space-clear-unused-fields.patch b/queue-3.14/ib-core-when-marshaling-ucma-path-from-user-space-clear-unused-fields.patch new file mode 100644 index 00000000000..c35400a8840 --- /dev/null +++ b/queue-3.14/ib-core-when-marshaling-ucma-path-from-user-space-clear-unused-fields.patch @@ -0,0 +1,37 @@ +From c2be9dc0e0fa59cc43c2c7084fc42b430809a0fe Mon Sep 17 00:00:00 2001 +From: Ilya Nelkenbaum +Date: Thu, 5 Feb 2015 13:53:48 +0200 +Subject: IB/core: When marshaling ucma path from user-space, clear unused fields + +From: Ilya Nelkenbaum + +commit c2be9dc0e0fa59cc43c2c7084fc42b430809a0fe upstream. + +When marshaling a user path to the kernel struct ib_sa_path, we need +to zero smac and dmac and set the vlan id to the "no vlan" value. + +This is to ensure that Ethernet attributes are not used with +InfiniBand QPs. + +Fixes: dd5f03beb4f7 ("IB/core: Ethernet L2 attributes in verbs/cm structures") +Signed-off-by: Ilya Nelkenbaum +Signed-off-by: Or Gerlitz +Signed-off-by: Roland Dreier +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/infiniband/core/ucma.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/infiniband/core/ucma.c ++++ b/drivers/infiniband/core/ucma.c +@@ -1124,6 +1124,9 @@ static int ucma_set_ib_path(struct ucma_ + if (!optlen) + return -EINVAL; + ++ memset(&sa_path, 0, sizeof(sa_path)); ++ sa_path.vlan_id = 0xffff; ++ + ib_sa_unpack_path(path_data->path_rec, &sa_path); + ret = rdma_set_ib_paths(ctx->cm_id, &sa_path, 1); + if (ret) diff --git a/queue-3.14/ib-mlx4-fix-wrong-usage-of-ipv4-protocol-for-multicast-attach-detach.patch b/queue-3.14/ib-mlx4-fix-wrong-usage-of-ipv4-protocol-for-multicast-attach-detach.patch new file mode 100644 index 00000000000..7e68de39207 --- /dev/null +++ b/queue-3.14/ib-mlx4-fix-wrong-usage-of-ipv4-protocol-for-multicast-attach-detach.patch @@ -0,0 +1,56 @@ +From e9a7faf11af94957e5107b40af46c2e329541510 Mon Sep 17 00:00:00 2001 +From: Or Gerlitz +Date: Wed, 17 Dec 2014 16:17:34 +0200 +Subject: IB/mlx4: Fix wrong usage of IPv4 protocol for multicast attach/detach + +From: Or Gerlitz + +commit e9a7faf11af94957e5107b40af46c2e329541510 upstream. + +The MLX4_PROT_IB_IPV4 protocol should only be used with RoCEv2 and such. +Removing this wrong usage allows to run multicast applications over RoCE. + +Fixes: d487ee77740c ("IB/mlx4: Use IBoE (RoCE) IP based GIDs in the port GID table") +Reported-by: Carol Soto +Signed-off-by: Or Gerlitz +Signed-off-by: Roland Dreier +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/infiniband/hw/mlx4/main.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/infiniband/hw/mlx4/main.c ++++ b/drivers/infiniband/hw/mlx4/main.c +@@ -1161,8 +1161,7 @@ static int mlx4_ib_mcg_attach(struct ib_ + struct mlx4_ib_qp *mqp = to_mqp(ibqp); + u64 reg_id; + struct mlx4_ib_steering *ib_steering = NULL; +- enum mlx4_protocol prot = (gid->raw[1] == 0x0e) ? +- MLX4_PROT_IB_IPV4 : MLX4_PROT_IB_IPV6; ++ enum mlx4_protocol prot = MLX4_PROT_IB_IPV6; + + if (mdev->dev->caps.steering_mode == + MLX4_STEERING_MODE_DEVICE_MANAGED) { +@@ -1175,8 +1174,10 @@ static int mlx4_ib_mcg_attach(struct ib_ + !!(mqp->flags & + MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), + prot, ®_id); +- if (err) ++ if (err) { ++ pr_err("multicast attach op failed, err %d\n", err); + goto err_malloc; ++ } + + err = add_gid_entry(ibqp, gid); + if (err) +@@ -1224,8 +1225,7 @@ static int mlx4_ib_mcg_detach(struct ib_ + struct net_device *ndev; + struct mlx4_ib_gid_entry *ge; + u64 reg_id = 0; +- enum mlx4_protocol prot = (gid->raw[1] == 0x0e) ? +- MLX4_PROT_IB_IPV4 : MLX4_PROT_IB_IPV6; ++ enum mlx4_protocol prot = MLX4_PROT_IB_IPV6; + + if (mdev->dev->caps.steering_mode == + MLX4_STEERING_MODE_DEVICE_MANAGED) { diff --git a/queue-3.14/ib-qib-do-not-write-eeprom.patch b/queue-3.14/ib-qib-do-not-write-eeprom.patch new file mode 100644 index 00000000000..b983aebe800 --- /dev/null +++ b/queue-3.14/ib-qib-do-not-write-eeprom.patch @@ -0,0 +1,340 @@ +From 18c0b82a3e4501511b08d0e8676fb08ac08734a3 Mon Sep 17 00:00:00 2001 +From: Mitko Haralanov +Date: Fri, 16 Jan 2015 08:55:27 -0500 +Subject: IB/qib: Do not write EEPROM + +From: Mitko Haralanov + +commit 18c0b82a3e4501511b08d0e8676fb08ac08734a3 upstream. + +This changeset removes all the code that allows the driver to write to +the EEPROM and update the recorded error counters and power on hours. + +These two stats are unused and writing them exposes a timing risk +which could leave the EEPROM in a bad state preventing further normal +operation of the HCA. + +Reviewed-by: Mike Marciniszyn +Signed-off-by: Mitko Haralanov +Signed-off-by: Mike Marciniszyn +Signed-off-by: Roland Dreier +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/infiniband/hw/qib/qib.h | 9 - + drivers/infiniband/hw/qib/qib_eeprom.c | 181 -------------------------------- + drivers/infiniband/hw/qib/qib_iba6120.c | 2 + drivers/infiniband/hw/qib/qib_iba7220.c | 2 + drivers/infiniband/hw/qib/qib_iba7322.c | 2 + drivers/infiniband/hw/qib/qib_init.c | 1 + drivers/infiniband/hw/qib/qib_sysfs.c | 24 ---- + 7 files changed, 1 insertion(+), 220 deletions(-) + +--- a/drivers/infiniband/hw/qib/qib.h ++++ b/drivers/infiniband/hw/qib/qib.h +@@ -1080,12 +1080,6 @@ struct qib_devdata { + /* control high-level access to EEPROM */ + struct mutex eep_lock; + uint64_t traffic_wds; +- /* active time is kept in seconds, but logged in hours */ +- atomic_t active_time; +- /* Below are nominal shadow of EEPROM, new since last EEPROM update */ +- uint8_t eep_st_errs[QIB_EEP_LOG_CNT]; +- uint8_t eep_st_new_errs[QIB_EEP_LOG_CNT]; +- uint16_t eep_hrs; + /* + * masks for which bits of errs, hwerrs that cause + * each of the counters to increment. +@@ -1307,8 +1301,7 @@ int qib_twsi_blk_rd(struct qib_devdata * + int qib_twsi_blk_wr(struct qib_devdata *dd, int dev, int addr, + const void *buffer, int len); + void qib_get_eeprom_info(struct qib_devdata *); +-int qib_update_eeprom_log(struct qib_devdata *dd); +-void qib_inc_eeprom_err(struct qib_devdata *dd, u32 eidx, u32 incr); ++#define qib_inc_eeprom_err(dd, eidx, incr) + void qib_dump_lookup_output_queue(struct qib_devdata *); + void qib_force_pio_avail_update(struct qib_devdata *); + void qib_clear_symerror_on_linkup(unsigned long opaque); +--- a/drivers/infiniband/hw/qib/qib_eeprom.c ++++ b/drivers/infiniband/hw/qib/qib_eeprom.c +@@ -267,190 +267,9 @@ void qib_get_eeprom_info(struct qib_devd + "Board SN %s did not pass functional test: %s\n", + dd->serial, ifp->if_comment); + +- memcpy(&dd->eep_st_errs, &ifp->if_errcntp, QIB_EEP_LOG_CNT); +- /* +- * Power-on (actually "active") hours are kept as little-endian value +- * in EEPROM, but as seconds in a (possibly as small as 24-bit) +- * atomic_t while running. +- */ +- atomic_set(&dd->active_time, 0); +- dd->eep_hrs = ifp->if_powerhour[0] | (ifp->if_powerhour[1] << 8); +- + done: + vfree(buf); + + bail:; + } + +-/** +- * qib_update_eeprom_log - copy active-time and error counters to eeprom +- * @dd: the qlogic_ib device +- * +- * Although the time is kept as seconds in the qib_devdata struct, it is +- * rounded to hours for re-write, as we have only 16 bits in EEPROM. +- * First-cut code reads whole (expected) struct qib_flash, modifies, +- * re-writes. Future direction: read/write only what we need, assuming +- * that the EEPROM had to have been "good enough" for driver init, and +- * if not, we aren't making it worse. +- * +- */ +-int qib_update_eeprom_log(struct qib_devdata *dd) +-{ +- void *buf; +- struct qib_flash *ifp; +- int len, hi_water; +- uint32_t new_time, new_hrs; +- u8 csum; +- int ret, idx; +- unsigned long flags; +- +- /* first, check if we actually need to do anything. */ +- ret = 0; +- for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) { +- if (dd->eep_st_new_errs[idx]) { +- ret = 1; +- break; +- } +- } +- new_time = atomic_read(&dd->active_time); +- +- if (ret == 0 && new_time < 3600) +- goto bail; +- +- /* +- * The quick-check above determined that there is something worthy +- * of logging, so get current contents and do a more detailed idea. +- * read full flash, not just currently used part, since it may have +- * been written with a newer definition +- */ +- len = sizeof(struct qib_flash); +- buf = vmalloc(len); +- ret = 1; +- if (!buf) { +- qib_dev_err(dd, +- "Couldn't allocate memory to read %u bytes from eeprom for logging\n", +- len); +- goto bail; +- } +- +- /* Grab semaphore and read current EEPROM. If we get an +- * error, let go, but if not, keep it until we finish write. +- */ +- ret = mutex_lock_interruptible(&dd->eep_lock); +- if (ret) { +- qib_dev_err(dd, "Unable to acquire EEPROM for logging\n"); +- goto free_bail; +- } +- ret = qib_twsi_blk_rd(dd, dd->twsi_eeprom_dev, 0, buf, len); +- if (ret) { +- mutex_unlock(&dd->eep_lock); +- qib_dev_err(dd, "Unable read EEPROM for logging\n"); +- goto free_bail; +- } +- ifp = (struct qib_flash *)buf; +- +- csum = flash_csum(ifp, 0); +- if (csum != ifp->if_csum) { +- mutex_unlock(&dd->eep_lock); +- qib_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n", +- csum, ifp->if_csum); +- ret = 1; +- goto free_bail; +- } +- hi_water = 0; +- spin_lock_irqsave(&dd->eep_st_lock, flags); +- for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) { +- int new_val = dd->eep_st_new_errs[idx]; +- if (new_val) { +- /* +- * If we have seen any errors, add to EEPROM values +- * We need to saturate at 0xFF (255) and we also +- * would need to adjust the checksum if we were +- * trying to minimize EEPROM traffic +- * Note that we add to actual current count in EEPROM, +- * in case it was altered while we were running. +- */ +- new_val += ifp->if_errcntp[idx]; +- if (new_val > 0xFF) +- new_val = 0xFF; +- if (ifp->if_errcntp[idx] != new_val) { +- ifp->if_errcntp[idx] = new_val; +- hi_water = offsetof(struct qib_flash, +- if_errcntp) + idx; +- } +- /* +- * update our shadow (used to minimize EEPROM +- * traffic), to match what we are about to write. +- */ +- dd->eep_st_errs[idx] = new_val; +- dd->eep_st_new_errs[idx] = 0; +- } +- } +- /* +- * Now update active-time. We would like to round to the nearest hour +- * but unless atomic_t are sure to be proper signed ints we cannot, +- * because we need to account for what we "transfer" to EEPROM and +- * if we log an hour at 31 minutes, then we would need to set +- * active_time to -29 to accurately count the _next_ hour. +- */ +- if (new_time >= 3600) { +- new_hrs = new_time / 3600; +- atomic_sub((new_hrs * 3600), &dd->active_time); +- new_hrs += dd->eep_hrs; +- if (new_hrs > 0xFFFF) +- new_hrs = 0xFFFF; +- dd->eep_hrs = new_hrs; +- if ((new_hrs & 0xFF) != ifp->if_powerhour[0]) { +- ifp->if_powerhour[0] = new_hrs & 0xFF; +- hi_water = offsetof(struct qib_flash, if_powerhour); +- } +- if ((new_hrs >> 8) != ifp->if_powerhour[1]) { +- ifp->if_powerhour[1] = new_hrs >> 8; +- hi_water = offsetof(struct qib_flash, if_powerhour) + 1; +- } +- } +- /* +- * There is a tiny possibility that we could somehow fail to write +- * the EEPROM after updating our shadows, but problems from holding +- * the spinlock too long are a much bigger issue. +- */ +- spin_unlock_irqrestore(&dd->eep_st_lock, flags); +- if (hi_water) { +- /* we made some change to the data, uopdate cksum and write */ +- csum = flash_csum(ifp, 1); +- ret = eeprom_write_with_enable(dd, 0, buf, hi_water + 1); +- } +- mutex_unlock(&dd->eep_lock); +- if (ret) +- qib_dev_err(dd, "Failed updating EEPROM\n"); +- +-free_bail: +- vfree(buf); +-bail: +- return ret; +-} +- +-/** +- * qib_inc_eeprom_err - increment one of the four error counters +- * that are logged to EEPROM. +- * @dd: the qlogic_ib device +- * @eidx: 0..3, the counter to increment +- * @incr: how much to add +- * +- * Each counter is 8-bits, and saturates at 255 (0xFF). They +- * are copied to the EEPROM (aka flash) whenever qib_update_eeprom_log() +- * is called, but it can only be called in a context that allows sleep. +- * This function can be called even at interrupt level. +- */ +-void qib_inc_eeprom_err(struct qib_devdata *dd, u32 eidx, u32 incr) +-{ +- uint new_val; +- unsigned long flags; +- +- spin_lock_irqsave(&dd->eep_st_lock, flags); +- new_val = dd->eep_st_new_errs[eidx] + incr; +- if (new_val > 255) +- new_val = 255; +- dd->eep_st_new_errs[eidx] = new_val; +- spin_unlock_irqrestore(&dd->eep_st_lock, flags); +-} +--- a/drivers/infiniband/hw/qib/qib_iba6120.c ++++ b/drivers/infiniband/hw/qib/qib_iba6120.c +@@ -2682,8 +2682,6 @@ static void qib_get_6120_faststats(unsig + spin_lock_irqsave(&dd->eep_st_lock, flags); + traffic_wds -= dd->traffic_wds; + dd->traffic_wds += traffic_wds; +- if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD) +- atomic_add(5, &dd->active_time); /* S/B #define */ + spin_unlock_irqrestore(&dd->eep_st_lock, flags); + + qib_chk_6120_errormask(dd); +--- a/drivers/infiniband/hw/qib/qib_iba7220.c ++++ b/drivers/infiniband/hw/qib/qib_iba7220.c +@@ -3299,8 +3299,6 @@ static void qib_get_7220_faststats(unsig + spin_lock_irqsave(&dd->eep_st_lock, flags); + traffic_wds -= dd->traffic_wds; + dd->traffic_wds += traffic_wds; +- if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD) +- atomic_add(5, &dd->active_time); /* S/B #define */ + spin_unlock_irqrestore(&dd->eep_st_lock, flags); + done: + mod_timer(&dd->stats_timer, jiffies + HZ * ACTIVITY_TIMER); +--- a/drivers/infiniband/hw/qib/qib_iba7322.c ++++ b/drivers/infiniband/hw/qib/qib_iba7322.c +@@ -5191,8 +5191,6 @@ static void qib_get_7322_faststats(unsig + spin_lock_irqsave(&ppd->dd->eep_st_lock, flags); + traffic_wds -= ppd->dd->traffic_wds; + ppd->dd->traffic_wds += traffic_wds; +- if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD) +- atomic_add(ACTIVITY_TIMER, &ppd->dd->active_time); + spin_unlock_irqrestore(&ppd->dd->eep_st_lock, flags); + if (ppd->cpspec->qdr_dfe_on && (ppd->link_speed_active & + QIB_IB_QDR) && +--- a/drivers/infiniband/hw/qib/qib_init.c ++++ b/drivers/infiniband/hw/qib/qib_init.c +@@ -922,7 +922,6 @@ static void qib_shutdown_device(struct q + } + } + +- qib_update_eeprom_log(dd); + } + + /** +--- a/drivers/infiniband/hw/qib/qib_sysfs.c ++++ b/drivers/infiniband/hw/qib/qib_sysfs.c +@@ -611,28 +611,6 @@ bail: + return ret < 0 ? ret : count; + } + +-static ssize_t show_logged_errs(struct device *device, +- struct device_attribute *attr, char *buf) +-{ +- struct qib_ibdev *dev = +- container_of(device, struct qib_ibdev, ibdev.dev); +- struct qib_devdata *dd = dd_from_dev(dev); +- int idx, count; +- +- /* force consistency with actual EEPROM */ +- if (qib_update_eeprom_log(dd) != 0) +- return -ENXIO; +- +- count = 0; +- for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) { +- count += scnprintf(buf + count, PAGE_SIZE - count, "%d%c", +- dd->eep_st_errs[idx], +- idx == (QIB_EEP_LOG_CNT - 1) ? '\n' : ' '); +- } +- +- return count; +-} +- + /* + * Dump tempsense regs. in decimal, to ease shell-scripts. + */ +@@ -679,7 +657,6 @@ static DEVICE_ATTR(nctxts, S_IRUGO, show + static DEVICE_ATTR(nfreectxts, S_IRUGO, show_nfreectxts, NULL); + static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL); + static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); +-static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL); + static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL); + static DEVICE_ATTR(localbus_info, S_IRUGO, show_localbus_info, NULL); + static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset); +@@ -693,7 +670,6 @@ static struct device_attribute *qib_attr + &dev_attr_nfreectxts, + &dev_attr_serial, + &dev_attr_boardversion, +- &dev_attr_logged_errors, + &dev_attr_tempsense, + &dev_attr_localbus_info, + &dev_attr_chip_reset, diff --git a/queue-3.14/series b/queue-3.14/series index 87e76513df3..c923ca8a03f 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -66,3 +66,8 @@ tty-fix-up-atime-mtime-mess-take-four.patch alsa-pcm-don-t-leave-prepared-state-after-draining.patch alsa-hda-add-pin-configs-for-asus-mobo-with-idt-92hd73xx-codec.patch alsa-hda-disable-runtime-pm-for-panther-point-again.patch +sg-fix-read-error-reporting.patch +ib-qib-do-not-write-eeprom.patch +ib-mlx4-fix-wrong-usage-of-ipv4-protocol-for-multicast-attach-detach.patch +ib-core-fix-deadlock-on-uverbs-modify_qp-error-flow.patch +ib-core-when-marshaling-ucma-path-from-user-space-clear-unused-fields.patch diff --git a/queue-3.14/sg-fix-read-error-reporting.patch b/queue-3.14/sg-fix-read-error-reporting.patch new file mode 100644 index 00000000000..3a4f757c3c4 --- /dev/null +++ b/queue-3.14/sg-fix-read-error-reporting.patch @@ -0,0 +1,43 @@ +From 3b524a683af8991b4eab4182b947c65f0ce1421b Mon Sep 17 00:00:00 2001 +From: Tony Battersby +Date: Wed, 11 Feb 2015 11:32:06 -0500 +Subject: sg: fix read() error reporting + +From: Tony Battersby + +commit 3b524a683af8991b4eab4182b947c65f0ce1421b upstream. + +Fix SCSI generic read() incorrectly returning success after detecting an +error. + +Signed-off-by: Tony Battersby +Acked-by: Douglas Gilbert +Signed-off-by: James Bottomley +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/scsi/sg.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -522,7 +522,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) { +@@ -551,8 +551,8 @@ sg_new_read(Sg_fd * sfp, char __user *bu + 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