Commit dd98708c authored by Edward Cree's avatar Edward Cree Committed by David S. Miller

sfc: Assert filter_sem write locked when required

Based on a patch by Andrew Rybchenko <Andrew.Rybchenko@oktetlabs.ru>
Signed-off-by: default avatarEdward Cree <ecree@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ebfcd0fd
...@@ -3735,6 +3735,12 @@ static int efx_ef10_filter_table_probe(struct efx_nic *efx) ...@@ -3735,6 +3735,12 @@ static int efx_ef10_filter_table_probe(struct efx_nic *efx)
size_t outlen; size_t outlen;
int rc; int rc;
if (!efx_rwsem_assert_write_locked(&efx->filter_sem))
return -EINVAL;
if (efx->filter_state) /* already probed */
return 0;
table = kzalloc(sizeof(*table), GFP_KERNEL); table = kzalloc(sizeof(*table), GFP_KERNEL);
if (!table) if (!table)
return -ENOMEM; return -ENOMEM;
...@@ -3846,7 +3852,6 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx) ...@@ -3846,7 +3852,6 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx)
nic_data->must_restore_filters = false; nic_data->must_restore_filters = false;
} }
/* Caller must hold efx->filter_sem for write */
static void efx_ef10_filter_table_remove(struct efx_nic *efx) static void efx_ef10_filter_table_remove(struct efx_nic *efx)
{ {
struct efx_ef10_filter_table *table = efx->filter_state; struct efx_ef10_filter_table *table = efx->filter_state;
...@@ -3856,6 +3861,15 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx) ...@@ -3856,6 +3861,15 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx)
int rc; int rc;
efx->filter_state = NULL; efx->filter_state = NULL;
/* If we were called without locking, then it's not safe to free
* the table as others might be using it. So we just WARN, leak
* the memory, and potentially get an inconsistent filter table
* state.
* This should never actually happen.
*/
if (!efx_rwsem_assert_write_locked(&efx->filter_sem))
return;
if (!table) if (!table)
return; return;
......
...@@ -274,4 +274,13 @@ static inline void efx_device_detach_sync(struct efx_nic *efx) ...@@ -274,4 +274,13 @@ static inline void efx_device_detach_sync(struct efx_nic *efx)
netif_tx_unlock_bh(dev); netif_tx_unlock_bh(dev);
} }
static inline bool efx_rwsem_assert_write_locked(struct rw_semaphore *sem)
{
if (WARN_ON(down_read_trylock(sem))) {
up_read(sem);
return false;
}
return true;
}
#endif /* EFX_EFX_H */ #endif /* EFX_EFX_H */
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