見出し画像

プログラマー探偵の事件簿:Volume was not properly unmounted. Some data may be corrupt.

プログラムを作っていると何だか得体のしれないエラーメッセージに悩まされる事件が起こる。自分の作ったプログラムのソースコードをいくら調べても何の手がかりも得られない。そんな事件の真相を突き止めたプログラマー探偵の物語である。もちろん助手は猫である。

第一話は、

の一つだ。

事件の始まり

LinuxというOSで動作するプログラムを開発していた時、いつの間にかログに

FAT-fs (sda): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.

というメッセージが出ているのに気づいた。開発中にエラーログが気になるのは、これまでの失敗経験で身についた性分である。とりあえずGoogleに翻訳してもらうと

ボリューム(*1)は適切にアンマウントされませんでした。 一部のデータが破損している可能性があります。 fsckを実行してください。

*1  ここでボリュームはハードディスクの意味

「データが破損している可能性」とは危険な匂いがする。アンマウントして再起動してもメッセージは消えない。何度やってもだめ。

犯人は私か?

ディスクをマウント/アンマウントする処理は私が作っているプログラムである。まずは、このプログラム(自分)を疑ってみる。ソースコードをいくら調べても怪しいところはない。アンマウントする関数のマニュアル

を見ても問題は見つからない。やっぱり、私は間違っていない。では、何が悪いのか?助手の猫は熟睡しているので聞くと厄介なことになりそうなのでやめた。

Googleに聞いてみる

Googleで遭遇したエラーメッセージやログをそのまま検索すると何かわかることがある。世界中の開発者がやっていることだ。
今回のメッセージを検索すると

画像1

24万件もヒットした。世界中には同じ事件に遭遇した仲間が沢山いるようだ。どれどれ、いくつか読んでみる。
どれも、エラーメッセージにもあるfsckというコマンドを

fsck -w -r /dev/sdb1

のように実行すればよいと書いてある。ほとんどの場合は見つけた方法をそのまま実施してエラーメッセージが消えれば解決だ。私も深く考えずにそうしていることが多い。(それで良いのか?悩むところだが)

ところが今回はそうはいかない。作っているものが特殊なので困ったことにfsckというコマンドがないのだ!

悪あがきで時間がすぎる

fsckを使わず何とか簡単に解決できる手段はないか?利用しているマウントアンマウントする関数のパラメータを変えたり一発で解決できる関数を探したり試行錯誤を繰り返すうちに時間がすぎていく。いろいろやったあげく途方にくれる。
ふとfsckコマンドの実行でエラーメッセージが消えた本当の理由を知らないことに気づいた。そもそも、このエラーメッセージが出る真相も知らない。

真相にせまる

闇雲に何かやるより真面目にエラーメッセージが出る真相を調べることにした。手がかりは、LinuxというOSが出力していることと、このメッセージの含まれる単語ぐらい。ここから真相にせまることになる。

幸いなことにLinuxというOSはWindowsとは違いソースコードが公開されている。

から誰でも手に入れることができる。
ソースコードを調べれば、このエラーメッセージをどこで出しているか見つけることができる。ソースコードをダウンロードしてエディタの検索機能やgrepコマンドを使って

Volume was not properly unmounted. Some data may be corrupt

を出力する行を探す。この検索もGoogleで検索する時に選ぶキーワードと同じようにある種のノウハウが必要だ。メッセージを全部指定してもヒットしない場合が多い。私は特徴的な単語で絞り込んでいく作戦を使っている。うまく検索できた。

というソースコードにある

static void fat_set_state(struct super_block *sb,
			unsigned int set, unsigned int force)
{
	struct buffer_head *bh;
	struct fat_boot_sector *b;
	struct msdos_sb_info *sbi = MSDOS_SB(sb);

	/* do not change any thing if mounted read only */
	if (sb_rdonly(sb) && !force)
		return;

	/* do not change state if fs was dirty */
	if (sbi->dirty) {
		/* warn only on set (mount). */
		if (set)
			fat_msg(sb, KERN_WARNING, "Volume was not properly "
				"unmounted. Some data may be corrupt. "
				"Please run fsck.");
		return;
	}

	bh = sb_bread(sb, 0);
	if (bh == NULL) {
		fat_msg(sb, KERN_ERR, "unable to read boot sector "
			"to mark fs as dirty");
		return;
	}

	b = (struct fat_boot_sector *) bh->b_data;

	if (is_fat32(sbi)) {
		if (set)
			b->fat32.state |= FAT_STATE_DIRTY;
		else
			b->fat32.state &= ~FAT_STATE_DIRTY;
	} else /* fat 16 and 12 */ {
		if (set)
			b->fat16.state |= FAT_STATE_DIRTY;
		else
			b->fat16.state &= ~FAT_STATE_DIRTY;
	}

	mark_buffer_dirty(bh);
	sync_dirty_buffer(bh);
	brelse(bh);
}

という関数で出していることにたどり着いた。エラーメッセージを出している部分は、ここ

fat_msg(sb, KERN_WARNING, "Volume was not properly "
				"unmounted. Some data may be corrupt. "
				"Please run fsck.");

このプログラムを簡単に説明するとマウントした時ディスクにDIRTYというマークを付ける。アンマウントした時、DIRTYというマークを取る。マウントした時に 、DIRTYというマークがついていれば、このエラーメッセージを出す。ん、コメントに

do not change state if fs was dirty

と書いてある。
「ああ、そうだったのか!」
このソースコードを見た時、自分が闇雲にやっていたことの愚かさに気づいた。一度、DIRTYマークが付いたディスクは、アンマウント、マウントを繰り返してもDIRTYが消えることはない。fsckというコマンドでDIRTYマークを取らないと永久にこのエラーメッセージに悩まされるのだ。
fsckもソースコードが公開されているので、実施している処理やDIRTYマークを取る方法を調べてこの事件を解決した。

この事件について思うこと

LinuxのようにOSやライブラリのソースコードが公開されているものならば、どこまでもソースコードを調べることができる。真面目に調べれば真相にたどり着くことができる。自分の見える世界だけで闇雲に対策するより真相を知った上で対策したほうが、きっと良い結果を得られる。WindowsのようにOSやライブラリがブラックボックスだと、その中で何が起こっているのか知ることが出来ない。これは、ソフトウェア開発を厄介なものにしている原因かと思う。

助手の猫はこの解決までの間ずっと熟睡していた。私にそのことを気づかせるために、あえて寝ていたのかもしれない。



開発のための諸経費(機材、Appleの開発者、サーバー運用)に利用します。 ソフトウェアのマニュアルをnoteの記事で提供しています。 サポートによりnoteの運営にも貢献できるのでよろしくお願います。