LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH] netfilter: replace horrible hack with ksize()
@ 2008-03-05 21:20 Pekka J Enberg
  2008-03-05 21:56 ` Christoph Lameter
  2008-03-06 14:03 ` Patrick McHardy
  0 siblings, 2 replies; 13+ messages in thread
From: Pekka J Enberg @ 2008-03-05 21:20 UTC (permalink / raw)
  To: netfilter-devel; +Cc: clameter, joe, linux-kernel, netdev

From: Pekka Enberg <penberg@cs.helsinki.fi>

There's a horrible slab abuse in net/netfilter/nf_conntrack_extend.c that 
can be replaced with a call to ksize().

Cc: Christoph Lameter <clameter@sgi.com>
Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
---
 include/net/netfilter/nf_conntrack_extend.h |    1 -
 net/netfilter/nf_conntrack_extend.c         |   19 +++----------------
 2 files changed, 3 insertions(+), 17 deletions(-)

Index: linux-2.6/include/net/netfilter/nf_conntrack_extend.h
===================================================================
--- linux-2.6.orig/include/net/netfilter/nf_conntrack_extend.h
+++ linux-2.6/include/net/netfilter/nf_conntrack_extend.h
@@ -17,7 +17,6 @@ enum nf_ct_ext_id
 struct nf_ct_ext {
 	u8 offset[NF_CT_EXT_NUM];
 	u8 len;
-	u8 real_len;
 	char data[0];
 };
 
Index: linux-2.6/net/netfilter/nf_conntrack_extend.c
===================================================================
--- linux-2.6.orig/net/netfilter/nf_conntrack_extend.c
+++ linux-2.6/net/netfilter/nf_conntrack_extend.c
@@ -19,14 +19,6 @@
 static struct nf_ct_ext_type *nf_ct_ext_types[NF_CT_EXT_NUM];
 static DEFINE_MUTEX(nf_ct_ext_type_mutex);
 
-/* Horrible trick to figure out smallest amount worth kmallocing. */
-#define CACHE(x) (x) + 0 *
-enum {
-	NF_CT_EXT_MIN_SIZE =
-#include <linux/kmalloc_sizes.h>
-	1 };
-#undef CACHE
-
 void __nf_ct_ext_destroy(struct nf_conn *ct)
 {
 	unsigned int i;
@@ -53,7 +45,7 @@ EXPORT_SYMBOL(__nf_ct_ext_destroy);
 static void *
 nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp)
 {
-	unsigned int off, len, real_len;
+	unsigned int off, len;
 	struct nf_ct_ext_type *t;
 
 	rcu_read_lock();
@@ -61,16 +53,14 @@ nf_ct_ext_create(struct nf_ct_ext **ext,
 	BUG_ON(t == NULL);
 	off = ALIGN(sizeof(struct nf_ct_ext), t->align);
 	len = off + t->len;
-	real_len = t->alloc_size;
 	rcu_read_unlock();
 
-	*ext = kzalloc(real_len, gfp);
+	*ext = kzalloc(t->alloc_size, gfp);
 	if (!*ext)
 		return NULL;
 
 	(*ext)->offset[id] = off;
 	(*ext)->len = len;
-	(*ext)->real_len = real_len;
 
 	return (void *)(*ext) + off;
 }
@@ -95,7 +85,7 @@ void *__nf_ct_ext_add(struct nf_conn *ct
 	newlen = newoff + t->len;
 	rcu_read_unlock();
 
-	if (newlen >= ct->ext->real_len) {
+	if (newlen >= ksize(ct->ext)) {
 		new = kmalloc(newlen, gfp);
 		if (!new)
 			return NULL;
@@ -114,7 +104,6 @@ void *__nf_ct_ext_add(struct nf_conn *ct
 			rcu_read_unlock();
 		}
 		kfree(ct->ext);
-		new->real_len = newlen;
 		ct->ext = new;
 	}
 
@@ -156,8 +145,6 @@ static void update_alloc_size(struct nf_
 			t1->alloc_size = ALIGN(t1->alloc_size, t2->align)
 					 + t2->len;
 		}
-		if (t1->alloc_size < NF_CT_EXT_MIN_SIZE)
-			t1->alloc_size = NF_CT_EXT_MIN_SIZE;
 	}
 }
 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-05 21:20 [PATCH] netfilter: replace horrible hack with ksize() Pekka J Enberg
@ 2008-03-05 21:56 ` Christoph Lameter
  2008-03-05 21:57   ` Pekka Enberg
  2008-03-05 22:19   ` David Miller
  2008-03-06 14:03 ` Patrick McHardy
  1 sibling, 2 replies; 13+ messages in thread
From: Christoph Lameter @ 2008-03-05 21:56 UTC (permalink / raw)
  To: Pekka J Enberg; +Cc: netfilter-devel, joe, linux-kernel, netdev, davem

Acked-by: Christoph Lameter <clameter@sgi.com>

I guess this should go through the netdev tree?



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-05 21:56 ` Christoph Lameter
@ 2008-03-05 21:57   ` Pekka Enberg
  2008-03-05 22:19   ` David Miller
  1 sibling, 0 replies; 13+ messages in thread
From: Pekka Enberg @ 2008-03-05 21:57 UTC (permalink / raw)
  To: Christoph Lameter; +Cc: netfilter-devel, joe, linux-kernel, netdev, davem

Hi,

Christoph Lameter wrote:
> Acked-by: Christoph Lameter <clameter@sgi.com>
> 
> I guess this should go through the netdev tree?

Yup.

		Pekka

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-05 21:56 ` Christoph Lameter
  2008-03-05 21:57   ` Pekka Enberg
@ 2008-03-05 22:19   ` David Miller
  1 sibling, 0 replies; 13+ messages in thread
From: David Miller @ 2008-03-05 22:19 UTC (permalink / raw)
  To: clameter; +Cc: penberg, netfilter-devel, joe, linux-kernel, netdev, kaber

From: Christoph Lameter <clameter@sgi.com>
Date: Wed, 5 Mar 2008 13:56:13 -0800 (PST)

> Acked-by: Christoph Lameter <clameter@sgi.com>
> 
> I guess this should go through the netdev tree?

It should go through Patrick McHardy and the netfilter-devel
folks, who in turn will queue it up to me and -stable if
appropriate.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-05 21:20 [PATCH] netfilter: replace horrible hack with ksize() Pekka J Enberg
  2008-03-05 21:56 ` Christoph Lameter
@ 2008-03-06 14:03 ` Patrick McHardy
  2008-03-06 14:14   ` Pekka J Enberg
  1 sibling, 1 reply; 13+ messages in thread
From: Patrick McHardy @ 2008-03-06 14:03 UTC (permalink / raw)
  To: Pekka J Enberg
  Cc: netfilter-devel, clameter, joe, linux-kernel, netdev,
	Netfilter Development Mailinglist

Pekka J Enberg wrote:
> From: Pekka Enberg <penberg@cs.helsinki.fi>
> 
> There's a horrible slab abuse in net/netfilter/nf_conntrack_extend.c that 
> can be replaced with a call to ksize().

This doesn't look right.

> @@ -95,7 +85,7 @@ void *__nf_ct_ext_add(struct nf_conn *ct
>  	newlen = newoff + t->len;
>  	rcu_read_unlock();
>  
> -	if (newlen >= ct->ext->real_len) {
> +	if (newlen >= ksize(ct->ext)) {


This needs to look at the currently allocated size, otherwise
it will always realloc when adding new extensions after having
used up ksize(ct->ext) space.

>  		new = kmalloc(newlen, gfp);

And this should use ksize(newlen) and store the real length
in real_len below.

>  		if (!new)
>  			return NULL;
> @@ -114,7 +104,6 @@ void *__nf_ct_ext_add(struct nf_conn *ct
>  			rcu_read_unlock();
>  		}
>  		kfree(ct->ext);
> -		new->real_len = newlen;
>  		ct->ext = new;
>  	}


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-06 14:03 ` Patrick McHardy
@ 2008-03-06 14:14   ` Pekka J Enberg
  2008-03-06 14:20     ` Pekka J Enberg
  2008-03-06 16:41     ` Christoph Lameter
  0 siblings, 2 replies; 13+ messages in thread
From: Pekka J Enberg @ 2008-03-06 14:14 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: Netfilter Development Mailinglist, clameter, joe, linux-kernel,
	netdev, Netfilter Development Mailinglist

Hi Patrick,

On Thu, 6 Mar 2008, Patrick McHardy wrote:
> > @@ -95,7 +85,7 @@ void *__nf_ct_ext_add(struct nf_conn *ct
> >   newlen = newoff + t->len;
> >   rcu_read_unlock();
> > 
> > -	if (newlen >= ct->ext->real_len) {
> > +	if (newlen >= ksize(ct->ext)) {
> 
> This needs to look at the currently allocated size, otherwise
> it will always realloc when adding new extensions after having
> used up ksize(ct->ext) space.

Lets say you

  p = kmalloc(8, ...);

Then ksize(p) will return the currently allocated size which is 32 bytes 
when page size is 4 KB, and not 8 bytes. So it should be equivalent of 
what the current code does.

What am I missing here?

			Pekka

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-06 14:14   ` Pekka J Enberg
@ 2008-03-06 14:20     ` Pekka J Enberg
  2008-03-06 14:35       ` Patrick McHardy
  2008-03-06 16:41     ` Christoph Lameter
  1 sibling, 1 reply; 13+ messages in thread
From: Pekka J Enberg @ 2008-03-06 14:20 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: Netfilter Development Mailinglist, clameter, joe, linux-kernel,
	netdev, Netfilter Development Mailinglist

On Thu, 6 Mar 2008, Pekka J Enberg wrote:
> > > -	if (newlen >= ct->ext->real_len) {
> > > +	if (newlen >= ksize(ct->ext)) {
> > 
> > This needs to look at the currently allocated size, otherwise
> > it will always realloc when adding new extensions after having
> > used up ksize(ct->ext) space.
> 
> Lets say you
> 
>   p = kmalloc(8, ...);
> 
> Then ksize(p) will return the currently allocated size which is 32 bytes 
> when page size is 4 KB, and not 8 bytes. So it should be equivalent of 
> what the current code does.
> 
> What am I missing here?

Ok, it's not equivalent. We have two sizes: object size (8 bytes) and 
buffer size (32 bytes) here. In netfilter, ->real_len is same as object 
size, not buffer size as ksize() is.

But now I am officially even more confused, why does the netfilter code 
decided whether to reallocate based on _object size_ and not _buffer size_ 
(as krealloc() does, for example)?

			Pekka

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-06 14:20     ` Pekka J Enberg
@ 2008-03-06 14:35       ` Patrick McHardy
  2008-03-06 14:41         ` Pekka J Enberg
  0 siblings, 1 reply; 13+ messages in thread
From: Patrick McHardy @ 2008-03-06 14:35 UTC (permalink / raw)
  To: Pekka J Enberg
  Cc: Netfilter Development Mailinglist, clameter, joe, linux-kernel, netdev

Pekka J Enberg wrote:
> On Thu, 6 Mar 2008, Pekka J Enberg wrote:
>>>> -	if (newlen >= ct->ext->real_len) {
>>>> +	if (newlen >= ksize(ct->ext)) {
>>> This needs to look at the currently allocated size, otherwise
>>> it will always realloc when adding new extensions after having
>>> used up ksize(ct->ext) space.
>> Lets say you
>>
>>   p = kmalloc(8, ...);
>>
>> Then ksize(p) will return the currently allocated size which is 32 bytes 
>> when page size is 4 KB, and not 8 bytes. So it should be equivalent of 
>> what the current code does.
>>
>> What am I missing here?
> 
> Ok, it's not equivalent. We have two sizes: object size (8 bytes) and 
> buffer size (32 bytes) here. In netfilter, ->real_len is same as object 
> size, not buffer size as ksize() is.
> 
> But now I am officially even more confused, why does the netfilter code 
> decided whether to reallocate based on _object size_ and not _buffer size_ 
> (as krealloc() does, for example)?


It decides to reallocate when the remaining space isn't enough
to hold the new data. NF_CT_EXT_MIN_SIZE is used to make sure it
doesn't allocate anything smaller than the minimum slab size and
hopefully avoid reallocations in the future. Unless I'm
misunderstanding what ksize() does, the easiest way to get
rid of this would be to replace NF_CT_EXT_MIN_SIZE by ksize(0).

Even better would be to not only avoid waste on the first allocation,
but also on reallocations. This would look something like this:

__nf_ct_ext_add():
{
         struct nf_ct_ext *new;
-       int i, newlen, newoff;
+	int i, newlen, newoff, reallen;
...
         if (newlen >= ct->ext->real_len) {
+		reallen = ksize(newlen);
-               new = kmalloc(newlen, gfp);
+		new = kmalloc(reallen, gfp);
                 if (!new)
                         return NULL;
...
-               new->real_len = newlen;
+		new->real_len = reallen;
                 ct->ext = new;
         }


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-06 14:35       ` Patrick McHardy
@ 2008-03-06 14:41         ` Pekka J Enberg
  2008-03-06 14:51           ` Patrick McHardy
  0 siblings, 1 reply; 13+ messages in thread
From: Pekka J Enberg @ 2008-03-06 14:41 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: Netfilter Development Mailinglist, clameter, joe, linux-kernel, netdev

On Thu, 6 Mar 2008, Patrick McHardy wrote:
> It decides to reallocate when the remaining space isn't enough
> to hold the new data. NF_CT_EXT_MIN_SIZE is used to make sure it
> doesn't allocate anything smaller than the minimum slab size and
> hopefully avoid reallocations in the future. Unless I'm
> misunderstanding what ksize() does, the easiest way to get
> rid of this would be to replace NF_CT_EXT_MIN_SIZE by ksize(0).

I think you are misunderstanding ksize() (see mm/slub.c::ksize() for 
example). Furthermore, I think your current reallocation code is broken 
too as explained in a previous mail and my patch fixes that to behave as 
krealloc() does.

			Pekka

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-06 14:41         ` Pekka J Enberg
@ 2008-03-06 14:51           ` Patrick McHardy
  2008-03-06 15:49             ` Pekka Enberg
  0 siblings, 1 reply; 13+ messages in thread
From: Patrick McHardy @ 2008-03-06 14:51 UTC (permalink / raw)
  To: Pekka J Enberg
  Cc: Netfilter Development Mailinglist, clameter, joe, linux-kernel, netdev

Pekka J Enberg wrote:
> On Thu, 6 Mar 2008, Patrick McHardy wrote:
>> It decides to reallocate when the remaining space isn't enough
>> to hold the new data. NF_CT_EXT_MIN_SIZE is used to make sure it
>> doesn't allocate anything smaller than the minimum slab size and
>> hopefully avoid reallocations in the future. Unless I'm
>> misunderstanding what ksize() does, the easiest way to get
>> rid of this would be to replace NF_CT_EXT_MIN_SIZE by ksize(0).
> 
> I think you are misunderstanding ksize() (see mm/slub.c::ksize() for 
> example).

The ksize() description in mm/slab.c matches exactly what netfilter
wants to do:

  * kmalloc may internally round up allocations and return more memory
  * than requested. ksize() can be used to determine the actual amount 
of
  * memory allocated. The caller may use this additional memory, even though
  * a smaller amount of memory was initially specified with the kmalloc 
call.

> Furthermore, I think your current reallocation code is broken 
> too as explained in a previous mail and my patch fixes that to behave as 
> krealloc() does.

I don't think there is anything broken with that code.

The initial allocation size is calculated as max(size, min slab size)
and is stored as ext->alloc_size. When adding the first extension,
it allocates ext->alloc_size of memory and stores both the real amount
of space used (ext->len) and the actual size (ext->real_len).
When adding further extensions, it calculates the new total amount of
space needed (newlen). If that is larger than the real amount of
memory allocated (real_len), it reallocates.

What am I missing here?


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-06 14:51           ` Patrick McHardy
@ 2008-03-06 15:49             ` Pekka Enberg
  2008-03-10 17:57               ` Patrick McHardy
  0 siblings, 1 reply; 13+ messages in thread
From: Pekka Enberg @ 2008-03-06 15:49 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: Netfilter Development Mailinglist, clameter, joe, linux-kernel, netdev

Hi Patrick,

Patrick McHardy wrote:
> > I think you are misunderstanding ksize() (see mm/slub.c::ksize() for 
> > example).
> 
> The ksize() description in mm/slab.c matches exactly what netfilter
> wants to do:

Agreed.

Patrick McHardy wrote:
> The initial allocation size is calculated as max(size, min slab size)
> and is stored as ext->alloc_size. When adding the first extension,

Yes, this part is correct, however...

> it allocates ext->alloc_size of memory and stores both the real amount
> of space used (ext->len) and the actual size (ext->real_len).
> When adding further extensions, it calculates the new total amount of
> space needed (newlen). If that is larger than the real amount of
> memory allocated (real_len), it reallocates.

...looking at nf_ct_ext_create() you do:

         *ext = kzalloc(real_len, gfp);
                        ^^^^^^^^
         if (!*ext)
                 return NULL;

         (*ext)->offset[id] = off;
         (*ext)->len = len;
         (*ext)->real_len = real_len;
                            ^^^^^^^^

You are storing the _object size_ (total amount of memory requested) and 
not the _buffer size_ (total amount of memory allocated). Keep in mind 
that object size < buffer size and that ksize() returns the latter.

Now continuing in __nf_ct_ext_add() you do:

        if (newlen >= ct->ext->real_len) {
                               ^^^^^^^^
                 new = kmalloc(newlen, gfp);
                 if (!new)
                         return NULL;

So you're comparing newlen to the object size and not the buffer size 
which is what you want and what ksize() and consequently my patch does.

Take a look at mm/util.c::krealloc(). It does exactly what you want 
modulo the RCU bits. My patch converts the netfilter code to follow the 
exact same semantics.

			Pekka

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-06 14:14   ` Pekka J Enberg
  2008-03-06 14:20     ` Pekka J Enberg
@ 2008-03-06 16:41     ` Christoph Lameter
  1 sibling, 0 replies; 13+ messages in thread
From: Christoph Lameter @ 2008-03-06 16:41 UTC (permalink / raw)
  To: Pekka J Enberg
  Cc: Patrick McHardy, Netfilter Development Mailinglist, joe,
	linux-kernel, netdev, Netfilter Development Mailinglist

On Thu, 6 Mar 2008, Pekka J Enberg wrote:

> Then ksize(p) will return the currently allocated size which is 32 bytes 
> when page size is 4 KB, and not 8 bytes. So it should be equivalent of 
> what the current code does.

True for SLAB. SLUB will actually allocate only 8 bytes.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH] netfilter: replace horrible hack with ksize()
  2008-03-06 15:49             ` Pekka Enberg
@ 2008-03-10 17:57               ` Patrick McHardy
  0 siblings, 0 replies; 13+ messages in thread
From: Patrick McHardy @ 2008-03-10 17:57 UTC (permalink / raw)
  To: Pekka Enberg
  Cc: Netfilter Development Mailinglist, clameter, joe, linux-kernel, netdev

Pekka Enberg wrote:
> Hi Patrick,
> 
> Patrick McHardy wrote:
>> > I think you are misunderstanding ksize() (see mm/slub.c::ksize() for 
>> > example).
>>
>> The ksize() description in mm/slab.c matches exactly what netfilter
>> wants to do:
> 
> Agreed.
> 
> Patrick McHardy wrote:
>> The initial allocation size is calculated as max(size, min slab size)
>> and is stored as ext->alloc_size. When adding the first extension,
> 
> Yes, this part is correct, however...
> 
>> it allocates ext->alloc_size of memory and stores both the real amount
>> of space used (ext->len) and the actual size (ext->real_len).
>> When adding further extensions, it calculates the new total amount of
>> space needed (newlen). If that is larger than the real amount of
>> memory allocated (real_len), it reallocates.
> 
> ...looking at nf_ct_ext_create() you do:
> 
>         *ext = kzalloc(real_len, gfp);
>                        ^^^^^^^^
>         if (!*ext)
>                 return NULL;
> 
>         (*ext)->offset[id] = off;
>         (*ext)->len = len;
>         (*ext)->real_len = real_len;
>                            ^^^^^^^^
> 
> You are storing the _object size_ (total amount of memory requested) and 
> not the _buffer size_ (total amount of memory allocated). Keep in mind 
> that object size < buffer size and that ksize() returns the latter.


For all length <= minimum slab size alloc_size (and thus
real_len) is equal to the buffer size. You are correct
however that your patch is fine, I somehow misread the

+       if (newlen >= ksize(ct->ext)) {

part and thought you would always compare against the
minimum slab size.

I've queued your patch and will pass it upstream after
some testing, thanks.

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2008-03-10 17:58 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-05 21:20 [PATCH] netfilter: replace horrible hack with ksize() Pekka J Enberg
2008-03-05 21:56 ` Christoph Lameter
2008-03-05 21:57   ` Pekka Enberg
2008-03-05 22:19   ` David Miller
2008-03-06 14:03 ` Patrick McHardy
2008-03-06 14:14   ` Pekka J Enberg
2008-03-06 14:20     ` Pekka J Enberg
2008-03-06 14:35       ` Patrick McHardy
2008-03-06 14:41         ` Pekka J Enberg
2008-03-06 14:51           ` Patrick McHardy
2008-03-06 15:49             ` Pekka Enberg
2008-03-10 17:57               ` Patrick McHardy
2008-03-06 16:41     ` Christoph Lameter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).