Commit 860dc73608a091e0b325218acc2701709d5f221a

Authored by James Bottomley
1 parent 3bf3583b6a

[SCSI] fix async scan add/remove race resulting in an oops

Async scanning introduced a very wide window where the SCSI device is
up and running but has not yet been added to sysfs.  We delay the
adding until all scans have completed to retain the same ordering as
sync scanning.

This delay in visibility causes an oops if a device is removed before
we make it visible because the SCSI removal routines have an inbuilt
assumption that if a device is in SDEV_RUNNING state, it must be
visible (which is not necessarily true in the async scanning case).

Fix this by introducing an additional is_visible flag which we can use
to condition the tear down so we do the right thing for running but
not yet made visible.

Reported-by: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>

Showing 3 changed files with 32 additions and 50 deletions Side-by-side Diff

drivers/scsi/scsi_scan.c
... ... @@ -952,16 +952,6 @@
952 952 return SCSI_SCAN_LUN_PRESENT;
953 953 }
954 954  
955   -static inline void scsi_destroy_sdev(struct scsi_device *sdev)
956   -{
957   - scsi_device_set_state(sdev, SDEV_DEL);
958   - if (sdev->host->hostt->slave_destroy)
959   - sdev->host->hostt->slave_destroy(sdev);
960   - transport_destroy_device(&sdev->sdev_gendev);
961   - put_device(&sdev->sdev_dev);
962   - put_device(&sdev->sdev_gendev);
963   -}
964   -
965 955 #ifdef CONFIG_SCSI_LOGGING
966 956 /**
967 957 * scsi_inq_str - print INQUIRY data from min to max index, strip trailing whitespace
... ... @@ -1139,7 +1129,7 @@
1139 1129 }
1140 1130 }
1141 1131 } else
1142   - scsi_destroy_sdev(sdev);
  1132 + __scsi_remove_device(sdev);
1143 1133 out:
1144 1134 return res;
1145 1135 }
... ... @@ -1500,7 +1490,7 @@
1500 1490 /*
1501 1491 * the sdev we used didn't appear in the report luns scan
1502 1492 */
1503   - scsi_destroy_sdev(sdev);
  1493 + __scsi_remove_device(sdev);
1504 1494 return ret;
1505 1495 }
1506 1496  
... ... @@ -1710,7 +1700,7 @@
1710 1700 shost_for_each_device(sdev, shost) {
1711 1701 if (!scsi_host_scan_allowed(shost) ||
1712 1702 scsi_sysfs_add_sdev(sdev) != 0)
1713   - scsi_destroy_sdev(sdev);
  1703 + __scsi_remove_device(sdev);
1714 1704 }
1715 1705 }
1716 1706  
... ... @@ -1943,7 +1933,7 @@
1943 1933 {
1944 1934 BUG_ON(sdev->id != sdev->host->this_id);
1945 1935  
1946   - scsi_destroy_sdev(sdev);
  1936 + __scsi_remove_device(sdev);
1947 1937 }
1948 1938 EXPORT_SYMBOL(scsi_free_host_dev);
drivers/scsi/scsi_sysfs.c
... ... @@ -854,82 +854,73 @@
854 854 transport_configure_device(&starget->dev);
855 855 error = device_add(&sdev->sdev_gendev);
856 856 if (error) {
857   - put_device(sdev->sdev_gendev.parent);
858 857 printk(KERN_INFO "error 1\n");
859   - return error;
  858 + goto out_remove;
860 859 }
861 860 error = device_add(&sdev->sdev_dev);
862 861 if (error) {
863 862 printk(KERN_INFO "error 2\n");
864   - goto clean_device;
  863 + device_del(&sdev->sdev_gendev);
  864 + goto out_remove;
865 865 }
  866 + transport_add_device(&sdev->sdev_gendev);
  867 + sdev->is_visible = 1;
866 868  
867 869 /* create queue files, which may be writable, depending on the host */
868 870 if (sdev->host->hostt->change_queue_depth)
869 871 error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_depth_rw);
870 872 else
871 873 error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);
872   - if (error) {
873   - __scsi_remove_device(sdev);
874   - goto out;
875   - }
  874 + if (error)
  875 + goto out_remove;
  876 +
876 877 if (sdev->host->hostt->change_queue_type)
877 878 error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw);
878 879 else
879 880 error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type);
880   - if (error) {
881   - __scsi_remove_device(sdev);
882   - goto out;
883   - }
  881 + if (error)
  882 + goto out_remove;
884 883  
885 884 error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL);
886 885  
887 886 if (error)
  887 + /* we're treating error on bsg register as non-fatal,
  888 + * so pretend nothing went wrong */
888 889 sdev_printk(KERN_INFO, sdev,
889 890 "Failed to register bsg queue, errno=%d\n", error);
890 891  
891   - /* we're treating error on bsg register as non-fatal, so pretend
892   - * nothing went wrong */
893   - error = 0;
894   -
895 892 /* add additional host specific attributes */
896 893 if (sdev->host->hostt->sdev_attrs) {
897 894 for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
898 895 error = device_create_file(&sdev->sdev_gendev,
899 896 sdev->host->hostt->sdev_attrs[i]);
900   - if (error) {
901   - __scsi_remove_device(sdev);
902   - goto out;
903   - }
  897 + if (error)
  898 + goto out_remove;
904 899 }
905 900 }
906 901  
907   - transport_add_device(&sdev->sdev_gendev);
908   - out:
909   - return error;
  902 + return 0;
910 903  
911   - clean_device:
912   - scsi_device_set_state(sdev, SDEV_CANCEL);
913   -
914   - device_del(&sdev->sdev_gendev);
915   - transport_destroy_device(&sdev->sdev_gendev);
916   - put_device(&sdev->sdev_dev);
917   - put_device(&sdev->sdev_gendev);
918   -
  904 + out_remove:
  905 + __scsi_remove_device(sdev);
919 906 return error;
  907 +
920 908 }
921 909  
922 910 void __scsi_remove_device(struct scsi_device *sdev)
923 911 {
924 912 struct device *dev = &sdev->sdev_gendev;
925 913  
926   - if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
927   - return;
  914 + if (sdev->is_visible) {
  915 + if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
  916 + return;
928 917  
929   - bsg_unregister_queue(sdev->request_queue);
930   - device_unregister(&sdev->sdev_dev);
931   - transport_remove_device(dev);
932   - device_del(dev);
  918 + bsg_unregister_queue(sdev->request_queue);
  919 + device_unregister(&sdev->sdev_dev);
  920 + transport_remove_device(dev);
  921 + device_del(dev);
  922 + } else
  923 + put_device(&sdev->sdev_dev);
933 924 scsi_device_set_state(sdev, SDEV_DEL);
934 925 if (sdev->host->hostt->slave_destroy)
935 926 sdev->host->hostt->slave_destroy(sdev);
include/scsi/scsi_device.h
... ... @@ -145,6 +145,7 @@
145 145 unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */
146 146 unsigned last_sector_bug:1; /* do not use multisector accesses on
147 147 SD_LAST_BUGGY_SECTORS */
  148 + unsigned is_visible:1; /* is the device visible in sysfs */
148 149  
149 150 DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */
150 151 struct list_head event_list; /* asserted events */