diff options
| -rw-r--r-- | drivers/scsi/sg.c | 62 |
1 files changed, 28 insertions, 34 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 5cbc4bb1b395..64df1ab141e5 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c | |||
| @@ -106,7 +106,8 @@ static int sg_add(struct device *, struct class_interface *); | |||
| 106 | static void sg_remove(struct device *, struct class_interface *); | 106 | static void sg_remove(struct device *, struct class_interface *); |
| 107 | 107 | ||
| 108 | static DEFINE_IDR(sg_index_idr); | 108 | static DEFINE_IDR(sg_index_idr); |
| 109 | static DEFINE_RWLOCK(sg_index_lock); | 109 | static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock |
| 110 | file descriptor list for device */ | ||
| 110 | 111 | ||
| 111 | static struct class_interface sg_interface = { | 112 | static struct class_interface sg_interface = { |
| 112 | .add_dev = sg_add, | 113 | .add_dev = sg_add, |
| @@ -143,7 +144,8 @@ typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */ | |||
| 143 | } Sg_request; | 144 | } Sg_request; |
| 144 | 145 | ||
| 145 | typedef struct sg_fd { /* holds the state of a file descriptor */ | 146 | typedef struct sg_fd { /* holds the state of a file descriptor */ |
| 146 | struct list_head sfd_siblings; /* protected by sfd_lock of device */ | 147 | /* sfd_siblings is protected by sg_index_lock */ |
| 148 | struct list_head sfd_siblings; | ||
| 147 | struct sg_device *parentdp; /* owning device */ | 149 | struct sg_device *parentdp; /* owning device */ |
| 148 | wait_queue_head_t read_wait; /* queue read until command done */ | 150 | wait_queue_head_t read_wait; /* queue read until command done */ |
| 149 | rwlock_t rq_list_lock; /* protect access to list in req_arr */ | 151 | rwlock_t rq_list_lock; /* protect access to list in req_arr */ |
| @@ -168,7 +170,7 @@ typedef struct sg_device { /* holds the state of each scsi generic device */ | |||
| 168 | struct scsi_device *device; | 170 | struct scsi_device *device; |
| 169 | int sg_tablesize; /* adapter's max scatter-gather table size */ | 171 | int sg_tablesize; /* adapter's max scatter-gather table size */ |
| 170 | u32 index; /* device index number */ | 172 | u32 index; /* device index number */ |
| 171 | spinlock_t sfd_lock; /* protect file descriptor list for device */ | 173 | /* sfds is protected by sg_index_lock */ |
| 172 | struct list_head sfds; | 174 | struct list_head sfds; |
| 173 | struct rw_semaphore o_sem; /* exclude open should hold this rwsem */ | 175 | struct rw_semaphore o_sem; /* exclude open should hold this rwsem */ |
| 174 | volatile char detached; /* 0->attached, 1->detached pending removal */ | 176 | volatile char detached; /* 0->attached, 1->detached pending removal */ |
| @@ -225,9 +227,9 @@ static int sfds_list_empty(Sg_device *sdp) | |||
| 225 | unsigned long flags; | 227 | unsigned long flags; |
| 226 | int ret; | 228 | int ret; |
| 227 | 229 | ||
| 228 | spin_lock_irqsave(&sdp->sfd_lock, flags); | 230 | read_lock_irqsave(&sg_index_lock, flags); |
| 229 | ret = list_empty(&sdp->sfds); | 231 | ret = list_empty(&sdp->sfds); |
| 230 | spin_unlock_irqrestore(&sdp->sfd_lock, flags); | 232 | read_unlock_irqrestore(&sg_index_lock, flags); |
| 231 | return ret; | 233 | return ret; |
| 232 | } | 234 | } |
| 233 | 235 | ||
| @@ -1391,7 +1393,6 @@ static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) | |||
| 1391 | disk->first_minor = k; | 1393 | disk->first_minor = k; |
| 1392 | sdp->disk = disk; | 1394 | sdp->disk = disk; |
| 1393 | sdp->device = scsidp; | 1395 | sdp->device = scsidp; |
| 1394 | spin_lock_init(&sdp->sfd_lock); | ||
| 1395 | INIT_LIST_HEAD(&sdp->sfds); | 1396 | INIT_LIST_HEAD(&sdp->sfds); |
| 1396 | init_rwsem(&sdp->o_sem); | 1397 | init_rwsem(&sdp->o_sem); |
| 1397 | sdp->sg_tablesize = queue_max_segments(q); | 1398 | sdp->sg_tablesize = queue_max_segments(q); |
| @@ -1526,13 +1527,11 @@ static void sg_remove(struct device *cl_dev, struct class_interface *cl_intf) | |||
| 1526 | 1527 | ||
| 1527 | /* Need a write lock to set sdp->detached. */ | 1528 | /* Need a write lock to set sdp->detached. */ |
| 1528 | write_lock_irqsave(&sg_index_lock, iflags); | 1529 | write_lock_irqsave(&sg_index_lock, iflags); |
| 1529 | spin_lock(&sdp->sfd_lock); | ||
| 1530 | sdp->detached = 1; | 1530 | sdp->detached = 1; |
| 1531 | list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) { | 1531 | list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) { |
| 1532 | wake_up_interruptible(&sfp->read_wait); | 1532 | wake_up_interruptible(&sfp->read_wait); |
| 1533 | kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP); | 1533 | kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP); |
| 1534 | } | 1534 | } |
| 1535 | spin_unlock(&sdp->sfd_lock); | ||
| 1536 | write_unlock_irqrestore(&sg_index_lock, iflags); | 1535 | write_unlock_irqrestore(&sg_index_lock, iflags); |
| 1537 | 1536 | ||
| 1538 | sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); | 1537 | sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); |
| @@ -2057,13 +2056,13 @@ sg_add_sfp(Sg_device * sdp, int dev) | |||
| 2057 | sfp->cmd_q = SG_DEF_COMMAND_Q; | 2056 | sfp->cmd_q = SG_DEF_COMMAND_Q; |
| 2058 | sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; | 2057 | sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; |
| 2059 | sfp->parentdp = sdp; | 2058 | sfp->parentdp = sdp; |
| 2060 | spin_lock_irqsave(&sdp->sfd_lock, iflags); | 2059 | write_lock_irqsave(&sg_index_lock, iflags); |
| 2061 | if (sdp->detached) { | 2060 | if (sdp->detached) { |
| 2062 | spin_unlock_irqrestore(&sdp->sfd_lock, iflags); | 2061 | write_unlock_irqrestore(&sg_index_lock, iflags); |
| 2063 | return ERR_PTR(-ENODEV); | 2062 | return ERR_PTR(-ENODEV); |
| 2064 | } | 2063 | } |
| 2065 | list_add_tail(&sfp->sfd_siblings, &sdp->sfds); | 2064 | list_add_tail(&sfp->sfd_siblings, &sdp->sfds); |
| 2066 | spin_unlock_irqrestore(&sdp->sfd_lock, iflags); | 2065 | write_unlock_irqrestore(&sg_index_lock, iflags); |
| 2067 | SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); | 2066 | SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); |
| 2068 | if (unlikely(sg_big_buff != def_reserved_size)) | 2067 | if (unlikely(sg_big_buff != def_reserved_size)) |
| 2069 | sg_big_buff = def_reserved_size; | 2068 | sg_big_buff = def_reserved_size; |
| @@ -2110,12 +2109,11 @@ static void sg_remove_sfp_usercontext(struct work_struct *work) | |||
| 2110 | static void sg_remove_sfp(struct kref *kref) | 2109 | static void sg_remove_sfp(struct kref *kref) |
| 2111 | { | 2110 | { |
| 2112 | struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref); | 2111 | struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref); |
| 2113 | struct sg_device *sdp = sfp->parentdp; | ||
| 2114 | unsigned long iflags; | 2112 | unsigned long iflags; |
| 2115 | 2113 | ||
| 2116 | spin_lock_irqsave(&sdp->sfd_lock, iflags); | 2114 | write_lock_irqsave(&sg_index_lock, iflags); |
| 2117 | list_del(&sfp->sfd_siblings); | 2115 | list_del(&sfp->sfd_siblings); |
| 2118 | spin_unlock_irqrestore(&sdp->sfd_lock, iflags); | 2116 | write_unlock_irqrestore(&sg_index_lock, iflags); |
| 2119 | 2117 | ||
| 2120 | INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext); | 2118 | INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext); |
| 2121 | schedule_work(&sfp->ew.work); | 2119 | schedule_work(&sfp->ew.work); |
| @@ -2502,7 +2500,7 @@ static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v) | |||
| 2502 | return 0; | 2500 | return 0; |
| 2503 | } | 2501 | } |
| 2504 | 2502 | ||
| 2505 | /* must be called while holding sg_index_lock and sfd_lock */ | 2503 | /* must be called while holding sg_index_lock */ |
| 2506 | static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) | 2504 | static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) |
| 2507 | { | 2505 | { |
| 2508 | int k, m, new_interface, blen, usg; | 2506 | int k, m, new_interface, blen, usg; |
| @@ -2587,26 +2585,22 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v) | |||
| 2587 | 2585 | ||
| 2588 | read_lock_irqsave(&sg_index_lock, iflags); | 2586 | read_lock_irqsave(&sg_index_lock, iflags); |
| 2589 | sdp = it ? sg_lookup_dev(it->index) : NULL; | 2587 | sdp = it ? sg_lookup_dev(it->index) : NULL; |
| 2590 | if (sdp) { | 2588 | if (sdp && !list_empty(&sdp->sfds)) { |
| 2591 | spin_lock(&sdp->sfd_lock); | 2589 | struct scsi_device *scsidp = sdp->device; |
| 2592 | if (!list_empty(&sdp->sfds)) { | ||
| 2593 | struct scsi_device *scsidp = sdp->device; | ||
| 2594 | 2590 | ||
| 2595 | seq_printf(s, " >>> device=%s ", sdp->disk->disk_name); | 2591 | seq_printf(s, " >>> device=%s ", sdp->disk->disk_name); |
| 2596 | if (sdp->detached) | 2592 | if (sdp->detached) |
| 2597 | seq_printf(s, "detached pending close "); | 2593 | seq_printf(s, "detached pending close "); |
| 2598 | else | 2594 | else |
| 2599 | seq_printf | 2595 | seq_printf |
| 2600 | (s, "scsi%d chan=%d id=%d lun=%d em=%d", | 2596 | (s, "scsi%d chan=%d id=%d lun=%d em=%d", |
| 2601 | scsidp->host->host_no, | 2597 | scsidp->host->host_no, |
| 2602 | scsidp->channel, scsidp->id, | 2598 | scsidp->channel, scsidp->id, |
| 2603 | scsidp->lun, | 2599 | scsidp->lun, |
| 2604 | scsidp->host->hostt->emulated); | 2600 | scsidp->host->hostt->emulated); |
| 2605 | seq_printf(s, " sg_tablesize=%d excl=%d\n", | 2601 | seq_printf(s, " sg_tablesize=%d excl=%d\n", |
| 2606 | sdp->sg_tablesize, sdp->exclude); | 2602 | sdp->sg_tablesize, sdp->exclude); |
| 2607 | sg_proc_debug_helper(s, sdp); | 2603 | sg_proc_debug_helper(s, sdp); |
| 2608 | } | ||
| 2609 | spin_unlock(&sdp->sfd_lock); | ||
| 2610 | } | 2604 | } |
| 2611 | read_unlock_irqrestore(&sg_index_lock, iflags); | 2605 | read_unlock_irqrestore(&sg_index_lock, iflags); |
| 2612 | return 0; | 2606 | return 0; |
