diff mbox

[RFC] PCI, pciehp: make every slot have its own workqueue to avoid deadlock

Message ID 1351667452-9952-1-git-send-email-wangyijing@huawei.com
State Superseded
Headers show

Commit Message

Yijing Wang Oct. 31, 2012, 7:10 a.m. UTC
Currently, pciehp use global pciehp_wq to handle hotplug event from hardware.
Hot remove path will be blocked if a hotplug slot connected a IO-BOX(composed of PCIe
Switch and some slots which support hotplug, eg.PLX8696). The hot removed work was queued 
into pciehp_wq. But in the hot-remove path, pciehp driver would flush pciehp_wq when
the pcie port(support pciehp) was removed. In this case the hot-remove path blocked.
This patch remove the global pciehp_wq and create a new workqueue for every slot to
avoid above problem.

-+-[0000:40]-+-00.0-[0000:41]--
 |           +-01.0-[0000:42]--+-00.0  Intel Corporation 82576 Gigabit Network Connection
 |           |                 \-00.1  Intel Corporation 82576 Gigabit Network Connection
 |           +-03.0-[0000:43]----00.0  LSI Logic / Symbios Logic SAS1064ET PCI-Express Fusion-MPT SAS
 |           +-04.0-[0000:44]--
 |           +-05.0-[0000:45]--
 |           +-07.0-[0000:46-4f]----00.0-[0000:47-4f]--+-04.0-[0000:48-49]----00.0-[0000:49]--
 |           |(hotplug slot)                           +-08.0-[0000:4a]--
 |           |                                         +-09.0-[0000:4b]--
 |           |                                         +-10.0-[0000:4c]--
 |           |                                         +-11.0-[0000:4d]--
 |           |                                         +-14.0-[0000:4e]--
 |           |                                         \-15.0-[0000:4f]--+-00.0  Intel Corporation 82576 Gigabit Network Connection
 |           |                                         (hotplug slot)    \-00.1  Intel Corporation 82576 Gigabit Network Connection


Signed-off-by: Yijing Wang <wangyijing@huawei.com>
---
 drivers/pci/hotplug/pciehp.h      |    2 +-
 drivers/pci/hotplug/pciehp_core.c |   11 ++---------
 drivers/pci/hotplug/pciehp_ctrl.c |    8 ++++----
 drivers/pci/hotplug/pciehp_hpc.c  |   14 ++++++++++++--
 4 files changed, 19 insertions(+), 16 deletions(-)

Comments

Kenji Kaneshige Oct. 31, 2012, 9:20 a.m. UTC | #1
Let me confirm the problem. My understanding of the problem is below.
Is my understanding correct?

- Your hardware has nested PCIe hotplug slots like below.

    --<slot A>--<Slot B>

- Hot-removal request (attention button event) comes to <slot A>
- Pciehp driver queue the hot-removal work
- This hot-removal work try to remove <slot B>
- To remove <slot B>, pciehp flush the pciehp_wq, but it never finishes
  because hot-removal work is in progress. ===> deadlock

Regards,
Kenji Kaneshige



> -----Original Message-----
> From: Yijing Wang [mailto:wangyijing@huawei.com]
> Sent: Wednesday, October 31, 2012 4:11 PM
> To: Bjorn Helgaas; Yinghai Lu; Kaneshige, Kenji/金重 憲治; Rafael; Rusty
> Russell; Mauro Carvalho Chehab; Oliver Neukum
> Cc: linux-pci@vger.kernel.org; Hanjun Guo; jiang.liu@huawei.com; Yijing
> Wang
> Subject: [RFC][PATCH] PCI, pciehp: make every slot have its own workqueue
> to avoid deadlock
> 
> Currently, pciehp use global pciehp_wq to handle hotplug event from
> hardware.
> Hot remove path will be blocked if a hotplug slot connected a IO-BOX(composed
> of PCIe
> Switch and some slots which support hotplug, eg.PLX8696). The hot removed
> work was queued
> into pciehp_wq. But in the hot-remove path, pciehp driver would flush
> pciehp_wq when
> the pcie port(support pciehp) was removed. In this case the hot-remove path
> blocked.
> This patch remove the global pciehp_wq and create a new workqueue for every
> slot to
> avoid above problem.
> 
> -+-[0000:40]-+-00.0-[0000:41]--
>  |           +-01.0-[0000:42]--+-00.0  Intel Corporation 82576 Gigabit
> Network Connection
>  |           |                 \-00.1  Intel Corporation 82576 Gigabit
> Network Connection
>  |           +-03.0-[0000:43]----00.0  LSI Logic / Symbios Logic
> SAS1064ET PCI-Express Fusion-MPT SAS
>  |           +-04.0-[0000:44]--
>  |           +-05.0-[0000:45]--
>  |
> +-07.0-[0000:46-4f]----00.0-[0000:47-4f]--+-04.0-[0000:48-49]----00.0-
> [0000:49]--
>  |           |(hotplug slot)
> +-08.0-[0000:4a]--
>  |           |
> +-09.0-[0000:4b]--
>  |           |
> +-10.0-[0000:4c]--
>  |           |
> +-11.0-[0000:4d]--
>  |           |
> +-14.0-[0000:4e]--
>  |           |
> \-15.0-[0000:4f]--+-00.0  Intel Corporation 82576 Gigabit Network
> Connection
>  |           |                                         (hotplug slot)
> \-00.1  Intel Corporation 82576 Gigabit Network Connection
> 
> 
> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
> ---
>  drivers/pci/hotplug/pciehp.h      |    2 +-
>  drivers/pci/hotplug/pciehp_core.c |   11 ++---------
>  drivers/pci/hotplug/pciehp_ctrl.c |    8 ++++----
>  drivers/pci/hotplug/pciehp_hpc.c  |   14 ++++++++++++--
>  4 files changed, 19 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
> index 26ffd3e..2c113de 100644
> --- a/drivers/pci/hotplug/pciehp.h
> +++ b/drivers/pci/hotplug/pciehp.h
> @@ -44,7 +44,6 @@ extern bool pciehp_poll_mode;
>  extern int pciehp_poll_time;
>  extern bool pciehp_debug;
>  extern bool pciehp_force;
> -extern struct workqueue_struct *pciehp_wq;
> 
>  #define dbg(format, arg...)
> 	\
>  do {
> 	\
> @@ -78,6 +77,7 @@ struct slot {
>  	struct hotplug_slot *hotplug_slot;
>  	struct delayed_work work;	/* work for button event */
>  	struct mutex lock;
> +	struct workqueue_struct *wq;
>  };
> 
>  struct event_info {
> diff --git a/drivers/pci/hotplug/pciehp_core.c
> b/drivers/pci/hotplug/pciehp_core.c
> index 916bf4f..0914211 100644
> --- a/drivers/pci/hotplug/pciehp_core.c
> +++ b/drivers/pci/hotplug/pciehp_core.c
> @@ -42,7 +42,6 @@ bool pciehp_debug;
>  bool pciehp_poll_mode;
>  int pciehp_poll_time;
>  bool pciehp_force;
> -struct workqueue_struct *pciehp_wq;
> 
>  #define DRIVER_VERSION	"0.4"
>  #define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg
> Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
> @@ -340,18 +339,13 @@ static int __init pcied_init(void)
>  {
>  	int retval = 0;
> 
> -	pciehp_wq = alloc_workqueue("pciehp", 0, 0);
> -	if (!pciehp_wq)
> -		return -ENOMEM;
> -
>  	pciehp_firmware_init();
>  	retval = pcie_port_service_register(&hpdriver_portdrv);
>   	dbg("pcie_port_service_register = %d\n", retval);
>    	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
> - 	if (retval) {
> -		destroy_workqueue(pciehp_wq);
> +	if (retval)
>  		dbg("Failure to register service\n");
> -	}
> +
>  	return retval;
>  }
> 
> @@ -359,7 +353,6 @@ static void __exit pcied_cleanup(void)
>  {
>  	dbg("unload_pciehpd()\n");
>  	pcie_port_service_unregister(&hpdriver_portdrv);
> -	destroy_workqueue(pciehp_wq);
>  	info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
>  }
> 
> diff --git a/drivers/pci/hotplug/pciehp_ctrl.c
> b/drivers/pci/hotplug/pciehp_ctrl.c
> index 27f4429..38f0186 100644
> --- a/drivers/pci/hotplug/pciehp_ctrl.c
> +++ b/drivers/pci/hotplug/pciehp_ctrl.c
> @@ -49,7 +49,7 @@ static int queue_interrupt_event(struct slot *p_slot,
> u32 event_type)
>  	info->p_slot = p_slot;
>  	INIT_WORK(&info->work, interrupt_event_handler);
> 
> -	queue_work(pciehp_wq, &info->work);
> +	queue_work(p_slot->wq, &info->work);
> 
>  	return 0;
>  }
> @@ -344,7 +344,7 @@ void pciehp_queue_pushbutton_work(struct work_struct
> *work)
>  		kfree(info);
>  		goto out;
>  	}
> -	queue_work(pciehp_wq, &info->work);
> +	queue_work(p_slot->wq, &info->work);
>   out:
>  	mutex_unlock(&p_slot->lock);
>  }
> @@ -377,7 +377,7 @@ static void handle_button_press_event(struct slot
> *p_slot)
>  		if (ATTN_LED(ctrl))
>  			pciehp_set_attention_status(p_slot, 0);
> 
> -		queue_delayed_work(pciehp_wq, &p_slot->work, 5*HZ);
> +		queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
>  		break;
>  	case BLINKINGOFF_STATE:
>  	case BLINKINGON_STATE:
> @@ -439,7 +439,7 @@ static void handle_surprise_event(struct slot *p_slot)
>  	else
>  		p_slot->state = POWERON_STATE;
> 
> -	queue_work(pciehp_wq, &info->work);
> +	queue_work(p_slot->wq, &info->work);
>  }
> 
>  static void interrupt_event_handler(struct work_struct *work)
> diff --git a/drivers/pci/hotplug/pciehp_hpc.c
> b/drivers/pci/hotplug/pciehp_hpc.c
> index 13b2eaf..8e5e571 100644
> --- a/drivers/pci/hotplug/pciehp_hpc.c
> +++ b/drivers/pci/hotplug/pciehp_hpc.c
> @@ -773,23 +773,33 @@ static void pcie_shutdown_notification(struct
> controller *ctrl)
>  static int pcie_init_slot(struct controller *ctrl)
>  {
>  	struct slot *slot;
> +	char name[32];
> 
>  	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
>  	if (!slot)
>  		return -ENOMEM;
> -
> +
> +	snprintf(name, sizeof(name), "pciehpd_%s",
> +		pci_name(ctrl->pcie->port));
> +	slot->wq = create_singlethread_workqueue(name);
> +	if (!slot->wq)
> +		goto abort;
>  	slot->ctrl = ctrl;
>  	mutex_init(&slot->lock);
>  	INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
>  	ctrl->slot = slot;
>  	return 0;
> +abort:
> +	kfree(slot);
> +	return -1;
>  }
> 
>  static void pcie_cleanup_slot(struct controller *ctrl)
>  {
>  	struct slot *slot = ctrl->slot;
>  	cancel_delayed_work(&slot->work);
> -	flush_workqueue(pciehp_wq);
> +	flush_workqueue(slot->wq);
> +	destroy_workqueue(slot->wq);
>  	kfree(slot);
>  }
> 
> --
> 1.7.1
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Yijing Wang Oct. 31, 2012, 9:33 a.m. UTC | #2
On 2012/10/31 17:20, Kaneshige, Kenji wrote:
> Let me confirm the problem. My understanding of the problem is below.
> Is my understanding correct?
> 

Yes,exactly.

> - Your hardware has nested PCIe hotplug slots like below.
> 
>     --<slot A>--<Slot B>
> 
> - Hot-removal request (attention button event) comes to <slot A>
> - Pciehp driver queue the hot-removal work
> - This hot-removal work try to remove <slot B>
> - To remove <slot B>, pciehp flush the pciehp_wq, but it never finishes
>   because hot-removal work is in progress. ===> deadlock
> 
> Regards,
> Kenji Kaneshige
> 
> 
> 
>> -----Original Message-----
>> From: Yijing Wang [mailto:wangyijing@huawei.com]
>> Sent: Wednesday, October 31, 2012 4:11 PM
>> To: Bjorn Helgaas; Yinghai Lu; Kaneshige, Kenji/金重 憲治; Rafael; Rusty
>> Russell; Mauro Carvalho Chehab; Oliver Neukum
>> Cc: linux-pci@vger.kernel.org; Hanjun Guo; jiang.liu@huawei.com; Yijing
>> Wang
>> Subject: [RFC][PATCH] PCI, pciehp: make every slot have its own workqueue
>> to avoid deadlock
>>
>> Currently, pciehp use global pciehp_wq to handle hotplug event from
>> hardware.
>> Hot remove path will be blocked if a hotplug slot connected a IO-BOX(composed
>> of PCIe
>> Switch and some slots which support hotplug, eg.PLX8696). The hot removed
>> work was queued
>> into pciehp_wq. But in the hot-remove path, pciehp driver would flush
>> pciehp_wq when
>> the pcie port(support pciehp) was removed. In this case the hot-remove path
>> blocked.
>> This patch remove the global pciehp_wq and create a new workqueue for every
>> slot to
>> avoid above problem.
>>
>> -+-[0000:40]-+-00.0-[0000:41]--
>>  |           +-01.0-[0000:42]--+-00.0  Intel Corporation 82576 Gigabit
>> Network Connection
>>  |           |                 \-00.1  Intel Corporation 82576 Gigabit
>> Network Connection
>>  |           +-03.0-[0000:43]----00.0  LSI Logic / Symbios Logic
>> SAS1064ET PCI-Express Fusion-MPT SAS
>>  |           +-04.0-[0000:44]--
>>  |           +-05.0-[0000:45]--
>>  |
>> +-07.0-[0000:46-4f]----00.0-[0000:47-4f]--+-04.0-[0000:48-49]----00.0-
>> [0000:49]--
>>  |           |(hotplug slot)
>> +-08.0-[0000:4a]--
>>  |           |
>> +-09.0-[0000:4b]--
>>  |           |
>> +-10.0-[0000:4c]--
>>  |           |
>> +-11.0-[0000:4d]--
>>  |           |
>> +-14.0-[0000:4e]--
>>  |           |
>> \-15.0-[0000:4f]--+-00.0  Intel Corporation 82576 Gigabit Network
>> Connection
>>  |           |                                         (hotplug slot)
>> \-00.1  Intel Corporation 82576 Gigabit Network Connection
>>
>>
>> Signed-off-by: Yijing Wang <wangyijing@huawei.com>
>> ---
>>  drivers/pci/hotplug/pciehp.h      |    2 +-
>>  drivers/pci/hotplug/pciehp_core.c |   11 ++---------
>>  drivers/pci/hotplug/pciehp_ctrl.c |    8 ++++----
>>  drivers/pci/hotplug/pciehp_hpc.c  |   14 ++++++++++++--
>>  4 files changed, 19 insertions(+), 16 deletions(-)
>>
>> diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
>> index 26ffd3e..2c113de 100644
>> --- a/drivers/pci/hotplug/pciehp.h
>> +++ b/drivers/pci/hotplug/pciehp.h
>> @@ -44,7 +44,6 @@ extern bool pciehp_poll_mode;
>>  extern int pciehp_poll_time;
>>  extern bool pciehp_debug;
>>  extern bool pciehp_force;
>> -extern struct workqueue_struct *pciehp_wq;
>>
>>  #define dbg(format, arg...)
>> 	\
>>  do {
>> 	\
>> @@ -78,6 +77,7 @@ struct slot {
>>  	struct hotplug_slot *hotplug_slot;
>>  	struct delayed_work work;	/* work for button event */
>>  	struct mutex lock;
>> +	struct workqueue_struct *wq;
>>  };
>>
>>  struct event_info {
>> diff --git a/drivers/pci/hotplug/pciehp_core.c
>> b/drivers/pci/hotplug/pciehp_core.c
>> index 916bf4f..0914211 100644
>> --- a/drivers/pci/hotplug/pciehp_core.c
>> +++ b/drivers/pci/hotplug/pciehp_core.c
>> @@ -42,7 +42,6 @@ bool pciehp_debug;
>>  bool pciehp_poll_mode;
>>  int pciehp_poll_time;
>>  bool pciehp_force;
>> -struct workqueue_struct *pciehp_wq;
>>
>>  #define DRIVER_VERSION	"0.4"
>>  #define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg
>> Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
>> @@ -340,18 +339,13 @@ static int __init pcied_init(void)
>>  {
>>  	int retval = 0;
>>
>> -	pciehp_wq = alloc_workqueue("pciehp", 0, 0);
>> -	if (!pciehp_wq)
>> -		return -ENOMEM;
>> -
>>  	pciehp_firmware_init();
>>  	retval = pcie_port_service_register(&hpdriver_portdrv);
>>   	dbg("pcie_port_service_register = %d\n", retval);
>>    	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
>> - 	if (retval) {
>> -		destroy_workqueue(pciehp_wq);
>> +	if (retval)
>>  		dbg("Failure to register service\n");
>> -	}
>> +
>>  	return retval;
>>  }
>>
>> @@ -359,7 +353,6 @@ static void __exit pcied_cleanup(void)
>>  {
>>  	dbg("unload_pciehpd()\n");
>>  	pcie_port_service_unregister(&hpdriver_portdrv);
>> -	destroy_workqueue(pciehp_wq);
>>  	info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
>>  }
>>
>> diff --git a/drivers/pci/hotplug/pciehp_ctrl.c
>> b/drivers/pci/hotplug/pciehp_ctrl.c
>> index 27f4429..38f0186 100644
>> --- a/drivers/pci/hotplug/pciehp_ctrl.c
>> +++ b/drivers/pci/hotplug/pciehp_ctrl.c
>> @@ -49,7 +49,7 @@ static int queue_interrupt_event(struct slot *p_slot,
>> u32 event_type)
>>  	info->p_slot = p_slot;
>>  	INIT_WORK(&info->work, interrupt_event_handler);
>>
>> -	queue_work(pciehp_wq, &info->work);
>> +	queue_work(p_slot->wq, &info->work);
>>
>>  	return 0;
>>  }
>> @@ -344,7 +344,7 @@ void pciehp_queue_pushbutton_work(struct work_struct
>> *work)
>>  		kfree(info);
>>  		goto out;
>>  	}
>> -	queue_work(pciehp_wq, &info->work);
>> +	queue_work(p_slot->wq, &info->work);
>>   out:
>>  	mutex_unlock(&p_slot->lock);
>>  }
>> @@ -377,7 +377,7 @@ static void handle_button_press_event(struct slot
>> *p_slot)
>>  		if (ATTN_LED(ctrl))
>>  			pciehp_set_attention_status(p_slot, 0);
>>
>> -		queue_delayed_work(pciehp_wq, &p_slot->work, 5*HZ);
>> +		queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
>>  		break;
>>  	case BLINKINGOFF_STATE:
>>  	case BLINKINGON_STATE:
>> @@ -439,7 +439,7 @@ static void handle_surprise_event(struct slot *p_slot)
>>  	else
>>  		p_slot->state = POWERON_STATE;
>>
>> -	queue_work(pciehp_wq, &info->work);
>> +	queue_work(p_slot->wq, &info->work);
>>  }
>>
>>  static void interrupt_event_handler(struct work_struct *work)
>> diff --git a/drivers/pci/hotplug/pciehp_hpc.c
>> b/drivers/pci/hotplug/pciehp_hpc.c
>> index 13b2eaf..8e5e571 100644
>> --- a/drivers/pci/hotplug/pciehp_hpc.c
>> +++ b/drivers/pci/hotplug/pciehp_hpc.c
>> @@ -773,23 +773,33 @@ static void pcie_shutdown_notification(struct
>> controller *ctrl)
>>  static int pcie_init_slot(struct controller *ctrl)
>>  {
>>  	struct slot *slot;
>> +	char name[32];
>>
>>  	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
>>  	if (!slot)
>>  		return -ENOMEM;
>> -
>> +
>> +	snprintf(name, sizeof(name), "pciehpd_%s",
>> +		pci_name(ctrl->pcie->port));
>> +	slot->wq = create_singlethread_workqueue(name);
>> +	if (!slot->wq)
>> +		goto abort;
>>  	slot->ctrl = ctrl;
>>  	mutex_init(&slot->lock);
>>  	INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
>>  	ctrl->slot = slot;
>>  	return 0;
>> +abort:
>> +	kfree(slot);
>> +	return -1;
>>  }
>>
>>  static void pcie_cleanup_slot(struct controller *ctrl)
>>  {
>>  	struct slot *slot = ctrl->slot;
>>  	cancel_delayed_work(&slot->work);
>> -	flush_workqueue(pciehp_wq);
>> +	flush_workqueue(slot->wq);
>> +	destroy_workqueue(slot->wq);
>>  	kfree(slot);
>>  }
>>
>> --
>> 1.7.1
>>
> 
> 
> .
>
Kenji Kaneshige Nov. 7, 2012, 10:47 a.m. UTC | #3
Hi Yijing,

I have some comments. Sorry for the delay.

<snip.>

> --- a/drivers/pci/hotplug/pciehp_hpc.c
> +++ b/drivers/pci/hotplug/pciehp_hpc.c
> @@ -773,23 +773,33 @@ static void pcie_shutdown_notification(struct controller *ctrl)
>  static int pcie_init_slot(struct controller *ctrl)
>  {
>  	struct slot *slot;
> +	char name[32];
> 
>  	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
>  	if (!slot)
>  		return -ENOMEM;
> -
> +
> +	snprintf(name, sizeof(name), "pciehpd_%s",
> +		pci_name(ctrl->pcie->port));

The name of the threads seems to be cut off.

$ ps aux | grep pciehp
root        125  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:00]
root        126  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:00]
root        127  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:0b]
root        128  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:0b]
root        129  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:0b]
root        130  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:0b]
root        131  0.0  0.0      0     0 ?        S<   18:55   0:00 [pciehpd_0000:1a]
root        132  0.0  0.0      0     0 ?        S<   18:55   0:00 [pciehpd_0000:1a]
root        133  0.0  0.0      0     0 ?        S<   18:55   0:00 [pciehpd_0000:1a]
root        134  0.0  0.0      0     0 ?        S<   18:55   0:00 [pciehpd_0000:1a]

How about using slot name for the thread name?

<snip.>

> 
>  static void pcie_cleanup_slot(struct controller *ctrl)
>  {
>  	struct slot *slot = ctrl->slot;
>  	cancel_delayed_work(&slot->work);
> -	flush_workqueue(pciehp_wq);
> +	flush_workqueue(slot->wq);
> +	destroy_workqueue(slot->wq);
>  	kfree(slot);
>  }

I think flush_workqueue() call is no longer required because
it is done in destroy_workqueue() code path.

Regards,
Kenji Kaneshige

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Yijing Wang Nov. 8, 2012, 1:16 a.m. UTC | #4
On 2012/11/7 18:47, Kaneshige, Kenji wrote:
> Hi Yijing,
> 
> I have some comments. Sorry for the delay.
> 
> <snip.>
> 

Hi Kaneshige,
   Thanks for your review and comments very much!

I will update this patch and using slot name instead of device name, it's really a good suggestion.
Also I will remove the redundant flush_workqueue().

Thanks!
Yijing.

>> --- a/drivers/pci/hotplug/pciehp_hpc.c
>> +++ b/drivers/pci/hotplug/pciehp_hpc.c
>> @@ -773,23 +773,33 @@ static void pcie_shutdown_notification(struct controller *ctrl)
>>  static int pcie_init_slot(struct controller *ctrl)
>>  {
>>  	struct slot *slot;
>> +	char name[32];
>>
>>  	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
>>  	if (!slot)
>>  		return -ENOMEM;
>> -
>> +
>> +	snprintf(name, sizeof(name), "pciehpd_%s",
>> +		pci_name(ctrl->pcie->port));
> 
> The name of the threads seems to be cut off.
> 
> $ ps aux | grep pciehp
> root        125  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:00]
> root        126  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:00]
> root        127  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:0b]
> root        128  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:0b]
> root        129  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:0b]
> root        130  0.0  0.0      0     0 ?        S<   18:54   0:00 [pciehpd_0000:0b]
> root        131  0.0  0.0      0     0 ?        S<   18:55   0:00 [pciehpd_0000:1a]
> root        132  0.0  0.0      0     0 ?        S<   18:55   0:00 [pciehpd_0000:1a]
> root        133  0.0  0.0      0     0 ?        S<   18:55   0:00 [pciehpd_0000:1a]
> root        134  0.0  0.0      0     0 ?        S<   18:55   0:00 [pciehpd_0000:1a]
> 
> How about using slot name for the thread name?
> 
> <snip.>
> 
>>
>>  static void pcie_cleanup_slot(struct controller *ctrl)
>>  {
>>  	struct slot *slot = ctrl->slot;
>>  	cancel_delayed_work(&slot->work);
>> -	flush_workqueue(pciehp_wq);
>> +	flush_workqueue(slot->wq);
>> +	destroy_workqueue(slot->wq);
>>  	kfree(slot);
>>  }
> 
> I think flush_workqueue() call is no longer required because
> it is done in destroy_workqueue() code path.
> 
> Regards,
> Kenji Kaneshige
> 
> 
> .
>
diff mbox

Patch

diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 26ffd3e..2c113de 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -44,7 +44,6 @@  extern bool pciehp_poll_mode;
 extern int pciehp_poll_time;
 extern bool pciehp_debug;
 extern bool pciehp_force;
-extern struct workqueue_struct *pciehp_wq;
 
 #define dbg(format, arg...)						\
 do {									\
@@ -78,6 +77,7 @@  struct slot {
 	struct hotplug_slot *hotplug_slot;
 	struct delayed_work work;	/* work for button event */
 	struct mutex lock;
+	struct workqueue_struct *wq;
 };
 
 struct event_info {
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 916bf4f..0914211 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -42,7 +42,6 @@  bool pciehp_debug;
 bool pciehp_poll_mode;
 int pciehp_poll_time;
 bool pciehp_force;
-struct workqueue_struct *pciehp_wq;
 
 #define DRIVER_VERSION	"0.4"
 #define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
@@ -340,18 +339,13 @@  static int __init pcied_init(void)
 {
 	int retval = 0;
 
-	pciehp_wq = alloc_workqueue("pciehp", 0, 0);
-	if (!pciehp_wq)
-		return -ENOMEM;
-
 	pciehp_firmware_init();
 	retval = pcie_port_service_register(&hpdriver_portdrv);
  	dbg("pcie_port_service_register = %d\n", retval);
   	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
- 	if (retval) {
-		destroy_workqueue(pciehp_wq);
+	if (retval)
 		dbg("Failure to register service\n");
-	}
+
 	return retval;
 }
 
@@ -359,7 +353,6 @@  static void __exit pcied_cleanup(void)
 {
 	dbg("unload_pciehpd()\n");
 	pcie_port_service_unregister(&hpdriver_portdrv);
-	destroy_workqueue(pciehp_wq);
 	info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
 }
 
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 27f4429..38f0186 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -49,7 +49,7 @@  static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
 	info->p_slot = p_slot;
 	INIT_WORK(&info->work, interrupt_event_handler);
 
-	queue_work(pciehp_wq, &info->work);
+	queue_work(p_slot->wq, &info->work);
 
 	return 0;
 }
@@ -344,7 +344,7 @@  void pciehp_queue_pushbutton_work(struct work_struct *work)
 		kfree(info);
 		goto out;
 	}
-	queue_work(pciehp_wq, &info->work);
+	queue_work(p_slot->wq, &info->work);
  out:
 	mutex_unlock(&p_slot->lock);
 }
@@ -377,7 +377,7 @@  static void handle_button_press_event(struct slot *p_slot)
 		if (ATTN_LED(ctrl))
 			pciehp_set_attention_status(p_slot, 0);
 
-		queue_delayed_work(pciehp_wq, &p_slot->work, 5*HZ);
+		queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
 		break;
 	case BLINKINGOFF_STATE:
 	case BLINKINGON_STATE:
@@ -439,7 +439,7 @@  static void handle_surprise_event(struct slot *p_slot)
 	else
 		p_slot->state = POWERON_STATE;
 
-	queue_work(pciehp_wq, &info->work);
+	queue_work(p_slot->wq, &info->work);
 }
 
 static void interrupt_event_handler(struct work_struct *work)
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 13b2eaf..8e5e571 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -773,23 +773,33 @@  static void pcie_shutdown_notification(struct controller *ctrl)
 static int pcie_init_slot(struct controller *ctrl)
 {
 	struct slot *slot;
+	char name[32];
 
 	slot = kzalloc(sizeof(*slot), GFP_KERNEL);
 	if (!slot)
 		return -ENOMEM;
-
+
+	snprintf(name, sizeof(name), "pciehpd_%s",
+		pci_name(ctrl->pcie->port));
+	slot->wq = create_singlethread_workqueue(name);
+	if (!slot->wq)
+		goto abort;
 	slot->ctrl = ctrl;
 	mutex_init(&slot->lock);
 	INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
 	ctrl->slot = slot;
 	return 0;
+abort:
+	kfree(slot);
+	return -1;
 }
 
 static void pcie_cleanup_slot(struct controller *ctrl)
 {
 	struct slot *slot = ctrl->slot;
 	cancel_delayed_work(&slot->work);
-	flush_workqueue(pciehp_wq);
+	flush_workqueue(slot->wq);
+	destroy_workqueue(slot->wq);
 	kfree(slot);
 }