From: Robert Hancock Date: Fri, 7 Jun 2019 16:42:36 +0000 (-0600) Subject: net: sfp: add mutex to prevent concurrent state checks X-Git-Tag: v5.1.20~300 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b892e3cf62cc35109a618ba15d005858679979b1;p=thirdparty%2Fkernel%2Fstable.git net: sfp: add mutex to prevent concurrent state checks [ Upstream commit 2158e856f56bb762ef90f3ec244d41a519826f75 ] sfp_check_state can potentially be called by both a threaded IRQ handler and delayed work. If it is concurrently called, it could result in incorrect state management. Add a st_mutex to protect the state - this lock gets taken outside of code that checks and handle state changes, and the existing sm_mutex nests inside of it. Suggested-by: Russell King Signed-off-by: Robert Hancock Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 71812be0ac645..b6efd2d41dce3 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -186,10 +186,11 @@ struct sfp { struct gpio_desc *gpio[GPIO_MAX]; bool attached; + struct mutex st_mutex; /* Protects state */ unsigned int state; struct delayed_work poll; struct delayed_work timeout; - struct mutex sm_mutex; + struct mutex sm_mutex; /* Protects state machine */ unsigned char sm_mod_state; unsigned char sm_dev_state; unsigned short sm_state; @@ -1719,6 +1720,7 @@ static void sfp_check_state(struct sfp *sfp) { unsigned int state, i, changed; + mutex_lock(&sfp->st_mutex); state = sfp_get_state(sfp); changed = state ^ sfp->state; changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT; @@ -1744,6 +1746,7 @@ static void sfp_check_state(struct sfp *sfp) sfp_sm_event(sfp, state & SFP_F_LOS ? SFP_E_LOS_HIGH : SFP_E_LOS_LOW); rtnl_unlock(); + mutex_unlock(&sfp->st_mutex); } static irqreturn_t sfp_irq(int irq, void *data) @@ -1774,6 +1777,7 @@ static struct sfp *sfp_alloc(struct device *dev) sfp->dev = dev; mutex_init(&sfp->sm_mutex); + mutex_init(&sfp->st_mutex); INIT_DELAYED_WORK(&sfp->poll, sfp_poll); INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);