2012年8月10日金曜日

FreeBSD で Windows 用の NAS をマウントする (1)

まとめ

  1. NFS(Network File System) に非対応の Windows 用の NAS(LANハードディスク, SMB 用) を、なんとかして FreeBSD から普通に使いたい
  2. そのために Windows 用の NAS 内に巨大な1個のイメージファイル(fs.img)を作り、そのファイルを仮想ファイルシステム(仮想 HDD) として ufs2 でフォーマットして、FreeBSD9.0 からマウントする 
  3. geli コマンドで仮想ファイルシステム全体の暗号化もしてみた 
  4. このような使い方でも、ファイルへのアクセス速度は極端に遅くはならなかった(が同時アクセスには弱い。本文参照)
  5. この状態でネットワークに重大なエラーが発生すると FreeBSD9.0 が kernel panic で止まる。その場合でもマウント中の仮想 HDD が致命的に破損するケースには遭遇していない 



動機


FreeBSD サーバからネットワークストレージをマウントして使いたい。最近 NAS は簡単に買えるようになったが、なぜか NFS に対応した NAS がほとんど見当たらない(昔は普通に対応していた気がするのだが)。職場で使っているネットギア社の ReadyNAS シリーズでは、NFSに対応しているのは「ハイパフォーマンスモデル」だけ。「スタンダードモデル」だとWindowsファイル共有(SMB,CIFS) と Macファイル共有(AFP)のみに対応と書いてある。しかもかなり高価。

FreeBSD も Windowsファイル共有(SMB)には対応しているので、Windows 用の NAS を一応直接マウントすることはできる。マウントするためのコマンドはこんな感じ(オプションの詳細は後述)。
# mount_smbfs -E euc-jp:cp932 -I 192.168.100.200 //nas@LANDISK/share /mnt/smb

試しにこれで FreeBSD から Windows ファイル共有を使ってみたが、以下の問題があってかなり使いにくかった。
  1. パーミションが自由に設定できない 
  2. シンボリックリンクが作れない 
  3. ディレクトリに大量のファイルがある時に、ファイルの一覧表示に異常に時間がかかる(ls -l packages/All/ を実行した時など。ファイル数=約20000 で約10-30秒。しかもキャッシュされていないようで毎回遅い) 

そこで、一番上の図のように、まず FreeBSD サーバから Windows 用の NAS を SMB でマウントして、そこに巨大な(1.4TB)ファイルを作り、これを mdconfig コマンドで仮想ファイルシステムにする。その仮想ファイルシステムを ufs2 でフォーマットしてマウントしたところ(マウント先にあるファイルをさらにマウントするという、二重で妙な形にはなるが)、上記の問題 1,2,3 が解決して、NFS とほぼ同様に使うことができるようになった。

こういう使い方をした場合、以下のような懸念があったので、本当に大丈夫なのかの実験もしてみた。
  1. ファイルへのアクセス速度は遅くならないか 
  2. ネットワークのエラーで仮想ファイルシステムが破損したりしないか 

使った機器


◇ FreeBSD サーバ
Shuttle Japan XS35 V2
  • OS: FreeBSD9.0-RELEASE, 起動 CD-ROM(FreeBSD-9.0-RELEASE-i386-bootonly.iso) から起動してネットワークインストール
  • ハードウェア: Shuttle Japan XS35 V2, Atom D525(1.8GHz), RAM 2GB, ファンレスマシン。ただし HDD/SSD は今回搭載せず、USB メモリ(Buffalo RUF2-PS16GS, 16GB)に OS をインストールしてあるちょっと変わったマシン
  • XS35 V2 の有線 LAN のチップは JMicron JMC250 (FreeBSD で使われるデバイスドライバは jme。省電力対応のギガビットハブと通信できない問題がある)

◇ Windows ファイル共有に対応した NAS

I/O-DATA HDL-GTR3.0
  • I/O-DATA HDL-GTR3.0
  • RAID1+0 で使用、容量1.5TB
  • 他の機種では試していないが、巨大なファイルを作成する必要があるので,NAS 内蔵の HDD のフォーマット形式に注意する必要がありそう

初期設定の手順

1. NAS の設定

NAS の Web インタフェースにログインして、ユーザ(今回は "nas" というユーザ名)を作成し、パスワードを付けておく。IP アドレス(192.168.100.200)、マシン名(LANDISK)を設定、共有(share)を作成しておく

2. FreeBSD サーバから Windows 用の NAS をマウントする

FreeBSD から以下のコマンドで NAS で作成した共有をマウントする。

# mount_smbfs -E euc-jp:cp932 -f 600 -d 700 -I 192.168.1.200 //nas@LANDISK/share /mnt/smb

このコマンドを実行すると NAS 側で設定したユーザ (ユーザ名=nas) のパスワードを聞かれるので入力する。実際にはここでマウントした先 (/mnt/smb) には巨大なイメージファイル fs.img を1個置くだけ。それ以外には直接は使用しない。

mount_smbfs コマンドの引数の説明
  • -E: -E FreeBSD側の文字コード : NAS側の文字コード
  • -f: ファイルに対するパーミション
  • -d: ディレクトリに対するパーミッション
  • -I: NAS のIPアドレス
  • マウント元: NASのユーザ名=nas, NASのマシン名=LANDISK, 共有名=share (あらかじめ NAS の Web インタフェースで作成しておく)
  • マウント先: /mnt/smb
引数ではパーミッションも指定している。/mnt/smb は root だけが読み書きできるだけでよい(それでも他のユーザは仮想ディスクに読み書きできる)し、誤って一般ユーザが仮想HDDのファイルを書き換えたり消したりすると、ディスクが全滅するので、パーミションの値は 600,700 として root のみに読み書きを許可した。

3. マウントした Windows 共有上に空のイメージファイルを作成する

# dd if=/dev/zero of=/mnt/smb/fs.img bs=1M seek=1400000 count=1
このコマンドで約1.4TB(1468007448576 byte)の空のファイル /mnt/smb/fs.img が作成できた。巨大な空のファイルを作成するときには、 dd コマンドで seek オプションを使うのが便利。seek オプションを使わないと(大量の通信が発生して)おそらくものすごく時間がかかる。

4. 作成したイメージファイルを仮想HDDにする

# mdconfig -a -t vnode -f /mnt/smb/fs.img -u 1
# bsdlabel -w md1 auto

実行すると /mnt/smb/fs.img が /dev/md1 というデバイスファイルに割り当てられて、これ以降このデバイスファイルが仮想 HDD のように扱える。

5. 仮想HDDを暗号化する

# geli init -s 4096 /dev/md1a
# geli attach /dev/md1a

仮想 HDD の暗号化を行ってみた。上のコマンドを実行すると、/dev/md1a.eli というデバイスファイルができ、このデバイスファイルが暗号化された仮想HDDとして扱える。つまりイメージファイル fs.img への書き込みが自動的に暗号化されて、fs.img を生で読んでも解読できなくなる。"geli init" コマンドの実行時にパスフレーズを付けるように要求される。

※ 後日パスフレーズを変更する場合は
# geli setkey /dev/md1a

6. ファイルシステムの作成

# newfs /dev/md1a.eli
# tunefs -j enable -n enable /dev/md1a.eli
実行すると、5で作った暗号化仮想 HDD /dev/md1a.eli が ufs2 でフォーマットされる。tunefs コマンドは FreeBSD9.0 で使えるようになったジャーナリング(Soft Update Journaling, SU+J) を有効にするため。有効にしておくとクラッシュ時の fsck が高速になるはず。

7. マウント

# mount /dev/md1a.eli /mnt/img
実行すると、仮想 HDD が /mnt/img にマウントされて、読み書きできるようになる。実際の読み書きは(暗号化された上で) NAS 上のファイル fs.img に対して行われる。

マウントする


一度上記の手順で初期化すれば、二回目からは以下の手順でマウントできる。シェルスクリプトにでもしておこう。

# mount_smbfs -E euc-jp:cp932 -f 600 -d 700 -I 192.168.100.200 /nas@LANDISK/share /mnt/smb
# mdconfig -a -t vnode -f /mnt/smb/fs.img -u 1
# geli attach /dev/md1a
# mount /dev/md1a.eli /mnt/img
mount_smbfs コマンドでは nas のパスワードを、 geli コマンドでは暗号化時に付けたパスフレーズを聞かれるので、それぞれ入力する。

マウントしてから mount, df -H コマンドを実行すると、それぞれ次のように表示された。

# mount
/dev/da0p2 on / (ufs, NFS exported, local, noatime, journaled soft-updates)
devfs on /dev (devfs, local, multilabel)
tmpfs on /tmp (tmpfs, local)
//NAS@LANDISK/SHARE on /mnt/smb (smbfs)
/dev/md1a.eli on /mnt/img (ufs, local, journaled soft-updates)
# df -H
Filesystem       Size    Used   Avail Capacity  Mounted on
/dev/da0p2      14G    7.4G    6.3G    54%    /
devfs               1.0k    1.0k      0B   100%    /dev
tmpfs               1.0G    4.1k      1G     0%    /tmp
/dev/md1a.eli    1.4T    528G    801G    40%    /mnt/img

マウントできなくなった場合の対応(重要)


システムのクラッシュ後にマウントしようとすると、最後の
# mount /dev/md1a.eli /mnt/img

を実行したときに
mount: /dev/md1a.eli : Operation not permitted

というエラーが出てマウントできなくなる。その場合は以下のコマンドで仮想 HDD に手動で fsck_ufs を実行してからマウントすればよい。ジャーナリングのおかげで fsck はすぐに終わるはず。

(上記の「マウントする」の "geli attach /dev/md1a" までを実行してから)
# fsck_ufs /dev/md1a.eli
# mount /dev/md1a.eli /mnt/img

アンマウントする


手動で強制的にアンマウントする手順

# umount -f /mnt/img
# geli detach md1a.eli
# mdconfig -d -u 1
# umount -f /mnt/smb


[続く

3 件のコメント:

  1. ジャーナリングを有効にしておかないと、1.4TB の仮想 HDD の fsck に10分以上(もっと?)かかります。

    返信削除
  2. 思いつきなので確証ないですが、同時アクセスに弱いあたりは仮想ディスクのファイルを複数に分割してストライピング状態にしてあげれば改善できませんかね?

    返信削除
    返信
    1. コメントどうもありがとうございます。それは面白いアイデアですね。仮想ディスクをストライピングにするとどうなるのか、全然想像つきません。今度試してみたいと思います。

      削除