hiroの長い冒険日記

主にコンピュータ周辺の興味を持った内容を綴ります

systemd ... SysVinit との違いと動作について その3

当日記ではアフィリエイト広告を利用しています

前回は、systemctl を使って unit ファイルの名前や有効/無効状態、12種類の unit の名称と役割、unit の依存関係と control group についてザックリと調べてみた。

hiro20180901.hatenablog.com

/etc/systemd や /lib/systemd、/run/systemd 以下に設定ファイルがない unit もあり、どういう状態になっているか試行錯誤して確認を進めてみた。今回は unit の type 毎にもう少し細かく調べてみた。

automount、mount

これらは、仮想含む filesystem を mount する unit である。

$ systemctl list-unit-files *mount
UNIT FILE                         STATE    
proc-sys-fs-binfmt_misc.automount static   
-.mount                           generated
dev-hugepages.mount               static   
dev-mqueue.mount                  static   
media-cdrom0.mount                generated
proc-sys-fs-binfmt_misc.mount     static   
sys-fs-fuse-connections.mount     static   
sys-kernel-config.mount           static   
sys-kernel-debug.mount            static   

9 unit files listed.

  • systemd では、path 区切り文字が '/' から '-' に置き換えられている。なので、UNIT FILE の proc-sys-fs-binfmt_misc は /proc/sys/fs/binfmt_misc に対応する。
  • STATE が generated の行は動的生成された unit、static の行は設定ファイルが存在する unit。
  • 動的生成された unit は、-.mount と media-cdrom0.mount の2つ。/etc/fstab から動的生成されている。
    • -.mount は '/' (root fs) を mount する unit。今の環境では '/' (root fs) のみだが、/usr や /var や /home を分けている場合には複数存在しているはず。
    • media-cdrom0.mount は /dev/sr0 を mount する unit。DVD drive を1台接続しているので、install の際に /etc/fstab に entry が作成されていた。

binfmt_misc

いろんな (お好みの) バイナリフォーマットのカーネルサポート v1.1
===============================================================

このカーネルでは、シェルからその名前をタイプするだけで、ほとんどのプログラムを (制限は下を参照) 起動することができます。この中には、例えばコンパイル済みの Java(TM)、PythonEmacs プログラムが含まれます。

これをできるようにするには、どのバイナリをどのインタプリタで起動するかを binfmt_misc に教えてやらなければなりません。binfmt_misc は、指定された
マジックバイトシーケンスとファイルの先頭の何バイトかを (特定のビットはマスクして) 比較し、バイナリタイプを判定します。binfmt_misc は「.com」や
「.exe」といったファイル名の拡張子も認識することができます。

  • script は、最初の行に '#!/bin/sh' とか指定すると、どの script 言語で実行すれば良いか分かる。
  • それに対して binary は、別環境のものをそのまま実行することは出来ない。(windows の exe は linux では実行できない)
  • binfmt_misc は、間に qemu 等の別環境を実行する為の binary を登録しておく事で、Host 環境と同じように別環境の binary を実行することができる。現在の環境では pythonqemu が登録されていた。

$ ls /proc/sys/fs/binfmt_misc
python2.7     qemu-armeb       qemu-mips64    qemu-ppc64abi32  qemu-sparc
python3.5     qemu-cris        qemu-mips64el  qemu-ppc64le     qemu-sparc32plus
qemu-aarch64  qemu-m68k        qemu-mipsel    qemu-s390x       qemu-sparc64
qemu-alpha    qemu-microblaze  qemu-ppc       qemu-sh4         register
qemu-arm      qemu-mips        qemu-ppc64     qemu-sh4eb       status

$ ls /var/lib/binfmts
python2.7     qemu-armeb       qemu-mips64    qemu-ppc64abi32  qemu-sparc
python3.5     qemu-cris        qemu-mips64el  qemu-ppc64le     qemu-sparc32plus
qemu-aarch64  qemu-m68k        qemu-mipsel    qemu-s390x       qemu-sparc64
qemu-alpha    qemu-microblaze  qemu-ppc       qemu-sh4
qemu-arm      qemu-mips        qemu-ppc64     qemu-sh4eb

$ dpkg -S /var/lib/binfmts
binfmt-support: /var/lib/binfmts

$ ls /usr/share/binfmts
python2.7  python3.5

$ dpkg -S /usr/share/binfmts
binfmt-support, python3.5-minimal, python2.7-minimal: /usr/share/binfmts

  • qemu の設定ファイルは見つからないので、apt で install される際に update-binfmts で登録されているのだろう。python は /usr/share/binfmts 以下にあった。
  • qemu full emulation で試してみた後で、user mode emulation もそのうち使ってみよう。

HugePages

Debian Wiki:

When a process uses some memory, the CPU is marking the RAM as used by that process. For efficiency, the CPU allocate RAM by chunks of 4K bytes (it's the default value on many platforms). Those chunks are named pages. Those pages can be swapped to disk, etc.

Since the process address space are virtual, the CPU and the operating system have to remember which page belong to which process, and where it is stored. Obviously, the more pages you have, the more time it takes to find where the memory is mapped. When a process uses 1GB of memory, that's 262144 entries to look up (1GB / 4K). If one Page Table Entry consume 8bytes, that's 2MB (262144 * 8) to look-up.

Most current CPU architectures support bigger pages (so the CPU/OS have less entries to look-up), those are named Huge pages (on Linux), Super Pages (on BSD) or Large Pages (on Windows), but it all the same thing.

  • 最近の PC では memory size が大きいので、memory 管理 table が 4kiB pages だと table が大きくなる。Page size を amd64 なら 2MiB か 1GiB pages (CPU依存)にする事により効率を上げる。他の OS でも同様の考えを導入している。

$ grep flags /proc/cpuinfo | head -1 | perl -pe 's/ /\n/g' | grep -e 'pse$' -e 'pdpe1gb$'
pse
$ grep Huge /proc/meminfo
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB

  • pse なので 2MiB
  • memory を大量に使用する database とかで使われている模様。
  • 他には qemu でも使われているようだが、設定が必要で、起動しただけでは使われなかった。

https://tech.hylogics.com/entry/qemu_memorytuningtech.hylogics.com

mqueue

$ diff -u mqread.c.orig mqread.c
--- mqread.c.orig	2019-03-17 22:43:59.444848284 +0900
+++ mqread.c	2019-03-17 22:32:00.550998379 +0900
@@ -22,15 +22,21 @@
 
         memset(&attr, 0, sizeof(attr));
 
+	attr.mq_flags = 0;
+	attr.mq_maxmsg = 10;
+	attr.mq_msgsize = 1024;
+	attr.mq_curmsgs = 0;
+
         mq_unlink("/mq1");
         mq_unlink("/mq2");
+
         if ((fd1 = mq_open("/mq1", O_RDONLY|O_NONBLOCK|O_CREAT|O_EXCL,
-                         S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
+                         S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, &attr)) == -1) {
                 perror("open /mq1");
                 exit(-1);
         }
         if ((fd2 = mq_open("/mq2", O_WRONLY|O_NONBLOCK|O_CREAT|O_EXCL,
-                         S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
+                         S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, &attr)) == -1) {
                 perror("open /mq2");
                 exit(-1);
         }

    • compile & run。-lrt が必要。

$ gcc -lrt -g -o mqread mqread.c
$ gcc -lrt -g -o mqwrite mqwrite.c 
$ ./mqread   // 別端末で実行しておく
$ time ./mqwrite 1000000
write loop= 500000

real	0m6.822s
user	0m0.716s
sys	0m3.436s

Filesystem in Userspace (FUSE)

ja.m.wikipedia.org

Filesystem in Userspace (FUSE) はUnix系コンピュータオペレーティングシステム用のソフトウェアインタフェースである。権限を持たないユーザがカーネルコードを修正することなく独自のファイルシステムを作成できる機能を提供する。これは、ファイルシステムのコードをユーザ空間で実行することでなされるもので、その際FUSEモジュールは実際のカーネルインタフェースへの「橋渡し」しか提供しない。

ja.wikipedia.org
/sys/fs/fuse/connections 以下に数字の directory が存在するが、gvfsd で使用されている。

$ systemctl list-units *mount
UNIT                              LOAD   ACTIVE SUB     DESCRIPTION                                                  
proc-sys-fs-binfmt_misc.automount loaded active running Arbitrary Executable File Formats File System Automount Point
-.mount                           loaded active mounted Root Mount                                                   
dev-hugepages.mount               loaded active mounted Huge Pages File System                                       
dev-mqueue.mount                  loaded active mounted POSIX Message Queue File System                              
proc-sys-fs-binfmt_misc.mount     loaded active mounted Arbitrary Executable File Formats File System                
run-user-1000-gvfs.mount          loaded active mounted /run/user/1000/gvfs                                          
run-user-1000.mount               loaded active mounted /run/user/1000                                               
run-user-110-gvfs.mount           loaded active mounted /run/user/110/gvfs                                           
run-user-110.mount                loaded active mounted /run/user/110                                                
sys-fs-fuse-connections.mount     loaded active mounted FUSE Control File System                                     
sys-kernel-debug.mount            loaded active mounted Debug File System                                            

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

11 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

unit file は存在していないが、動的生成されて run-user-*-gvfs.mount が実行されている模様。

Configfs

/sys/kernel/config.mount は Configfs。これは、unit は存在しているが有効にはなっていない。

$ systemctl list-unit-files *config*mount
UNIT FILE               STATE 
sys-kernel-config.mount static

1 unit files listed.
$ systemctl list-units *config*mount
0 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

ただ、Wikipedia を見ても用途が良く分からなかった。
en.wikipedia.org
こちらの sample を見ると、configfs + α で kernel や module と直接やりとり出来る virtual filesystem である事が分かる。
wiki.bit-hive.com
次の page を見て、組み込み用途で便利な機能だという事が分かった位。
Zynq + Yocto で USB デバイスをつくってみた - Qiita
電気回路/zynq/Device Tree Overlay - 武内@筑波大
FPGA+SoC+LinuxでDevice Tree Overlayを試してみた - Qiita
後でもう少し調べてみる。

Debugfs

/sys/kernel/debug.mount は、Debugfs。
en.wikipedia.org

debugfs is a simple-to-use RAM-based file system specially designed for debugging purposes.

debug 用途の virtual filesystem。module ではなく、kernel 組み込みになっている。

$ cat /boot/config-4.9.0-8-amd64 | grep CONFIG_DEBUG_FS
CONFIG_DEBUG_FS=y

日本語では、こちらの page がわかりやすい。
https://qiita.com/satoru_takeuchi/items/d2760c32a88376e1bc4aqiita.com
なんとなく Configfs と被る部分がありそう。実際に上の page では情報の取得・設定に使用しているし。単純に、使いやすい方を使うやり方なのだろうか。それとも、Debugfs が主流で Configfs は傍流、だから標準では読み込まれないのだろうか。

結果

automount、mount の unit について一通り調べてみた。

どちらかというと、kernel の機能を調べているような感じだが、これを通して linux kernel についての理解が深められたらと思う。