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