WSLのシステムコール実装/未実装を確認する

Windows Subsystem for Linux を使っていると、カーネル側の機能が無いためにうまく動かないコマンドが結構あるのが気になった。

# dmesg
dmesg: カーネルバッファの読み込みに失敗しました: 関数は実装されていません

# ipcrm -q 1
ipcrm: ID の処理に失敗しました: 関数は実装されていません

ということで、各システムコールの実装/未実装を調べてみる。適当な引数でシステムコールを叩いてみて、ENOSYSで失敗すれば未実装、そうでなければ実装と判断する。

#!/usr/bin/perl
use strict;

# カーネルバージョン
print `uname -a`;

# システムコール定義ファイルを読み込む
my %table = ();
open(DEFFILE, "< /usr/include/asm/unistd_64.h") or
  open(DEFFILE, "< /usr/include/x86_64-linux-gnu/asm/unistd_64.h") or
    die("open failed : $!");
while (my $line = <DEFFILE>) {
  if ($line =~ /^#define\s+__NR_(\S+)\s+(\d+)/) { $table{$2} = $1; }
}
close(DEFFILE);

# システムコールを発行して実装/未実装を判定する
foreach my $num (sort {$a <=> $b} keys(%table)) {
  my $name = $table{$num};
  print "[$num] $name ... ";
  if ($name =~ /^(vhangup|rt_sigreturn)$/) {
    print "SKIP (unsafe)\n";
    next;
  }

  # 子プロセス側でシステムコールを発行する
  my $pid = fork;
  if ($pid == 0) {
    local $SIG{ALRM} = sub { exit 222; };
    close(STDERR);
    alarm(1);
    if ($name eq 'brk') {
      syscall($num, 0);
    } else {
      syscall($num, -1);
    }
    exit $!;
  }

  # 子プロセスの終了ステータスを判定する
  waitpid($pid, 0);
  my $e = $? >> 8;
  if ($e == 0) {
    print "OK\n";
  } elsif ($e == 222) {
    print "TIMEOUT\n";
  } elsif ($e == 38) {
    print "ENOSYS\n";
  } else {
    print "FAIL ($e)\n";
  }
}

exit 0;

結局、現在のWSLでは以下のシステムコールが未実装と思われる。

Linux XXXXXXXX 4.4.0-17134-Microsoft #345-Microsoft Wed Sep 19 17:47:00 PST 2018 x86_64 x86_64 x86_64 GNU/Linux

[27] mincore
[68] msgget
[69] msgsnd
[70] msgrcv
[71] msgctl
[103] syslog
[129] rt_sigqueueinfo
[134] uselib
[136] ustat
[139] sysfs
[148] sched_rr_get_interval
[151] mlockall
[152] munlockall
[154] modify_ldt
[156] _sysctl
[159] adjtimex
[163] acct
[167] swapon
[168] swapoff
[172] iopl
[173] ioperm
[174] create_module
[175] init_module
[176] delete_module
[177] get_kernel_syms
[178] query_module
[179] quotactl
[180] nfsservctl
[181] getpmsg
[182] putpmsg
[183] afs_syscall
[184] tuxcall
[185] security
[187] readahead
[202] futex
[205] set_thread_area
[206] io_setup
[207] io_destroy
[208] io_getevents
[209] io_submit
[210] io_cancel
[211] get_thread_area
[212] lookup_dcookie
[214] epoll_ctl_old
[215] epoll_wait_old
[216] remap_file_pages
[227] clock_settime
[236] vserver
[237] mbind
[238] set_mempolicy
[239] get_mempolicy
[240] mq_open
[241] mq_unlink
[242] mq_timedsend
[243] mq_timedreceive
[244] mq_notify
[245] mq_getsetattr
[246] kexec_load
[248] add_key
[249] request_key
[250] keyctl
[256] migrate_pages
[261] futimesat
[277] sync_file_range
[278] vmsplice
[279] move_pages
[297] rt_tgsigqueueinfo
[300] fanotify_init
[301] fanotify_mark
[303] name_to_handle_at
[304] open_by_handle_at
[305] clock_adjtime
[312] kcmp
[313] finit_module
[314] sched_setattr
[315] sched_getattr
[316] renameat2
[317] seccomp
[319] memfd_create
[320] kexec_file_load
[321] bpf
[322] execveat
[323] userfaultfd
[324] membarrier
[325] mlock2
[326] copy_file_range
[327] preadv2
[328] pwritev2
[329] pkey_mprotect
[330] pkey_alloc
[331] pkey_free
[332] statx

syslogは実害があまり無いからいいとして、メッセージキューは実装してほしい。mlockall, munlockallはスタブでも構わないから受け付けてほしい。