Skip to content

Commit 49e6123

Browse files
TaeheeYoodavem330
authored andcommitted
net: sfc: fix memory leak due to ptp channel
It fixes memory leak in ring buffer change logic. When ring buffer size is changed(ethtool -G eth0 rx 4096), sfc driver works like below. 1. stop all channels and remove ring buffers. 2. allocates new buffer array. 3. allocates rx buffers. 4. start channels. While the above steps are working, it skips some steps if the channel doesn't have a ->copy callback function. Due to ptp channel doesn't have ->copy callback, these above steps are skipped for ptp channel. It eventually makes some problems. a. ptp channel's ring buffer size is not changed, it works only 1024(default). b. memory leak. The reason for memory leak is to use the wrong ring buffer values. There are some values, which is related to ring buffer size. a. efx->rxq_entries - This is global value of rx queue size. b. rx_queue->ptr_mask - used for access ring buffer as circular ring. - roundup_pow_of_two(efx->rxq_entries) - 1 c. rx_queue->max_fill - efx->rxq_entries - EFX_RXD_HEAD_ROOM These all values should be based on ring buffer size consistently. But ptp channel's values are not. a. efx->rxq_entries - This is global(for sfc) value, always new ring buffer size. b. rx_queue->ptr_mask - This is always 1023(default). c. rx_queue->max_fill - This is new ring buffer size - EFX_RXD_HEAD_ROOM. Let's assume we set 4096 for rx ring buffer, normal channel ptp channel efx->rxq_entries 4096 4096 rx_queue->ptr_mask 4095 1023 rx_queue->max_fill 4086 4086 sfc driver allocates rx ring buffers based on these values. When it allocates ptp channel's ring buffer, 4086 ring buffers are allocated then, these buffers are attached to the allocated array. But ptp channel's ring buffer array size is still 1024(default) and ptr_mask is still 1023 too. So, 3062 ring buffers will be overwritten to the array. This is the reason for memory leak. Test commands: ethtool -G <interface name> rx 4096 while : do ip link set <interface name> up ip link set <interface name> down done In order to avoid this problem, it adds ->copy callback to ptp channel type. So that rx_queue->ptr_mask value will be updated correctly. Fixes: 7c236c4 ("sfc: Add support for IEEE-1588 PTP") Signed-off-by: Taehee Yoo <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1c7ab9c commit 49e6123

File tree

3 files changed

+20
-2
lines changed

3 files changed

+20
-2
lines changed

drivers/net/ethernet/sfc/efx_channels.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,9 @@ static void efx_set_xdp_channels(struct efx_nic *efx)
867867

868868
int efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
869869
{
870-
struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel;
870+
struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel,
871+
*ptp_channel = efx_ptp_channel(efx);
872+
struct efx_ptp_data *ptp_data = efx->ptp_data;
871873
unsigned int i, next_buffer_table = 0;
872874
u32 old_rxq_entries, old_txq_entries;
873875
int rc, rc2;
@@ -938,6 +940,7 @@ int efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
938940

939941
efx_set_xdp_channels(efx);
940942
out:
943+
efx->ptp_data = NULL;
941944
/* Destroy unused channel structures */
942945
for (i = 0; i < efx->n_channels; i++) {
943946
channel = other_channel[i];
@@ -948,6 +951,7 @@ int efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
948951
}
949952
}
950953

954+
efx->ptp_data = ptp_data;
951955
rc2 = efx_soft_enable_interrupts(efx);
952956
if (rc2) {
953957
rc = rc ? rc : rc2;
@@ -966,6 +970,7 @@ int efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
966970
efx->txq_entries = old_txq_entries;
967971
for (i = 0; i < efx->n_channels; i++)
968972
swap(efx->channel[i], other_channel[i]);
973+
efx_ptp_update_channel(efx, ptp_channel);
969974
goto out;
970975
}
971976

drivers/net/ethernet/sfc/ptp.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "farch_regs.h"
4646
#include "tx.h"
4747
#include "nic.h" /* indirectly includes ptp.h */
48+
#include "efx_channels.h"
4849

4950
/* Maximum number of events expected to make up a PTP event */
5051
#define MAX_EVENT_FRAGS 3
@@ -541,6 +542,12 @@ struct efx_channel *efx_ptp_channel(struct efx_nic *efx)
541542
return efx->ptp_data ? efx->ptp_data->channel : NULL;
542543
}
543544

545+
void efx_ptp_update_channel(struct efx_nic *efx, struct efx_channel *channel)
546+
{
547+
if (efx->ptp_data)
548+
efx->ptp_data->channel = channel;
549+
}
550+
544551
static u32 last_sync_timestamp_major(struct efx_nic *efx)
545552
{
546553
struct efx_channel *channel = efx_ptp_channel(efx);
@@ -1443,6 +1450,11 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
14431450
int rc = 0;
14441451
unsigned int pos;
14451452

1453+
if (efx->ptp_data) {
1454+
efx->ptp_data->channel = channel;
1455+
return 0;
1456+
}
1457+
14461458
ptp = kzalloc(sizeof(struct efx_ptp_data), GFP_KERNEL);
14471459
efx->ptp_data = ptp;
14481460
if (!efx->ptp_data)
@@ -2176,7 +2188,7 @@ static const struct efx_channel_type efx_ptp_channel_type = {
21762188
.pre_probe = efx_ptp_probe_channel,
21772189
.post_remove = efx_ptp_remove_channel,
21782190
.get_name = efx_ptp_get_channel_name,
2179-
/* no copy operation; there is no need to reallocate this channel */
2191+
.copy = efx_copy_channel,
21802192
.receive_skb = efx_ptp_rx,
21812193
.want_txqs = efx_ptp_want_txqs,
21822194
.keep_eventq = false,

drivers/net/ethernet/sfc/ptp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ struct ethtool_ts_info;
1616
int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel);
1717
void efx_ptp_defer_probe_with_channel(struct efx_nic *efx);
1818
struct efx_channel *efx_ptp_channel(struct efx_nic *efx);
19+
void efx_ptp_update_channel(struct efx_nic *efx, struct efx_channel *channel);
1920
void efx_ptp_remove(struct efx_nic *efx);
2021
int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr);
2122
int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr);

0 commit comments

Comments
 (0)