ehea: fix race condition

When ehea_stop is called the function
cancel_work_sync(&port->reset_task) is used to ensure
that the reset task is not running anymore. We need an
additional flag to ensure that it can not be scheduled
after this call again for a certain time.

Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
Jan-Bernd Themann 2008-07-03 15:18:51 +01:00 committed by Jeff Garzik
parent b0afffe89b
commit 2f69ae01c8
2 changed files with 16 additions and 7 deletions

View file

@ -40,7 +40,7 @@
#include <asm/io.h> #include <asm/io.h>
#define DRV_NAME "ehea" #define DRV_NAME "ehea"
#define DRV_VERSION "EHEA_0091" #define DRV_VERSION "EHEA_0092"
/* eHEA capability flags */ /* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1 #define DLPAR_PORT_ADD_REM 1
@ -478,6 +478,7 @@ struct ehea_port {
int num_add_tx_qps; int num_add_tx_qps;
int num_mcs; int num_mcs;
int resets; int resets;
u64 flags;
u64 mac_addr; u64 mac_addr;
u32 logical_port_id; u32 logical_port_id;
u32 port_speed; u32 port_speed;
@ -501,7 +502,8 @@ struct port_res_cfg {
}; };
enum ehea_flag_bits { enum ehea_flag_bits {
__EHEA_STOP_XFER __EHEA_STOP_XFER,
__EHEA_DISABLE_PORT_RESET
}; };
void ehea_set_ethtool_ops(struct net_device *netdev); void ehea_set_ethtool_ops(struct net_device *netdev);

View file

@ -138,6 +138,12 @@ void ehea_dump(void *adr, int len, char *msg)
} }
} }
void ehea_schedule_port_reset(struct ehea_port *port)
{
if (!test_bit(__EHEA_DISABLE_PORT_RESET, &port->flags))
schedule_work(&port->reset_task);
}
static void ehea_update_firmware_handles(void) static void ehea_update_firmware_handles(void)
{ {
struct ehea_fw_handle_entry *arr = NULL; struct ehea_fw_handle_entry *arr = NULL;
@ -588,7 +594,7 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
"Resetting port.", pr->qp->init_attr.qp_nr); "Resetting port.", pr->qp->init_attr.qp_nr);
ehea_dump(cqe, sizeof(*cqe), "CQE"); ehea_dump(cqe, sizeof(*cqe), "CQE");
} }
schedule_work(&pr->port->reset_task); ehea_schedule_port_reset(pr->port);
return 1; return 1;
} }
@ -766,7 +772,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
ehea_error("Send Completion Error: Resetting port"); ehea_error("Send Completion Error: Resetting port");
if (netif_msg_tx_err(pr->port)) if (netif_msg_tx_err(pr->port))
ehea_dump(cqe, sizeof(*cqe), "Send CQE"); ehea_dump(cqe, sizeof(*cqe), "Send CQE");
schedule_work(&pr->port->reset_task); ehea_schedule_port_reset(pr->port);
break; break;
} }
@ -886,7 +892,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
eqe = ehea_poll_eq(port->qp_eq); eqe = ehea_poll_eq(port->qp_eq);
} }
schedule_work(&port->reset_task); ehea_schedule_port_reset(port);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -2606,13 +2612,14 @@ static int ehea_stop(struct net_device *dev)
if (netif_msg_ifdown(port)) if (netif_msg_ifdown(port))
ehea_info("disabling port %s", dev->name); ehea_info("disabling port %s", dev->name);
set_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
cancel_work_sync(&port->reset_task); cancel_work_sync(&port->reset_task);
mutex_lock(&port->port_lock); mutex_lock(&port->port_lock);
netif_stop_queue(dev); netif_stop_queue(dev);
port_napi_disable(port); port_napi_disable(port);
ret = ehea_down(dev); ret = ehea_down(dev);
mutex_unlock(&port->port_lock); mutex_unlock(&port->port_lock);
clear_bit(__EHEA_DISABLE_PORT_RESET, &port->flags);
return ret; return ret;
} }
@ -2942,7 +2949,7 @@ static void ehea_tx_watchdog(struct net_device *dev)
if (netif_carrier_ok(dev) && if (netif_carrier_ok(dev) &&
!test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
schedule_work(&port->reset_task); ehea_schedule_port_reset(port);
} }
int ehea_sense_adapter_attr(struct ehea_adapter *adapter) int ehea_sense_adapter_attr(struct ehea_adapter *adapter)