mirror of https://gitee.com/openkylin/linux.git
[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>
This commit is contained in:
parent
9a993302cc
commit
276b20d09b
|
@ -576,7 +576,6 @@ static int scsi_sdev_check_buf_bit(const char *buf)
|
|||
* Create the actual show/store functions and data structures.
|
||||
*/
|
||||
sdev_rd_attr (device_blocked, "%d\n");
|
||||
sdev_rd_attr (queue_depth, "%d\n");
|
||||
sdev_rd_attr (device_busy, "%d\n");
|
||||
sdev_rd_attr (type, "%d\n");
|
||||
sdev_rd_attr (scsi_level, "%d\n");
|
||||
|
@ -720,7 +719,37 @@ show_queue_type_field(struct device *dev, struct device_attribute *attr,
|
|||
return snprintf(buf, 20, "%s\n", name);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL);
|
||||
static ssize_t
|
||||
store_queue_type_field(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
struct scsi_host_template *sht = sdev->host->hostt;
|
||||
int tag_type = 0, retval;
|
||||
int prev_tag_type = scsi_get_tag_type(sdev);
|
||||
|
||||
if (!sdev->tagged_supported || !sht->change_queue_type)
|
||||
return -EINVAL;
|
||||
|
||||
if (strncmp(buf, "ordered", 7) == 0)
|
||||
tag_type = MSG_ORDERED_TAG;
|
||||
else if (strncmp(buf, "simple", 6) == 0)
|
||||
tag_type = MSG_SIMPLE_TAG;
|
||||
else if (strncmp(buf, "none", 4) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (tag_type == prev_tag_type)
|
||||
return count;
|
||||
|
||||
retval = sht->change_queue_type(sdev, tag_type);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
|
||||
store_queue_type_field);
|
||||
|
||||
static ssize_t
|
||||
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)
|
|||
DECLARE_EVT(mode_parameter_change_reported, MODE_PARAMETER_CHANGE_REPORTED)
|
||||
DECLARE_EVT(lun_change_reported, LUN_CHANGE_REPORTED)
|
||||
|
||||
/* Default template for device attributes. May NOT be modified */
|
||||
static struct attribute *scsi_sdev_attrs[] = {
|
||||
&dev_attr_device_blocked.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_scsi_level.attr,
|
||||
&dev_attr_device_busy.attr,
|
||||
&dev_attr_vendor.attr,
|
||||
&dev_attr_model.attr,
|
||||
&dev_attr_rev.attr,
|
||||
&dev_attr_rescan.attr,
|
||||
&dev_attr_delete.attr,
|
||||
&dev_attr_state.attr,
|
||||
&dev_attr_timeout.attr,
|
||||
&dev_attr_eh_timeout.attr,
|
||||
&dev_attr_iocounterbits.attr,
|
||||
&dev_attr_iorequest_cnt.attr,
|
||||
&dev_attr_iodone_cnt.attr,
|
||||
&dev_attr_ioerr_cnt.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
REF_EVT(media_change),
|
||||
REF_EVT(inquiry_change_reported),
|
||||
REF_EVT(capacity_change_reported),
|
||||
REF_EVT(soft_threshold_reached),
|
||||
REF_EVT(mode_parameter_change_reported),
|
||||
REF_EVT(lun_change_reported),
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group scsi_sdev_attr_group = {
|
||||
.attrs = scsi_sdev_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *scsi_sdev_attr_groups[] = {
|
||||
&scsi_sdev_attr_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
sdev_store_queue_depth(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int depth, retval;
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
|
@ -856,10 +848,10 @@ sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr,
|
|||
|
||||
return count;
|
||||
}
|
||||
sdev_show_function(queue_depth, "%d\n");
|
||||
|
||||
static struct device_attribute sdev_attr_queue_depth_rw =
|
||||
__ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
|
||||
sdev_store_queue_depth_rw);
|
||||
static DEVICE_ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
|
||||
sdev_store_queue_depth);
|
||||
|
||||
static ssize_t
|
||||
sdev_show_queue_ramp_up_period(struct device *dev,
|
||||
|
@ -887,40 +879,73 @@ sdev_store_queue_ramp_up_period(struct device *dev,
|
|||
return period;
|
||||
}
|
||||
|
||||
static struct device_attribute sdev_attr_queue_ramp_up_period =
|
||||
__ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR,
|
||||
sdev_show_queue_ramp_up_period,
|
||||
sdev_store_queue_ramp_up_period);
|
||||
static DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR,
|
||||
sdev_show_queue_ramp_up_period,
|
||||
sdev_store_queue_ramp_up_period);
|
||||
|
||||
static ssize_t
|
||||
sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static umode_t scsi_sdev_attr_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int i)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
struct scsi_host_template *sht = sdev->host->hostt;
|
||||
int tag_type = 0, retval;
|
||||
int prev_tag_type = scsi_get_tag_type(sdev);
|
||||
|
||||
if (!sdev->tagged_supported || !sht->change_queue_type)
|
||||
return -EINVAL;
|
||||
|
||||
if (strncmp(buf, "ordered", 7) == 0)
|
||||
tag_type = MSG_ORDERED_TAG;
|
||||
else if (strncmp(buf, "simple", 6) == 0)
|
||||
tag_type = MSG_SIMPLE_TAG;
|
||||
else if (strncmp(buf, "none", 4) != 0)
|
||||
return -EINVAL;
|
||||
if (attr == &dev_attr_queue_depth.attr &&
|
||||
!sdev->host->hostt->change_queue_depth)
|
||||
return S_IRUGO;
|
||||
|
||||
if (tag_type == prev_tag_type)
|
||||
return count;
|
||||
if (attr == &dev_attr_queue_ramp_up_period.attr &&
|
||||
!sdev->host->hostt->change_queue_depth)
|
||||
return 0;
|
||||
|
||||
retval = sht->change_queue_type(sdev, tag_type);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
if (attr == &dev_attr_queue_type.attr &&
|
||||
!sdev->host->hostt->change_queue_type)
|
||||
return S_IRUGO;
|
||||
|
||||
return count;
|
||||
return attr->mode;
|
||||
}
|
||||
|
||||
/* Default template for device attributes. May NOT be modified */
|
||||
static struct attribute *scsi_sdev_attrs[] = {
|
||||
&dev_attr_device_blocked.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_scsi_level.attr,
|
||||
&dev_attr_device_busy.attr,
|
||||
&dev_attr_vendor.attr,
|
||||
&dev_attr_model.attr,
|
||||
&dev_attr_rev.attr,
|
||||
&dev_attr_rescan.attr,
|
||||
&dev_attr_delete.attr,
|
||||
&dev_attr_state.attr,
|
||||
&dev_attr_timeout.attr,
|
||||
&dev_attr_eh_timeout.attr,
|
||||
&dev_attr_iocounterbits.attr,
|
||||
&dev_attr_iorequest_cnt.attr,
|
||||
&dev_attr_iodone_cnt.attr,
|
||||
&dev_attr_ioerr_cnt.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_queue_depth.attr,
|
||||
&dev_attr_queue_type.attr,
|
||||
&dev_attr_queue_ramp_up_period.attr,
|
||||
REF_EVT(media_change),
|
||||
REF_EVT(inquiry_change_reported),
|
||||
REF_EVT(capacity_change_reported),
|
||||
REF_EVT(soft_threshold_reached),
|
||||
REF_EVT(mode_parameter_change_reported),
|
||||
REF_EVT(lun_change_reported),
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group scsi_sdev_attr_group = {
|
||||
.attrs = scsi_sdev_attrs,
|
||||
.is_visible = scsi_sdev_attr_is_visible,
|
||||
};
|
||||
|
||||
static const struct attribute_group *scsi_sdev_attr_groups[] = {
|
||||
&scsi_sdev_attr_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int scsi_target_add(struct scsi_target *starget)
|
||||
{
|
||||
int error;
|
||||
|
@ -943,10 +968,6 @@ static int scsi_target_add(struct scsi_target *starget)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct device_attribute sdev_attr_queue_type_rw =
|
||||
__ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
|
||||
sdev_store_queue_type_rw);
|
||||
|
||||
/**
|
||||
* scsi_sysfs_add_sdev - add scsi device to sysfs
|
||||
* @sdev: scsi_device to add
|
||||
|
@ -1000,25 +1021,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
|
|||
transport_add_device(&sdev->sdev_gendev);
|
||||
sdev->is_visible = 1;
|
||||
|
||||
/* create queue files, which may be writable, depending on the host */
|
||||
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_ramp_up_period);
|
||||
}
|
||||
else
|
||||
error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (sdev->host->hostt->change_queue_type)
|
||||
error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw);
|
||||
else
|
||||
error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL);
|
||||
|
||||
if (error)
|
||||
|
|
Loading…
Reference in New Issue