diff options
author | Dan Williams <dan.j.williams@intel.com> | 2012-03-09 14:00:06 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-04-23 07:03:39 -0400 |
commit | 22b9153faa2263aa89625de25e71c7d44c8dbd16 (patch) | |
tree | 1157d64a9c63c5b7b48b4a5b3610965d8d4c9624 /drivers/scsi/libsas/sas_init.c | |
parent | f8fc75dc576eac0c996e4a792a4701819d999260 (diff) |
[SCSI] libsas: introduce sas_work to fix sas_drain_work vs sas_queue_work
When requeuing work to a draining workqueue the last work instance may
not be idle, so sas_queue_work() must not touch work->entry. Introduce
sas_work with a drain_node list_head to have a private list for
collecting work deferred due to drain collision.
Fixes reports like:
BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [<ffffffff810410d4>] process_one_work+0x2e/0x338
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas/sas_init.c')
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 11 |
1 files changed, 5 insertions, 6 deletions
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 120bff64be30..10cb5ae30977 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c | |||
@@ -94,8 +94,7 @@ void sas_hash_addr(u8 *hashed, const u8 *sas_addr) | |||
94 | 94 | ||
95 | void sas_hae_reset(struct work_struct *work) | 95 | void sas_hae_reset(struct work_struct *work) |
96 | { | 96 | { |
97 | struct sas_ha_event *ev = | 97 | struct sas_ha_event *ev = to_sas_ha_event(work); |
98 | container_of(work, struct sas_ha_event, work); | ||
99 | struct sas_ha_struct *ha = ev->ha; | 98 | struct sas_ha_struct *ha = ev->ha; |
100 | 99 | ||
101 | clear_bit(HAE_RESET, &ha->pending); | 100 | clear_bit(HAE_RESET, &ha->pending); |
@@ -369,14 +368,14 @@ static void sas_phy_release(struct sas_phy *phy) | |||
369 | 368 | ||
370 | static void phy_reset_work(struct work_struct *work) | 369 | static void phy_reset_work(struct work_struct *work) |
371 | { | 370 | { |
372 | struct sas_phy_data *d = container_of(work, typeof(*d), reset_work); | 371 | struct sas_phy_data *d = container_of(work, typeof(*d), reset_work.work); |
373 | 372 | ||
374 | d->reset_result = transport_sas_phy_reset(d->phy, d->hard_reset); | 373 | d->reset_result = transport_sas_phy_reset(d->phy, d->hard_reset); |
375 | } | 374 | } |
376 | 375 | ||
377 | static void phy_enable_work(struct work_struct *work) | 376 | static void phy_enable_work(struct work_struct *work) |
378 | { | 377 | { |
379 | struct sas_phy_data *d = container_of(work, typeof(*d), enable_work); | 378 | struct sas_phy_data *d = container_of(work, typeof(*d), enable_work.work); |
380 | 379 | ||
381 | d->enable_result = sas_phy_enable(d->phy, d->enable); | 380 | d->enable_result = sas_phy_enable(d->phy, d->enable); |
382 | } | 381 | } |
@@ -389,8 +388,8 @@ static int sas_phy_setup(struct sas_phy *phy) | |||
389 | return -ENOMEM; | 388 | return -ENOMEM; |
390 | 389 | ||
391 | mutex_init(&d->event_lock); | 390 | mutex_init(&d->event_lock); |
392 | INIT_WORK(&d->reset_work, phy_reset_work); | 391 | INIT_SAS_WORK(&d->reset_work, phy_reset_work); |
393 | INIT_WORK(&d->enable_work, phy_enable_work); | 392 | INIT_SAS_WORK(&d->enable_work, phy_enable_work); |
394 | d->phy = phy; | 393 | d->phy = phy; |
395 | phy->hostdata = d; | 394 | phy->hostdata = d; |
396 | 395 | ||