Plan 9とGo言語のブログ

主にPlan 9やGo言語の日々気づいたことを書きます。

I/O errorでユーザーにログインできなくなった

普段使っているユーザーでLinuxデスクトップにログインできなくなった。正しいパスワードを入力すると画面が1秒程度切り変わるけど、すぐディスプレイマネージャのログイン画面に戻ってしまう状態だった。

エラーの内容を調べる

rootではログインできたので、Ctl+Alt+F4などでディスプレイマネージャからコンソールに切り替えて、ログインできなくなった原因を調べる。問題のユーザーはsystemd-homedでLUKSイメージを使った環境だったので、activateしてみるとI/Oエラーが出力された。

# homectl activate lufia
[  152.810994] loop0: detected capacity change from 0 to 764010613
[  152.812280] blk_update_request: I/O error, dev loop0, sector 764010608 op 0x0:(READ) flags 0x80700 phys_seg 1 prio class 0
[  152.812446] blk_update_request: I/O error, dev loop0, sector 764010608 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
[  152.812554] Buffer I/O error on dev loop0, logical block 95501326, async page read
[  152.813969] blk_update_request: I/O error, dev loop0, sector 764010608 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
[  152.814210] Buffer I/O error on dev loop0, logical block 95501326, async page read
[  152.815182] blk_update_request: I/O error, dev loop0, sector 764010608 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
[  152.815344] Buffer I/O error on dev loop0, logical block 95501326, async page read
[  153.564587] device-mapper: table: 254:0: len=763977845 not aligned to h/w logical block size 4096 of loop0
[  153.564591] device-mapper: core: Cannot calculate initial queue limits
[  153.564716] device-mapper: ioctl: unable to set up device queue for new table.
[  153.568854] blk_update_request: I/O error, dev loop0, sector 764010608 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0
[  153.569169] Buffer I/O error on dev loop0, logical block 95501326, async page read

ここで

blk_update_request: I/O error, dev loop0, sector xxx

という嫌なエラーがみえる。また、homectl inspecthomectl listなどで現在の状態を調べると、dirtyという状態になっていることがわかる。systemd-homedはdeactivateせず終了したとき、dirty状態になるらしい*1

# homectl list
NAME  UID   GID   STATE REALNAME HOME        SHELL
lufia 60331 60331 dirty lufia    /home/lufia /bin/bash

1 home areas listed.

このフラグは、/home/[user].homeにあるLUKSイメージにhome-dirty=1として属性が付けられている。属性を消せばinactive状態に戻る。

# attr -l /home/lufia.home
Attribute "home-dirty" has a 1 byte value for /home/lufia.home

# attr -r /home/lufia.home home-dirty

systemd-homedのLUKSストレージ構造

systemd-homedはディレクトリやCIFSサーバなどにストレージを切り替えられるようになっていて、LUKS+Btrfsなファイルシステムイメージがデフォルトとして使われる。この場合、以下の要素が使われる。

LUKSストレージでユーザーが作られると、ユーザーのホームディレクトリは/home/[user].homeという名前のイメージファイルで管理されるようになる。イメージファイルはそのままではマウントできないので、device-mapperでイメージをloopデバイスにする。このデバイスは、LUKSで暗号化したうえでBtrfsファイルシステムとしてフォーマットされる。こうして作られたファイルシステムはログインするとsystemd-homedによって/home/[user]へマウントされるので、ユーザーのデータは最終的に[user].homeのイメージファイルへ書かれることになる。

データを取り出す

ローカルには紛失すると困るものはないはずだが、作業中のソースコードなどは救出したいので必要なデータを取り出した。systemd-homed - ArchWikiにレスキューコマンドがあったのでそのまま使う。

# losetup -fP lufia.home
# cryptsetup open /dev/loop0p1 rescue
# mount /dev/mapper/rescue /mnt/

これで/mnt/[user]からファイルを参照できるようになるので、あとはtarなどで必要なファイルをコピーする。それが終わったら新しくユーザーを作って、逃がしておいたファイルを戻せばよい。ここでは、新しいユーザーはLUKSイメージを使わないストレージにした。

# userctl create --storage=directory --uid=60331 --member-of=wheel lufia

暗号化はディスク全体でやればいいし、Btrfsディスクイメージの利点もあまり感じていなかった。

コマンドとsystemd-homedの違い(未解決)

レスキュー用のコマンドではマウントできるのに、systemd-homedではactivateできないところが不思議だったのでjournalctlでログを読む。

# journalctl -u systemd-homed --since=today
Jan 03 10:49:54 plage systemd-homed[359]: lufia: changing state inactive → activating
Jan 03 10:49:54 plage systemd-homework[506]: Provided password unlocks user record.
Jan 03 10:49:54 plage systemd-homework[506]: Successfully locked image file '/home/lufia.home'.
Jan 03 10:49:54 plage systemd-homework[506]: Backing file is fully allocated already.
Jan 03 10:49:54 plage systemd-homework[506]: Setting up loopback device /dev/loop0 completed.
Jan 03 10:49:55 plage systemd-homework[506]: device-mapper: reload ioctl on home-lufia (254:0) failed: Invalid argument
Jan 03 10:49:55 plage systemd-homework[506]: Failed to unlock LUKS superblock: No such device
Jan 03 10:49:55 plage systemd-homed[359]: block device /sys/devices/virtual/block/loop0 has been removed.
Jan 03 10:49:55 plage systemd-homed[359]: Activation failed: No such device
Jan 03 10:49:55 plage systemd-homed[359]: lufia: changing state activating → inactive

ここで、

block device /sys/devices/virtual/block/loop0 has been removed.
Activation failed: No such device

とあるのは、systemd-homedの処理途中でエラーが発生した場合にloopデバイスが残らないように削除しているだけなので問題ではない。なのでおそらく

device-mapper: reload ioctl on home-lufia (254:0) failed: Invalid argument

が、レスキュー用のコマンドとの差異だろう。次の行に出力されたログから、

のどこかでioctlがエラーになっているのだと思うが、簡単には追えそうになかったので諦めた。

参考情報

調べているときに参考になった記事。