Skip to content

Commit 735522e

Browse files
committed
batman-adv: tvlv: avoid unnecessary OGM buffer reallocations
Both OGMv1 (on the primary interface) and OGM2 unconditionally reallocated their packet buffer on every transmission cycle, regardless of whether the required size had changed. This meant a kfree/kmalloc pair even when the TVLV payload size was identical to the previous send. Introduce struct batadv_ogm_buf to encapsulate the OGM packet buffer together with its current length, allocated capacity, and fixed header length. This consolidates the separate buf/len arguments that were previously threaded through each call site. In batadv_tvlv_realloc_packet_buff(), the capacity is rounded up to the next power of two so that small growth or shrinkage in TVLV data does not trigger a reallocation. When kmalloc fails but the existing buffer is large enough to hold the new data, the oversized buffer is reused rather than returning an error. Signed-off-by: Sven Eckelmann <sven@narfation.org>
1 parent 5ffd4dd commit 735522e

5 files changed

Lines changed: 88 additions & 67 deletions

File tree

net/batman-adv/bat_iv_ogm.c

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -195,14 +195,17 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
195195
get_random_bytes(&random_seqno, sizeof(random_seqno));
196196
atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno);
197197

198-
hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN;
199-
ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff_len, GFP_ATOMIC);
198+
hard_iface->bat_iv.ogm_buff.len = BATADV_OGM_HLEN;
199+
hard_iface->bat_iv.ogm_buff.capacity = BATADV_OGM_HLEN;
200+
hard_iface->bat_iv.ogm_buff.header_length = BATADV_OGM_HLEN;
201+
202+
ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff.capacity, GFP_ATOMIC);
200203
if (!ogm_buff) {
201204
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
202205
return -ENOMEM;
203206
}
204207

205-
hard_iface->bat_iv.ogm_buff = ogm_buff;
208+
hard_iface->bat_iv.ogm_buff.buf = ogm_buff;
206209

207210
batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
208211
batadv_ogm_packet->packet_type = BATADV_IV_OGM;
@@ -221,8 +224,9 @@ static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
221224
{
222225
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
223226

224-
kfree(hard_iface->bat_iv.ogm_buff);
225-
hard_iface->bat_iv.ogm_buff = NULL;
227+
kfree(hard_iface->bat_iv.ogm_buff.buf);
228+
memset(&hard_iface->bat_iv.ogm_buff, 0,
229+
sizeof(hard_iface->bat_iv.ogm_buff));
226230

227231
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
228232

@@ -236,7 +240,7 @@ static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface)
236240

237241
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
238242

239-
ogm_buff = hard_iface->bat_iv.ogm_buff;
243+
ogm_buff = hard_iface->bat_iv.ogm_buff.buf;
240244
if (!ogm_buff)
241245
goto unlock;
242246

@@ -258,7 +262,7 @@ batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
258262

259263
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
260264

261-
ogm_buff = hard_iface->bat_iv.ogm_buff;
265+
ogm_buff = hard_iface->bat_iv.ogm_buff.buf;
262266
if (!ogm_buff)
263267
goto unlock;
264268

@@ -796,10 +800,9 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface)
796800
static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
797801
{
798802
struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
799-
unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff;
803+
struct batadv_ogm_buf *ogm_buff = &hard_iface->bat_iv.ogm_buff;
800804
struct batadv_ogm_packet *batadv_ogm_packet;
801805
struct batadv_hard_iface *primary_if, *tmp_hard_iface;
802-
int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len;
803806
struct list_head *iter;
804807
u32 seqno;
805808
u16 tvlv_len = 0;
@@ -811,7 +814,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
811814
lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex);
812815

813816
/* interface already disabled by batadv_iv_ogm_iface_disable */
814-
if (!*ogm_buff)
817+
if (!ogm_buff->buf)
815818
return;
816819

817820
/* the interface gets activated here to avoid race conditions between
@@ -830,9 +833,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
830833
* appended as it may alter the tt tvlv container
831834
*/
832835
batadv_tt_local_commit_changes(bat_priv);
833-
ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff,
834-
ogm_buff_len,
835-
BATADV_OGM_HLEN);
836+
ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff);
836837
if (ret < 0) {
837838
reschedule = true;
838839
goto out;
@@ -841,7 +842,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
841842
tvlv_len = ret;
842843
}
843844

844-
batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff);
845+
batadv_ogm_packet = ogm_buff->buf;
845846
batadv_ogm_packet->tvlv_len = htons(tvlv_len);
846847

847848
/* change sequence number to network order */
@@ -857,7 +858,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
857858
/* OGMs from secondary interfaces are only scheduled on their
858859
* respective interfaces.
859860
*/
860-
scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len,
861+
scheduled = batadv_iv_ogm_queue_add(bat_priv, ogm_buff->buf, ogm_buff->len,
861862
hard_iface, hard_iface, 1, send_time);
862863
if (!scheduled)
863864
reschedule = true;
@@ -873,8 +874,8 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
873874
if (!kref_get_unless_zero(&tmp_hard_iface->refcount))
874875
continue;
875876

876-
scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
877-
*ogm_buff_len, hard_iface,
877+
scheduled = batadv_iv_ogm_queue_add(bat_priv, ogm_buff->buf,
878+
ogm_buff->len, hard_iface,
878879
tmp_hard_iface, 1, send_time);
879880
batadv_hardif_put(tmp_hard_iface);
880881

net/batman-adv/bat_v_ogm.c

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -270,10 +270,9 @@ static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv)
270270
{
271271
struct batadv_hard_iface *hard_iface;
272272
struct batadv_ogm2_packet *ogm_packet;
273+
struct batadv_ogm_buf *ogm_buff;
273274
struct sk_buff *skb, *skb_tmp;
274-
unsigned char **ogm_buff;
275275
struct list_head *iter;
276-
int *ogm_buff_len;
277276
u16 tvlv_len;
278277
int ret;
279278

@@ -283,26 +282,23 @@ static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv)
283282
goto out;
284283

285284
ogm_buff = &bat_priv->bat_v.ogm_buff;
286-
ogm_buff_len = &bat_priv->bat_v.ogm_buff_len;
287285

288286
/* tt changes have to be committed before the tvlv data is
289287
* appended as it may alter the tt tvlv container
290288
*/
291289
batadv_tt_local_commit_changes(bat_priv);
292-
ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff,
293-
ogm_buff_len,
294-
BATADV_OGM2_HLEN);
290+
ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff);
295291
if (ret < 0)
296292
goto reschedule;
297293

298294
tvlv_len = ret;
299295

300-
skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + *ogm_buff_len);
296+
skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff->len);
301297
if (!skb)
302298
goto reschedule;
303299

304300
skb_reserve(skb, ETH_HLEN);
305-
skb_put_data(skb, *ogm_buff, *ogm_buff_len);
301+
skb_put_data(skb, ogm_buff->buf, ogm_buff->len);
306302

307303
ogm_packet = (struct batadv_ogm2_packet *)skb->data;
308304
ogm_packet->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno));
@@ -448,10 +444,10 @@ void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface)
448444
struct batadv_ogm2_packet *ogm_packet;
449445

450446
mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
451-
if (!bat_priv->bat_v.ogm_buff)
447+
if (!bat_priv->bat_v.ogm_buff.buf)
452448
goto unlock;
453449

454-
ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
450+
ogm_packet = bat_priv->bat_v.ogm_buff.buf;
455451
ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr);
456452

457453
unlock:
@@ -1052,12 +1048,15 @@ int batadv_v_ogm_init(struct batadv_priv *bat_priv)
10521048
unsigned char *ogm_buff;
10531049
u32 random_seqno;
10541050

1055-
bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
1056-
ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
1051+
bat_priv->bat_v.ogm_buff.len = BATADV_OGM2_HLEN;
1052+
bat_priv->bat_v.ogm_buff.capacity = BATADV_OGM2_HLEN;
1053+
bat_priv->bat_v.ogm_buff.header_length = BATADV_OGM2_HLEN;
1054+
1055+
ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff.capacity, GFP_ATOMIC);
10571056
if (!ogm_buff)
10581057
return -ENOMEM;
10591058

1060-
bat_priv->bat_v.ogm_buff = ogm_buff;
1059+
bat_priv->bat_v.ogm_buff.buf = ogm_buff;
10611060
ogm_packet = (struct batadv_ogm2_packet *)ogm_buff;
10621061
ogm_packet->packet_type = BATADV_OGM2;
10631062
ogm_packet->version = BATADV_COMPAT_VERSION;
@@ -1085,9 +1084,8 @@ void batadv_v_ogm_free(struct batadv_priv *bat_priv)
10851084

10861085
mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
10871086

1088-
kfree(bat_priv->bat_v.ogm_buff);
1089-
bat_priv->bat_v.ogm_buff = NULL;
1090-
bat_priv->bat_v.ogm_buff_len = 0;
1087+
kfree(bat_priv->bat_v.ogm_buff.buf);
1088+
memset(&bat_priv->bat_v.ogm_buff, 0, sizeof(bat_priv->bat_v.ogm_buff));
10911089

10921090
mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
10931091
}

net/batman-adv/tvlv.c

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/limits.h>
1818
#include <linux/list.h>
1919
#include <linux/lockdep.h>
20+
#include <linux/log2.h>
2021
#include <linux/netdevice.h>
2122
#include <linux/pkt_sched.h>
2223
#include <linux/rculist.h>
@@ -267,32 +268,48 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv,
267268
/**
268269
* batadv_tvlv_realloc_packet_buff() - reallocate packet buffer to accommodate
269270
* requested packet size
270-
* @packet_buff: packet buffer
271-
* @packet_buff_len: packet buffer size
272-
* @min_packet_len: requested packet minimum size
271+
* @ogm_buff: ogm packet buffer
273272
* @additional_packet_len: requested additional packet size on top of minimum
274273
* size
275274
*
276275
* Return: true of the packet buffer could be changed to the requested size,
277276
* false otherwise.
278277
*/
279-
static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff,
280-
int *packet_buff_len,
281-
int min_packet_len,
282-
int additional_packet_len)
278+
static bool batadv_tvlv_realloc_packet_buff(struct batadv_ogm_buf *ogm_buff,
279+
size_t additional_packet_len)
283280
{
284281
unsigned char *new_buff;
282+
size_t newcapacity;
283+
size_t newlen;
285284

286-
new_buff = kmalloc(min_packet_len + additional_packet_len, GFP_ATOMIC);
285+
newlen = ogm_buff->header_length + additional_packet_len;
286+
newcapacity = roundup_pow_of_two(newlen);
287+
288+
/* nothing to reallocate */
289+
if (newcapacity == ogm_buff->capacity) {
290+
ogm_buff->len = newlen;
291+
return true;
292+
}
293+
294+
new_buff = kmalloc(newcapacity, GFP_ATOMIC);
287295

288296
/* keep old buffer if kmalloc should fail */
289-
if (!new_buff)
297+
if (!new_buff) {
298+
/* continue to use oversize buffer if new data fits */
299+
if (newlen <= ogm_buff->capacity) {
300+
ogm_buff->len = newlen;
301+
return true;
302+
}
303+
290304
return false;
305+
}
306+
307+
memcpy(new_buff, ogm_buff->buf, ogm_buff->header_length);
308+
kfree(ogm_buff->buf);
291309

292-
memcpy(new_buff, *packet_buff, min_packet_len);
293-
kfree(*packet_buff);
294-
*packet_buff = new_buff;
295-
*packet_buff_len = min_packet_len + additional_packet_len;
310+
ogm_buff->buf = new_buff;
311+
ogm_buff->len = newlen;
312+
ogm_buff->capacity = newcapacity;
296313

297314
return true;
298315
}
@@ -301,10 +318,7 @@ static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff,
301318
* batadv_tvlv_container_ogm_append() - append tvlv container content to given
302319
* OGM packet buffer
303320
* @bat_priv: the bat priv with all the mesh interface information
304-
* @packet_buff: ogm packet buffer
305-
* @packet_buff_len: ogm packet buffer size including ogm header and tvlv
306-
* content
307-
* @packet_min_len: ogm header size to be preserved for the OGM itself
321+
* @ogm_buff: ogm packet buffer
308322
*
309323
* The ogm packet might be enlarged or shrunk depending on the current size
310324
* and the size of the to-be-appended tvlv containers.
@@ -313,8 +327,7 @@ static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff,
313327
* if operation failed
314328
*/
315329
int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
316-
unsigned char **packet_buff,
317-
int *packet_buff_len, int packet_min_len)
330+
struct batadv_ogm_buf *ogm_buff)
318331
{
319332
struct batadv_tvlv_container *tvlv;
320333
struct batadv_tvlv_hdr *tvlv_hdr;
@@ -330,8 +343,7 @@ int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
330343
goto end;
331344
}
332345

333-
ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len,
334-
packet_min_len, tvlv_value_len);
346+
ret = batadv_tvlv_realloc_packet_buff(ogm_buff, tvlv_value_len);
335347
if (!ret) {
336348
tvlv_len_ret = -ENOMEM;
337349
goto end;
@@ -342,7 +354,7 @@ int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
342354
if (!tvlv_value_len)
343355
goto end;
344356

345-
tvlv_value = (*packet_buff) + packet_min_len;
357+
tvlv_value = (u8 *)ogm_buff->buf + ogm_buff->header_length;
346358

347359
hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) {
348360
tvlv_hdr = tvlv_value;

net/batman-adv/tvlv.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv,
1717
u8 type, u8 version,
1818
void *tvlv_value, u16 tvlv_value_len);
1919
int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv,
20-
unsigned char **packet_buff,
21-
int *packet_buff_len, int packet_min_len);
20+
struct batadv_ogm_buf *ogm_buff);
2221
void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv,
2322
struct batadv_ogm_packet *batadv_ogm_packet,
2423
struct batadv_orig_node *orig_node);

net/batman-adv/types.h

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,23 +71,37 @@ enum batadv_dhcp_recipient {
7171
*/
7272
#define BATADV_TT_SYNC_MASK 0x00F0
7373

74+
/**
75+
* struct batadv_ogm_buf - Buffer to construct an OGM with TVLV
76+
*/
77+
struct batadv_ogm_buf {
78+
/** @buf: buffer holding the OGM packet */
79+
void *buf;
80+
81+
/** @len: length of the OGM packet buffer data */
82+
size_t len;
83+
84+
/** @capacity: size of allocated buf */
85+
size_t capacity;
86+
87+
/** @header_length: fixed size header length (must be <= len) */
88+
size_t header_length;
89+
};
90+
7491
/**
7592
* struct batadv_hard_iface_bat_iv - per hard-interface B.A.T.M.A.N. IV data
7693
*/
7794
struct batadv_hard_iface_bat_iv {
7895
/** @ogm_buff: buffer holding the OGM packet */
79-
unsigned char *ogm_buff;
80-
81-
/** @ogm_buff_len: length of the OGM packet buffer */
82-
int ogm_buff_len;
96+
struct batadv_ogm_buf ogm_buff;
8397

8498
/** @ogm_seqno: OGM sequence number - used to identify each OGM */
8599
atomic_t ogm_seqno;
86100

87101
/** @reschedule_work: recover OGM schedule after schedule error */
88102
struct delayed_work reschedule_work;
89103

90-
/** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */
104+
/** @ogm_buff_mutex: lock protecting ogm_buff */
91105
struct mutex ogm_buff_mutex;
92106
};
93107

@@ -1481,15 +1495,12 @@ struct batadv_meshif_vlan {
14811495
*/
14821496
struct batadv_priv_bat_v {
14831497
/** @ogm_buff: buffer holding the OGM packet */
1484-
unsigned char *ogm_buff;
1485-
1486-
/** @ogm_buff_len: length of the OGM packet buffer */
1487-
int ogm_buff_len;
1498+
struct batadv_ogm_buf ogm_buff;
14881499

14891500
/** @ogm_seqno: OGM sequence number - used to identify each OGM */
14901501
atomic_t ogm_seqno;
14911502

1492-
/** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */
1503+
/** @ogm_buff_mutex: lock protecting ogm_buff */
14931504
struct mutex ogm_buff_mutex;
14941505

14951506
/** @ogm_wq: workqueue used to schedule OGM transmissions */

0 commit comments

Comments
 (0)