diff options
author | Vaughan Cao <vaughan.cao@oracle.com> | 2013-08-28 22:00:39 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-09-03 10:28:10 -0400 |
commit | 1f962ebcdfa15cede59e9edb299d1330949eec92 (patch) | |
tree | 0b2018c25b6774bd8cd3d97c1201670c1470de52 /drivers/scsi | |
parent | e32c9e6300e3af659cbfe45e90a1e7dcd3572ada (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.c | 62 |
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 *); | |||
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); /* Also used to lock | 109 | static DEFINE_RWLOCK(sg_index_lock); |
110 | file descriptor list for device */ | ||
111 | 110 | ||
112 | static struct class_interface sg_interface = { | 111 | static 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 | ||
146 | typedef struct sg_fd { /* holds the state of a file descriptor */ | 145 | typedef 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) | |||
2109 | static void sg_remove_sfp(struct kref *kref) | 2110 | static 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 */ |
2504 | static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) | 2506 | static 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; |