Commit 2f69ae01 authored by Jan-Bernd Themann's avatar Jan-Bernd Themann Committed by Jeff Garzik
Browse files

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: default avatarJan-Bernd Themann <themann@de.ibm.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent b0afffe8
Loading
Loading
Loading
Loading
+4 −2
Original line number Original line Diff line number Diff line
@@ -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);
+12 −5
Original line number Original line Diff line number Diff line
@@ -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)