USB HDD自動マウント時のオプションをいじる  

概要  

Gnomeでの自動マウントにおいてマウントオプションを無理矢理カスタマイズしたときの記録です。

CentOS6にUSBハードディスクを接続したとき、ファイルシステムがvfatの時は以下のマウントオプションで自動マウントされます。

rw,nosuid,nodev,uhelper=udisks,uid=500,gid=500,shortname=mixed,dmask=0077,utf8=1,flush

ところが、データ処理を行う際、flushオプションによりディスク書き込みのパフォーマンスが低下し、結果として処理に非常に時間がかかってしまうという事象が発生しました(ext3の6倍ぐらい時間がかかる)。手動マウントでflushオプションを外してみたところ問題は解消されました。

例えばこういう理由で自動マウント時に適用されるマウントオプションを修正したい場合、ちょっとトリッキーな手順で実現してみましたのでメモしておきます。ここで示した方法だと自動マウント時の動作もカスタマイズできるはずです。

自動マウントの仕組み  

CentOS6では通常、USBのハードディスク等を接続すると自動マウントされます。USB接続時の自動マウントは歴史的な経緯もあり、AutoFS(automount)やHAL、udev、udisksなどで実現されており、いろいろあって非常にややこしいのですが、CentOS6ではudisksが使用されているようです。

完全に理解したわけではありませんが、udisksでは以下のような順序で実現しているようです。

  1. DBus(messagebus)にorg.freedesktop.UDisksサービスが登録される
  2. サービスとしてudisks-daemonが起動
  3. USB接続イベントに対してudisks-daemonがボリュームをマウント
    • mountを呼び出してマウントする

こんな感じです。

問題点  

私が調べた限り、自動マウント時のマウントオプションの変更はみなさん苦労しているらしく、根本的な解決方法はなさそうです [sad]。HALを使っている場合は/etc/hal/fdi/policy以下のファイルなどを修正するなどの解決方法があるようですが、udisksでの解決方法は見つけられませんでした(よくfstabに記述しろとかありますが、接続するUSBストレージ全般、という意味では適さない)。

ここに記録した方法では柔軟性はありますが、若干トリッキーな方法で実現していますのでGnomeのバージョンなどによって影響を受ける可能性があります。

解決方法  

オプション設定の原理  

以下のような方法で解決しました。

  1. udisks-daemonのヘルパープログラムディレクトリを指定する
  2. そのディレクトリに/bin/mountのラッパーとして動作するmountスクリプトを作成

ここで作成するmountスクリプトを使えば柔軟にオプションに対応できるはずです。つまり、マウント時に作成したmountコマンドが呼び出される→本来のmountにオプションを渡す、というやり方です。

実際の方法  

/usr/share/dbus-1/system-services/org.freedesktop.UDisks.serviceファイルを修正します。

[D-BUS Service]
Name=org.freedesktop.UDisks
Exec=/usr/libexec/udisks-daemon --helper-dir=/usr/libexec/udisks-opt-helpers <-- ここを修正
User=root

この設定ファイルはDBusにUDisksサービスを追加するためのファイルですが、そこでudisks-daemon起動時にhelper-dirオプションを追加します。
ヘルパープログラムはudisks-daemonがマウントなどを行う際に呼び出されるプログラムで、結局のところudisks-daemonもmountを呼び出して自動マウントを実現しています。straceで調べたところ以下順で探し、見つかったときに呼び出しているみたいです。

  1. (helper-dirで指定したディレクトリ)/mount
  2. /usr/libexec/mount
  3. /sbin/mount
  4. /bin/mount

つまりhelper-dirで指定したディレクトリにmountという名前の実行ファイルを置いておけば、マウント処理をフックできるというわけです。

そこで、以下のようなスクリプトを用意しました。シェルスクリプトは苦手なのでPythonで書きました。この例ではudisks-opt-helpersという名前にしていますが、セキュリティ上の問題(誰でも書き換えられるとか)がなければどこでもいいと思います(だたし、名前は必ずmountでなければいけません)。ファイルを作成した後実行属性をつけておきます。また、作成したmountはroot権限で実行されますので、危険なことはしないようにしましょう(原理上、USBを指した瞬間システムを消すような動作もできるはずです)。またセキュリティ上、1行目は使用するpythonの実体を指定した方がいいと思います(/usr/bin/env pythonとかじゃなくて)。

/usr/libexec/udisks-opt-helpers/mount
#!/usr/bin/python
import sys, subprocess
args = sys.argv[:]
if args[2] == "vfat":
    opts = args[4].split(",")
    if "flush" in opts:
        opts.remove("flush")
    args[4] = ",".join(opts)
args[0] = "/bin/mount"
subprocess.call(args)

引数は決まっているのでargs[2]でファイルシステムタイプを確認し、vfatの時、マウントオプションにflushが入っていたら除外する、という仕組みです。その後使用するmountは/bin/mount固定でいいと思います。Pythonなのでオーバーヘッドが気になりますが、マウントはそれほど頻繁に行う作業ではありませんのであまり気にする必要はないでしょう。

このスクリプトを応用すれば自動マウント時にあらゆる事が実現できるはずです。

結局半日ぐらい悩みました…

helper-dirを使わない場合

ここでは--helper-dirを指定しましたが、/usr/libexec/mountを作成すればhelper-dirオプションは不要です。標準ディレクトリに紛らわしい実行ファイルを配置したくなかったので、上述のようにしました。

コメント  

コメントなどありましたらよろしくお願いします。