Hello.
I can't pass memory allocated by kmalloc() to ksize()
if it is allocated by SLUB allocator and
size is larger than (I guess) PAGE_SIZE / 2.
Regards.
---------- Kernel config (grep CONFIG_SLUB .config) ----------
CONFIG_SLUB_DEBUG=y
CONFIG_SLUB=y
# CONFIG_SLUB_DEBUG_ON is not set
---------- Testing program (ksize_test.c) ----------
#include <linux/module.h>
#include <linux/slab.h>
static int __init init_ksize_test(void)
{
void *p = kmalloc(2049, GFP_KERNEL);
printk("ksize(%p) = %d\n", p, ksize(p));
kfree(p);
return -ENOMEM;
}
module_init(init_ksize_test)
MODULE_LICENSE("GPL");
------------[ cut here ]------------
kernel BUG at mm/slub.c:2562!
invalid opcode: 0000 [#1] SMP
Modules linked in: ksize_test
Pid: 8473, comm: modprobe Not tainted (2.6.24-rc3-git6 #4)
EIP: 0060:[<c01714a2>] EFLAGS: 00010246 CPU: 1
EIP is at ksize+0x1b/0x4a
EAX: 00000000 EBX: dd776000 ECX: c16721d0 EDX: 00000000
ESI: e081b280 EDI: df3a396c EBP: dd595ea0 ESP: dd595ea0
DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
Process modprobe (pid: 8473, ti=dd595000 task=d347cd60 task.ti=dd595000)
Stack: dd595eb8 e081e01a dd595eb8 c014010c ffffffff e08193e0 dd595fb0 c0150b18
00000000 00000000 00001866 00000000 dd4dac00 d347cd60 c14366ac 00000230
0000135c 0000000e dd4dac00 e081b280 00000000 00000000 00000000 00000000
Call Trace:
[<c0106008>] show_trace_log_lvl+0x1a/0x2f
[<c01060b8>] show_stack_log_lvl+0x9b/0xa3
[<c0106167>] show_registers+0xa7/0x178
[<c010634c>] die+0x114/0x1f5
[<c0417018>] do_trap+0x8a/0xa3
[<c01066ec>] do_invalid_op+0x88/0x92
[<c0416dea>] error_code+0x72/0x78
[<e081e01a>] init_ksize_test+0x1a/0x40 [ksize_test]
[<c0150b18>] sys_init_module+0x13d3/0x14ff
[<c0104f7e>] sysenter_past_esp+0x5f/0xa5
=======================
Code: 8b 02 5d 84 c0 b8 00 00 00 00 0f 49 d0 89 d0 c3 55 85 c0 89 e5 75 04 0f 0b eb fe 31 d2 83 f8 10 74 34 e8 b4 ff ff ff 85 c0 75 04 <0f> 0b eb fe 8b 40 0c 85 c0 75 04 0f 0b eb fe 8b 10 f6 c6 0c 74
EIP: [<c01714a2>] ksize+0x1b/0x4a SS:ESP 0068:dd595ea0
Tetsuo Handa wrote:
> Hello.
>
> I can't pass memory allocated by kmalloc() to ksize()
> if it is allocated by SLUB allocator and
> size is larger than (I guess) PAGE_SIZE / 2.
>
> Regards.
>
> ---------- Kernel config (grep CONFIG_SLUB .config) ----------
> CONFIG_SLUB_DEBUG=y
> CONFIG_SLUB=y
> # CONFIG_SLUB_DEBUG_ON is not set
>
> ---------- Testing program (ksize_test.c) ----------
> #include <linux/module.h>
> #include <linux/slab.h>
>
> static int __init init_ksize_test(void)
> {
> void *p = kmalloc(2049, GFP_KERNEL);
> printk("ksize(%p) = %d\n", p, ksize(p));
> kfree(p);
> return -ENOMEM;
> }
>
> module_init(init_ksize_test)
>
> MODULE_LICENSE("GPL");
>
> ------------[ cut here ]------------
> kernel BUG at mm/slub.c:2562!
> invalid opcode: 0000 [#1] SMP
> Modules linked in: ksize_test
>
> Pid: 8473, comm: modprobe Not tainted (2.6.24-rc3-git6 #4)
> EIP: 0060:[<c01714a2>] EFLAGS: 00010246 CPU: 1
> EIP is at ksize+0x1b/0x4a
> EAX: 00000000 EBX: dd776000 ECX: c16721d0 EDX: 00000000
> ESI: e081b280 EDI: df3a396c EBP: dd595ea0 ESP: dd595ea0
> DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
> Process modprobe (pid: 8473, ti=dd595000 task=d347cd60 task.ti=dd595000)
> Stack: dd595eb8 e081e01a dd595eb8 c014010c ffffffff e08193e0 dd595fb0 c0150b18
> 00000000 00000000 00001866 00000000 dd4dac00 d347cd60 c14366ac 00000230
> 0000135c 0000000e dd4dac00 e081b280 00000000 00000000 00000000 00000000
> Call Trace:
> [<c0106008>] show_trace_log_lvl+0x1a/0x2f
> [<c01060b8>] show_stack_log_lvl+0x9b/0xa3
> [<c0106167>] show_registers+0xa7/0x178
> [<c010634c>] die+0x114/0x1f5
> [<c0417018>] do_trap+0x8a/0xa3
> [<c01066ec>] do_invalid_op+0x88/0x92
> [<c0416dea>] error_code+0x72/0x78
> [<e081e01a>] init_ksize_test+0x1a/0x40 [ksize_test]
> [<c0150b18>] sys_init_module+0x13d3/0x14ff
> [<c0104f7e>] sysenter_past_esp+0x5f/0xa5
> =======================
> Code: 8b 02 5d 84 c0 b8 00 00 00 00 0f 49 d0 89 d0 c3 55 85 c0 89 e5 75 04 0f 0b eb fe 31 d2 83 f8 10 74 34 e8 b4 ff ff ff 85 c0 75 04 <0f> 0b eb fe 8b 40 0c 85 c0 75 04 0f 0b eb fe 8b 10 f6 c6 0c 74
> EIP: [<c01714a2>] ksize+0x1b/0x4a SS:ESP 0068:dd595ea0
..
Is "p" NULL ? Where'd your printk() output go to?
Mark Lord wrote:
> Tetsuo Handa wrote:
>> Hello.
>>
>> I can't pass memory allocated by kmalloc() to ksize()
>> if it is allocated by SLUB allocator and
>> size is larger than (I guess) PAGE_SIZE / 2.
>>
>> Regards.
>>
>> ---------- Kernel config (grep CONFIG_SLUB .config) ----------
>> CONFIG_SLUB_DEBUG=y
>> CONFIG_SLUB=y
>> # CONFIG_SLUB_DEBUG_ON is not set
>>
>> ---------- Testing program (ksize_test.c) ----------
>> #include <linux/module.h>
>> #include <linux/slab.h>
>>
>> static int __init init_ksize_test(void)
>> {
>> void *p = kmalloc(2049, GFP_KERNEL);
>> printk("ksize(%p) = %d\n", p, ksize(p));
>> kfree(p);
>> return -ENOMEM;
>> }
>>
>> module_init(init_ksize_test)
>>
>> MODULE_LICENSE("GPL");
>>
>> ------------[ cut here ]------------
>> kernel BUG at mm/slub.c:2562!
>> invalid opcode: 0000 [#1] SMP
>> Modules linked in: ksize_test
>>
>> Pid: 8473, comm: modprobe Not tainted (2.6.24-rc3-git6 #4)
>> EIP: 0060:[<c01714a2>] EFLAGS: 00010246 CPU: 1
>> EIP is at ksize+0x1b/0x4a
>> EAX: 00000000 EBX: dd776000 ECX: c16721d0 EDX: 00000000
>> ESI: e081b280 EDI: df3a396c EBP: dd595ea0 ESP: dd595ea0
>> DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
>> Process modprobe (pid: 8473, ti=dd595000 task=d347cd60 task.ti=dd595000)
>> Stack: dd595eb8 e081e01a dd595eb8 c014010c ffffffff e08193e0 dd595fb0
>> c0150b18
>> 00000000 00000000 00001866 00000000 dd4dac00 d347cd60 c14366ac
>> 00000230
>> 0000135c 0000000e dd4dac00 e081b280 00000000 00000000 00000000
>> 00000000
>> Call Trace:
>> [<c0106008>] show_trace_log_lvl+0x1a/0x2f
>> [<c01060b8>] show_stack_log_lvl+0x9b/0xa3
>> [<c0106167>] show_registers+0xa7/0x178
>> [<c010634c>] die+0x114/0x1f5
>> [<c0417018>] do_trap+0x8a/0xa3
>> [<c01066ec>] do_invalid_op+0x88/0x92
>> [<c0416dea>] error_code+0x72/0x78
>> [<e081e01a>] init_ksize_test+0x1a/0x40 [ksize_test]
>> [<c0150b18>] sys_init_module+0x13d3/0x14ff
>> [<c0104f7e>] sysenter_past_esp+0x5f/0xa5
>> =======================
>> Code: 8b 02 5d 84 c0 b8 00 00 00 00 0f 49 d0 89 d0 c3 55 85 c0 89 e5
>> 75 04 0f 0b eb fe 31 d2 83 f8 10 74 34 e8 b4 ff ff ff 85 c0 75 04 <0f>
>> 0b eb fe 8b 40 0c 85 c0 75 04 0f 0b eb fe 8b 10 f6 c6 0c 74
>> EIP: [<c01714a2>] ksize+0x1b/0x4a SS:ESP 0068:dd595ea0
> ..
>
> Is "p" NULL ? Where'd your printk() output go to?
..
Mmm.. just tried it here, same result, and "p" is definitely not NULL.
On Sun, Dec 02, 2007 at 07:39:59PM +0900, Tetsuo Handa wrote:
> Hello.
>
> I can't pass memory allocated by kmalloc() to ksize()
> if it is allocated by SLUB allocator and
> size is larger than (I guess) PAGE_SIZE / 2.
>
> Regards.
>
> ---------- Kernel config (grep CONFIG_SLUB .config) ----------
> CONFIG_SLUB_DEBUG=y
> CONFIG_SLUB=y
> # CONFIG_SLUB_DEBUG_ON is not set
>
> ---------- Testing program (ksize_test.c) ----------
> #include <linux/module.h>
> #include <linux/slab.h>
>
> static int __init init_ksize_test(void)
> {
> void *p = kmalloc(2049, GFP_KERNEL);
> printk("ksize(%p) = %d\n", p, ksize(p));
> kfree(p);
> return -ENOMEM;
> }
>
> module_init(init_ksize_test)
>
> MODULE_LICENSE("GPL");
>
> ------------[ cut here ]------------
> kernel BUG at mm/slub.c:2562!
> invalid opcode: 0000 [#1] SMP
> Modules linked in: ksize_test
>
> Pid: 8473, comm: modprobe Not tainted (2.6.24-rc3-git6 #4)
> EIP: 0060:[<c01714a2>] EFLAGS: 00010246 CPU: 1
> EIP is at ksize+0x1b/0x4a
> EAX: 00000000 EBX: dd776000 ECX: c16721d0 EDX: 00000000
> ESI: e081b280 EDI: df3a396c EBP: dd595ea0 ESP: dd595ea0
> DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
> Process modprobe (pid: 8473, ti=dd595000 task=d347cd60 task.ti=dd595000)
> Stack: dd595eb8 e081e01a dd595eb8 c014010c ffffffff e08193e0 dd595fb0 c0150b18
> 00000000 00000000 00001866 00000000 dd4dac00 d347cd60 c14366ac 00000230
> 0000135c 0000000e dd4dac00 e081b280 00000000 00000000 00000000 00000000
> Call Trace:
> [<c0106008>] show_trace_log_lvl+0x1a/0x2f
> [<c01060b8>] show_stack_log_lvl+0x9b/0xa3
> [<c0106167>] show_registers+0xa7/0x178
> [<c010634c>] die+0x114/0x1f5
> [<c0417018>] do_trap+0x8a/0xa3
> [<c01066ec>] do_invalid_op+0x88/0x92
> [<c0416dea>] error_code+0x72/0x78
> [<e081e01a>] init_ksize_test+0x1a/0x40 [ksize_test]
> [<c0150b18>] sys_init_module+0x13d3/0x14ff
> [<c0104f7e>] sysenter_past_esp+0x5f/0xa5
> =======================
> Code: 8b 02 5d 84 c0 b8 00 00 00 00 0f 49 d0 89 d0 c3 55 85 c0 89 e5 75 04 0f 0b eb fe 31 d2 83 f8 10 74 34 e8 b4 ff ff ff 85 c0 75 04 <0f> 0b eb fe 8b 40 0c 85 c0 75 04 0f 0b eb fe 8b 10 f6 c6 0c 74
> EIP: [<c01714a2>] ksize+0x1b/0x4a SS:ESP 0068:dd595ea0
Can you confirm that it works in 2.6.23?
If yes this is most likely caused by
commit aadb4bc4a1f9108c1d0fbd121827c936c2ed4217
cu
Adrian
--
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon Seed
On Sun, Dec 02, 2007 at 10:56:11AM -0500, Mark Lord wrote:
> Tetsuo Handa wrote:
>...
>> kernel BUG at mm/slub.c:2562!
>...
> Is "p" NULL ? Where'd your printk() output go to?
Check the source, that's not the BUG_ON(!object), it's the
BUG_ON(!page).
cu
Adrian
--
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon Seed
On Dec 2, 2007 11:39 AM, Tetsuo Handa
<[email protected]> wrote:
> Hello.
>
> I can't pass memory allocated by kmalloc() to ksize()
> if it is allocated by SLUB allocator and
> size is larger than (I guess) PAGE_SIZE / 2.
>
> Regards.
Take a look at mm/slub.c around line 2560, in __kmalloc:
if (unlikely(size > PAGE_SIZE / 2))
return (void *)__get_free_pages(flags | __GFP_COMP,
get_order(size));
So it seems that kmalloc simply returns pages from the page allocator
in this case. Therefore no SLUB metadata will be available for the
allocation.
The error of ksize() seems to be that it does not check if the
allocation was made by SLUB or the page allocator. Maybe something
like this will fix it? (completely untested)
diff --git a/mm/slub.c b/mm/slub.c
index 9acb413..1cdca59 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2552,6 +2552,7 @@ EXPORT_SYMBOL(__kmalloc_node);
size_t ksize(const void *object)
{
struct page *page;
+ struct page *head;
struct kmem_cache *s;
BUG_ON(!object);
@@ -2560,6 +2561,13 @@ size_t ksize(const void *object)
page = get_object_page(object);
BUG_ON(!page);
+
+ head = compound_head(page);
+ BUG_ON(!head);
+
+ if (unlikely(!(head->flags & PG_slab)))
+ return PAGE_SIZE << compound_order(head);
+
s = page->slab;
BUG_ON(!s);
It's going to round up, though, so you would get ksize(kmalloc(2049))
= PAGE_SIZE.
Vegard
On Dec 2, 2007 5:30 PM, Vegard Nossum <[email protected]> wrote:
> On Dec 2, 2007 11:39 AM, Tetsuo Handa
> <[email protected]> wrote:
> > Hello.
> >
> > I can't pass memory allocated by kmalloc() to ksize()
> > if it is allocated by SLUB allocator and
> > size is larger than (I guess) PAGE_SIZE / 2.
> >
> > Regards.
> The error of ksize() seems to be that it does not check if the
> allocation was made by SLUB or the page allocator. Maybe something
> like this will fix it? (completely untested)
That didn't work. I guess that's what you get for no testing ;-) After
some more investigations, it seems that this is the correct way to fix
it (and tested!):
diff --git a/mm/slub.c b/mm/slub.c
index 9acb413..b9f37cb 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2558,8 +2558,12 @@ size_t ksize(const void *object)
if (unlikely(object == ZERO_SIZE_PTR))
return 0;
- page = get_object_page(object);
+ page = virt_to_head_page(object);
BUG_ON(!page);
+
+ if (unlikely(!PageSlab(page)))
+ return PAGE_SIZE << compound_order(page);
+
s = page->slab;
BUG_ON(!s);
> It's going to round up, though, so you would get ksize(kmalloc(2049))
> = PAGE_SIZE.
Vegard
Hi Vegard,
On 12/2/07, Vegard Nossum <[email protected]> wrote:
> diff --git a/mm/slub.c b/mm/slub.c
> index 9acb413..b9f37cb 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -2558,8 +2558,12 @@ size_t ksize(const void *object)
> if (unlikely(object == ZERO_SIZE_PTR))
> return 0;
>
> - page = get_object_page(object);
> + page = virt_to_head_page(object);
> BUG_ON(!page);
> +
> + if (unlikely(!PageSlab(page)))
> + return PAGE_SIZE << compound_order(page);
> +
> s = page->slab;
> BUG_ON(!s);
Looks good to me.
Reviewed-by: Pekka Enberg <[email protected]>
Hello.
Vegard Nossum wrote:
> That didn't work. I guess that's what you get for no testing ;-) After
> some more investigations, it seems that this is the correct way to fix
> it (and tested!):
It worked in my environment too.
Please apply to 2.6.24-rc3-git6's tree.
Thank you.