Commit ed9fd93e authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6:
  [SCSI] fix crash when disconnecting usb storage
  [SCSI] fix async scan add/remove race resulting in an oops
  [SCSI] sd: Return correct error code for DIF
parents 52c7b3f4 4e46bf89
...@@ -164,8 +164,8 @@ void scsi_remove_host(struct Scsi_Host *shost) ...@@ -164,8 +164,8 @@ void scsi_remove_host(struct Scsi_Host *shost)
return; return;
} }
spin_unlock_irqrestore(shost->host_lock, flags); spin_unlock_irqrestore(shost->host_lock, flags);
mutex_unlock(&shost->scan_mutex);
scsi_forget_host(shost); scsi_forget_host(shost);
mutex_unlock(&shost->scan_mutex);
scsi_proc_host_rm(shost); scsi_proc_host_rm(shost);
spin_lock_irqsave(shost->host_lock, flags); spin_lock_irqsave(shost->host_lock, flags);
......
...@@ -952,16 +952,6 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, ...@@ -952,16 +952,6 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
return SCSI_SCAN_LUN_PRESENT; return SCSI_SCAN_LUN_PRESENT;
} }
static inline void scsi_destroy_sdev(struct scsi_device *sdev)
{
scsi_device_set_state(sdev, SDEV_DEL);
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
transport_destroy_device(&sdev->sdev_gendev);
put_device(&sdev->sdev_dev);
put_device(&sdev->sdev_gendev);
}
#ifdef CONFIG_SCSI_LOGGING #ifdef CONFIG_SCSI_LOGGING
/** /**
* scsi_inq_str - print INQUIRY data from min to max index, strip trailing whitespace * scsi_inq_str - print INQUIRY data from min to max index, strip trailing whitespace
...@@ -1139,7 +1129,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, ...@@ -1139,7 +1129,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
} }
} }
} else } else
scsi_destroy_sdev(sdev); __scsi_remove_device(sdev);
out: out:
return res; return res;
} }
...@@ -1500,7 +1490,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, ...@@ -1500,7 +1490,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
/* /*
* the sdev we used didn't appear in the report luns scan * the sdev we used didn't appear in the report luns scan
*/ */
scsi_destroy_sdev(sdev); __scsi_remove_device(sdev);
return ret; return ret;
} }
...@@ -1710,7 +1700,7 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost) ...@@ -1710,7 +1700,7 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
shost_for_each_device(sdev, shost) { shost_for_each_device(sdev, shost) {
if (!scsi_host_scan_allowed(shost) || if (!scsi_host_scan_allowed(shost) ||
scsi_sysfs_add_sdev(sdev) != 0) scsi_sysfs_add_sdev(sdev) != 0)
scsi_destroy_sdev(sdev); __scsi_remove_device(sdev);
} }
} }
...@@ -1943,7 +1933,7 @@ void scsi_free_host_dev(struct scsi_device *sdev) ...@@ -1943,7 +1933,7 @@ void scsi_free_host_dev(struct scsi_device *sdev)
{ {
BUG_ON(sdev->id != sdev->host->this_id); BUG_ON(sdev->id != sdev->host->this_id);
scsi_destroy_sdev(sdev); __scsi_remove_device(sdev);
} }
EXPORT_SYMBOL(scsi_free_host_dev); EXPORT_SYMBOL(scsi_free_host_dev);
...@@ -854,82 +854,73 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) ...@@ -854,82 +854,73 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
transport_configure_device(&starget->dev); transport_configure_device(&starget->dev);
error = device_add(&sdev->sdev_gendev); error = device_add(&sdev->sdev_gendev);
if (error) { if (error) {
put_device(sdev->sdev_gendev.parent);
printk(KERN_INFO "error 1\n"); printk(KERN_INFO "error 1\n");
return error; goto out_remove;
} }
error = device_add(&sdev->sdev_dev); error = device_add(&sdev->sdev_dev);
if (error) { if (error) {
printk(KERN_INFO "error 2\n"); printk(KERN_INFO "error 2\n");
goto clean_device; device_del(&sdev->sdev_gendev);
goto out_remove;
} }
transport_add_device(&sdev->sdev_gendev);
sdev->is_visible = 1;
/* create queue files, which may be writable, depending on the host */ /* create queue files, which may be writable, depending on the host */
if (sdev->host->hostt->change_queue_depth) if (sdev->host->hostt->change_queue_depth)
error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_depth_rw); error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_depth_rw);
else else
error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth); error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);
if (error) { if (error)
__scsi_remove_device(sdev); goto out_remove;
goto out;
}
if (sdev->host->hostt->change_queue_type) if (sdev->host->hostt->change_queue_type)
error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw); error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw);
else else
error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type); error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type);
if (error) { if (error)
__scsi_remove_device(sdev); goto out_remove;
goto out;
}
error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL); error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL);
if (error) if (error)
/* we're treating error on bsg register as non-fatal,
* so pretend nothing went wrong */
sdev_printk(KERN_INFO, sdev, sdev_printk(KERN_INFO, sdev,
"Failed to register bsg queue, errno=%d\n", error); "Failed to register bsg queue, errno=%d\n", error);
/* we're treating error on bsg register as non-fatal, so pretend
* nothing went wrong */
error = 0;
/* add additional host specific attributes */ /* add additional host specific attributes */
if (sdev->host->hostt->sdev_attrs) { if (sdev->host->hostt->sdev_attrs) {
for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) { for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
error = device_create_file(&sdev->sdev_gendev, error = device_create_file(&sdev->sdev_gendev,
sdev->host->hostt->sdev_attrs[i]); sdev->host->hostt->sdev_attrs[i]);
if (error) { if (error)
__scsi_remove_device(sdev); goto out_remove;
goto out;
}
} }
} }
transport_add_device(&sdev->sdev_gendev); return 0;
out:
return error;
clean_device:
scsi_device_set_state(sdev, SDEV_CANCEL);
device_del(&sdev->sdev_gendev);
transport_destroy_device(&sdev->sdev_gendev);
put_device(&sdev->sdev_dev);
put_device(&sdev->sdev_gendev);
out_remove:
__scsi_remove_device(sdev);
return error; return error;
} }
void __scsi_remove_device(struct scsi_device *sdev) void __scsi_remove_device(struct scsi_device *sdev)
{ {
struct device *dev = &sdev->sdev_gendev; struct device *dev = &sdev->sdev_gendev;
if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0) if (sdev->is_visible) {
return; if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
return;
bsg_unregister_queue(sdev->request_queue); bsg_unregister_queue(sdev->request_queue);
device_unregister(&sdev->sdev_dev); device_unregister(&sdev->sdev_dev);
transport_remove_device(dev); transport_remove_device(dev);
device_del(dev); device_del(dev);
} else
put_device(&sdev->sdev_dev);
scsi_device_set_state(sdev, SDEV_DEL); scsi_device_set_state(sdev, SDEV_DEL);
if (sdev->host->hostt->slave_destroy) if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev); sdev->host->hostt->slave_destroy(sdev);
......
...@@ -418,7 +418,7 @@ int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_s ...@@ -418,7 +418,7 @@ int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_s
__func__, virt, phys, be32_to_cpu(sdt->ref_tag), __func__, virt, phys, be32_to_cpu(sdt->ref_tag),
be16_to_cpu(sdt->app_tag)); be16_to_cpu(sdt->app_tag));
return -EIO; return -EILSEQ;
} }
/* /*
......
...@@ -145,6 +145,7 @@ struct scsi_device { ...@@ -145,6 +145,7 @@ struct scsi_device {
unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */ unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */
unsigned last_sector_bug:1; /* do not use multisector accesses on unsigned last_sector_bug:1; /* do not use multisector accesses on
SD_LAST_BUGGY_SECTORS */ SD_LAST_BUGGY_SECTORS */
unsigned is_visible:1; /* is the device visible in sysfs */
DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
struct list_head event_list; /* asserted events */ struct list_head event_list; /* asserted events */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment