From 8a53c6db1b421de7f1b6aa94b362b72606d759a1 Mon Sep 17 00:00:00 2001 From: Xiongfeng Wang Date: Mon, 1 Jul 2019 10:38:46 +0800 Subject: [PATCH] pciehp: use delayed_work private data to pass pending events euler inclusion category: bugfix bugzilla: NA CVE: NA --------------------------- We use 'work_struct' private data to pass the pending events when we schedule a 'delayed_work' in the following commit. 764cafd9875e ("pciehp: fix a race between pciehp and removing operations by sysfs") But workqueue framework will use this member, such as workqueue core function 'set_work_pool_and_keep_pending()'. This patch add a new member in 'struct delayed_work' and use this member to pass the pending events. This patch also add more debug info. Fixes: 764cafd9875e ("pciehp: fix a race between pciehp and removing operations by sysfs") Signed-off-by: Xiongfeng Wang Reviewed-by: Yao Hongbo Reviewed-by: Hanjun Guo Signed-off-by: Yang Yingliang --- drivers/pci/hotplug/pciehp_ctrl.c | 5 ++--- drivers/pci/hotplug/pciehp_hpc.c | 15 ++++++++++----- include/linux/workqueue.h | 2 ++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index d5f993d2f5f3..b6274e58f95d 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -145,8 +145,7 @@ void pciehp_queue_pushbutton_work(struct work_struct *work) { struct slot *p_slot = container_of(work, struct slot, work.work); struct controller *ctrl = p_slot->ctrl; - int events = atomic_long_read(&work->data) & (PCI_EXP_SLTSTA_PDC | - PCI_EXP_SLTSTA_DLLSC | DISABLE_SLOT); + int events = p_slot->work.data; mutex_lock(&p_slot->lock); switch (p_slot->state) { @@ -188,7 +187,7 @@ void pciehp_handle_button_press(struct slot *p_slot) /* blink green LED and turn off amber */ pciehp_green_led_blink(p_slot); pciehp_set_attention_status(p_slot, 0); - atomic_long_set(&p_slot->work.work.data, 0); + p_slot->work.data = 0; schedule_delayed_work(&p_slot->work, 5 * HZ); break; case BLINKINGOFF_STATE: diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index a8298b483e9c..43bb78122795 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -693,18 +693,22 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) slot->state == BLINKINGON_STATE) pciehp_handle_disable_request(slot); else { + ctrl_info(ctrl, "Slot(%s): DISABLE_SLOT event in remove or rescan process!\n", + slot_name(slot)); /* * we use the work_struct private data to store * the event type */ - atomic_long_set(&slot->work.work.data, - DISABLE_SLOT); + slot->work.data = DISABLE_SLOT; /* * If 'work.timer' is pending, schedule the work will * cause BUG_ON(). */ if (!timer_pending(&slot->work.timer)) schedule_delayed_work(&slot->work, 3 * HZ); + else + ctrl_info(ctrl, "Slot(%s): Didn't schedule delayed_work because timer is pending!\n", + slot_name(slot)); } } } else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC)) { @@ -723,11 +727,12 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id) */ ctrl_info(ctrl, "Slot(%s): Surprise link down/up in remove or rescan process!\n", slot_name(slot)); - atomic_long_set(&slot->work.work.data, - events & (PCI_EXP_SLTSTA_PDC | - PCI_EXP_SLTSTA_DLLSC)); + slot->work.data = events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); if (!timer_pending(&slot->work.timer)) schedule_delayed_work(&slot->work, 3 * HZ); + else + ctrl_info(ctrl, "Slot(%s): Didn't schedule delayed_work because timer is pending!\n", + slot_name(slot)); } } } diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index cd9ae7672203..59bc6b302997 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -125,6 +125,8 @@ struct delayed_work { /* target workqueue and CPU ->timer uses to queue ->work */ struct workqueue_struct *wq; int cpu; + /* delayed_work private data, only used in pciehp now */ + unsigned long data; KABI_RESERVE(1) KABI_RESERVE(2) -- GitLab