diff mbox

[3/3,net-next] net_device: Add minimal padding to allow for net_device pointer alignment

Message ID 1676328eb3e9d02a4432783494d0c5a13f0d4656.1428622095.git.tgraf@suug.ch
State Awaiting Upstream
Headers show

Commit Message

Thomas Graf April 9, 2015, 11:43 p.m. UTC
Makes use of the __alignof__ GCC builtin to determine the minimal
amount of padding required to align the pointer afterwards.

Due to use of ____cacheline_aligned_in_smp inside net_device,
struct net_device is actually always a multiple of SMP_CACHE_BYTES
so typically no padding is needed but this logic is kept in place
in case that is no longer the case.

Signed-off-by: Thomas Graf <tgraf@suug.ch>
---
 include/linux/kernel.h | 2 ++
 net/core/dev.c         | 3 +--
 2 files changed, 3 insertions(+), 2 deletions(-)

Comments

Eric Dumazet April 10, 2015, 12:34 a.m. UTC | #1
On Fri, 2015-04-10 at 01:43 +0200, Thomas Graf wrote:
> Makes use of the __alignof__ GCC builtin to determine the minimal
> amount of padding required to align the pointer afterwards.
> 
> Due to use of ____cacheline_aligned_in_smp inside net_device,
> struct net_device is actually always a multiple of SMP_CACHE_BYTES
> so typically no padding is needed but this logic is kept in place
> in case that is no longer the case.
> 
> Signed-off-by: Thomas Graf <tgraf@suug.ch>
> ---
>  include/linux/kernel.h | 2 ++
>  net/core/dev.c         | 3 +--
>  2 files changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/kernel.h b/include/linux/kernel.h
> index d6d630d..4ec018f 100644
> --- a/include/linux/kernel.h
> +++ b/include/linux/kernel.h
> @@ -50,6 +50,8 @@
>  #define __ALIGN_MASK(x, mask)	__ALIGN_KERNEL_MASK((x), (mask))
>  #define PTR_ALIGN(p, a)		((typeof(p))ALIGN((unsigned long)(p), (a)))
>  #define IS_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)
> +#define PTR_ALIGN_PAD(type, a) \
> +	({ (__alignof__(type) < (a)) ? (a) - __alignof__(type) : 0; })
>  
>  #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
>  
> diff --git a/net/core/dev.c b/net/core/dev.c
> index b2775f0..2b43aba 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -6794,8 +6794,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
>  		alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
>  		alloc_size += sizeof_priv;
>  	}
> -	/* ensure 32-byte alignment of whole construct */
> -	alloc_size += NETDEV_ALIGN - 1;
> +	alloc_size += PTR_ALIGN_PAD(struct net_device, NETDEV_ALIGN);
>  
>  	p = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
>  	if (!p)


I believe code intent was to get an alignment even if kmalloc() returns
say 0xxxxx0008.

AFAIK, SLAB in debug mode was able to do this.
Thomas Graf April 10, 2015, 8:48 a.m. UTC | #2
On 04/09/15 at 05:34pm, Eric Dumazet wrote:
> On Fri, 2015-04-10 at 01:43 +0200, Thomas Graf wrote:
> > diff --git a/net/core/dev.c b/net/core/dev.c
> > index b2775f0..2b43aba 100644
> > --- a/net/core/dev.c
> > +++ b/net/core/dev.c
> > @@ -6794,8 +6794,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
> >  		alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
> >  		alloc_size += sizeof_priv;
> >  	}
> > -	/* ensure 32-byte alignment of whole construct */
> > -	alloc_size += NETDEV_ALIGN - 1;
> > +	alloc_size += PTR_ALIGN_PAD(struct net_device, NETDEV_ALIGN);
> >  
> >  	p = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
> >  	if (!p)
> 
> 
> I believe code intent was to get an alignment even if kmalloc() returns
> say 0xxxxx0008.
> 
> AFAIK, SLAB in debug mode was able to do this.

I assumed kmalloc would guarantee alignment of the return pointer as
indicated by __alignof__ but I now realize that this can't possibly be the
case. kmalloc only knows about the size. We'll have to drop patch 3.
Fortunately it's still below 2K.
Eric Dumazet April 10, 2015, 9:03 a.m. UTC | #3
On Fri, 2015-04-10 at 09:48 +0100, Thomas Graf wrote:

> 
> I assumed kmalloc would guarantee alignment of the return pointer as
> indicated by __alignof__ but I now realize that this can't possibly be the
> case. kmalloc only knows about the size. We'll have to drop patch 3.
> Fortunately it's still below 2K.


If you really care for this, take a look at qdisc_alloc()
and commit d276055c4e90a7278cd5167ba9755c9b214bcff7
("net_sched: reduce fifo qdisc size")

(Note that some setups require ~3 network devices but 3000+ qdisc)

I guess it might be nice to define a common helper and reuse it.
diff mbox

Patch

diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index d6d630d..4ec018f 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -50,6 +50,8 @@ 
 #define __ALIGN_MASK(x, mask)	__ALIGN_KERNEL_MASK((x), (mask))
 #define PTR_ALIGN(p, a)		((typeof(p))ALIGN((unsigned long)(p), (a)))
 #define IS_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)
+#define PTR_ALIGN_PAD(type, a) \
+	({ (__alignof__(type) < (a)) ? (a) - __alignof__(type) : 0; })
 
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
 
diff --git a/net/core/dev.c b/net/core/dev.c
index b2775f0..2b43aba 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6794,8 +6794,7 @@  struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
 		alloc_size = ALIGN(alloc_size, NETDEV_ALIGN);
 		alloc_size += sizeof_priv;
 	}
-	/* ensure 32-byte alignment of whole construct */
-	alloc_size += NETDEV_ALIGN - 1;
+	alloc_size += PTR_ALIGN_PAD(struct net_device, NETDEV_ALIGN);
 
 	p = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
 	if (!p)