3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

NetBSDAdvent Calendar 2018

Day 14

NetBSDのユーザ空間でファイルシステムを動作させるpuffsを試してみる

Posted at

NetBSD Advent Calendar 2018 14日目の記事です。
今日はNetBSDのユーザランド上でファイルシステムを実現する、PUFFSを試してみようと思います。

puffsって何?

puffs(3)のmanページを見ると、ユーザ空間でファイルシステムを開発するためのフレームワークのようです。LinuxでいうところのFuseと考えて良さそうです。
また、 libpuffs というライブラリの形で機能が提供されているようです。

NAME
     puffs - Pass-to-Userspace Framework File System development interface

LIBRARY
     puffs Convenience Library (libpuffs, -lpuffs)

puffsのサンプルを試してみる

まずはpuffsの使い方や動作を把握するため、サンプルを探してみます。
カーネルソースツリーの /usr/src/share/examples/puffs にサンプルがあるようです。

$ sudo bash
# cd /usr/src/share/examples/puffs
# ls -F
CVS/      Makefile  dtfs/     icfs/     pgfs/     pnullfs/  rot13fs/

pnullfsサンプルを試してみる

pnullfsディレクトリにある pnullfs.c を見ると、"puffs nullfs example"というコメントがあります。どうやらpuffsを利用した何もしないファイルシステムのサンプルのようです。
これを動かしてみれば、puffsの使い方を把握できそうです。
実際に試してみると分かるのですが、ここで言う「何もしない」はマウント先で書き込まれたデータはpuffs側で加工することなく、そのままファイルに書き出すという意味でのpnullfsになっています。
(てっきり /dev/null 的な意味での pnullfs だと勘違いしていました...)

# cd pnullfs
# cat pnullfs.c
 ...
/*
 * pnullfs: puffs nullfs example
 */
 ...

さっそくビルドしてみます。 pnullfs という実行ファイルが生成されました。

# make
# ls -F
.gdbinit   CVS/       Makefile   pnullfs*   pnullfs.c  pnullfs.o

nullpathmountpath を指定して起動すれば良さそうです。

# ./pnullfs
pnullfs: usage: pnullfs [-s] [-o mntopts] nullpath mountpath

適当なディレクトリを作成し、 nullpath に指定してみます。pnullfs コマンドを実行すると、 /mnt にファイルタイプが"puffs|pnullfs|としてマウントされています。

# mkdir _null_dir
# ./pnullfs ./_null_dir /mnt
#
# mount
...
./_null_dir on /mnt type puffs|pnullfs

マウント先に書き込んだファイルが、そのまま nullpath で指定した場所に書き込まれるという動作になっています。
これで大まかな使い方のイメージが把握できました。

# echo 'hello,world.' > /mnt/hello.txt
# cat ./_null_dir/hello.txt
hello,world.

rot13fsを試してみる

rot13fs というサンプルもあるので、こちらも試してみます。シーザー暗号のひとつであるROT13の名前が付いているので、おそらくマウント先に書き込まれたデータを暗号化してファイルに書き込むというサンプルのように思えます。

さっそくビルドして動かしてみます。

# make
# ls -F
.gdbinit   CVS/       Makefile   _tmp/      rot13fs*   rot13fs.c  rot13fs.o

コマンドの実行時引数は先ほどの pnullfs と同じですね。

# ./rot13fs
rot13fs: usage: rot13fs [-s] [-o mntopts] rot13path mountpath
#
# mkdir _rot13_dir
# ./rot13fs ./_rot13_dir /mnt
# mount
...
./_rot13_dir on /mnt type puffs|rot13
# echo 'hello,world.' > /mnt/hello.txt
# ls /mnt
hello.txt
# ls _rot13_dir
uryyb.gkg
# cat ./_rot13_dir/uryyb.gkg
uryyb,jbeyq.

ちょっとだけサンプルソースを眺めてみる

サンプルからpuffsの使い方と振る舞いがざっくり把握できました。サンプルソースの pnullfs.c から実装の大まかな流れも見てみましょう。

puffsの初期化は PUFFSOF_INIT()puffs_init() で行うようです。

/usr/src/share/examples/puffs/pnullfs/pnullfs.c:
     48 int
     49 main(int argc, char *argv[])
     50 {
     51         struct puffs_usermount *pu;
     52         struct puffs_ops *pops;
     53         struct puffs_pathobj *po_root;
     54         struct puffs_node *pn_root;
     ...
     96         PUFFSOP_INIT(pops);
     97         puffs_null_setops(pops);
     98
     99         if ((pu = puffs_init(pops, argv[0], "pnullfs", NULL, pflags)) == NULL)
    100                 err(1, "init");

PUFFSOF_INIT() の中ではpuffsに必要なメモリの確保を行っています。

/usr/src/lib/libpuffs/puffs.h:
428 #define PUFFSOP_INIT(ops)                                               \
429     ops = malloc(sizeof(struct puffs_ops));                             \
430     memset(ops, 0, sizeof(struct puffs_ops))

puffs_init() で取得した struct puffs_usermount を指定して、 puffs_pn_new() を呼び出しだします。
puffsの / を設定しているようです。

    102         pn_root = puffs_pn_new(pu, NULL);
    103         if (pn_root == NULL)
    104                 err(1, "puffs_pn_new");
    105         puffs_setroot(pu, pn_root);
    106         puffs_setfhsize(pu, 0, PUFFS_FHFLAG_PASSTHROUGH);
    107
    108         po_root = puffs_getrootpathobj(pu);
    109         if (po_root == NULL)
    110                 err(1, "getrootpathobj");
    111         po_root->po_path = argv[0];
    112         po_root->po_len = strlen(argv[0]);
    113         puffs_stat2vattr(&pn_root->pn_va, &sb);

最後に puffs_mount() でpuffs的なマウント処理を行うという流れになっています。

    119         if (puffs_mount(pu, argv[1], mntflags, pn_root) == -1)
    120                 err(1, "puffs_mount");
    121         if (puffs_mainloop(pu) == -1)
    122                 err(1, "mainloop");
    123
    124         return 0;

まとめ

NetBSDのpuffsのサンプルを試してみました。OS的な設定等は不要で、 libpuffs を利用したユーザランドのアプリケーションプログラムという位置付けで考えると良さそうです。
明日の記事では、このpuffsを使ってサンプルアプリを作る手順を紹介できればと思います。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?