Skip to contentSkip to conversation

net: dsa: Remove VLA usage

PATCH In review Kees Cook 5 participants 7 messages Jul 17, 2018 – Jul 30, 2018

Subsystems (3)
lore
Share & tools
lore

Kees Cook

author
#0 lore raw

PATCH v2 1/1 net: dsa: Remove VLA usage

From: Salvatore Mesoraca <[email protected]>

We avoid 2 VLAs by using a pre-allocated field in dsa_switch. We also try to avoid dynamic allocation whenever possible (when using fewer than bits-per-long ports, which is the common case).

---
 include/net/dsa.h |  3 +++
 net/dsa/dsa2.c    | 14 ++++++++++++++
 net/dsa/switch.c  | 22 ++++++++++------------
 3 files changed, 27 insertions(+), 12 deletions(-)
include/net/dsa.h +3 -0
index fdbd6082945d..461e8a7661b7 100644
@@ -259,6 +259,9 @@ struct dsa_switch {
 	/* Number of switch port queues */
 	unsigned int		num_tx_queues;
 
+	unsigned long		*bitmap;
+	unsigned long		_bitmap;
+
 	/* Dynamically allocated ports, keep last */
 	size_t num_ports;
 	struct dsa_port ports[];
net/dsa/dsa2.c +14 -0
index dc5d9af3dc80..a1917025e155 100644
@@ -775,6 +775,20 @@ struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n)
 	if (!ds)
 		return NULL;
 
+	/* We avoid allocating memory outside dsa_switch
+	 * if it is not needed.
+	 */
+	if (n <= sizeof(ds->_bitmap) * 8) {
+		ds->bitmap = &ds->_bitmap;
+	} else {
+		ds->bitmap = devm_kcalloc(dev,
+					  BITS_TO_LONGS(n),
+					  sizeof(unsigned long),
+					  GFP_KERNEL);
+		if (unlikely(!ds->bitmap))
+			return NULL;
+	}
+
 	ds->dev = dev;
 	ds->num_ports = n;
 
net/dsa/switch.c +10 -12
index b93511726069..142b294d3446 100644
@@ -136,21 +136,20 @@ static int dsa_switch_mdb_add(struct dsa_switch *ds,
 {
 	const struct switchdev_obj_port_mdb *mdb = info->mdb;
 	struct switchdev_trans *trans = info->trans;
-	DECLARE_BITMAP(group, ds->num_ports);
 	int port;
 
 	/* Build a mask of Multicast group members */
-	bitmap_zero(group, ds->num_ports);
+	bitmap_zero(ds->bitmap, ds->num_ports);
 	if (ds->index == info->sw_index)
-		set_bit(info->port, group);
+		set_bit(info->port, ds->bitmap);
 	for (port = 0; port < ds->num_ports; port++)
 		if (dsa_is_dsa_port(ds, port))
-			set_bit(port, group);
+			set_bit(port, ds->bitmap);
 
 	if (switchdev_trans_ph_prepare(trans))
-		return dsa_switch_mdb_prepare_bitmap(ds, mdb, group);
+		return dsa_switch_mdb_prepare_bitmap(ds, mdb, ds->bitmap);
 
-	dsa_switch_mdb_add_bitmap(ds, mdb, group);
+	dsa_switch_mdb_add_bitmap(ds, mdb, ds->bitmap);
 
 	return 0;
 }
@@ -204,21 +203,20 @@ static int dsa_switch_vlan_add(struct dsa_switch *ds,
 {
 	const struct switchdev_obj_port_vlan *vlan = info->vlan;
 	struct switchdev_trans *trans = info->trans;
-	DECLARE_BITMAP(members, ds->num_ports);
 	int port;
 
 	/* Build a mask of VLAN members */
-	bitmap_zero(members, ds->num_ports);
+	bitmap_zero(ds->bitmap, ds->num_ports);
 	if (ds->index == info->sw_index)
-		set_bit(info->port, members);
+		set_bit(info->port, ds->bitmap);
 	for (port = 0; port < ds->num_ports; port++)
 		if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
-			set_bit(port, members);
+			set_bit(port, ds->bitmap);
 
 	if (switchdev_trans_ph_prepare(trans))
-		return dsa_switch_vlan_prepare_bitmap(ds, vlan, members);
+		return dsa_switch_vlan_prepare_bitmap(ds, vlan, ds->bitmap);
 
-	dsa_switch_vlan_add_bitmap(ds, vlan, members);
+	dsa_switch_vlan_add_bitmap(ds, vlan, ds->bitmap);
 
 	return 0;
 }
Signature · 6 lines
2.17.1


-- 
Kees Cook
Pixel Security
maintainer
#1 lore raw

From: Kees Cook <[email protected]>
Date: Mon, 16 Jul 2018 21:10:34 -0700

Quoted 11 lines

From: Salvatore Mesoraca <[email protected]>

We avoid 2 VLAs by using a pre-allocated field in dsa_switch. We also try to avoid dynamic allocation whenever possible (when using fewer than bits-per-long ports, which is the common case).

Florian and Andrew, please review.

maintainer Reviewed-by
#2 lore raw
Quoted 9 lines · David Miller

From: Kees Cook <[email protected]>
Date: Mon, 16 Jul 2018 21:10:34 -0700

Quoted 6 lines

From: Salvatore Mesoraca <[email protected]>

We avoid 2 VLAs by using a pre-allocated field in dsa_switch. We also try to avoid dynamic allocation whenever possible (when using fewer than bits-per-long ports, which is the common case).

Quoted 7 lines
Quoted 5 lines

Florian and Andrew, please review.

Last time there was some discussion of just always allocating it to make the code simpler. But the extra complexity is O.K.

Andrew

maintainer
#3 lore raw

From: Andrew Lunn <[email protected]>
Date: Wed, 18 Jul 2018 22:37:25 +0200

Quoted 16 lines · David Miller
Quoted 15 lines

From: Kees Cook <[email protected]>
Date: Mon, 16 Jul 2018 21:10:34 -0700

Quoted 11 lines

From: Salvatore Mesoraca <[email protected]>

We avoid 2 VLAs by using a pre-allocated field in dsa_switch. We also try to avoid dynamic allocation whenever possible (when using fewer than bits-per-long ports, which is the common case).

Quoted 6 lines
Quoted 1 line

Florian and Andrew, please review.

Last time there was some discussion of just always allocating it to make the code simpler. But the extra complexity is O.K.

Great, applied, thanks!

#4 lore raw
In reply to Kees Cook

Hi!

Quoted 20 lines

We avoid 2 VLAs by using a pre-allocated field in dsa_switch. We also try to avoid dynamic allocation whenever possible (when using fewer than bits-per-long ports, which is the common case).

---
 include/net/dsa.h |  3 +++
 net/dsa/dsa2.c    | 14 ++++++++++++++
 net/dsa/switch.c  | 22 ++++++++++------------
 3 files changed, 27 insertions(+), 12 deletions(-)
include/net/dsa.h +0 -0
index fdbd6082945d..461e8a7661b7 100644

include/net/dsa.h struct dsa_switch { · line 263

Quoted 5 lines
include/net/dsa.h +2 -0
@@ -259,6 +259,9 @@ struct dsa_switch {
 	/* Number of switch port queues */
 	unsigned int		num_tx_queues;
 
+	unsigned long		*bitmap;
+	unsigned long		_bitmap;

This looks rather confusing. _bitmap -> bitmap_data? bitmap_bits?

Thanks,
Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#5 lore raw

Hi!

Quoted 23 lines
Quoted 23 lines

We avoid 2 VLAs by using a pre-allocated field in dsa_switch. We also try to avoid dynamic allocation whenever possible (when using fewer than bits-per-long ports, which is the common case).

---
 include/net/dsa.h |  3 +++
 net/dsa/dsa2.c    | 14 ++++++++++++++
 net/dsa/switch.c  | 22 ++++++++++------------
 3 files changed, 27 insertions(+), 12 deletions(-)
include/net/dsa.h +0 -0
index fdbd6082945d..461e8a7661b7 100644
@@ -259,6 +259,9 @@ struct dsa_switch {
 	/* Number of switch port queues */
 	unsigned int		num_tx_queues;
 
Quoted 4 lines

include/net/dsa.h struct dsa_switch { · line 263

Quoted 2 lines
include/net/dsa.h +2 -0
+	unsigned long		*bitmap;
+	unsigned long		_bitmap;

This looks rather confusing. _bitmap -> bitmap_data? bitmap_bits?

Actually, AFAICT that long is not used as a long, but as array of bits. So maybe char bitmap_data[8] would be more appropriate?

(resend, now with right cc list).
Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#6 lore raw

From: Pavel Machek

Quoted 1 line

Sent: 29 July 2018 12:40

...

Quoted 7 lines
Quoted 4 lines

include/net/dsa.h struct dsa_switch { · line 263

Quoted 2 lines
include/net/dsa.h +2 -0
+	unsigned long		*bitmap;
+	unsigned long		_bitmap;

This looks rather confusing. _bitmap -> bitmap_data? bitmap_bits?

Actually, AFAICT that long is not used as a long, but as array of bits. So maybe char bitmap_data[8] would be more appropriate?

Unfortunately the 'bitmap' functions are defined to work in a specific way on unsigned long[].
This means, for example, that they can't use the x86 'bit' instructions.

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)