Skip to content

Commit ea32690

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: sja1105: serialize sja1105_port_mcast_flood() with other FDB accesses
sja1105_fdb_add() runs from the dsa_owq, and sja1105_port_mcast_flood() runs from switchdev_deferred_process_work(). Prior to the blamed commit, they used to be indirectly serialized through the rtnl_lock(), which no longer holds true because dsa_owq dropped that. So, it is now possible that we traverse the static config BLK_IDX_L2_LOOKUP elements concurrently compared to when we change them, in sja1105_static_fdb_change(). That is not ideal, since it might result in data corruption. Introduce a mutex which serializes accesses to the hardware FDB and to the static config elements for the L2 Address Lookup table. I can't find a good reason to add locking around sja1105_fdb_dump(). I'll add it later if needed. Fixes: 0faf890 ("net: dsa: drop rtnl_lock from dsa_slave_switchdev_event_work") Signed-off-by: Vladimir Oltean <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7cef293 commit ea32690

File tree

2 files changed

+45
-13
lines changed

2 files changed

+45
-13
lines changed

drivers/net/dsa/sja1105/sja1105.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ struct sja1105_private {
266266
* the switch doesn't confuse them with one another.
267267
*/
268268
struct mutex mgmt_lock;
269+
/* Serializes accesses to the FDB */
270+
struct mutex fdb_lock;
269271
/* PTP two-step TX timestamp ID, and its serialization lock */
270272
spinlock_t ts_id_lock;
271273
u8 ts_id;

drivers/net/dsa/sja1105/sja1105_main.c

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,6 +1798,7 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port,
17981798
struct dsa_db db)
17991799
{
18001800
struct sja1105_private *priv = ds->priv;
1801+
int rc;
18011802

18021803
if (!vid) {
18031804
switch (db.type) {
@@ -1812,12 +1813,16 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port,
18121813
}
18131814
}
18141815

1815-
return priv->info->fdb_add_cmd(ds, port, addr, vid);
1816+
mutex_lock(&priv->fdb_lock);
1817+
rc = priv->info->fdb_add_cmd(ds, port, addr, vid);
1818+
mutex_unlock(&priv->fdb_lock);
1819+
1820+
return rc;
18161821
}
18171822

1818-
static int sja1105_fdb_del(struct dsa_switch *ds, int port,
1819-
const unsigned char *addr, u16 vid,
1820-
struct dsa_db db)
1823+
static int __sja1105_fdb_del(struct dsa_switch *ds, int port,
1824+
const unsigned char *addr, u16 vid,
1825+
struct dsa_db db)
18211826
{
18221827
struct sja1105_private *priv = ds->priv;
18231828

@@ -1837,6 +1842,20 @@ static int sja1105_fdb_del(struct dsa_switch *ds, int port,
18371842
return priv->info->fdb_del_cmd(ds, port, addr, vid);
18381843
}
18391844

1845+
static int sja1105_fdb_del(struct dsa_switch *ds, int port,
1846+
const unsigned char *addr, u16 vid,
1847+
struct dsa_db db)
1848+
{
1849+
struct sja1105_private *priv = ds->priv;
1850+
int rc;
1851+
1852+
mutex_lock(&priv->fdb_lock);
1853+
rc = __sja1105_fdb_del(ds, port, addr, vid, db);
1854+
mutex_unlock(&priv->fdb_lock);
1855+
1856+
return rc;
1857+
}
1858+
18401859
static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
18411860
dsa_fdb_dump_cb_t *cb, void *data)
18421861
{
@@ -1899,6 +1918,8 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port)
18991918
};
19001919
int i;
19011920

1921+
mutex_lock(&priv->fdb_lock);
1922+
19021923
for (i = 0; i < SJA1105_MAX_L2_LOOKUP_COUNT; i++) {
19031924
struct sja1105_l2_lookup_entry l2_lookup = {0};
19041925
u8 macaddr[ETH_ALEN];
@@ -1912,7 +1933,7 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port)
19121933
if (rc) {
19131934
dev_err(ds->dev, "Failed to read FDB: %pe\n",
19141935
ERR_PTR(rc));
1915-
return;
1936+
break;
19161937
}
19171938

19181939
if (!(l2_lookup.destports & BIT(port)))
@@ -1924,14 +1945,16 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port)
19241945

19251946
u64_to_ether_addr(l2_lookup.macaddr, macaddr);
19261947

1927-
rc = sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid, db);
1948+
rc = __sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid, db);
19281949
if (rc) {
19291950
dev_err(ds->dev,
19301951
"Failed to delete FDB entry %pM vid %lld: %pe\n",
19311952
macaddr, l2_lookup.vlanid, ERR_PTR(rc));
1932-
return;
1953+
break;
19331954
}
19341955
}
1956+
1957+
mutex_unlock(&priv->fdb_lock);
19351958
}
19361959

19371960
static int sja1105_mdb_add(struct dsa_switch *ds, int port,
@@ -2955,7 +2978,9 @@ static int sja1105_port_mcast_flood(struct sja1105_private *priv, int to,
29552978
{
29562979
struct sja1105_l2_lookup_entry *l2_lookup;
29572980
struct sja1105_table *table;
2958-
int match;
2981+
int match, rc;
2982+
2983+
mutex_lock(&priv->fdb_lock);
29592984

29602985
table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP];
29612986
l2_lookup = table->entries;
@@ -2968,18 +2993,22 @@ static int sja1105_port_mcast_flood(struct sja1105_private *priv, int to,
29682993
if (match == table->entry_count) {
29692994
NL_SET_ERR_MSG_MOD(extack,
29702995
"Could not find FDB entry for unknown multicast");
2971-
return -ENOSPC;
2996+
rc = -ENOSPC;
2997+
goto out;
29722998
}
29732999

29743000
if (flags.val & BR_MCAST_FLOOD)
29753001
l2_lookup[match].destports |= BIT(to);
29763002
else
29773003
l2_lookup[match].destports &= ~BIT(to);
29783004

2979-
return sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
2980-
l2_lookup[match].index,
2981-
&l2_lookup[match],
2982-
true);
3005+
rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP,
3006+
l2_lookup[match].index,
3007+
&l2_lookup[match], true);
3008+
out:
3009+
mutex_unlock(&priv->fdb_lock);
3010+
3011+
return rc;
29833012
}
29843013

29853014
static int sja1105_port_pre_bridge_flags(struct dsa_switch *ds, int port,
@@ -3349,6 +3378,7 @@ static int sja1105_probe(struct spi_device *spi)
33493378
mutex_init(&priv->ptp_data.lock);
33503379
mutex_init(&priv->dynamic_config_lock);
33513380
mutex_init(&priv->mgmt_lock);
3381+
mutex_init(&priv->fdb_lock);
33523382
spin_lock_init(&priv->ts_id_lock);
33533383

33543384
rc = sja1105_parse_dt(priv);

0 commit comments

Comments
 (0)