Commit c7bf2df4 authored by Robert Hancock's avatar Robert Hancock Committed by Greg Kroah-Hartman

net: sfp: add mutex to prevent concurrent state checks

[ Upstream commit 2158e856 ]

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: default avatarRussell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarRobert Hancock <hancock@sedsystems.ca>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent fa4059c5
...@@ -185,10 +185,11 @@ struct sfp { ...@@ -185,10 +185,11 @@ struct sfp {
struct gpio_desc *gpio[GPIO_MAX]; struct gpio_desc *gpio[GPIO_MAX];
bool attached; bool attached;
struct mutex st_mutex; /* Protects state */
unsigned int state; unsigned int state;
struct delayed_work poll; struct delayed_work poll;
struct delayed_work timeout; struct delayed_work timeout;
struct mutex sm_mutex; struct mutex sm_mutex; /* Protects state machine */
unsigned char sm_mod_state; unsigned char sm_mod_state;
unsigned char sm_dev_state; unsigned char sm_dev_state;
unsigned short sm_state; unsigned short sm_state;
...@@ -1718,6 +1719,7 @@ static void sfp_check_state(struct sfp *sfp) ...@@ -1718,6 +1719,7 @@ static void sfp_check_state(struct sfp *sfp)
{ {
unsigned int state, i, changed; unsigned int state, i, changed;
mutex_lock(&sfp->st_mutex);
state = sfp_get_state(sfp); state = sfp_get_state(sfp);
changed = state ^ sfp->state; changed = state ^ sfp->state;
changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT; changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
...@@ -1743,6 +1745,7 @@ static void sfp_check_state(struct sfp *sfp) ...@@ -1743,6 +1745,7 @@ static void sfp_check_state(struct sfp *sfp)
sfp_sm_event(sfp, state & SFP_F_LOS ? sfp_sm_event(sfp, state & SFP_F_LOS ?
SFP_E_LOS_HIGH : SFP_E_LOS_LOW); SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
rtnl_unlock(); rtnl_unlock();
mutex_unlock(&sfp->st_mutex);
} }
static irqreturn_t sfp_irq(int irq, void *data) static irqreturn_t sfp_irq(int irq, void *data)
...@@ -1773,6 +1776,7 @@ static struct sfp *sfp_alloc(struct device *dev) ...@@ -1773,6 +1776,7 @@ static struct sfp *sfp_alloc(struct device *dev)
sfp->dev = dev; sfp->dev = dev;
mutex_init(&sfp->sm_mutex); mutex_init(&sfp->sm_mutex);
mutex_init(&sfp->st_mutex);
INIT_DELAYED_WORK(&sfp->poll, sfp_poll); INIT_DELAYED_WORK(&sfp->poll, sfp_poll);
INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout); INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment