Linux(Gentoo)をサーバにしてMac OS X 10.6(Snow Leopard)とファイル共有してみた(AFP over TCP)
LinuxとMac間でファイルのやりとり出きるようにしていないことに気がついたので、AFPデーモンをLinuxに立ててファイル共有することにしました。
NFSも考えましたが設定がいろいろと面倒くさいのでやめてAFPにしました。AFPというのはAppleが開発したファイル共有プロトコルです。Mac OS X以前はAppleTalkの一部でしたが、現状はTCP/IP上で動くプロトコル(AFP over TCP)となっています。
環境
- ディストロ:Gentoo Linux
- クライアント:Mac OS X 10.6(Snow Leopard)
- AFPデーモン:netatalk-2.0.5
手順
/etc/netatalk/nettatalk.confを変更する
下記のように設定します。netatalk.confから変更が必要な部分だけを抽出しています。
ATALKD_RUN=no PAPD_RUN=no CNID_METAD_RUN=yes AFPD_RUN=yes TIMELORD_RUN=no A2BOOT_RUN=no
/etc/netatalk/afpd.confを変更する
下記の行をファイルに追加してください。それぞれの引数の意味は備考にまとめてあります。
- -noddp -uamlist uams_dhx2.so
/etc/netatalk/AppleVolumes.defaultを変更する
ここは設定できるボリュームの設定をします。ユーザのホームディレクトリやビデオやオーディオ、TimeMachineのバックアップ先の指定などが可能です。
ユーザのホームディレクトリの共有を行うのが目的なのでファイルに"~"を挿入します。というか、元々"~"は入っていました。
~
その他のオプションは備考で簡単に紹介します。
Macでマウントする
Finderの「サーバに接続」機能を使用します。下記で接続できます。
[ユーザ名]はサーバ側と同じであれば特に指定不要です。
# ユーザ名を指定する場合 afp://[ユーザ名]@[アドレス] # ユーザ名を指定しない場合 afp://アドレス
備考
AppleTalkはなくなりました
AppleTalkはMacに搭載されている辞書だと下記の用に紹介されています。
アップルが提供していた、コンピュータネットワークのためのソフトウェアツールのセットです。AppleTalk ネットワークシステムは、Mac OS X を使用する Macintosh コンピュータでは TCP/IP ネットワークにその役割が引き継がれました。
もともとAFPはAppleTalkプロトコル上で動いていた分けですが、AppleTalkプロトコルが廃止されるとともにAFP over TCP/IPとなりました。
CNIDとは
Catelog Node ID(CNID)の略称でファイルやディレクトリに割り当てられたIDです。AFPではこのIDを用いてファイルへの要求を行います(パスを用いては行いません)。例えばファイルの指定はファイルの指定に文字列使用し、ディレクトリの指定にCNIDを使用すると言った具合です。
netatalk.confの設定について
- unixcodepage
- maccodepage
上記の文字コード指定の項目がありますがUTF-8で運用していれば変更の必要はありません。
Mac OSのバージョンが古い(AFP2.2まで)場合などはクライアントの文字コードを正しく指定する必要がある場合があるので注意が必要です。詳しくはhttp://netatalk.sourceforge.net/2.0/htmldocs/configuration.html を参照ください。
afpd.confの設定について
- -noddp -uamlist uams_dhx2.so
下記に引数の意味をまとめました。
- noddp:AFPをAppleTalk上で扱うかどうかを設定しています。AppleTalkは使用しないので[no]を付加しています
- uamlist:使用するUAM(User Authentication Modules)を指定します
- uams_dhx2.so:パスワードが最大256文字までサポートされたモジュールです。MacOS X 10.2から導入されています
もし、AppleShare client 3.8.4〜Mac OS X 10.2より前のバージョンとでやり取りを行いたい場合は"uams_dhx.so"を指定します。
全てのMac OSを対象にしたい場合は"uams_randnumo.so"を指定することで可能になります。
モジュールは複数指定することも可能です(','で区切ることにより)。
AppleVolumes.defaultsの設定について
この記事ではホームディレクトリにアクセスするのが目的だったので"~"で終わらせてしまったので、ざっくり紹介。詳しくはmanをどうぞ。
下記が基本となる記述になっています。
path [ volume name ] [ options ]
- path:ボリュームへのパスを指定します。"/home/ktomoya/xx"といったパスや"/var/afpd/timemachine/$u"といった$[a-z]の記述でユーザ名など動的要素も指定できます。
- [ volume name ]:ボリュームの名称を指定します。"Music"といった名称や"Music for $g group"のようにパスと同様に動的要素も指定できます。
- [ options ]:allow,denyユーザやtimemachine対応か否か
感想
特に何もとらぶるなく終わってしまうと何のノウハウも蓄積されないので微妙。
今後
TimeMachineとか試しに使ってみようかなぁ。
参考
更なる情報は参考元をどうぞ。
manは日本語もありますが、古いので"LANG=c"で英語を見るのをお勧めします。
- man netatalk.conf
- man afpd.conf
- man AppleVolumes.default
- http://en.gentoo-wiki.com/wiki/Share_Directories_using_AFP
- Apple辞書(Mac OS X 10.6内蔵)
- http://netatalk.sourceforge.net/2.0/htmldocs/configuration.html
LSI Logic 3ware 9750-4iを導入する(Gentoo Linux)
LSI Logic 3ware 9750-4iを購入したのでGentooLinuxに突っ込んだときのログです。カーネルモジュールの有効〜ユニットの作成までをまとめてみました。
中で触れていませんが、ユニットの作成は3BM(BIOSベース)や3DM2(ブラウザベース)でやった方が簡単です。
環境
カーネルモジュールを有効にする
下記、モジュール各々を有効にします。
Device Drivers SCSI device support <*> SCSI disk support [*] SCSI low-level drivers ---> <M> 3ware 97xx SAS/SATA-RAID support # 起動ディスクにする場合は、 initrdにモジュールを含めるか、*にする
tw_cliの導入
tw_cliを導入します。tw_cliは3ware向けのコンフィギュレーションツールです。9750シリーズは、バージョン10以降が必要になります。
インストールパッケージのダウンロード
自分でパッケージのダウロードが必要です(ダウンロード時にライセンスに同意しないといけないから?)。また、ダウンロード先は変更される可能性があるので注意です。
ダウンロード後"/usr/portage/distfiles/"にコピーします。
http://www.lsi.com/DistributionSystem/AssetDocument/cli_linux_10.1.zip
package.keywordsへの追加
$sudo sh -c "echo 'sys-block/tw_cli' >> /etc/portage/package.keywords"
ユニット(とボリューム)の作成
ユニット/ボリュームの作成を行います。ユニットとボリュームの詳細は備考欄をご覧ください。
まずは、tw_cliを起動します。
#tw_cli
コントローラオブジェクトの番号確認とフォーカスの移動
追加したRAIDカードが何番目のコントローラーオブジェクトに割り当てられているかを調べます。
実行すると下記のようになります。
//xx>show Ctl Model (V)Ports Drives Units NotOpt RRate VRate BBU ------------------------------------------------------------------------ c6 9750-4i 3 3 1 0 1 1 -
c6に割り当てられているのでフォーカスを変更します。
//xx>focus /c6
ディスクの確認
RAIDカードに接続しているディスクのポートを確認します。
VPort 0-2にディスクが接続されていることが確認できます。今回は0-2のディスクを用いてRaid5を構築します。
//xx>show Unit UnitType Status %RCmpl %V/I/M Stripe Size(GB) Cache AVrfy ------------------------------------------------------------------------------ VPort Status Unit Size Type Phy Encl-Slot Model ------------------------------------------------------------------------------ p0 OK u0 1.82 TB SATA 0 - ST32000542AS p1 OK u0 1.82 TB SATA 1 - ST32000542AS p2 OK u0 1.82 TB SATA 2 - ST32000542AS
ユニット作成
ユニットの作成はaddコマンドを用いて行います。
//xx>/c6 add type=raid5 disk=0-2
- type:raidの種類(raid0,1....)を指定します。今回はraid5を指定しています。
- diskに使用するディスクのポート番号を指定します。今回はp0-2を指定しています。
また、下記項目は任意設定項目です。変更する必要がないので変更していません。他の設定値は備考やマニュアルをご覧ください。
- Read Cache:標準で有効
- Write Cache:標準で有効
- 先読み処理:標準で有効
- ストリップサイズ:256kb
- 他
ユニットの確認
作成したユニットを確認します。まずはコントローラオブジェクトレベルからです。
u0が作成されています。
//xx>/c6 show Unit UnitType Status %RCmpl %V/I/M Stripe Size(GB) Cache AVrfy ------------------------------------------------------------------------------ u0 RAID-5 OK - - 256K 3725.27 RiW ON VPort Status Unit Size Type Phy Encl-Slot Model ------------------------------------------------------------------------------ p0 OK u0 1.82 TB SATA 0 - ST32000542AS p1 OK u0 1.82 TB SATA 1 - ST32000542AS p2 OK u0 1.82 TB SATA 2 - ST32000542AS
次にユニットレベルで確認します。u0/v0というボリュームが作成されています。
このボリュームが実際にカーネルからディスクとして認識されます。(ボリュームの詳細は備考をご覧ください)。
//xx>/c6/u0 show Unit UnitType Status %RCmpl %V/I/M VPort Stripe Size(GB) ------------------------------------------------------------------------ u0 RAID-5 OK - - - 256K 3725.27 u0-0 DISK OK - - p0 - 1862.63 u0-1 DISK OK - - p1 - 1862.63 u0-2 DISK OK - - p2 - 1862.63 u0/v0 Volume - - - - - 3725.27
以上で作成完了です。dmesgからディスクが認識されていることが分かります。
$dmesg scsi 6:0:0:0: Direct-Access LSI 9750-4i DISK 5.12 PQ: 0 ANSI: 5 sd 6:0:0:0: [sdc] 7812456448 512-byte logical blocks: (3.99 TB/3.63 TiB) sd 6:0:0:0: Attached scsi generic sg4 type 0 sd 6:0:0:0: [sdc] Write Protect is off sd 6:0:0:0: [sdc] Mode Sense: 23 00 10 00 sd 6:0:0:0: [sdc] Write cache: disabled, read cache: enabled, supports DPO and FUA sdc1 sd 6:0:0:0: [sdc] Attached SCSI disk
今回は約3.7TBのディスクを作成しました。2Tバイト以上のパーティションはMBR(現行PC/ATで使用されているパーティションテーブル)で扱えないのでGPTを必要とします。GPTの扱いについては http://d.hatena.ne.jp/ktomoya/20100912/1284256525 を参照ください。
備考
LSI Logic 3ware 9750-4iについて
選択した理由は単純に3wareが枯れているからという理由です。。。あとは、メモリキャッシュが欲しかったけです。
- 4ポートSATA+SAS 6Gb/s
- ロープロファイル対応
- x8 PCI Express® 2.0 インターフェース
- 512MB DDRII ECC cache (800MHz)
- バッテリーバックアップオプション対応
- 最大96ディスク接続可能
- RAIDレベル0, 1, 5, 6, 10, 50,Single Disk対応
- リビルドにおけるオートリジューム
- 再編成におけるオートリジューム
- 動作中にディスクのサイズ変更可能
- 動作中にRAIDレベルの変更可能
- Global hot spare with revertible hot spare support
- 自動リビルド対応
- Single controller multipathing (failover)
- I/Oロードバランシング
- 広範囲に渡るRAID管理スイート
ユニットについて
ユニットは複数のディスクを束ねたオブジェクトを指します。束ね方はraidtypeで指定します。
ボリュームについて
ユニットを任意の容量で切り出し、実際にディスクとして認識されるオブジェクトです。
ユニット作成コマンド引数詳細
ユニット作成コマンドの引数について少し細かく説明します。
# 全体 /cx add type=<RaidType> disk=<p:-p> [stripe=size] [noscan] [group=<3|4|5|6|7|8|9|10|11|12|13|14|15|16>] [nowrcache] [nordcache| rdcachebasic] [autoverify] [noqpolicy] [ignoreECC] [name=string] [storsave=<protect|balance|perform>] [rapidrecovery=all|rebuild|disable] [v0=n|vol=a:b:c:d]
- type:作成するユニットのタイプを設定します。 タイプにはraid0,raid1,raid5,raid6,raid10,raid50,single(ディスク1つでユニットを作成するときに選択する), spare(スペアディスクとして設定) と多数あります。
# RAID0を選択した場合(diskは0と1) //xx>/cx add type=raid0 disk=0:1
- disk:ユニットに割り当てるディスクを選択する
# p0〜p2とp4を選択した場合 //xx>/cx add type=raid6 disk=0-1:4
- stripe(任意):RAIDカードがデータを管理する際のブロックサイズの設定です。16KB,64KB,256KBから選択可能です(RaidTypeによって選択可能なサイズはことなりますのでマニュアル参照)。
# Stripサイズに64Kを指定した場合 //xx>/cx add type=raid1 disk=1:2 stripe=64
- v0,vol(任意):ボリュームのサイズを指定します。
-
- v0:1つ目のボリュームのサイズを指定します。残り領域はもう一つのボリュームが作成されます
- vol:先頭から4つまでの任意のボリュームサイズを指定できます。4つで全て使い切らなかった場合には、carveサイズ単位でボリュームを作成します(標準:1TB, 最大:32TB)。carveサイズは変更可能です。
-
# v0で1つ目のボリュームサイズ(1024GB)のみを指定する。 //xx>/cx add type=raid5 disk=0-2 v0=1024 # volで複数のボリュームを作成します。10GB,5GB,200GB,5GBで切っています。 # ディスクの残りはcarveサイズ単位となります。 //xx>/cx add type raid5 disk=0-3 vol=10:5:200:5
下記以降はマニュアルをどぞ。
- group=3,4,5,6,7,8,9,10,11,12,13,14,15,16
- noscan(任意)
- nocache,nowrcache(任意):ライトバックキャッシュを無効にするとパフォーマンスが非常に落ちるのでおすすめしません。(10MB/sとかになりました。。。)
- nordcache,rdcachebasic(任意)
- autoverify(任意)
- noqpolicy(任意)
- ignorECC(任意)
- name=string(任意)
- rapidrecovery=all,rebuild,disable(任意)
- storsave=protect,balance,perform(任意)
その他のコマンド
- /cx/ux del:ユニットを削除します
- /cx/ux migrate:作成済みのユニットの構成を変更します(RAIDレベルの変更やstripeサイズの変更など)
今後
- 3DM2入れてみる
- ベンチとってみる(ストリップサイズの違いで)
参考
公式のマニュアルです。。
2TBより大きいパーティション扱う(Linux)+HDDのアライメントについて
最近はHDDだと、2TBの製品もだいぶ安くなったので人によってはRAID5やRAID6と組み合わせて、4TBや6TBの容量のパーティションを作成する機会も増えてきたかと思います。
私のメインPCも2TB * 3なRAID5を導入したので、そのときに行った手順のログです。
// 気がついたらHDDのアライメントについての記事になってしまいました。。
やること
- kernelの GPTを有効にする
- partedの導入
- partedでパーティションを作成する
- 備考
GPTを有効にする
カーネルのGPTのコンフィグを有効にします。自前でカーネルのコンフィグを変更してたら行ってください。
下記を有効にします。
File System -> Partition type -> Advanced partition selection -> EFI GUID Partition support
また、上記付近にある"PC BIOS (MSDOS partition tables) support"は消さないように注意です。既存のパーティションをマウントできなくなります。
partedでパーティションを作成する
partedでパーティションを作成します。下記が手順になります。
$sudo parted /dev/[ブロックデバイス] >mklabel gpt >mkpart p [ファイルシステム名] 1M -1 >q
- mklabel gpt
GPTの作成を行います。これは、MBRにかわるパーティション管理領域形式です。
- mkpart p [ファイルシステム名] 1M -1
- p:プライマリパーティションの作成を指定しています。なお、GPTにはプライマリパーティションのみとなります。これは、パーティションが128個作成可能なためです。
- [ファイルシステム名]:作成するファイルシステムを指定します。ext4,ext3などです。なお、ファイルシステムを指定してもファイルシステムの作成は行われません(mkpartfsというコマンドを使用するとパーティションの作成とファイルシステムの作成を同時に行えますが、注意があるので、備考欄を見てください)
- 1M:パーティション開始位置の指定です。1Mとしているのはアライメント警告を回避するためです(後述のHDDのアライメントをご覧ください)
- -1:ディスクの終端を意味します。
備考
- GPT(GUID Partition Table)について
2TB以上の容量を認識するためにはMBRではなく、GPTでテーブルを作成する必要があります。GPTはIntelの提唱するEFIのサブセットです。
- MBRで2TBまでの理由
MBRではディスクの総セクタ数を4バイト(32ビット)で表しているので、単純に計算すると、下記になります!ちなみに、開始セクタ位置も4バイトです。
512Bytes/セクタ * 2^32セクタ * ( 1 / (1024 *1024 * 1024 * 1024))T = 2TB
- fdiskを使用しない理由
GPTに対応していないためです。GPT対応のfdiskもあったりします。
- mkpartfsについて
このコマンドは、パーティションの作成と一緒にファイルシステムの作成も行うコマンドです。ただし、manの注意書きにもありますが、このコマンドは使わないことを推奨されています。理由はext2progs等の公式の外部ツールを用いてファイルシステムを作成していないためです。
- 第一パーティション開始位置のアライメント
最近のHDDは物理1セクタ4KB(従来は512バイト)になっていて、それをHDD内で論理1セクタ512バイト(1物理セクタ=8論理セクタ)に置き換えて互換性を実現しています。
HDDの第一パーティションは懐かしのCHSで位置を表していた頃の名残で1シリンダ目からという制限がMSDOSの時代からありました(WindowsVistaでこの歴史がソフトウェアレベルでは終わりました。Vistaは第1パーティションを1MBで始めます)。これだけだと、あぁそうなんだって感じなのですが、シリンダの単位に問題がありました。
1シリンダ = 63LBA(LBA=512バイト)
なのですが、これ8で割れないんですよね。なので、書き込み時、読み込み時に2つ分の物理セクタにアクセスすることになります。どういうことかというと、4KBは8*512バイトで構成されています。ここで1パーティション目を63LBAで開始すると、
C0:[8+8+...+8+7] C1:[1+8+....] )
というように、C1の先頭512バイト分だけ余分に別の物理セクタから調達してくる必要が出てきます。で、さらにここでファイルシステムのブロックファイルは4KBです。なのでHDDへのアクセスは4KBで8論理LBA単位です。
先ほど63LBAでパーティションを切ったので、8の倍数分(4KB)アクセスされると毎回2物理LBAの領域を書き換える必要があります。つまり、データの読み書きを行う度に余分なセクタへのアクセスが発生することになり、IOのパフォーマンスに影響します(特にランダムアクセス)。
この問題を避けるために、HDDでは1シリンダ目のアライメントとして、無効な論理セクタ領域を割り当てて、物理セクタがはみ出ないようにしています。1シリンダ目の問題をパスすれば後はLBA単位で考えればいいのでアライメントの問題は回避できます。
無効[1] C0[7+8+8+...+8] C1[8+8+8+...]
で、1シリンダ目からパーティションを作る場合はこれで平気なんですが、1MBから作るとどうなるの?って問題になります。8で割り切れないのを回避するためにアライメントしているので、逆に8の倍数で切られると半端が出てしまうということです。
ただ、この辺はメーカやHDDのモデルごとに事情が変わってくるので、一概に1MBはだめってことにならないです。またWindowsが1MBでやり始めたのでメーカは追従してくると考えるととりあえず1MBでいいと考えるのが妥当です。
- Performance測定
時間見つけて、どの程度性能差が出るのか調べてみます。(2TBのディスクやRAIDカードで)
後書き
GPTのコンフィグを有効にしていないことに気がつくのに2週間かかりました。。。
EXT4のゼロレングス問題(zero-length problem)に対処したマウントを行う
ext4で問題となっているゼロレングス問題に対処するためのマウント方法です。
方法は、noauto_da_allocオプションを追加してマウントするだけです。
マウント方法
$sudo mount デバイス ターゲット -t ext4 -o noauto_da_alloc
ゼロレングス問題(zero-length problem)とは
特定のファイル操作によりファイル置換が行われたのちに、システムが強制終了したなどが原因でsyncが完了していない状態で終了した場合に0バイトファイルになってしまうというものです。
特定のファイル操作とは、
- fd = open("foo.new")
- write(fd,..)
- close(fd)
- rename("foo.new", "foo")
などのパターン、あるいは
- fd = open("foo", O_TRUNC)
- write(fd,..)
- close(fd)
パターンで、fsync() を使わないで既存のファイルを入れ替えることです。
原因は、アプリのファイル操作に問題があり、EXT4から追加されたファイルブロックの遅延アロケーションで問題が発生するためです。
fd = open("foo.new")/write(fd,..)/close(fd)/rename("foo.new", "foo") の場合
- ファイル生成
- リネーム処理
- 遅延アロケーション
の順番に処理が行われる。ファイル生成ー>リネーム処理の流れで行うため、2で電源断が発生すると、ファイルを生成してリネーム処理を行ったという操作がファイルシステム上で有効になり、データの書き込みは行われていないため0バイトとなってしまいます。
fd = open("foo", O_TRUNC)/write(fd,..)/close(fd)パターンの場合
- fooファイルを0バイトにする
- 遅延アロケーション
これも原理は同じで、1.が完了して電源断が発生すると、0バイトファイルになってしまいます。
noauto_da_allocがやっていること
やっていることは単純で、上記のような処理の流れをファイルシステム側で検知して処理の順番を変更し、データの書き込みが完了してからリネームを行うようにします。
- ファイルの生成
- データの書き込み
- リネーム処理
EXT4をSSD向けにマウントする
EXT4を用いて、SSDで用いられているTrimコマンドを使用するためのオプションです。
Trimコマンドを有効にする
方法は非常に簡単で、discardオプションをマウント時に渡すだけです。
- mountコマンドでマウントする場合
$sudo mount /dev/sd[0-9]+ /mnt -t ext4 -o discard
他のオプションと組み合わせる
他、SSDに有効なオプションとして relatimeがあります。これは、必要な場合を除いてアクセス時間(ファイルを最後にオープンした時間)を更新しないものです。
- mountコマンドでマウントする場合
$sudo mount /dev/sd[0-9]+ /mnt -t ext4 -o discard,relatime
備考
Trimコマンドとは、SSDに対して使用していた領域が不要になったことを明示するものです。
SSDはウェアリングという、1つのブロックが使い続けられて寿命が一部だけ寿命が縮まるのを防ぐ技術で、ある、ブロックへの書き込み指示が発生した場合、使用回数が少ない空き領域を割り当てて使用回数を平均化します。このときに、空き領域である必要があるのすが、通常のファイルシステムの場合、ファイルを削除するとディレクトリツリーからの切り離しだけを行います。
つまり、SSDにとっては不要になったのかどうかを判断できない訳です。それをTrimコマンドで明示することで、ウェアリングの効率を向上させることができます。