Welcome! Log In Create A New Profile

how to get the address of other page descriptors from alloc_pages()?

Posted by luludede 
how to get the address of other page descriptors from alloc_pages()?
December 26, 2009 12:07AM
Hi,

In Linux kernel, alloc_pages() allocate a congiguous series of pages and return the page descriptor of the first page.
Can anyone tell me how to get the other page descriptors(2nd page descriptor, 3rd page descriptor)? Thank you.

In the code below, I assumed the page descriptors are also in contiguous memory but it just crashed the kernel with I add the page to page cache lru.

firstpage = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO|__GFP_COLD, 4);
if(unlikely(firstpage == NULL)) {
goto normal_handling;
}

for(i=0; i<16; i++) {/*add 16 pages to lru list*/
error= add_to_page_cache_lru(firstpage+i, mapping, first_index+i,GFP_KERNEL);
-Deng
Re: how to get the address of other page descriptors from alloc_pages()?
December 26, 2009 11:40AM
I use firstpage+i to access the other page descriptors and the program crashed when executing add_to_page_cache_lru(firstpage+2, mapping, first_index+i,GFP_KERNEL);
It seems that use firstpage+i can not get the correct page descriptors.
Can anyone tell me the right way to access the descriptors of the pages allocated by alloc_pages ?
Thank you very much.
========================================================
The code:
firstpage = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO|__GFP_COLD, 4);
if(unlikely(firstpage == NULL)) {
goto normal_handling;
}
printk(KERN_INFO "deng: all 16 pages are allocated in memory\n"winking smiley;
for(i=0; i<16; i++) {/*add 16 pages to lru list*/
printk(KERN_INFO "deng: add firstpage+%d to page cache lru\n", i);
error= add_to_page_cache_lru(firstpage+i, mapping,
first_index+i,GFP_KERNEL);

========================================================
kernel info:
deng: first page isn't in memory
deng: all 16 pages are not in memory
deng: all 16 pages are allocated in memory
deng: add firstpage+0 to page cache lru
deng: add firstpage+1 to page cache lru
------------[ cut here ]------------
kernel BUG at include/linux/mm.h:304!
invalid opcode: 0000 [#1] SMP
last sysfs file: /sys/devices/pci0000:00/0000:00:11.0/0000:02:00.0/usb2/devnum
Modules linked in: nfsd sco lockd nfs_acl auth_rpcgss exportfs bridge stp llc bnep l2cap bluetooth sunrpc ip6t_REJECT nf_conntrack_ipv6 ip6table_filter ip6_tables ipv6 dm_multipath raid0 raid1 raid456 raid6_pq async_xor async_memcpy async_tx xor uinput ppdev pcspkr snd_ens1371 gameport snd_rawmidi snd_seq_device snd_ac97_codec ac97_bus snd_pcm snd_timer snd soundcore pcnet32 snd_page_alloc mii parport_pc parport floppy i2c_piix4 i2c_core mptspi mptscsih mptbase scsi_transport_spi [last unloaded: microcode]

Pid: 2738, comm: spew Not tainted (2.6.30.9 #7) VMware Virtual Platform
EIP: 0060:[<c04917d7>] EFLAGS: 00010246 CPU: 0
EIP is at add_to_page_cache_locked+0x67/0xde
EAX: c143823c EBX: c143823c ECX: 00000000 EDX: 00000000
ESI: 00000000 EDI: d07a8ac8 EBP: de58de34 ESP: de58de20
DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
Process spew (pid: 2738, ti=de58c000 task=c9f90000 task.ti=de58c000)
Stack:
00000001 d07a8ad8 c143823c 00000001 c1438200 de58de48 c0491879 000000d0
00000001 00000001 de58dec8 c0492826 000000d0 c0862f4e 00000001 de58de64
00000000 00000000 00000000 de58df20 d333e288 de58df5c 00000000 00000000
Call Trace:
[<c0491879>] ? add_to_page_cache_lru+0x2b/0x5b
[<c0492826>] ? generic_file_aio_read+0x260/0x736
[<c04bc1d0>] ? do_sync_read+0xae/0xe9
[<c04495ec>] ? autoremove_wake_function+0x0/0x34
[<c05554fa>] ? selinux_file_permission+0x49/0x4d
[<c054f003>] ? security_file_permission+0x14/0x16
[<c04bc2a8>] ? rw_verify_area+0x9d/0xc0
[<c04bc122>] ? do_sync_read+0x0/0xe9
[<c04bc847>] ? vfs_read+0x82/0xe1
[<c04bc944>] ? sys_read+0x40/0x62
[<c04083bd>] ? syscall_call+0x7/0xb
Code: 89 c6 0f 85 91 00 00 00 8b 45 08 83 e0 fd e8 7c fe 0e 00 85 c0 89 c6 75 79 66 83 3b 00 89 d8 79 03 8b 43 0c 8b 50 04 85 d2 75 04 <0f> 0b eb fe 3e ff 40 04 8b 45 ec 89 7b 10 89 43 30 8d 47 10 89
EIP: [<c04917d7>] add_to_page_cache_locked+0x67/0xde SS:ESP 0068:de58de20
---[ end trace c12cba1f7403675e ]---
Re: how to get the address of other page descriptors from alloc_pages()?
December 27, 2009 12:47PM
By adding more traces, I found that the reason of kernel panic is because get_page() hit VM_BUG_ON(atomic_read(&page->_count) == 0) when the kernel was adding the second page to page cache and lru through add_to_page_cache_lru(), which invokes get_page().

Per the kernel code(2.6.30.9), alloc_pages() only initializes the firstpage's refcount (to be 1), and leave other pages' refcount to be 0. That's why add_to_page_cache_lru() succeeded on the first page but failed on the following pages.
I don't know whether there is special reason to initialize pages like this.

Can any one shed some light on it?

=========================================
Call stack:
alloc_pages(gfp_t gfp_mask, unsigned int order)
|alloc_pages_current(gfp_mask, order)
| |__alloc_pages_internal(gfp_mask, order, zonelist, nodemask)
| | |__alloc_pages_internal(gfp_mask, order, zonelist, nodemask)
| | |get_page_from_freelist(gfp_mask, nodemask, order, zonelist, high_zoneidx, alloc_flags)
| | | |buffered_rmqueue(preferred_zone, zone, order, gfp_mask)
| | | | |prep_new_page(page, order, gfp_flags)
| | | | | |set_page_refcounted(page) <<========only set the refcount of the first page
| | | | | | |set_page_count(page, 1)
====================================================
kernel message:
deng: first page isn't in memory
deng: all 16 pages are not in memory
deng: all 16 pages are allocated in memory
deng: firstpage+0->cout = 1 page desc: 0xc1d68fc0, page addr:0xf2510000
deng: firstpage+1->cout = 0 page desc: 0xc1d68ffc, page addr:0xf2511000
deng: firstpage+2->cout = 0 page desc: 0xc1d69038, page addr:0xf2512000
deng: firstpage+3->cout = 0 page desc: 0xc1d69074, page addr:0xf2513000
deng: firstpage+4->cout = 0 page desc: 0xc1d690b0, page addr:0xf2514000
deng: firstpage+5->cout = 0 page desc: 0xc1d690ec, page addr:0xf2515000
deng: firstpage+6->cout = 0 page desc: 0xc1d69128, page addr:0xf2516000
deng: firstpage+7->cout = 0 page desc: 0xc1d69164, page addr:0xf2517000
deng: firstpage+8->cout = 0 page desc: 0xc1d691a0, page addr:0xf2518000
deng: firstpage+9->cout = 0 page desc: 0xc1d691dc, page addr:0xf2519000
deng: firstpage+10->cout = 0 page desc: 0xc1d69218, page addr:0xf251a000
deng: firstpage+11->cout = 0 page desc: 0xc1d69254, page addr:0xf251b000
deng: firstpage+12->cout = 0 page desc: 0xc1d69290, page addr:0xf251c000
deng: firstpage+13->cout = 0 page desc: 0xc1d692cc, page addr:0xf251d000
deng: firstpage+14->cout = 0 page desc: 0xc1d69308, page addr:0xf251e000
deng: firstpage+15->cout = 0 page desc: 0xc1d69344, page addr:0xf251f000
deng: add firstpage[0]:c1d68fc0 to page cache lru
==========================================================
deng: add firstpage[1]:c1d68ffc to page cache lru
------------[ cut here ]------------
kernel BUG at include/linux/mm.h:304!
invalid opcode: 0000 [#1] SMP
last sysfs file: /sys/devices/pci0000:00/0000:00:1d.3/usb5/devnum
Modules linked in: sco bridge stp llc bnep l2cap bluetooth sunrpc ip6t_REJECT nf_conntrack_ipv6 ip6table_filter ip6_tables ipv6 p4_clockmod dm_multipath uinput ppdev snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_timer snd parport_pc iTCO_wdt parport soundcore pcspkr i2c_i801 e100 mii iTCO_vendor_support floppy snd_page_alloc ata_generic pata_acpi i915 drm i2c_algo_bit video output i2c_core [last unloaded: scsi_wait_scan]

Pid: 1747, comm: spew Not tainted (2.6.30.9 #10) Nobilis
EIP: 0060:[<c048d54d>] EFLAGS: 00010246 CPU: 0
EIP is at add_to_page_cache_locked+0x67/0xde
EAX: c1d68ffc EBX: c1d68ffc ECX: 00000000 EDX: 00000000
ESI: 00000000 EDI: f286f30c EBP: f2427e18 ESP: f2427e04
DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
Process spew (pid: 1747, ti=f2426000 task=f2ce9510 task.ti=f2426000)
Stack:
00000001 f286f31c c1d68ffc 00000001 00000001 f2427e2c c048d5ef 000000d0
c1d68ffc 00000001 f2427eb0 c048e658 000000d0 c08430b0 00000001 c1d68ffc
00000006 00000000 00000000 ffefffac f2427f08 f2475788 f2427f44 00000000
Call Trace:
[<c048d5ef>] ? add_to_page_cache_lru+0x2b/0x5b
[<c048e658>] ? generic_file_aio_read+0x298/0x767
[<c04b815c>] ? do_sync_read+0xb0/0xeb
[<c054facb>] ? file_has_perm+0x81/0x8a
[<c044a620>] ? autoremove_wake_function+0x0/0x34
[<c054b8b3>] ? security_file_permission+0x14/0x16
[<c04b8231>] ? rw_verify_area+0x9a/0xbb
[<c04b80ac>] ? do_sync_read+0x0/0xeb
[<c04b8821>] ? vfs_read+0x92/0xf1
[<c04b893c>] ? sys_read+0x4c/0x70
[<c040843d>] ? syscall_call+0x7/0xb
Code: 89 c6 0f 85 91 00 00 00 8b 45 08 83 e0 fd e8 02 e6 0e 00 85 c0 89 c6 75 79 66 83 3b 00 89 d8 79 03 8b 43 0c 8b 50 04 85 d2 75 04 <0f> 0b eb fe f0 ff 40 04 8b 45 ec 89 7b 10 89 43 30 8d 47 10 89
EIP: [<c048d54d>] add_to_page_cache_locked+0x67/0xde SS:ESP 0068:f2427e04
---[ end trace e585d47c75be7f1c ]---
Re: how to get the address of other page descriptors from alloc_pages()?
February 05, 2010 03:29AM
I think "firstpage+1" is not equal to next page descriptor.
Re: how to get the address of other page descriptors from alloc_pages()?
February 07, 2010 02:14AM
This was already discussed recently...

firstpage+1 is perfectly correct.

Crash is caused by alloc_pages() initializing use count only on the first struct page. On the rest, page count is left zero, so your call hits a BUG_ON() checking for non-zero use count.

Just call page_cache_get() for all pages but first.
Author:

Your Email:


Subject:


Message: