読者です 読者をやめる 読者になる 読者になる

__GFP_ZERO と 0 初期化

kvm のソースを読んでたら kvm_kvzalloc() なる関数が出てきた

/*
 * Avoid using vmalloc for a small buffer.
 * Should not be used when the size is statically known.
 */
void *kvm_kvzalloc(unsigned long size)
{
    if (size > PAGE_SIZE)
        return vzalloc(size);
    else
        return kzalloc(size, GFP_KERNEL);
}

割り当てたいサイズによって vzalloc() と kzalloc() を使い分ける。 kzalloc() は下記のような感じ

/**
 * kzalloc - allocate memory. The memory is set to zero.
 * @size: how many bytes of memory are required.
 * @flags: the type of memory to allocate (see kmalloc).
 */
static inline void *kzalloc(size_t size, gfp_t flags)
{
    return kmalloc(size, flags | __GFP_ZERO);

__GFP_ZERO を指定すると 割り当てた領域は 0 で初期化済みで返してくれる。

#define __GFP_ZERO  ((__force gfp_t)___GFP_ZERO)    /* Return zeroed page on success */

疑問

ここんところの実装がどうなってるかを追ってみた

github.com

といっても memset() しているだけだった。ちょっと面白みがないので下記のような検証を加えた

検証

まずは kzalloc() と kmalloc() したアドレスを dmesg に出すだけのカーネルモジュールを作る

#include <linux/module.h>
#include <linux/slab.h>

MODULE_AUTHOR("hiroya");
MODULE_DESCRIPTION("kzalloc test");
MODULE_LICENSE("GPL");

void *kz, *km;

static int __init kzalloc_init(void)
{
    kz  = kzalloc(PAGE_SIZE, GFP_KERNEL);
    km  = kmalloc(PAGE_SIZE, GFP_KERNEL);
    pr_info("kzalloc: %p kmalloc: %p\n", kz, km);

    return 0;
}

static void __exit kzalloc_exit(void)
{
    kfree(kz);
    kfree(km);
}

module_init(kzalloc_init);
module_exit(kzalloc_exit);

モジュールを insmod すると dmesg に下記のようなログがでる

[  334.125706] kzalloc: ffff880019f0d000 kmalloc: ffff880019f0f000

このアドレスを使って、メモリの内容を gdb + vmlinx + /proc/kcore でダンプする。ダンプの範囲は PAGE_SIZE = 4KB

$ sudo gdb /usr/lib/debug/lib/modules/3.10.0-327.36.3.el7.x86_64/vmlinux /proc/kcore
(gdb) dump mem /tmp/kzalloc 0xffff880019f0d000 0xffff880019f0e000
(gdb) dump mem /tmp/kmalloc 0xffff880019f1d000 0xffff880019f1e000

kzalloc() で割り当てた範囲のダンプは 0 初期化されているのが確認できる

$ hexdump -C /tmp/kzalloc 
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000

kmalloc() で割り当てた範囲のダンプは ゴミが混じっている。(何のデータかはわからない

$ hexdump -C /tmp/kmalloc 
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000002c0  00 00 00 00 00 00 00 00  67 b0 04 17 00 00 00 80  |........g.......|
000002d0  67 50 69 17 00 00 00 80  67 70 41 17 00 00 00 80  |gPi.....gpA.....|
000002e0  67 f0 68 17 00 00 00 80  00 00 00 00 00 00 00 00  |g.h.............|
000002f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000710  25 10 94 01 00 00 00 00  00 00 00 00 00 00 00 00  |%...............|
00000720  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000