diff options
author | Hannes Reinecke <hare@suse.de> | 2014-03-15 04:51:47 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2014-03-19 18:22:39 -0400 |
commit | 276b20d09be7a1c260f0a94880d33e0850efe200 (patch) | |
tree | d2f87fd172c04197f473235815eb18a01bf0b586 /drivers/scsi | |
parent | 9a993302cc7a2e0a22e0851122dcfb59b56abd7a (diff) |
[SCSI] scsi_sysfs: Implement 'is_visible' callback
Instead of modifying attributes after the device has been created
we should be using the 'is_visible' callback to avoid races.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/scsi_sysfs.c | 184 |
1 files changed, 93 insertions, 91 deletions
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 8dab6ddf8222..85098222a9e8 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -576,7 +576,6 @@ static int scsi_sdev_check_buf_bit(const char *buf) | |||
576 | * Create the actual show/store functions and data structures. | 576 | * Create the actual show/store functions and data structures. |
577 | */ | 577 | */ |
578 | sdev_rd_attr (device_blocked, "%d\n"); | 578 | sdev_rd_attr (device_blocked, "%d\n"); |
579 | sdev_rd_attr (queue_depth, "%d\n"); | ||
580 | sdev_rd_attr (device_busy, "%d\n"); | 579 | sdev_rd_attr (device_busy, "%d\n"); |
581 | sdev_rd_attr (type, "%d\n"); | 580 | sdev_rd_attr (type, "%d\n"); |
582 | sdev_rd_attr (scsi_level, "%d\n"); | 581 | sdev_rd_attr (scsi_level, "%d\n"); |
@@ -720,7 +719,37 @@ show_queue_type_field(struct device *dev, struct device_attribute *attr, | |||
720 | return snprintf(buf, 20, "%s\n", name); | 719 | return snprintf(buf, 20, "%s\n", name); |
721 | } | 720 | } |
722 | 721 | ||
723 | static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL); | 722 | static ssize_t |
723 | store_queue_type_field(struct device *dev, struct device_attribute *attr, | ||
724 | const char *buf, size_t count) | ||
725 | { | ||
726 | struct scsi_device *sdev = to_scsi_device(dev); | ||
727 | struct scsi_host_template *sht = sdev->host->hostt; | ||
728 | int tag_type = 0, retval; | ||
729 | int prev_tag_type = scsi_get_tag_type(sdev); | ||
730 | |||
731 | if (!sdev->tagged_supported || !sht->change_queue_type) | ||
732 | return -EINVAL; | ||
733 | |||
734 | if (strncmp(buf, "ordered", 7) == 0) | ||
735 | tag_type = MSG_ORDERED_TAG; | ||
736 | else if (strncmp(buf, "simple", 6) == 0) | ||
737 | tag_type = MSG_SIMPLE_TAG; | ||
738 | else if (strncmp(buf, "none", 4) != 0) | ||
739 | return -EINVAL; | ||
740 | |||
741 | if (tag_type == prev_tag_type) | ||
742 | return count; | ||
743 | |||
744 | retval = sht->change_queue_type(sdev, tag_type); | ||
745 | if (retval < 0) | ||
746 | return retval; | ||
747 | |||
748 | return count; | ||
749 | } | ||
750 | |||
751 | static DEVICE_ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, | ||
752 | store_queue_type_field); | ||
724 | 753 | ||
725 | static ssize_t | 754 | static ssize_t |
726 | show_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf) | 755 | show_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf) |
@@ -794,46 +823,9 @@ DECLARE_EVT(soft_threshold_reached, SOFT_THRESHOLD_REACHED_REPORTED) | |||
794 | DECLARE_EVT(mode_parameter_change_reported, MODE_PARAMETER_CHANGE_REPORTED) | 823 | DECLARE_EVT(mode_parameter_change_reported, MODE_PARAMETER_CHANGE_REPORTED) |
795 | DECLARE_EVT(lun_change_reported, LUN_CHANGE_REPORTED) | 824 | DECLARE_EVT(lun_change_reported, LUN_CHANGE_REPORTED) |
796 | 825 | ||
797 | /* Default template for device attributes. May NOT be modified */ | ||
798 | static struct attribute *scsi_sdev_attrs[] = { | ||
799 | &dev_attr_device_blocked.attr, | ||
800 | &dev_attr_type.attr, | ||
801 | &dev_attr_scsi_level.attr, | ||
802 | &dev_attr_device_busy.attr, | ||
803 | &dev_attr_vendor.attr, | ||
804 | &dev_attr_model.attr, | ||
805 | &dev_attr_rev.attr, | ||
806 | &dev_attr_rescan.attr, | ||
807 | &dev_attr_delete.attr, | ||
808 | &dev_attr_state.attr, | ||
809 | &dev_attr_timeout.attr, | ||
810 | &dev_attr_eh_timeout.attr, | ||
811 | &dev_attr_iocounterbits.attr, | ||
812 | &dev_attr_iorequest_cnt.attr, | ||
813 | &dev_attr_iodone_cnt.attr, | ||
814 | &dev_attr_ioerr_cnt.attr, | ||
815 | &dev_attr_modalias.attr, | ||
816 | REF_EVT(media_change), | ||
817 | REF_EVT(inquiry_change_reported), | ||
818 | REF_EVT(capacity_change_reported), | ||
819 | REF_EVT(soft_threshold_reached), | ||
820 | REF_EVT(mode_parameter_change_reported), | ||
821 | REF_EVT(lun_change_reported), | ||
822 | NULL | ||
823 | }; | ||
824 | |||
825 | static struct attribute_group scsi_sdev_attr_group = { | ||
826 | .attrs = scsi_sdev_attrs, | ||
827 | }; | ||
828 | |||
829 | static const struct attribute_group *scsi_sdev_attr_groups[] = { | ||
830 | &scsi_sdev_attr_group, | ||
831 | NULL | ||
832 | }; | ||
833 | |||
834 | static ssize_t | 826 | static ssize_t |
835 | sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr, | 827 | sdev_store_queue_depth(struct device *dev, struct device_attribute *attr, |
836 | const char *buf, size_t count) | 828 | const char *buf, size_t count) |
837 | { | 829 | { |
838 | int depth, retval; | 830 | int depth, retval; |
839 | struct scsi_device *sdev = to_scsi_device(dev); | 831 | struct scsi_device *sdev = to_scsi_device(dev); |
@@ -856,10 +848,10 @@ sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr, | |||
856 | 848 | ||
857 | return count; | 849 | return count; |
858 | } | 850 | } |
851 | sdev_show_function(queue_depth, "%d\n"); | ||
859 | 852 | ||
860 | static struct device_attribute sdev_attr_queue_depth_rw = | 853 | static DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth, |
861 | __ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth, | 854 | sdev_store_queue_depth); |
862 | sdev_store_queue_depth_rw); | ||
863 | 855 | ||
864 | static ssize_t | 856 | static ssize_t |
865 | sdev_show_queue_ramp_up_period(struct device *dev, | 857 | sdev_show_queue_ramp_up_period(struct device *dev, |
@@ -887,40 +879,73 @@ sdev_store_queue_ramp_up_period(struct device *dev, | |||
887 | return period; | 879 | return period; |
888 | } | 880 | } |
889 | 881 | ||
890 | static struct device_attribute sdev_attr_queue_ramp_up_period = | 882 | static DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR, |
891 | __ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR, | 883 | sdev_show_queue_ramp_up_period, |
892 | sdev_show_queue_ramp_up_period, | 884 | sdev_store_queue_ramp_up_period); |
893 | sdev_store_queue_ramp_up_period); | ||
894 | 885 | ||
895 | static ssize_t | 886 | static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj, |
896 | sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr, | 887 | struct attribute *attr, int i) |
897 | const char *buf, size_t count) | ||
898 | { | 888 | { |
889 | struct device *dev = container_of(kobj, struct device, kobj); | ||
899 | struct scsi_device *sdev = to_scsi_device(dev); | 890 | struct scsi_device *sdev = to_scsi_device(dev); |
900 | struct scsi_host_template *sht = sdev->host->hostt; | ||
901 | int tag_type = 0, retval; | ||
902 | int prev_tag_type = scsi_get_tag_type(sdev); | ||
903 | 891 | ||
904 | if (!sdev->tagged_supported || !sht->change_queue_type) | ||
905 | return -EINVAL; | ||
906 | 892 | ||
907 | if (strncmp(buf, "ordered", 7) == 0) | 893 | if (attr == &dev_attr_queue_depth.attr && |
908 | tag_type = MSG_ORDERED_TAG; | 894 | !sdev->host->hostt->change_queue_depth) |
909 | else if (strncmp(buf, "simple", 6) == 0) | 895 | return S_IRUGO; |
910 | tag_type = MSG_SIMPLE_TAG; | ||
911 | else if (strncmp(buf, "none", 4) != 0) | ||
912 | return -EINVAL; | ||
913 | 896 | ||
914 | if (tag_type == prev_tag_type) | 897 | if (attr == &dev_attr_queue_ramp_up_period.attr && |
915 | return count; | 898 | !sdev->host->hostt->change_queue_depth) |
899 | return 0; | ||
916 | 900 | ||
917 | retval = sht->change_queue_type(sdev, tag_type); | 901 | if (attr == &dev_attr_queue_type.attr && |
918 | if (retval < 0) | 902 | !sdev->host->hostt->change_queue_type) |
919 | return retval; | 903 | return S_IRUGO; |
920 | 904 | ||
921 | return count; | 905 | return attr->mode; |
922 | } | 906 | } |
923 | 907 | ||
908 | /* Default template for device attributes. May NOT be modified */ | ||
909 | static struct attribute *scsi_sdev_attrs[] = { | ||
910 | &dev_attr_device_blocked.attr, | ||
911 | &dev_attr_type.attr, | ||
912 | &dev_attr_scsi_level.attr, | ||
913 | &dev_attr_device_busy.attr, | ||
914 | &dev_attr_vendor.attr, | ||
915 | &dev_attr_model.attr, | ||
916 | &dev_attr_rev.attr, | ||
917 | &dev_attr_rescan.attr, | ||
918 | &dev_attr_delete.attr, | ||
919 | &dev_attr_state.attr, | ||
920 | &dev_attr_timeout.attr, | ||
921 | &dev_attr_eh_timeout.attr, | ||
922 | &dev_attr_iocounterbits.attr, | ||
923 | &dev_attr_iorequest_cnt.attr, | ||
924 | &dev_attr_iodone_cnt.attr, | ||
925 | &dev_attr_ioerr_cnt.attr, | ||
926 | &dev_attr_modalias.attr, | ||
927 | &dev_attr_queue_depth.attr, | ||
928 | &dev_attr_queue_type.attr, | ||
929 | &dev_attr_queue_ramp_up_period.attr, | ||
930 | REF_EVT(media_change), | ||
931 | REF_EVT(inquiry_change_reported), | ||
932 | REF_EVT(capacity_change_reported), | ||
933 | REF_EVT(soft_threshold_reached), | ||
934 | REF_EVT(mode_parameter_change_reported), | ||
935 | REF_EVT(lun_change_reported), | ||
936 | NULL | ||
937 | }; | ||
938 | |||
939 | static struct attribute_group scsi_sdev_attr_group = { | ||
940 | .attrs = scsi_sdev_attrs, | ||
941 | .is_visible = scsi_sdev_attr_is_visible, | ||
942 | }; | ||
943 | |||
944 | static const struct attribute_group *scsi_sdev_attr_groups[] = { | ||
945 | &scsi_sdev_attr_group, | ||
946 | NULL | ||
947 | }; | ||
948 | |||
924 | static int scsi_target_add(struct scsi_target *starget) | 949 | static int scsi_target_add(struct scsi_target *starget) |
925 | { | 950 | { |
926 | int error; | 951 | int error; |
@@ -943,10 +968,6 @@ static int scsi_target_add(struct scsi_target *starget) | |||
943 | return 0; | 968 | return 0; |
944 | } | 969 | } |
945 | 970 | ||
946 | static struct device_attribute sdev_attr_queue_type_rw = | ||
947 | __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, | ||
948 | sdev_store_queue_type_rw); | ||
949 | |||
950 | /** | 971 | /** |
951 | * scsi_sysfs_add_sdev - add scsi device to sysfs | 972 | * scsi_sysfs_add_sdev - add scsi device to sysfs |
952 | * @sdev: scsi_device to add | 973 | * @sdev: scsi_device to add |
@@ -1000,25 +1021,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) | |||
1000 | transport_add_device(&sdev->sdev_gendev); | 1021 | transport_add_device(&sdev->sdev_gendev); |
1001 | sdev->is_visible = 1; | 1022 | sdev->is_visible = 1; |
1002 | 1023 | ||
1003 | /* create queue files, which may be writable, depending on the host */ | ||
1004 | if (sdev->host->hostt->change_queue_depth) { | ||
1005 | error = device_create_file(&sdev->sdev_gendev, | ||
1006 | &sdev_attr_queue_depth_rw); | ||
1007 | error = device_create_file(&sdev->sdev_gendev, | ||
1008 | &sdev_attr_queue_ramp_up_period); | ||
1009 | } | ||
1010 | else | ||
1011 | error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth); | ||
1012 | if (error) | ||
1013 | return error; | ||
1014 | |||
1015 | if (sdev->host->hostt->change_queue_type) | ||
1016 | error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw); | ||
1017 | else | ||
1018 | error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type); | ||
1019 | if (error) | ||
1020 | return error; | ||
1021 | |||
1022 | error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL); | 1024 | error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL); |
1023 | 1025 | ||
1024 | if (error) | 1026 | if (error) |