NetBSD-7.0～8.0でのLuaカーネルモジュールの変更箇所(あまり変更なかった...(T_T))

[NetBSD Advent Calendar 2018](https://qiita.com/advent-calendar/2018/netbsd) 18日目の記事です。
今日はNetBSD-8.0におけるLuaカーネルモジュールについて紹介しようと思います。

LuaカーネルモジュールはNetBSD-7.0から搭載された機能で、以前にもいくつか記事を書いていました。

 * [NetBSD-7.0_RC3でLuaカーネルモジュールを試してみる](https://qiita.com/furandon_pig/items/9b762e7a59f08702a7f1)
 * [Luaカーネルモジュールでgetpid(2)やkill(2)相当の関数を呼んだりしてみる](https://qiita.com/furandon_pig/items/4f186c46a9e54e2649ae)

NetBSD-8.0では、Luaカーネルモジュールがどう進化(？)しているか見てみようと思います。

## NetBSD-8.0でLuaカーネルモジュールを動かす。

まずはさっそく、Luaカーネルモジュールのサンプルを動かしてみます。

### Luaカーネルモジュールのロード

Luaカーネルモジュールのロードの前に、 `./MAKEDEV lua` を実行しておきます。

```sh 
# cd /dev
# ./MAKEDEV lua
#
```

Luaカーネルモジュールをロードします。 `sysctl -w kern.lua.verbose=1` を設定しておくと、うまく動かない時に有用なデバッグ情報が得られるかもしれません。

```sh 
# moaload lua
# modstat | grep lua
lua                     misc     filesys  -        1  109317 -
luasystm                misc     filesys  -        0     889 lua
#
# sysctl -w kern.lua.verbose=1
kern.lua.verbose: 0 -> 1
```

サンプルLuaスクリプトを動かしてみます。 `/usr/src/sys/modules/examples/luahello/luahello.lua` を見ると以下のように書かれているので、この手順で実行します。

```lua 
/usr/src/sys/modules/examples/luahello/luahello.lua:
# Print `Hello Lua world' in dmesg(8)
#
# Tutorial
# 1. Load the lua and luasystm modules.
#    modload lua
#    modload luasystm
#
# 2. Create Lua state for our code
#    luactl create state1
#
# 3. Require systm(9lua) for state1
#    luactl require state1 systm
#
# 4. Load our code in state1
#    luactl load state1 ./luahello.lua
#
# NB. The path with our code must contain at least single '/' character
```

### サンプル実行時の地味な注意点

が、上記のサンプルを実行する際にひとつ注意する箇所があります。
Luaのソースコードコメントは `--` なのですが、NetBSDのライセンス表記は `#` で始まる行で記載されいています。
シェルスクリプト等では `#` から始まる行はコメント行として扱われますが、Luaでは文法エラーになってしまいます...。
`luactl load state1 ./luahello.lua` とかしても、以下のようなエラーになってしまうので注意してください。

```sh
# luactl load state1 ./luahello.lua
luactl: LUALOAD: Invalid argument
```

`sysctl -w kern.lua.verbose=1` しておくと以下のようなカーネルメッセージが出力されますが、ちょっとデバッグ情報としては弱いですね...。

<img width="361" alt="SnapCrab_netbsd8 (base) [実行中] - Oracle VM VirtualBox_2018-12-18_21-7-48_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/61137/7f181f0e-64e2-d04f-fe2d-1fc205e3926c.png">

### LuaでHello,Worldする

ごく簡単なサンプルなので、自分でHello,Worldを作成してしまうのが早そうです。
以下のようなサンプルを作成して動かしてみます。

```lua
systm.print("Hello, Lua kernel module (^_^)\n")
```

無事にHello,Worldが表示されました。

<img width="361" alt="SnapCrab_netbsd8 (base) [実行中] - Oracle VM VirtualBox_2018-12-18_21-10-26_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/61137/5ee87b13-2d59-361c-c6fe-f4ff92387083.png">

## NetBSDの7.0から8.0におけるLuaカーネルモジュールの変更箇所(あまり変わってなかった...)

さて、NetBSD 7.0から8.0でLuaカーネルモジュールがどう変わっているのか気になります。それぞれのカーネルソースツリーから差分を抽出し\\
、変更箇所を見てみます。

Lua周りのファイルは何か追加されているようです。

```sh
$ find /pub/src/NetBSD/8.0/usr/src/sys/modules/ | grep lua | grep -v CVS
/pub/src/NetBSD/8.0/usr/src/sys/modules/examples/luahello
/pub/src/NetBSD/8.0/usr/src/sys/modules/examples/luahello/luahello.lua
/pub/src/NetBSD/8.0/usr/src/sys/modules/examples/luareadhappy
/pub/src/NetBSD/8.0/usr/src/sys/modules/examples/luareadhappy/Makefile
/pub/src/NetBSD/8.0/usr/src/sys/modules/examples/luareadhappy/happy.lua
/pub/src/NetBSD/8.0/usr/src/sys/modules/examples/luareadhappy/luareadhappy.c
/pub/src/NetBSD/8.0/usr/src/sys/modules/lua
/pub/src/NetBSD/8.0/usr/src/sys/modules/lua/Makefile
/pub/src/NetBSD/8.0/usr/src/sys/modules/lua/infinite.lua
/pub/src/NetBSD/8.0/usr/src/sys/modules/lua/lua.c
/pub/src/NetBSD/8.0/usr/src/sys/modules/lua/luavar.h
/pub/src/NetBSD/8.0/usr/src/sys/modules/lua/test.lua
/pub/src/NetBSD/8.0/usr/src/sys/modules/luapmf
/pub/src/NetBSD/8.0/usr/src/sys/modules/luapmf/Makefile
/pub/src/NetBSD/8.0/usr/src/sys/modules/luapmf/luapmf.c
/pub/src/NetBSD/8.0/usr/src/sys/modules/luasystm
/pub/src/NetBSD/8.0/usr/src/sys/modules/luasystm/Makefile
/pub/src/NetBSD/8.0/usr/src/sys/modules/luasystm/luasystm.c
/pub/src/NetBSD/8.0/usr/src/sys/modules/luasystm/test.lua
$
$ find /pub/src/NetBSD/7.1.1/usr/src/sys/modules/ | grep lua | grep -v CVS
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/examples/luahello
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/examples/luahello/luahello.lua
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/lua
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/lua/Makefile
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/lua/infinite.lua
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/lua/lua.c
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/lua/luavar.h
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/lua/test.lua
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/luapmf
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/luapmf/Makefile
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/luapmf/luapmf.c
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/luasystm
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/luasystm/Makefile
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/luasystm/luasystm.c
/pub/src/NetBSD/7.1.1/usr/src/sys/modules/luasystm/test.lua
```

`/usr/src/sys/modules/examples/luareadhappy/happy.lua` というサンプルが追加されています。[3日目](https://qiita.com/furandon_pig/i\
tems/647c21cbe21eeb3aafc2)のカーネルモジュールの記事で紹介しした、 `readhappy` モジュールのLua版のようです。

```sh
$ find /pub/src/NetBSD/7.1.1/usr/src/sys/modules/ | grep lua | grep -v CVS | sed -e "s/^.*\/usr\//\/usr\//" > _7.1.1.txt
$ find /pub/src/NetBSD/8.0/usr/src/sys/modules/   | grep lua | grep -v CVS | sed -e "s/^.*\/usr\//\/usr\//" > _8.0.txt
$
$ diff -ur _7.1.1.txt _8.0.txt
--- _7.1.1.txt  2018-12-18 21:10:05.961585000 +0900
+++ _8.0.txt    2018-12-18 21:10:17.549985000 +0900
@@ -1,5 +1,9 @@
 /usr/src/sys/modules/examples/luahello
 /usr/src/sys/modules/examples/luahello/luahello.lua
+/usr/src/sys/modules/examples/luareadhappy
+/usr/src/sys/modules/examples/luareadhappy/Makefile
+/usr/src/sys/modules/examples/luareadhappy/happy.lua
+/usr/src/sys/modules/examples/luareadhappy/luareadhappy.c
 /usr/src/sys/modules/lua
 /usr/src/sys/modules/lua/Makefile
 /usr/src/sys/modules/lua/infinite.lua
```

`/usr/src/sys/modules/lua` 以下の差分を確認してみます。

```sh
$ cd /pub/src/NetBSD/8.0/usr/src/sys/modules/lua
$ for i in `find . -type f | grep -v CVS`
  do
      diff -ur /pub/src/NetBSD/7.1.1/usr/src/sys/modules/lua/${i} /pub/src/NetBSD/8.0/usr/src/sys/modules/lua/${i}
  done
```

差分は以下になるのですが、LuaモジュールについてはNetBSD 7.0から8.0で大きな変更が入った感じはないですね...。
(NetBSD-8.0に合わせたカーネル関数の扱い方の対応が入った的な修正のみのようです)

```diff
--- /pub/src/NetBSD/7.1.1/usr/src/sys/modules/lua/./lua.c	2017-07-23 14:56:36.000000000 +0900
+++ /pub/src/NetBSD/8.0/usr/src/sys/modules/lua/./lua.c	2018-01-07 18:27:32.000000000 +0900
@@ -1,8 +1,8 @@
-/*	$NetBSD: lua.c,v 1.13.2.3.4.1 2017/07/23 05:56:36 snj Exp $ */
+/*	$NetBSD: lua.c,v 1.23.2.1 2018/01/07 09:27:32 snj Exp $ */
 
 /*
+ * Copyright (c) 2011 - 2017 by Marc Balmer <mbalmer@NetBSD.org>.
  * Copyright (c) 2014 by Lourival Vieira Neto <lneto@NetBSD.org>.
- * Copyright (c) 2011, 2013 by Marc Balmer <mbalmer@NetBSD.org>.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -141,7 +141,8 @@
 	mutex_init(&sc->sc_state_lock, MUTEX_DEFAULT, IPL_VM);
 	cv_init(&sc->sc_state_cv, "luastate");
 
-	pmf_device_register(self, NULL, NULL);
+	if (!pmf_device_register(self, NULL, NULL))
+		aprint_error_dev(self, "couldn't establish power handler\n");
 
 	/* Sysctl to provide some control over behaviour */
         sysctl_createv(&sc->sc_log, 0, NULL, &node,
@@ -152,7 +153,7 @@
             CTL_KERN, CTL_CREATE, CTL_EOL);
 
         if (node == NULL) {
-		printf(": can't create sysctl node\n");
+		aprint_error(": can't create sysctl node\n");
                 return;
 	}
 
@@ -287,6 +288,7 @@
 	struct pathbuf *pb;
 	struct vattr va;
 	struct lua_loadstate ls;
+	struct lua_state_info *states;
 	int error, n;
 	klua_State *K;
 
@@ -306,14 +308,25 @@
 			LIST_FOREACH(s, &lua_states, lua_next) {
 				if (n > info->num_states)
 					break;
-				copyoutstr(s->lua_name, info->states[n].name,
-				    MAX_LUA_NAME, NULL);
-				copyoutstr(s->lua_desc, info->states[n].desc,
-				    MAX_LUA_DESC, NULL);
-				info->states[n].user = s->K->ks_user;
 				n++;
 			}
 			info->num_states = n;
+			states = kmem_alloc(sizeof(*states) * n, KM_SLEEP);
+			if (copyin(info->states, states, sizeof(*states) * n)
+			    == 0) {
+				n = 0;
+				LIST_FOREACH(s, &lua_states, lua_next) {
+					if (n > info->num_states)
+						break;
+					strcpy(states[n].name, s->lua_name);
+					strcpy(states[n].desc, s->lua_desc);
+					states[n].user = s->K->ks_user;
+					n++;
+				}
+				copyout(states, info->states,
+				    sizeof(*states) * n);
+				kmem_free(states, sizeof(*states) * n);
+			}
 		}
 		break;
 	case LUACREATE:
@@ -402,8 +415,8 @@
 				if (pb == NULL)
 					return ENOMEM;
 				NDINIT(&nd, LOOKUP, FOLLOW | NOCHROOT, pb);
-				pathbuf_destroy(pb);
 				error = vn_open(&nd, FREAD, 0);
+				pathbuf_destroy(pb);
 				if (error) {
 					if (lua_verbose)
 						device_printf(sc->sc_dev,
@@ -519,6 +532,10 @@
 					    md->mod_name);
 				luaL_requiref(L, md->mod_name, md->open, 0);
 
+				LIST_FOREACH(m, &s->lua_modules, mod_next)
+					if (m == md)
+						return 1;
+
 				md->refcount++;
 				LIST_INSERT_HEAD(&s->lua_modules, md, mod_next);
 				return 1;
@@ -640,7 +657,7 @@
 
 klua_State *
 klua_newstate(lua_Alloc f, void *ud, const char *name, const char *desc,
-		int ipl)
+    int ipl)
 {
 	klua_State *K;
 	struct lua_state *s;
@@ -707,6 +724,7 @@
 	struct lua_module *m;
 	int error = 0;
 
+	/* XXX consider registering a handler instead of a fixed name. */
 	lua_getglobal(K->L, "onClose");
 	if (lua_isfunction(K->L, -1))
 		lua_pcall(K->L, -1, 0, 0);
@@ -797,9 +815,11 @@
 static const struct cfiattrdata luabus_iattrdata = {
 	"luabus", 0, { { NULL, NULL, 0 },}
 };
+
 static const struct cfiattrdata *const lua_attrs[] = {
 	&luabus_iattrdata, NULL
 };
+
 CFDRIVER_DECL(lua, DV_DULL, lua_attrs);
 extern struct cfattach lua_ca;
 static int lualoc[] = {
@@ -807,6 +827,7 @@
 	-1,
 	-1
 };
+
 static struct cfdata lua_cfdata[] = {
 	{
 		.cf_name = "lua",
```
## まとめ

Luaカーネルモジュールについて、NetBSD 7.0と8.0の間での変更箇所を見てみました。実際にはほとんど変更がないという状態でしたが、 `luareadhappy` というサンプルが追加されており、ユーザランド側のLuaスクリプトで定義した関数をカーネル内から呼び出すというサンプルのようです。
明日の記事ではこのサンプルの中身を見てゆこうと思います。

## 参考URL

 * Lua Basic Syntax
   * https://www.tutorialspoint.com/lua/lua_basic_syntax.htm