Check that port is started when MAC filter is set

The MAC filter set may be called without softc_lock held in the case of
SIOCADDMULTI and SIOCDELMULTI ioctls. The ioctl handler checks IFF_DRV_RUNNING
flag which implies port started, but it is not guaranteed to remain.
softc_lock shared lock can't be held in the case of these ioctls processing,
since it results in failure where kernel complains that non-sleepable
lock is held in sleeping thread.

Both problems are repeatable on LAG with LACP proto bring up.

Submitted by:   Andrew Rybchenko <Andrew.Rybchenko at oktetlabs.ru>
Sponsored by:   Solarflare Communications, Inc.

MFC after:	2 weeks
This commit is contained in:
George V. Neville-Neil 2014-04-22 20:19:09 +00:00
parent 994f858a8b
commit 092a178372
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=264772

View file

@ -320,10 +320,21 @@ sfxge_mac_filter_set(struct sfxge_softc *sc)
struct sfxge_port *port = &sc->port;
int rc;
KASSERT(port->init_state == SFXGE_PORT_STARTED, ("port not started"));
mtx_lock(&port->lock);
rc = sfxge_mac_filter_set_locked(sc);
/*
* The function may be called without softc_lock held in the
* case of SIOCADDMULTI and SIOCDELMULTI ioctls. ioctl handler
* checks IFF_DRV_RUNNING flag which implies port started, but
* it is not guaranteed to remain. softc_lock shared lock can't
* be held in the case of these ioctls processing, since it
* results in failure where kernel complains that non-sleepable
* lock is held in sleeping thread. Both problems are repeatable
* on LAG with LACP proto bring up.
*/
if (port->init_state == SFXGE_PORT_STARTED)
rc = sfxge_mac_filter_set_locked(sc);
else
rc = 0;
mtx_unlock(&port->lock);
return rc;
}