ASUSルーターで使用していたNTFSが壊れたのでext3にした

 先日、ASUSルーターRT-AC56Sに接続して使用していたUSBストレージのファイルシステムが壊れ、いくつかのファイルを失ってしまいました。
 使用していたUSBストレージは、IO DATA製のUSB2.0接続の古い1TB HDDで、NTFSでフォーマットされていたものです(ちなみにこのHDDは過去にPogoplugに接続していたこともあるのですが、その際もやはりファイルシステムが壊れました)。
 ASUSルーター(やPogoplug)の中身はLinuxですから、MicrosoftNTFSよりもext4などのLinuxの世界で標準的なファイルシステムを利用した方が、壊れにくいのではないかと思ったため作業してみました。
 異常検知からext3利用までの一連の流れを参考までに記載します。
 

異常検知

 そもそもHDD内のデータが損傷していることに気付いたのは、空き容量を確認するためにdfコマンドを叩いたり、ディレクトリ別の使用量を確認しようとduコマンドを叩いたところ、以下のようにInput/output errorが表示されたことがきっかけでした。

# du -h -d 0 data/
du: data/images/IMG_0575_20140125_063532.JPG: Input/output error
du: data/images/IMG_0576_20140125_063836.JPG: Input/output error
du: data/images/IMG_0577_20140125_063848.JPG: Input/output error
… 中略…
163.8G  data/

 

ファイルシステムチェック

 ルーターのWeb管理画面から該当するDISKを[ヘルススキャナー]⇒[スキャン]したところ、ボロボロでした。このスキャン機能の実体はntfsckで、修復も試みられていますが最終的には"this seems to be endless."と、打ち切られてしまいます(同一inodeの修復を何度も試みているが、何度やっても無理なので諦めている)。

ntfsck 3014.5.21
Checking NTFS Superblock ...
Device name        : /dev/sdc1
NTFS volume version: 3.1
Cluster size       : 65536 bytes
Current volume size: 1000203026944 bytes (1000204 MB)
Current device size: 1000203091968 bytes (1000204 MB)
Checking for bad sectors ...
Scanning $MFT ...
Could not read "$RECYCLE.BIN" (inode=3414).
Checking directory structure ...
Corrupt directory found, inode=5 (0x5)
Repairing corrupt directories started.
  0.00 percent completed
… 中略 …
No file name found in inode 3706
No file name found in inode 3722
No file name found in inode 3743
No file name found in inode 3767
Could not read "IMG_0579_20140125_064015.JPG" (inode=3409).
Could not read "IndexerVolumeGuid" (inode=3413).
… 中略 …
Repairing corrupt directories completed.
Corrupt directory found, inode=54 (0x36)
Corrupt directory found, inode=767 (0x2ff)
Corrupt directory found, inode=35 (0x23)
… 中略 …
Repairing corrupt directories started.
  0.00 percent completed
… 中略 …
No file name found in inode 3706
No file name found in inode 3722
No file name found in inode 3743
No file name found in inode 3767
… 中略 …
100.00 percent completed
Repairing corrupt directories completed.
Repairing corrupt directories started.
  0.00 percent completed
… 中略 …
No file name found in inode 3706
No file name found in inode 3722
No file name found in inode 3743
No file name found in inode 3767
… 中略 …
100.00 percent completed
Repairing corrupt directories completed.
Repairing corrupt directories started.
  0.00 percent completed
… 中略 …
this seems to be endless.
Repairing corrupt directories completed.
Space in use       : 972925 MB (97.3%)
Done NTFS checking and repair on device '/dev/sdc1'.
Syncing device ...

 

他のマシンへのデータ移動を試行

 du等のコマンドで、Input/output errorと表示されたファイルを他のマシンからsamba経由で回収を試みたり、scpでコピーしようとしても、既に読み取れませんでした。
 この時dmesgには以下のような出力が大量に吐かれていました。

# dmesg | grep err
… 中略 …
tntfs error (device sdc1, pid 26973): ntfs_read_locked_inode(): Failed (error 5).  Marking corrupt inode 0x14c6 as bad.  Run chkdsk.
tntfs error (device sdc1, pid 26973): ntfs_mft_record_map(): Mft record 0x7f5 is corrupt (magic is 0x30 [0
tntfs error (device sdc1, pid 26973): ntfs_mft_record_map(): Failed with error code 5.
tntfs error (device sdc1, pid 26973): ntfs_read_locked_inode(): Failed (error 5).  Marking corrupt inode 0x7f5 as bad.  Run chkdsk.
tntfs error (device sdc1, pid 26973): ntfs_mft_record_map(): Mft record 0x156a is corrupt (magic is 0x30 [0
tntfs error (device sdc1, pid 26973): ntfs_mft_record_map(): Failed with error code 5.
tntfs error (device sdc1, pid 26973): ntfs_read_locked_inode(): Failed (error 5).  Marking corrupt inode 0x156a as bad.  Run chkdsk.
tntfs error (device sdc1, pid 26973): ntfs_mft_record_map(): Mft record 0x14d9 is corrupt (magic is 0x30 [0
tntfs error (device sdc1, pid 26973): ntfs_mft_record_map(): Failed with error code 5.
… 中略 …

# ps -w | grep 26973 | grep -v grep
26973 admin     1624 D    scp -r -f /tmp/mnt/sdc1/data

 

読み出せるファイルを退避

 適当なPCで根こそぎファイルコピーするのが手っ取り早いですが、障害が発生しているDISKをルーターからマウント解除して、他のマシンでマウントできなかったり、ルーターにも二度とマウントできなかったりするのは怖いので、現状の接続を維持したまま、(ルーターではない)LinuxマシンにUSB接続した別のHDDにscpすることにしました。
 duコマンドなどで"Input/output error"が発生していたファイルは、scpでもエラーとなりスキップされますが、一応コピーは完了します。
 

差分チェック

 が、元のDISKの状態を鑑みるに、正しく読み出せていたのかは怪しい気がするので、各ファイルを比較することにします。
 当初Linuxでdiffコマンドで差分チェックしようと考えたのですが、多数のディレクトリ階層下の大量のファイルを比較するには不適だと思えたため、Windowsのfcコマンドを使うことにしました(fcコマンドの比較対象にはディレクトリを指定することもできるためです)。ただし、再帰的にサブディレクトリを比較してくれないので、dirコマンドでdir /on /b /adとしてディレクトリ名だけ予め抽出し、得られた各ディレクトリをfcコマンドのパラメータにしたバッチファイルを作成し、その実行結果をリダイレクトしたファイルを正規表現で加工して差分を探すという手作業を行いました。
 結果的にLinux環境で、"Input/output error"が発生していたファイル以外は、全て完全一致することが確認できました。
 

障害が発生したDISKの論理/物理障害切り分け

 先にルータのdmesgに"Run chkdsk"の出力があったことから、Windows環境でchkdsk /fを実行した後(ルーターではない)Linuxマシンでマウントを試みたところ、事態は悪化しマウントすらできなくなりました。

$ sudo mount /dev/sdd1 /mnt/usb
$MFTMirr does not match $MFT (record 24).
Failed to mount '/dev/sdd1': Input/output error
NTFS is either inconsistent, or there is a hardware fault, or it's a
SoftRAID/FakeRAID hardware. In the first case run chkdsk /f on Windows
then reboot into Windows twice. The usage of the /f parameter is very
important! If the device is a SoftRAID/FakeRAID then first activate
it and mount a different device under the /dev/mapper/ directory, (e.g.
/dev/mapper/nvidia_eahaabcc1). Please see the 'dmraid' documentation
for more details.

 単にファイルシステムが損傷しているだけの論理障害なのか、HDDのH/W自体に異常をきたしている物理障害なのかを識別するため、まずはSMART情報を確認してみました。
 Windows環境でCrystal Disk Infoで確認してみたところ、確認できる値に特に異常は見られませんでした。

 また、このDISKは先述の通りIO DATA製ですが、中身のHDDはSamsung製でした。
 SamsungのHDD事業はSeagateに買収されていますので、SeatoolsでHDDの検査が出来るのではないかと思ったのですが、できませんでした。

 既に読み出せるデータは退避済なので、全領域にデータが記録できれば問題無かろうという思想で、Windows標準のdiskpartユーティリティのclean allコマンド(いわゆる0フィル)を実行したところ正常に完了しました。

 これらのことから、H/Wには問題無さそうで物理障害ではない、すなわち論理障害だろうと判断しました。
 論理障害であるならWindows環境で使用する訳でもないのに、わざわざNTFSを使う必要は無いのでext4でフォーマットし直して、再利用しようと思い立ちます。
 

ext4が使えない

 ルーターのWeb管理画面からUSBストレージのフォーマットができるのですが、フォーマットタイプの選択肢にはNTFS/FAT/HFSしかありません。
 とは言え、SSHログインしてルーターLinuxバージョンを確認してみると以下の通りでした。

# uname -srm
Linux 2.6.36.4brcmarm armv7l

 だいぶ古いカーネルながら、このバージョンならext4サポートしてるはずです。

 と言うわけで、(ルーターではない)Linuxマシンでパーティション作成及びext4ファイルシステム作成後、ルータに接続してみたのですがマウントされません(普通は接続したら自動でマウントされる)。
 dmesgを確認してみると以下の出力がありました。

EXT4-fs (sdc1): couldn't mount RDWR because of unsupported optional features (400)
EXT3-fs (sdc1): error: couldn't mount because of unsupported optional features (2c0)
EXT2-fs (sdc1): error: couldn't mount because of unsupported optional features (2c0)

 サポートしてないオプション機能を使っているからext4でもext3でもext2でもマウントできないと言っているようです。

 今度はSSHコンソールから手動でマウントを試みます。が、マウントできません。

# mount /dev/sdc1 /tmp/mnt/sdc1
mount: mounting /dev/sdc1 on /tmp/mnt/sdc1 failed: Invalid argument

 この時も先と同様のログがdmesgに出力されていました。

EXT3-fs (sdc1): error: couldn't mount because of unsupported optional features (2c0)
EXT4-fs (sdc1): couldn't mount RDWR because of unsupported optional features (400)
EXT2-fs (sdc1): error: couldn't mount because of unsupported optional features (2c0)
tfat: fail_safe is enabled
tntfs info (device sdc1, pid 12995): ntfs_fill_super(): fail_safe is enabled

 ext3, ext4, ext2, tfat, tntfsいずれでもマウントできないと言っているようです。

 改めて、明示的にext4を指定してマウントを試みます。

# mount -t ext4 /dev/sdc1 /tmp/mnt/sdc1
mount: mounting /dev/sdc1 on /tmp/mnt/sdc1 failed: Invalid argument

 が、やはりマウントできませんでした。今度はdmesgにext4でマウントできなかった旨だけ出力されていました。

EXT4-fs (sdc1): couldn't mount RDWR because of unsupported optional features (400)

 他のマシン(Ubuntu 18.04環境)で普通にext4ファイルシステム作成しただけなので"unsupported optional features"と言われる意味が解りませんが、ルータ内の古い組み込みLinuxではサポートしていない何かが使われているのでしょう。
 ならば、ルーター自体でext4ファイルシステムを作成すれば問題無かろうと思いました。
 ところが、ルータでmkfsやmkfs.ext4を叩いてみるも、コマンドが無い。それでもWeb管理画面からNTFS/FAT/HFSでフォーマットできるのだから、何らかのコマンドはあるはずです。

 困ったときのbusyboxを確認してみると、

# busybox
BusyBox v1.17.4 (2018-05-27 16:22:58 CST) multi-call binary.
Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko
and others. Licensed under GPLv2.
See source distribution for full notice.

Usage: busybox [function] [arguments]...
   or: function [arguments]...

        BusyBox is a multi-call binary that combines many common Unix
        utilities into a single executable.  Most people will create a
        link to busybox for each function they wish to use and BusyBox
        will act like whatever it was invoked as.

Currently defined functions:
        [, [[, arp, ash, awk, basename, blkid, cat, chmod, chown, chpasswd,
        clear, cmp, cp, crond, cut, date, dd, devmem, df, dirname, dmesg, du,
        e2fsck, echo, egrep, env, ether-wake, expr, fdisk, fgrep, find, flock,
        free, fsck, fsck.ext2, fsck.ext3, fsck.minix, fsync, grep, gunzip,
        gzip, head, ifconfig, insmod, ionice, kill, killall, klogd, less, ln,
        logger, login, ls, lsmod, lsusb, md5sum, mdev, mkdir, mke2fs,
        mkfs.ext2, mkfs.ext3, mknod, mkswap, modprobe, more, mount, mv,
        netstat, nice, nohup, nslookup, pidof, ping, ping6, printf, ps, pwd,
        readlink, renice, rm, rmdir, rmmod, route, sed, setconsole, sh, sleep,
        sort, strings, swapoff, swapon, sync, syslogd, tail, tar, telnetd,
        test, top, touch, tr, traceroute, traceroute6, true, tune2fs, udhcpc,
        umount, uname, unzip, uptime, usleep, vconfig, vi, watch, wc, which,
        zcat, zcip

 ありました。mke2fs, mkfs.ext2, mkfs.ext3 って、ext4がない!

 別マシンで作ったext4が扱えず、ルーター内でext4を作ることもできないなら、ext3でもいいか。と、妥協することにしました。
 

ext3ファイルシステム作成

 まずは、既存の認識できないext4パーティション(ここではsdc1)を削除します。

# ls -l /dev/sdc*
brw-r--r--    1 admin    root        8,  32 Nov 13 21:17 /dev/sdc
brw-r--r--    1 admin    root        8,  33 Nov 13 21:17 /dev/sdc1

# fdisk /dev/sdc

The number of cylinders for this disk is set to 382818.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
   (e.g., DOS FDISK, OS/2 FDISK)

Command (m for help): p

Disk /dev/sdc: 1000.2 GB, 1000204886016 bytes
81 heads, 63 sectors/track, 382818 cylinders
Units = cylinders of 5103 * 512 = 2612736 bytes

   Device Boot      Start         End      Blocks  Id System
/dev/sdc1               1      382819   976761560  83 Linux

Command (m for help): d
Selected partition 1

Command (m for help): p

Disk /dev/sdc: 1000.2 GB, 1000204886016 bytes
81 heads, 63 sectors/track, 382818 cylinders
Units = cylinders of 5103 * 512 = 2612736 bytes

   Device Boot      Start         End      Blocks  Id System

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table

# ls -l /dev/sdc*
brw-r--r--    1 admin    root        8,  32 Nov 13 21:41 /dev/sdc

 
 改めてパーティション作成します。

# fdisk /dev/sdc

The number of cylinders for this disk is set to 121601.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
   (e.g., DOS FDISK, OS/2 FDISK)

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
Partition number (1-4): 1
First cylinder (1-121601, default 1): Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-121601, default 121601): Using default value 121601

Command (m for help): p

Disk /dev/sdc: 1000.2 GB, 1000204886016 bytes
255 heads, 63 sectors/track, 121601 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks  Id System
/dev/sdc1               1      121601   976760001  83 Linux

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table


# ls /dev/sdc*
/dev/sdc   /dev/sdc1

 まっさらのsdc1パーティションが出来たので、ここにext3ファイルシステムを作成します。
 その前に、busyboxに実装されたmkfs.ext3のパラメータを確認しておくと以下の通り。

# mkfs.ext3 --help
BusyBox v1.17.4 (2018-05-27 16:22:58 CST) multi-call binary.

Usage: mkfs.ext3 [-c|-l filename] [-b block-size] [-f fragment-size] [-g blocks-per-group] [-i bytes-per-inode] [-j] [-J journal-options] [-N number-of-inodes] [-n] [-m reserved-blocks-percentage] [-o creator-os] [-O feature[,...]] [-q] [r fs-revision-level] [-E extended-options] [-v] [-F] [-L volume-label] [-M last-mounted-directory] [-S] [-T filesystem-type] device [blocks-count]

        -b size         Block size in bytes
        -c              Check for bad blocks before creating
        -E opts         Set extended options
        -f size         Fragment size in bytes
        -F              Force (ignore sanity checks)
        -g num          Number of blocks in a block group
        -i ratio        The bytes/inode ratio
        -j              Create a journal (ext3)
        -J opts         Set journal options (size/device)
        -l file         Read bad blocks list from file
        -L lbl          Set the volume label
        -m percent      Percent of fs blocks to reserve for admin
        -M dir          Set last mounted directory
        -n              Do not actually create anything
        -N num          Number of inodes to create
        -o os           Set the 'creator os' field
        -O features     Dir_index/filetype/has_journal/journal_dev/sparse_super
        -q              Quiet
        -r rev          Set filesystem revision
        -S              Write superblock and group descriptors only
        -T fs-type      Set usage type (news/largefile/largefile4)
        -v              Verbose

 
 今回は特に拘りはないので単に対象パーティション名を指定するだけにします。が、"Could not set up superblock"というエラーが発生し、ファイルシステムが作成できません。

# mkfs.ext3 /dev/sdc1
mke2fs 1.38 (30-Jun-2005)

Could not set up superblock

 検索してみるとメモリが足りないとこのエラーが発生することがあるようです。
 現状の空メモリを確認します。

# free
              total         used         free       shared      buffers
  Mem:       125960        69048        56912            0          632
 Swap:            0            0            0
Total:       125960        69048        56912

 128MB程度のメモリを搭載していますが約56MBの空では足りないということになります。ので、とりあえずスワップ領域を追加してやり過ごそうと思います。

# dd if=/dev/zero of=/tmp/mnt/sdb1/swap bs=1M count=128
128+0 records in
128+0 records out

# mkswap /tmp/mnt/sdb1/swap
Setting up swapspace version 1, size = 134213632 bytes
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

# swapon /tmp/mnt/sdb1/swap

# free
              total         used         free       shared      buffers
  Mem:       125960        95616        30344            0          360
 Swap:       131068            0       131068
Total:       257028        95616       161412

 161MB程度の空き領域が確保できましたので、再度mkfs.ext3を実行します。
 が、30分以上たっても完了せず… 固まった …
 そもそもこの環境、ルーターなんですけど、ネットワーク内の機器と通信できなくなったり、インターネット接続もできない状態に陥っていることに気付きました。
 待ってればいつかは終わるのかもしれませんが、弊害が大きすぎるので強制的に電源を落として再起動させました。

 といった有様なのでルータ自体でext3ファイルシステムを作成することは諦めました。
 ext4ファイルシステムを作成した時と同様に、Ubuntu 18.04の別のLinuxマシンでext3ファイルシステムを作成しました(mkfs -t ext3 /dev/sdc1)。PCならすぐ終わります。
 

ext3のマウント

 Ubuntu 18.04のマシンから取り外して、ルーターに接続しただけで自動マウントされました!この際、dmesgには以下の出力が確認できます。

EXT3-fs: barriers not enabled
kjournald starting.  Commit interval 5 seconds
EXT3-fs (sdd1): using internal journal
EXT3-fs (sdd1): mounted filesystem with ordered data mode

 

パーミッション周り

 NTFSではないので、所有者の概念に注意する必要があります。
 自動でマウントされたDISKは管理者のユーザ・グループとなっていますので、Samba経由でアクセスするユーザが管理者では無ければ、当然アクセスできません。
 かと言って、管理者ユーザでsambaアクセスさせるのも望ましくないでしょうから、以下のように当該パーティション配下を根こそぎsambaユーザにchownしてしまうのが手っ取り早いと思います。

# chown -R user:user /tmp/mnt/sdd1

 また、Samba経由でファイルを作成すると、ファイルパーミッションがrwxrwxrwx(777)となります。
 これは、以下のようにsmb.confでforce create modeが0777指定されているためだと考えられますが、smb.confはWeb管理画面の操作で自動生成・更新されるため、このファイルを直接手で編集するのはお勧めできません。

# grep mode /etc/smb.conf
force directory mode = 0777
force create mode = 0777
dos filemode = yes

 

まとめ

 ASUSルーター(RT-AC56S)では、

 と言えます。但し、メーカーがEXT3サポートを公言しているわけではないので、自己責任で利用することになります。
 



以上。