diff options
author | James Bottomley <JBottomley@Parallels.com> | 2013-10-25 05:21:57 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-10-25 05:58:07 -0400 |
commit | c0d3b9c29ed22d449481bcfac267a879034a3a5b (patch) | |
tree | e1e67d3d50fab46ed53c3d021767a018ee38a2a9 | |
parent | 10c580e4239df5c3344ca00322eca86ab2de880b (diff) |
[SCSI] Revert "sg: push file descriptor list locking down to per-device locking"
This reverts commit 1f962ebcdfa15cede59e9edb299d1330949eec92.
This is one of four patches that was causing this bug
[ 205.372823] ================================================
[ 205.372901] [ BUG: lock held when returning to user space! ]
[ 205.372979] 3.12.0-rc6-hw-debug-pagealloc+ #67 Not tainted
[ 205.373055] ------------------------------------------------
[ 205.373132] megarc.bin/5283 is leaving the kernel with locks still held!
[ 205.373212] 1 lock held by megarc.bin/5283:
[ 205.373285] #0: (&sdp->o_sem){.+.+..}, at: [<ffffffff8161e650>] sg_open+0x3a0/0x4d0
Cc: Vaughan Cao <vaughan.cao@oracle.com>
Acked-by: Douglas Gilbert <dgilbert@interlog.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-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; |