TenForward

技術ブログ。はてなダイアリーから移転しました

xkbのファイルを書き換えてキーマップを調整する

Plamo 7.0 環境で、USB 切替器を使って USB キーボードを切り替えると、切り替え後に fcitx のオンオフができなくなってハマっていました。つまり USB キーボードを抜き差ししたあとに fcitx のオンオフができなくなっていました。

fcitx のオンオフはこのように設定していました。HHKB を使ってます。

  • Command キー(スペースの横)を "Super_L" に割り当てている
    • .Xmodmap ファイルに書いて、fcitx の "X Keyboard Integration" Addon で、その .Xmodmap を読み込ませていた
    • xmodmap -e "keycode 102 = Super_L" みたいな
  • オンオフキーを Super+Space に割り当てていた

よくよく調べると xmodmap で行った変更設定が切り替え後に消えていてデフォルトの Muhenkan に戻っていることがわかりました。

最初は udev イベントでキーボードさされたのを検知して xmodmap を実行しようかと思ったら、現在開いているデスクトップ環境と実行する環境のセッションも違うし、DISPLAY 環境変数与えたりしてもイマイチうまくいかないので、キーマップ書き換えてしまえ、ということでやりました。

まず、現在使われいてるキーボードマップを調べます。

$ setxkbmap -print
xkb_keymap {
    xkb_keycodes  { include "evdev+aliases(qwerty)"  };
    xkb_types     { include "complete"   };
    xkb_compat    { include "complete"   };
    xkb_symbols   { include "pc+us+inet(evdev)"  };
    xkb_geometry  { include "pc(pc105)"  };
};

keycode は evdevalias を使っているということで、まず /usr/share/X11/xkb/keycode/evdev を見ると、keycode 102<MUHE> であることがわかりました。

        <MUHE> = 102;   // Muhenkan

これが定義されているところを xkb_symbolspc+us+inet(evdev) の方で調べると、

$ grep MUHE pc us inet
inet:    key <MUHE>   {      [ Muhenkan               ]       };

と出ますので、ここを強引に、

$ grep MUHE pc us inet
inet:    //key <MUHE>   {      [ Muhenkan              ]       };
inet:    key <MUHE>   {      [ Super_L               ]       };

のように書き換えて、.Xmodmap の読み込みを止めて再起動すると、無事、xmodmap なしで keycode 102Super_L になりました。

参考

Linux 4.14 で導入された Namespaced file capabilities(おまけ)

4.14 で設定した Namespaced file capability を 4.13 以前のカーネルに戻したら

まあ、こんな物好きなことをする人はいないでしょうが、確認してみました。

tenforward.hatenablog.com

の環境のまま、ホスト環境のカーネルを 4.13 に戻して、コンテナを起動し、コンテナ内で一般ユーザーとなって pingping2 コマンドを両方とも実行しました。

$ ./ping www.google.com
-su: ./ping: Numerical result out of range
$ ./ping2 www.google.com
-su: ./ping2: Numerical result out of range

構造体が変わっていたので読み取れないようですね。

Namespaced file capability に設定された id で User Namespace 外から実行してみる

tenforward.hatenablog.com

で、User Namespace 内の root の id が 200000 に設定されていたので、コンテナ内で設定した File capability も 200000 という情報が記録されていました。そこで User Namespace 内の root と同じ id を持つホスト上のユーザーから、file capability を設定したコマンドを実行してみました。

今回は unshare コマンドを使います。

  • ホスト上の uid: 1000 のユーザーを User namespace 内の rootマッピング

ちょっと色々試行錯誤しながら試したので変なことしてるようだったら教えてください。

ホスト上のユーザーは 1000:100 です。ここで unshare します。

$ id -u
1000
$ id -g
100
$ unshare --user --setgroups allow
nobody@borg:~$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)

マッピングがまだできていないので、この時点では User namespace 内では nobody ユーザーになります。

ここで別のシェルからホスト上の rootマッピングを投入します。(Plamo なので gid がちょっと普通と異なるかな)

# echo "0 1000 65534" > /proc/22471/uid_map 
# echo "0 100 65534" > /proc/22471/gid_map

ここで元の User namespace 内のシェルに戻ると、無事 root になりました。

$ id
uid=0(root) gid=0(root) groups=0(root),65534(nogroup)

これで他の namespace が作れますので、Network namespace を作ります(これを作らないと file capability 設定しても ping 実行できなかったので)。

$ unshare --net
# ip link set lo up
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever

ここで一般ユーザーになります。ping コマンドをコピーして実行してみます。当然失敗しますね。

$ su karma
$ id -u
1000
$ cd /tmp
$ cp /bin/ping .
$ ls -l ping
-rwxr-xr-x 1 karma users 56,920  32401:02 ping*
$ ./ping 127.0.0.1
ping: socket: Operation not permitted
$ exit

ここで User namespace 内の root で file capability を設定します。

# setcap cap_net_raw+ep /tmp/ping 
# getcap -n /tmp/ping 
/tmp/ping = cap_net_raw+ep [rootid=1000]

id:1000 で Namespaced file capability が設定されています。ここで再度一般ユーザーになります。

# su - karma
$ /tmp/ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.012 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.012/0.012/0.012/0.000 ms

User namespace 内で実行できましたね。ここでおもむろに namespace 外のシェルから、id:1000 のユーザーでこの ping を実行してみます。

$ id -u
1000
$ /tmp/ping 127.0.0.1
ping: socket: Operation not permitted

実行はできませんね。

Linux 4.14 で導入された Namespaced file capabilities(2)

User Namespace 外から Namespaced file capability を設定する

前回、

tenforward.hatenablog.com

では、非特権ユーザで起動したコンテナ内の root ユーザーで File capability を設定しました。

ここで、自作コンテナ派の皆様が気になるのは、この capability をコンテナ外から設定するのはどうしたらいいのだろう? というところではないかと思います。コンテナランタイム側からコンテナ内の capability を設定する必要があるかもしれません。

もちろん、これも簡単にできます。先に getcap コマンドに -n オプションを付与しましたが、これと同じオプションが setcap にも存在します。

setcap -n 200000 cap_net_raw+ep ./ping

と言ったように、User Namespace 内の root の uid を指定して capability を指定します。

まず、コンテナ内からアクセスできるように、ホスト環境上で ping コマンドをコンテナの rootfs 内にコピーします。LXC の非特権コンテナは次のようなディレクトリ以下に rootfs が置かれますので、ここにコピーします。ping2 という名前でコピーしました。

$ sudo cp /bin/ping ~/.local/share/lxc/c3/rootfs/home/karma/ping2

次にコピーした ping2 バイナリに対して setcap します。

$ sudo setcap -n 200000 cap_net_raw+ep ~/.local/share/lxc/c3/rootfs/home/karma/ping2 (-nオプションでroot uidを指定)
$ sudo getcap -n ~/.local/share/lxc/c3/rootfs/home/karma/ping2
/home/karma/.local/share/lxc/c3/rootfs/home/karma/ping2 = cap_net_raw+ep [rootid=200000]
$ sudo getfattr -d -m "security" ~/.local/share/lxc/c3/rootfs/home/karma/ping2
getfattr: Removing leading '/' from absolute path names
# file: home/karma/.local/share/lxc/c3/rootfs/home/karma/ping2
security.capability=0sAQAAAwAgAAAAAAAAAAAAAAAAAABADQMA

設定されましたね。

再度コンテナ内に入ってみましょう。

$ lxc-attach c3
# su - karma
$ ls -l ./ping*
-rwxr-xr-x 1 karma  users   56,920  2月 21日  16:30 ./ping*
-rwxr-xr-x 1 nobody nogroup 56,920  2月 21日  16:39 ./ping2*

ホスト側の権限でコピーしていますので、ファイルの所有権が nobody:nogroup になっていますね。

$ sudo getcap -n ./ping2
./ping2 = cap_net_raw+ep [rootid=200000]

capability を確認すると、設定されているのがわかります。では、実行してみましょう。

$ ./ping2 -c 1 www.google.com
PING www.google.com (216.58.196.228) 56(84) bytes of data.
64 bytes from kix06s01-in-f228.1e100.net (216.58.196.228): icmp_seq=1 ttl=49 time=1.22 ms

--- www.google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.226/1.226/1.226/0.000 ms

実行できました。

Namespace 外からでも問題なく設定できますね。

kernel のデータ構造の変更

ここからは素人なので間違ってる可能性あります。詳しくはご自分でどうぞ。

4.13 までは include/uapi/linux/capability.h を見ると、以下のような構造体がありました。

#define VFS_CAP_FLAGS_EFFECTIVE 0x000001

  : (snip)

#define VFS_CAP_REVISION_2 0x02000000

struct vfs_cap_data {
    __le32 magic_etc;            /* Little endian */
    struct {
        __le32 permitted;    /* Little endian */
        __le32 inheritable;  /* Little endian */
    } data[VFS_CAP_U32];
};

https://elixir.bootlin.com/linux/v4.13/source/include/uapi/linux/capability.h#L53 付近)

この permittedinheritable に必要な capability を設定するわけですね。effective セットは file capability の場合はオンオフだったと思いますので、magic_etc に設定します。

effective セットを設定する場合、これ(4.13)までは、

struct vfs_cap_data xattr;

xattr.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;

のように設定したようです。

4.14 以降で Namespaced file capability が導入されたあとは、

#define VFS_CAP_REVISION_2  0x02000000
#define VFS_CAP_U32_2           2
#define XATTR_CAPS_SZ_2         (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))

#define VFS_CAP_REVISION_3 0x03000000
#define VFS_CAP_U32_3           2
#define XATTR_CAPS_SZ_3         (sizeof(__le32)*(2 + 2*VFS_CAP_U32_3))

#define XATTR_CAPS_SZ           XATTR_CAPS_SZ_3
#define VFS_CAP_U32             VFS_CAP_U32_3
#define VFS_CAP_REVISION   VFS_CAP_REVISION_3

struct vfs_cap_data {
    __le32 magic_etc;            /* Little endian */
    struct {
        __le32 permitted;    /* Little endian */
        __le32 inheritable;  /* Little endian */
    } data[VFS_CAP_U32];
};

/*
 * same as vfs_cap_data but with a rootid at the end
 */
struct vfs_ns_cap_data {
    __le32 magic_etc;
    struct {
        __le32 permitted;    /* Little endian */
        __le32 inheritable;  /* Little endian */
    } data[VFS_CAP_U32];
    __le32 rootid;
};

https://elixir.bootlin.com/linux/v4.14/source/include/uapi/linux/capability.h#L64 付近)

というように struct vfs_ns_cap_data という、vfs_cap_data の最後に rootid が追加された構造体が追加されています。そう、これが setcapgetcap で追加された -n オプションの正体ですね(たぶん)。

それと同時に、従来の Namespaced されていない file capability なのか、Namespaced な file capability なのかは、magic_etc に指定する file capability の Revision で指定します。

先のコードと対応する例だと、

struct vfs_ns_cap_data xattr;

xattr.magic_etc = VFS_CAP_REVISION_3 | VFS_CAP_FLAGS_EFFECTIVE;

となるわけですね(たぶん)。

Linux 4.14 で導入された Namespaced file capabilities(1)

Hosting Casual Talks #5

本題に入る前に、このブログエントリのネタを発表してきた勉強会の感想を。

ホスティング業界に関わるエンジニアが カジュアルに 情報交換をするという、全員発表型の勉強会 "Hosting Casual Talks #5" に参加してきました。飲みながら技術について情報交換できる カジュアルな 勉強会ではありますが、内容が全く カジュアルじゃない!!

connpass.com

ひとりあたり10 or 15分の LT サイズの時間割り当てなのですが、皆さんちゃんと解決したい問題があり、仮説を立て、検証して、考察すると言ったストーリー性のあるスライドになっていたり、問題を解決するためにコード書きました、こういうの作りましたというような、とても LT サイズに収まるものではなく、全員持ち時間はどこへやら、ガッツリと 6 時間、ガチな内容がひたすら続くなかなか内容の濃い勉強会になりました。

で、そこで真面目に 10 分サイズで軽めに作ったネタがコレでした。一発芸でオチもなく、Linux カーネルの機能を紹介してきました。次々とすごいガチな発表がされるので、こんなネタで発表するのが徐々に辛くなって…😅


4.14 kernel はいくつかコンテナ関連の機能が追加されているのですが、その中のひとつである "Namespaced file capabilities" の紹介です。

"Namespaced file capabilities" 機能についてはこのあたりが詳しいです。

コミットはこちら

File Capability

File Capability については色々と参考になる情報がありますので、そちらをどうぞ。

ここでは File Capability の説明あるあるの ping コマンドに cap_net_raw を与えて色々試してみます。

File Capability お試し

まずは普通に。ここでは Linux 4.13.16 上の Plamo Linux 7.0 で試しています。libcap は 2.26。

通常は setuid されている ping をコピーすると setuid は落とされて ping は一般ユーザーでは実行できません。

$ id -u
1000 (一般ユーザーです)
$ ls -l /bin/ping
-rwsr-sr-x 1 root root 56,920  2月 12日  20:31 /bin/ping* (setuid されています)
$ cp /bin/ping . (コピーする)
$ ls -l ./ping   (setuid は落ちています)
-rwxr-xr-x 1 karma users 56,920  3月 23日  23:35 ./ping*
$ ./ping www.google.com (setuid されていないので権限がなく実行できません)
ping: socket: Operation not permitted

ここで file capability を設定すると一般ユーザーでも限定的な権限が与えられ、実行できるようになります。

$ sudo setcap cap_net_raw+ep ./ping (cap_net_raw を与えます)
$ sudo getcap -n ./ping (cap_net_raw が設定されています)
./ping = cap_net_raw+ep
$ sudo getfattr -d -m "security" ./ping (拡張属性領域の確認。File Capability はここに保存されています)
# file: ping
security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA=

これで一般ユーザーでも ping が実行できます。

$ ./ping -c 1 www.google.com
PING www.google.com(kix05s01-in-x04.1e100.net (2404:6800:400a:808::2004)) 56 data bytes
64 bytes from kix05s01-in-x04.1e100.net (2404:6800:400a:808::2004): icmp_seq=1 ttl=51 time=7.08 ms

--- www.google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 7.087/7.087/7.087/0.000 ms

コンテナ内で File Capability を設定してみる(4.13.16 kernel)

これと同じ操作を一般ユーザー権限で実行しているコンテナ内で行ってみます。次のように root が uid: 200000 のユーザーにマッピングされているコンテナがあります。

karma@plamo71:~$ lxc-info c3
Name:           c3
State:          RUNNING
PID:            20569
IP:             10.0.3.122
CPU use:        0.17 seconds
BlkIO use:      12.45 MiB
Memory use:     16.59 MiB
KMem use:       1.89 MiB
Link:           vethBXNXMY
 TX bytes:      1.55 KiB
 RX bytes:      9.86 KiB
 Total bytes:   11.41 KiB
karma@plamo71:~$ sudo cat /proc/20569/{u,g}id_map
         0     200000      65536
         0     200000      65536
karma@plamo71:~$ ps auxf 20569
  : (snip)
200000   20569  0.0  0.0   4500  1600 pts/1    Ss+  18:38   0:00  \_ init [3]
200000   20772  0.0  0.1 172404  2488 ?        Ssl  18:38   0:00      \_ /sbin/rsyslogd -i /run/rsyslogd.pid
  : (snip)

このコンテナ内に入り、一般ユーザー権限で ping をコピーしてみます。当然実行はできません。

$ lxc-attach c3
# su - karma
$ id
uid=1000(karma) gid=100(users) groups=100(users),10(wheel),26(audio),28(dialout),29(video),32(cdrom),36(kvm),38(pulse),39(pulse-access),44(mlocate),47(libvirt),50(input)
$ uname -a
Linux c3 4.13.16-plamo64 #1 SMP PREEMPT Wed Dec 5 15:00:28 JST 2018 x86_64 GNU/Linux
$ cp /bin/ping .
$ ls -l ./ping 
-rwxr-xr-x 1 karma users 56,920  2月 20日  19:02 ./ping*
$ ./ping -c 1 www.google.com
ping: socket: Operation not permitted

ここで capability を設定してみましょう。

$ sudo setcap cap_net_raw+ep ./ping 
Failed to set capabilities on file `./ping' (Operation not permitted)
usage: setcap [-q] [-v] [-n <rootid>] (-r|-|<caps>) <filename> [ ... (-r|-|<capsN>) <filenameN> ]

 Note <filename> must be a regular (non-symlink) file.

エラーで setcap コマンドが実行できません。

4.14 以降のカーネルの コンテナ内で File Capability を設定してみる(4.20.10 kernel)

勉強会のときは 5.0.0 カーネルで試したデモを披露しましたが、ここでは 4.20.10 で試した結果です。

ちなみに 4.14 より前のカーネルを試そうと思って Ubuntu 16.04 の 4.4 kernel なら試せる!と思ったりすると、普通にこの機能はバックポートされていますのでご注意ください。つまりUbuntu 16.04 の 4.4 kernel でもこの機能を試せます。(←ハマった人)(2019-03-24 追記)

$ uname -a
Linux plamo71 4.20.10-plamo64 #5 SMP PREEMPT Mon Feb 18 16:16:45 JST 2019 x86_64 GNU/Linux
$ lxc-start c3
$ lxc-ls -f c3
NAME STATE   AUTOSTART GROUPS IPV4       IPV6 UNPRIVILEGED 
c3   RUNNING 0         -      10.0.3.122 -    true         
$ lxc-info c3
Name:           c3
State:          RUNNING
PID:            4817
IP:             10.0.3.122
CPU use:        0.17 seconds
BlkIO use:      12.55 MiB
Memory use:     16.97 MiB
KMem use:       2.16 MiB
Link:           vethH3LNCN
 TX bytes:      1.28 KiB
 RX bytes:      9.31 KiB
 Total bytes:   10.59 KiB
$ sudo cat /proc/4817/{u,g}id_map
         0     200000      65536
         0     200000      65536
$ ps auxf | less
  : (snip)
200000    4817  0.0  0.0   4500  1632 pts/1    Ss+  16:24   0:00  \_ init [3]
200000    5019  0.0  0.1 172404  2472 ?        Ssl  16:24   0:00      \_ /sbin/rsyslogd -i /run/rsyslogd.pid
  : (snip)

カーネルのバージョンが違う以外は同じコンテナを実行しています。

$ lxc-attach c3
# su - karma
$ id
uid=1000(karma) gid=100(users) groups=100(users),10(wheel),26(audio),28(dialout),29(video),32(cdrom),36(kvm),38(pulse),39(pulse-access),44(mlocate),47(libvirt),50(input)
$ uname -a
Linux c3 4.20.10-plamo64 #5 SMP PREEMPT Mon Feb 18 16:16:45 JST 2019 x86_64 GNU/Linux
$ cp /bin/ping .
$ ls -l ./ping
-rwxr-xr-x 1 karma users 56,920  2月 21日  16:30 ./ping*
$ ./ping www.google.com
ping: socket: Operation not permitted

当然ですが、ここまでは 4.13 カーネルのときと同じです。ここで 4.13 では失敗した setcap を試してみましょう。

$ sudo setcap cap_net_raw+ep ./ping
$ sudo getcap -n ./ping 
./ping = cap_net_raw+ep [rootid=200000]
$ sudo getfattr -d -m "security" ./ping 
# file: ping
security.capability=0sAQAAAwAgAAAAAAAAAAAAAAAAAABADQMA

4.13 では失敗した setcap が成功しています。ここで getcap-n を与えている所がミソで、これは結果のうち [rootid=200000] を表示させるために使っています。この 200000 は、コンテナの rootマッピングされている uid ですね。

つまり user namespace 内で setcap を実行すると、user namespace 内の root の uid の情報が設定されます。そして、その user namespace 内でのみ、その File capability が有効になり、権限が与えられた状態でコマンドが実行できます。

$ ./ping -c 1 www.google.com
PING www.google.com (216.58.197.4) 56(84) bytes of data.
64 bytes from kix06s02-in-f4.1e100.net (216.58.197.4): icmp_seq=1 ttl=48 time=1.30 ms

--- www.google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.303/1.303/1.303/0.000 ms

問題なく実行できていますね。

上記のファイルをコンテナの外で確認してみましょう。

$ id
uid=1000(karma) gid=100(users) groups=100(users),10(wheel),26(audio),28(dialout),29(video),32(cdrom),36(kvm),38(pulse),39(pulse-access),44(mlocate),47(libvirt),50(input)
$ sudo getcap -n ~/.local/share/lxc/c3/rootfs/home/karma/ping
/home/karma/.local/share/lxc/c3/rootfs/home/karma/ping = cap_net_raw+ep [rootid=200000]
$ ~/.local/share/lxc/c3/rootfs/home/karma/ping -c 1 www.google.com
ping: socket: Operation not permitted

コンテナ外で確認しても getcap の情報は変わりません。そしてコンテナ(user namespace)外から実行すると、設定したはずの capability は有効ではなく、ping は実行できません。

(つづく)

Linux 4.14 で導入された cpuset の cgroup v2 mode

(2019-02-23 少し追記しています)

4.14 kernel から cgroup の cpuset コントローラーに cpuset_v2_mode というオプションが使えるようになりました。

しばらく見ないうちに cpuset コントローラーをマウントするとファイルがたくさん増えていますが、このオプションを設定すると、従来からある cpuset.{cpus,mems} ファイルの動きが変わるようです。そしていつの間にか増えている cpuset.effective_{cpus,mems} ファイルと合わせて使って cpuset の制限を行うようです。

このオプションを設定したときの動きが、cgroup v2 の cpuset の動きになるようです(v2 の cpuset は現時点ではまだマージされていません)。

現在使える cpu や memory が effective で表示されており、それと cpuset.{cpus,mems} のマスクを取って、使える cpu, memory を導き出すようですね。

従来の cpuset(v1 mode)

# mount -t tmpfs cgroup /sys/fs/cgroup/
# mkdir /sys/fs/cgroup/cpuset
# mount -t cgroup -o cpuset cgroup /sys/fs/cgroup/cpuset/
# cd /sys/fs/cgroup/cpuset/
# mkdir test01
# cd test01
# echo "0-1" > cpuset.cpus
# echo "0" > cpuset.mems

この状態で test01 cgroup 内のファイルは、

# for f in $(ls cpuset.*cpus); do echo -n "$f: "; cat $f; done
cpuset.cpus: 0-1
cpuset.effective_cpus: 0-1

となっています。ここでおもむろに cpu をひとつオフラインにします。cpu1 です。

# echo 0 > /sys/devices/system/cpu/cpu1/online

すると、

# for f in $(ls cpuset.*cpus); do echo -n "$f: "; cat $f; done
cpuset.cpus: 0
cpuset.effective_cpus: 0

cpuset.cpuscpuset.effective_cpus0 になります。

ここで再度 cpu1 をオンラインにすると、

echo 1 > /sys/devices/system/cpu/cpu1/online
# cat /sys/devices/system/cpu/cpu1/online
1
# for f in $(ls cpuset.*cpus); do echo -n "$f: "; cat $f; done
cpuset.cpus: 0
cpuset.effective_cpus: 0

特に変化はありません。

cpuset_v2_mode 付きマウント(v2 mode)

マウントオプションとして cpuset_v2_mode を与えます。

# mount -t cgroup -o cpuset,cpuset_v2_mode cgroup /sys/fs/cgroup/cpuset/
# cat /proc/self/mounts | grep cpuset
cgroup /sys/fs/cgroup/cpuset cgroup rw,relatime,cpuset,cpuset_v2_mode 0 0

この状態では、さきほどと特に変化はありません。

# for f in $(ls cpuset.*cpus); do echo -n "$f: "; cat $f; done
cpuset.cpus: 0-1
cpuset.effective_cpus: 0-1

ここで cpu1 をオフラインにします。

# echo 0 > /sys/devices/system/cpu/cpu1/online

すると、

# for f in $(ls cpuset.*cpus); do echo -n "$f: "; cat $f; done
cpuset.cpus: 0-1
cpuset.effective_cpus: 0

cpuset.cpus はそのままで実際の cpuset.effective_cpus のみ値が変わります。

ここまで来ると動きは予想できますね。再度 cpu1 をオンラインにしてみます。

# echo 1 > /sys/devices/system/cpu/cpu1/online
# for f in $(ls cpuset.*cpus); do echo -n "$f: "; cat $f; done
cpuset.cpus: 0-1
cpuset.effective_cpus: 0-1

cgroup作成後にCPUが増えた時(2019-02-23 追記)

cgroup作成後にcpuが減って、また戻った場合の動きは見ましたが、cgroup作成後にonline の cpu が増えた場合にどうなるのかが気になったので試してみました。

# echo 0 > /sys/devices/system/cpu/cpu2/online
# mkdir test01
# cd test01
# cat cpuset.cpus

# cat cpuset.effective_cpus 
0-1
# echo "0-1" > cpuset.cpus 
# echo "0" > cpuset.mems 
# for f in $(ls cpuset.*cpus); do echo -n "$f: "; cat $f; done
cpuset.cpus: 0-1
cpuset.effective_cpus: 0-1
# echo 1 > /sys/devices/system/cpu/cpu2/online
# for f in $(ls cpuset.*cpus); do echo -n "$f: "; cat $f; done
cpuset.cpus: 0-1
cpuset.effective_cpus: 0-1

上の例のように CPU をひとつ(cpu2) offline にしておいて、cgroup を作成後、cpu2 を online にしても cpuset.effective_cpus の値は変化しません。

まとめ

CPU/メモリーの online, offline を切り替えると:

  • v1 mode: cpuset.{cpus,mems}cpuset.effective_{cpus,mems} の値も変化するが、その後再度状態が変わってもそのまま
  • v2 mode: cpuset.{cpus,mems} の値は変化しない。cpuset.effective_{cpus,mems} の値は実際に合わせて変化する

ただし、cpuset.effective_* の復元は cgroup 作成時の値まで。

おまけ(2019-02-23 追記)

ちなみにこのオプションが使えるようになったコミットは次のものですが、これはオプションの追加と、そのオプションが指定されているときの条件分岐を変更しているだけですので、処理自体はこの前にあらかじめ実装されているようですね。