[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>
This commit is contained in:

committed by
James Bottomley

parent
f8fc75dc57
commit
22b9153faa
@@ -208,8 +208,7 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone)
|
||||
|
||||
void sas_porte_bytes_dmaed(struct work_struct *work)
|
||||
{
|
||||
struct asd_sas_event *ev =
|
||||
container_of(work, struct asd_sas_event, work);
|
||||
struct asd_sas_event *ev = to_asd_sas_event(work);
|
||||
struct asd_sas_phy *phy = ev->phy;
|
||||
|
||||
clear_bit(PORTE_BYTES_DMAED, &phy->port_events_pending);
|
||||
@@ -219,8 +218,7 @@ void sas_porte_bytes_dmaed(struct work_struct *work)
|
||||
|
||||
void sas_porte_broadcast_rcvd(struct work_struct *work)
|
||||
{
|
||||
struct asd_sas_event *ev =
|
||||
container_of(work, struct asd_sas_event, work);
|
||||
struct asd_sas_event *ev = to_asd_sas_event(work);
|
||||
struct asd_sas_phy *phy = ev->phy;
|
||||
unsigned long flags;
|
||||
u32 prim;
|
||||
@@ -237,8 +235,7 @@ void sas_porte_broadcast_rcvd(struct work_struct *work)
|
||||
|
||||
void sas_porte_link_reset_err(struct work_struct *work)
|
||||
{
|
||||
struct asd_sas_event *ev =
|
||||
container_of(work, struct asd_sas_event, work);
|
||||
struct asd_sas_event *ev = to_asd_sas_event(work);
|
||||
struct asd_sas_phy *phy = ev->phy;
|
||||
|
||||
clear_bit(PORTE_LINK_RESET_ERR, &phy->port_events_pending);
|
||||
@@ -248,8 +245,7 @@ void sas_porte_link_reset_err(struct work_struct *work)
|
||||
|
||||
void sas_porte_timer_event(struct work_struct *work)
|
||||
{
|
||||
struct asd_sas_event *ev =
|
||||
container_of(work, struct asd_sas_event, work);
|
||||
struct asd_sas_event *ev = to_asd_sas_event(work);
|
||||
struct asd_sas_phy *phy = ev->phy;
|
||||
|
||||
clear_bit(PORTE_TIMER_EVENT, &phy->port_events_pending);
|
||||
@@ -259,8 +255,7 @@ void sas_porte_timer_event(struct work_struct *work)
|
||||
|
||||
void sas_porte_hard_reset(struct work_struct *work)
|
||||
{
|
||||
struct asd_sas_event *ev =
|
||||
container_of(work, struct asd_sas_event, work);
|
||||
struct asd_sas_event *ev = to_asd_sas_event(work);
|
||||
struct asd_sas_phy *phy = ev->phy;
|
||||
|
||||
clear_bit(PORTE_HARD_RESET, &phy->port_events_pending);
|
||||
|
Reference in New Issue
Block a user