From 70e28c9d9208decd9c98e8f91fd4cdd557974abe Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 25 Sep 2003 01:54:19 -0500 Subject: [PATCH] [PATCH] change sdev.access_count to an atomic_t For various reasons (e.g. the .my_devices lockdown) it's undesirable to have scsi_device_{get,put} blocking. Change .access_count to an atomic_t to avoid the driver model r/w semaphore. Sideeffects: - possible module reference leak in scsi_device_get when get_device fails fixes. - the access_count attribute is gone. We already have this exposed to userspace in too many places given that this whole second refcount will go away once Al fixes the block layer. --- drivers/scsi/scsi.c | 37 ++++++++++++++++++------------------- drivers/scsi/scsi_proc.c | 2 +- drivers/scsi/scsi_scan.c | 1 + drivers/scsi/scsi_sysfs.c | 21 ++++++++------------- drivers/scsi/sg.c | 4 ++-- include/scsi/scsi_device.h | 3 ++- 6 files changed, 32 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index cda15b271b212..a48092ca90cd6 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -889,21 +889,24 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth) int scsi_device_get(struct scsi_device *sdev) { struct class *class = class_get(&sdev_class); - int error = -ENXIO; - - if (class) { - down_write(&class->subsys.rwsem); - if (!test_bit(SDEV_DEL, &sdev->sdev_state)) - if (try_module_get(sdev->host->hostt->module)) - if (get_device(&sdev->sdev_gendev)) { - sdev->access_count++; - error = 0; - } - up_write(&class->subsys.rwsem); - class_put(&sdev_class); - } - return error; + if (!class) + goto out; + if (test_bit(SDEV_DEL, &sdev->sdev_state)) + goto out; + if (!try_module_get(sdev->host->hostt->module)) + goto out; + if (!get_device(&sdev->sdev_gendev)) + goto out_put_module; + atomic_inc(&sdev->access_count); + class_put(&sdev_class); + return 0; + + out_put_module: + module_put(sdev->host->hostt->module); + out: + class_put(&sdev_class); + return -ENXIO; } void scsi_device_put(struct scsi_device *sdev) @@ -913,15 +916,11 @@ void scsi_device_put(struct scsi_device *sdev) if (!class) return; - down_write(&class->subsys.rwsem); module_put(sdev->host->hostt->module); - if (--sdev->access_count == 0) { + if (atomic_dec_and_test(&sdev->access_count)) if (test_bit(SDEV_DEL, &sdev->sdev_state)) device_del(&sdev->sdev_gendev); - } put_device(&sdev->sdev_gendev); - up_write(&class->subsys.rwsem); - class_put(&sdev_class); } diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 2a82f72c9a8b3..24c4ab32eea81 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -215,7 +215,7 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun) sdev = scsi_find_device(shost, channel, id, lun); if (!sdev) goto out; - if (sdev->access_count) + if (atomic_read(&sdev->access_count)) goto out; scsi_remove_device(sdev); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 65b0733b6a894..4cc679d9caa44 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -196,6 +196,7 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, goto out; memset(sdev, 0, sizeof(*sdev)); + atomic_set(&sdev->access_count, 0); sdev->vendor = scsi_null_device_strs; sdev->model = scsi_null_device_strs; sdev->rev = scsi_null_device_strs; diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index cd1b6e02ec7db..3914cb67f0bd0 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -246,7 +246,6 @@ sdev_rd_attr (device_blocked, "%d\n"); sdev_rd_attr (queue_depth, "%d\n"); sdev_rd_attr (type, "%d\n"); sdev_rd_attr (scsi_level, "%d\n"); -sdev_rd_attr (access_count, "%d\n"); sdev_rd_attr (vendor, "%.8s\n"); sdev_rd_attr (model, "%.16s\n"); sdev_rd_attr (rev, "%.4s\n"); @@ -265,17 +264,14 @@ static ssize_t sdev_store_delete(struct device *dev, const char *buf, size_t count) { struct scsi_device *sdev = to_scsi_device(dev); - int res = count; - if (sdev->access_count) - /* - * FIXME and scsi_proc.c: racey use of access_count, - * possibly add a new arg to scsi_remove_device. - */ - res = -EBUSY; - else - scsi_remove_device(sdev); - return res; + /* + * FIXME and scsi_proc.c: racey use of access_count, + */ + if (atomic_read(&sdev->access_count)) + return -EBUSY; + scsi_remove_device(sdev); + return count; }; static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete); @@ -285,7 +281,6 @@ static struct device_attribute *scsi_sysfs_sdev_attrs[] = { &dev_attr_queue_depth, &dev_attr_type, &dev_attr_scsi_level, - &dev_attr_access_count, &dev_attr_vendor, &dev_attr_model, &dev_attr_rev, @@ -415,7 +410,7 @@ void scsi_remove_device(struct scsi_device *sdev) if (class) { down_write(&class->subsys.rwsem); set_bit(SDEV_DEL, &sdev->sdev_state); - if (sdev->access_count == 0) + if (atomic_read(&sdev->access_count)) device_del(&sdev->sdev_gendev); up_write(&class->subsys.rwsem); } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 1a23fadb551a5..5f5ed2a275666 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -912,7 +912,7 @@ sg_ioctl(struct inode *inode, struct file *filp, case SG_GET_VERSION_NUM: return put_user(sg_version_num, (int *) arg); case SG_GET_ACCESS_COUNT: - val = (sdp->device ? sdp->device->access_count : 0); + val = (sdp->device ? atomic_read(&sdp->device->access_count) : 0); return put_user(val, (int *) arg); case SG_GET_REQUEST_TABLE: result = verify_area(VERIFY_WRITE, (void *) arg, @@ -2901,7 +2901,7 @@ sg_proc_dev_info(char *buffer, int *len, off_t * begin, off_t offset, int size) PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, (int) scsidp->type, - (int) scsidp->access_count, + (int) atomic_read(&scsidp->access_count), (int) scsidp->queue_depth, (int) scsidp->device_busy, (int) scsidp->online); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 17cac6fdaa34d..ab5f075080290 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -4,6 +4,7 @@ #include #include #include +#include struct request_queue; struct scsi_cmnd; @@ -44,7 +45,7 @@ struct scsi_device { * vendor-specific cmd's */ unsigned sector_size; /* size in bytes */ - int access_count; /* Count of open channels/mounts */ + atomic_t access_count; /* Count of open channels/mounts */ void *hostdata; /* available to low-level driver */ char devfs_name[256]; /* devfs junk */ -- 2.53.0