aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-11-01 00:26:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-11-01 00:26:04 -0400
commit060b85b0d3064032b6810928973f8c7a15ab9c11 (patch)
tree475fb4d68926e255280bf4ea79169d740f014d82
parentaf7eba0158e9b4632dcd94c1cd4100689666e14f (diff)
parentd6a32b98099fb6b257e9b4f7b3febb5aae6f7408 (diff)
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI fixes from James Bottomley: "This is three essential bug fixes for various SCSI parts. The only affected users are SCSI multi-path via device handler (basically all the enterprise) and mvsas users. The dh bugs are an async entanglement in boot resulting in a serious WARN_ON trip and a use after free on remove leading to a crash with strict memory accounting. The mvsas bug manifests as a null deref oops but only on abort sequences; however, these can commonly occur with SATA attached devices, hence the fix" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi_dh: don't try to load a device handler during async probing scsi_dh: fix use-after-free when removing scsi device mvsas: Fix NULL pointer dereference in mvs_slot_task_free
-rw-r--r--drivers/scsi/mvsas/mv_sas.c2
-rw-r--r--drivers/scsi/scsi_dh.c8
-rw-r--r--drivers/scsi/scsi_priv.h2
-rw-r--r--drivers/scsi/scsi_sysfs.c2
4 files changed, 12 insertions, 2 deletions
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index 454536c49315..9c780740fb82 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -887,6 +887,8 @@ static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
887static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, 887static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
888 struct mvs_slot_info *slot, u32 slot_idx) 888 struct mvs_slot_info *slot, u32 slot_idx)
889{ 889{
890 if (!slot)
891 return;
890 if (!slot->task) 892 if (!slot->task)
891 return; 893 return;
892 if (!sas_protocol_ata(task->task_proto)) 894 if (!sas_protocol_ata(task->task_proto))
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index 0a2168e69bbc..e7649ed3f667 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -226,16 +226,20 @@ int scsi_dh_add_device(struct scsi_device *sdev)
226 226
227 drv = scsi_dh_find_driver(sdev); 227 drv = scsi_dh_find_driver(sdev);
228 if (drv) 228 if (drv)
229 devinfo = scsi_dh_lookup(drv); 229 devinfo = __scsi_dh_lookup(drv);
230 if (devinfo) 230 if (devinfo)
231 err = scsi_dh_handler_attach(sdev, devinfo); 231 err = scsi_dh_handler_attach(sdev, devinfo);
232 return err; 232 return err;
233} 233}
234 234
235void scsi_dh_remove_device(struct scsi_device *sdev) 235void scsi_dh_release_device(struct scsi_device *sdev)
236{ 236{
237 if (sdev->handler) 237 if (sdev->handler)
238 scsi_dh_handler_detach(sdev); 238 scsi_dh_handler_detach(sdev);
239}
240
241void scsi_dh_remove_device(struct scsi_device *sdev)
242{
239 device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr); 243 device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr);
240} 244}
241 245
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 644bb7339b55..4d01cdb1b348 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -173,9 +173,11 @@ extern struct async_domain scsi_sd_probe_domain;
173/* scsi_dh.c */ 173/* scsi_dh.c */
174#ifdef CONFIG_SCSI_DH 174#ifdef CONFIG_SCSI_DH
175int scsi_dh_add_device(struct scsi_device *sdev); 175int scsi_dh_add_device(struct scsi_device *sdev);
176void scsi_dh_release_device(struct scsi_device *sdev);
176void scsi_dh_remove_device(struct scsi_device *sdev); 177void scsi_dh_remove_device(struct scsi_device *sdev);
177#else 178#else
178static inline int scsi_dh_add_device(struct scsi_device *sdev) { return 0; } 179static inline int scsi_dh_add_device(struct scsi_device *sdev) { return 0; }
180static inline void scsi_dh_release_device(struct scsi_device *sdev) { }
179static inline void scsi_dh_remove_device(struct scsi_device *sdev) { } 181static inline void scsi_dh_remove_device(struct scsi_device *sdev) { }
180#endif 182#endif
181 183
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index b333389f248f..dff8fafb741c 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -399,6 +399,8 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
399 399
400 sdev = container_of(work, struct scsi_device, ew.work); 400 sdev = container_of(work, struct scsi_device, ew.work);
401 401
402 scsi_dh_release_device(sdev);
403
402 parent = sdev->sdev_gendev.parent; 404 parent = sdev->sdev_gendev.parent;
403 405
404 spin_lock_irqsave(sdev->host->host_lock, flags); 406 spin_lock_irqsave(sdev->host->host_lock, flags);