まえがき
週刊Railsウォッチというrailsを中心とした記事がとても良い感じで、これのカーネル版あったら嬉しなということで自分でやってみました(*´Д`)
どれくらいのボリュームでとか、毎週ちゃんと書くのかは全く不明でございます。
我々にはWelcome to LWN.net [LWN.net]やLinux Hardware Reviews, Open-Source Benchmarks & Linux Performance - Phoronixがあるし、基本的にこれらを読めば事足りる気はしますが。まあ、小ネタを拾っていこう的な感じです。
読むpatchについてはマージされるかどうかは別として、気になったものとかを取り上げようと思います。
今週のpatch
sl*bでコンストラクタ使う場合にスラブオブジェクトの取得時に__GFP_ZEROフラグ使わない
[PATCH v2 2/2] slab: __GFP_ZERO is incompatible with a constructor — Linux Kernelというpatchのお話です。4/12時点ではマージされてませんが。
sl*bではページを確保してスラブオブジェクトを新規に作る時にコンストラクタを渡して、作成時に処理を行うことができます。スラブの作成でkmem_cache_create()系の関数を使うとコンストラクタを渡せます。
struct kmem_cache *kmem_cache_create(const char *name, size_t size,
size_t align, slab_flags_t flags,
void (*ctor)(void *));
struct kmem_cache *kmem_cache_create_usercopy(const char *name,
size_t size, size_t align, slab_flags_t flags,
size_t useroffset, size_t usersize,
void (*ctor)(void *));
slubだとsetup_object()で1オブジェクト毎に指定されたコンストラクタを実行します。
static void setup_object(struct kmem_cache *s, struct page *page,
void *object)
{
setup_object_debug(s, page, object);
kasan_init_slab_obj(s, object);
if (unlikely(s->ctor)) {
kasan_unpoison_object_data(s, object);
s->ctor(object);
kasan_poison_object_data(s, object);
}
}
そして、kmem_cache_alloc()でスラブオブジェクトを取得する時にgfpフラグを渡して、メモリの確保方法を指定できます。
void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags) __assume_slab_alignment __malloc;
ここで、flagsにGFP_ZEROを渡した場合ですが、オブジェクトを確保してそのオブジェクトをmemset()で0クリアするのがslubでの処理です。そうすると、コンストラクタで何かしらの処理をオブジェクトにしていてもそれが0で上書きされてしまうので、その場合の対応が今回のpatchでした。
簡単なテストコードを書いて試してみましょう。コードはこんな感じです。kmem_cache_alloc()にGFP_ZEROを渡さない場合と渡す場合の2関数を作って呼びます。
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/gfp.h>
#include <linux/string.h>
MODULE_DESCRIPTION("slab constructor test");
MODULE_AUTHOR("masami256");
MODULE_LICENSE("GPL");
#define SCT_SLAB_NAME "sct"
static struct kmem_cache *sct_cache;
struct sct_test_struct {
int n;
char s[16];
};
static void sct_constructor(void *data)
{
struct sct_test_struct *p = (struct sct_test_struct *) data;
memset(p->s, 0x0, sizeof(p->s));
p->n = 0xffff;
strcpy(p->s, "hello");
}
static void sct_test(void)
{
struct sct_test_struct *p = kmem_cache_alloc(sct_cache, GFP_KERNEL);
pr_info("%s: %d, %s\n", __func__, p->n, p->s);
kmem_cache_free(sct_cache, p);
}
static void sct_test_with_gfp_zero(void)
{
struct sct_test_struct *p = kmem_cache_alloc(sct_cache, __GFP_ZERO);
pr_info("%s: %d, %s\n", __func__, p->n, p->s);
kmem_cache_free(sct_cache, p);
}
static int slab_ctor_test_init(void)
{
slab_flags_t flags = SLAB_PANIC;
pr_info("%s start\n", __func__);
sct_cache = kmem_cache_create(SCT_SLAB_NAME,
sizeof(struct sct_test_struct),
__alignof__(struct sct_test_struct),
flags,
&sct_constructor);
if (!sct_cache) {
pr_info("failed to create slab cache\n");
return -ENOMEM;
}
sct_test();
sct_test_with_gfp_zero();
return 0;
}
static void slab_ctor_test_cleanup(void)
{
if (sct_cache)
kmem_cache_destroy(sct_cache);
pr_info("%s bye\n", __func__);
}
module_init(slab_ctor_test_init);
module_exit(slab_ctor_test_cleanup);
実行結果はこうなります。__GFP_ZEROを付けた方はコンストラクタ設定した値が0で上書きされてますね/(^o^)\
masami@kerntest:~/slab_ctor_test$ dmesg
[ 225.077109] slab_ctor_test: slab_ctor_test_init start
[ 225.077156] slab_ctor_test: sct_test: 65535, hello
[ 225.077157] slab_ctor_test: sct_test_with_gfp_zero: 0,
(´-`).。oO(言われてみればその通りで、コンストラクタと__GFP_ZEROが共存するような使い方はあまり意味がないんだけどシステム的にはノーチェックだったんですね。ちなみに、これはf2fsの方で見つかったバグが発端になってるようです
アドレスを定義するときはunsigned longを使おう
[PATCH] x86/mm: vmemmap and vmalloc base addressess are usngined longs — Linux Kernelのpatchです。
こんな感じでULを付けましょうということです。
-#define __VMEMMAP_BASE_L4 0xffffea0000000000
-#define __VMEMMAP_BASE_L5 0xffd4000000000000
+#define __VMEMMAP_BASE_L4 0xffffea0000000000UL
+#define __VMEMMAP_BASE_L5 0xffd4000000000000UL
(´-`).。oO(忘れずにULをつけましょう
sizeof(void)とgccのワーニング
www.spinics.netのpatchです。gccのオプションで-Wpointer-arithを付けると c sizeof(void)
を使ってる時に警告がでます。この警告-Wallではでません。sparseがこの警告を大量に出してくるので警告のon/off切り替えをできるようにしたようです。
#include <stdio.h>
int main(int argc, char **argv)
{
sizeof(void);
return 0;
}
masami@saga:~$ gcc sizeof_void.c -Wpointer-arith
sizeof_void.c: In function ‘main’:
sizeof_void.c:5:9: warning: invalid application of ‘sizeof’ to a void type [-Wpointer-arith]
sizeof(void);
^~~~
(´-`).。oO(sizeof(void)は1です
あとがき
来週も書けるかな?