Logo address

MacFUSE 9P Bridge

2013/03/24 更新
2016/02/17 補足追加
2017/06/08 9pfs 追加
2021/10/03 9PFUSE 更新 (最近の知識に基づいて大幅に書き換え)
2021/10/29 v9fs 追加
2021/11/17 評価 更新

Aug 2007
夏休みになって時間が取れたので懸案であった問題に取り組んでみた。
MacFUSE を使って Plan 9 ホストのファイルシステムを Mac のノートブックにマウントする実験である。ノートブックは PowerBook と MacBook を試した。いずれもマウントに成功した。

May 2017
退職して時間が取れようになったので懸案であった問題に取り組んでみた。MacBook の環境改善である。その一つに Plan9 サーバーのマウント問題がある。FUSE を使うのであるが、新しい OSXFUSE をインストールしたら使えなくなった。1か月ほど悪戦苦闘の末、動く様になったので、その成果を纏める。

FUSE

FUSE とは

Plan9 を除く普通のOSではファイルシステムのコードはカーネルの中に存在し、そのことが新しいファイルシステムをOSに組み込むことを困難(開発が困難なばかりか、OSの配布者以外は事実上配布不可能)にしていた。Plan9 ではファイルシステムのコードをカーネルの外に置き、カーネルにはファイルシステムとのインターフェースに関するコードを置く。この考え方はFUSE(Filesystem in Userspace)として他のOSでも採用されつつある1。

FUSE(Filesystem in Userspace) を使うと、ユーザースペースのプログラムによってファイルシステムを構成できる。このメリットは計り知れない。例えば

などを挙げる事ができる。ユーザはファイルシステムに対して多様なニーズとアイデアを持っており、カーネルを拡張する事なく、必要に応じてファイルシステムの一部として使えるようになった訳である。FUSE は現在カーネルに組み込まれている多くのファイルシステムを時代遅れのものとし、カーネルのスリム化に役立つであろう。

現在までに FUSE を基にした多様なファイルシステムが作成されているが、僕とっては sshfs が役に立っている。
また僕が作った FUSE のサンプル Maxim があり、MacOS, Linux, FreeBSD で動作が確認されている。
FUSE の面白さが分かるサンプルにしたつもりである。

ファイルシステムをユーザスペースで構成するアプローチは Plan 9 由来のものである。

FUSE に関する Russ Cox の批評

現在 Plan 9 の開発の中心になって活躍している Russ Cox は次のように述べている1

From: rsc@plan9.bell-labs.com
Subject: [9fans] user-level file systems for Linux
Date: 2004年2月19日 10:57:42:JST
To: 9fans@cse.psu.edu
Reply-To: 9fans@cse.psu.edu

There is a user-level file system driver for Linux called FUSE that has just released a new stable version:
http://sourceforge.net/forum/forum.php?forum_id=350517
They have user-level servers to mount various archives and various network protocols (http, ftp, smb).

The protocol itself looks fairly similar to the old 9P:
http://tinyurl.com/28f2y

There is another similar project called LUFS
http://lufs.sourceforge.net/lufs/
though it seems more complicated than necessary and makes at least one (imo) critical mistake: no fids.

Actually there have been a handful of projects doing similar things over the past few years, and they've all died out. I'm optimistic about FUSE because it's almost an exact translation of the VFS layer, meaning that it's simple and as expressive as possible.

Russ


注1: Bell-Labs の Plan9 は、開発チームが Google に移って以来、止まっている。9front 及び 9atom が Plan9 を引き継いでいる。特に 9front の動きは注目に値する。Russ Cox は Bell-Labs の Plan9 開発チームが解散して以来 Plan9 の開発に関わっていない。(2017-05-23)

MacFUSE (OSXFUSE)

MacFUSE は OS X 10.4 以降で使える。発行元の Google のページには次のように書かれている。

Examples of file systems that work and have been tested (to varying degrees) include sshfs, ntfs-3g (read/write NTFS), ftpfs (read/write FTP), wdfs (WebDAV), cryptofs, encfs, bindfs, unionfs, beaglefs (yes, including the entire Beagle paraphernalia), and so on.
(http://code.google.com/p/macfuse/)
SpotlightFS と sshfs しか Google のページには見つからないが、これらのプロジェクトに関しては
http://fuse.sourceforge.net/wiki/index.php/FileSystems
に詳しい一覧が載っている。(2017現在ではリンク切れ)

注意: MacFUSE は現在では開発が止まっており、OSXFUSE が後を継いでいる。(2016/02/17)
OSXFUSE は
https://osxfuse.github.io/
から手に入る。基本的な使い方は MacFUSE と同じなので、以下の説明は変更の必要はないであろう。
GITHUB には OSXFUSE のソースコードが付属しているのであるがコンパイルできない。コンパイルできれば動作についていろいろ調べられるのだが...
他のオプションは Plan9port に含まれる 9pfuse である(注1を見よ)。筆者はこれを使っている。
9pfuse の著者は Russ Cox で、彼は非常に有能であり、Rob Pike の良いパートナーでもある。
注1: この部分は正しくない。9pfuse は fuse をベースにして、9P サーバー(Plan9 のファイルサーバー)と接続できるようにしている。(2021-10-03)

インストール (OSXFUSE)

2017-05-23 更新

https://osxfuse.github.io/
からダウンロードすれば良いと思う。"FUSE for macOS" のパッケージが置かれており、最新版は2017年5月時点で 3.5.8 である。パッケージのファイルは osxfuse-3.5.8.dmg である。

このバージョンのネーミングは非常に誤解を招く。FUSE を使ったアプリケーションにとって重要なのはライブラリである。

ライブラリのバージョン選択に関しては以下の点に注意する必要がある。

この2つはアプリケーションのインターフェースが大きく違っており、FUSE を使ったアプリケーションの選択に影響を与える。
(Mac の場合には FUSE2 を使ったアプリは全滅するはずである)

注意すべきは osxfuse-3.5.8.dmg のインストールで生成されるライブラリは FUSE2 である事である。

インストールすると /dev/osxfuse0, /dev/osxfuse1,..., が作成される。

Plan9port の 9PFUSE は FUSE の API(ライブラリ) は使っていないが、FUSE の提供するカーネル拡張とマウンタを使っている。従って FUSE バージョンの影響を受ける。
さらに重要なことは、9PFUSE は現時点では osxfuse.3.x.x の下では動かない。 → 動く様にしました(2017/05/27)

Mac は OS のバージョンアップが激しく、その度にアプケーションは大きな影響を受ける。

動作の確認

(以下の記事は古くなっている可能性がある)

動作確認には SpotlightFS を使うのが簡便であろう。
Gogle のページには次の例が載ってはいるが...

$ mkdir /Volumes/SpotlightFS/Hasselhoff
$ ls -lrt /Volumes/SpotlightFS/Hasselhoff
[... output omitted to avoid embarrassment ...]
mkdir が効かない!

-bash$ mkdir /Volumes/SpotlightFS/Google
mkdir: /Volumes/SpotlightFS/Google: Permission denied
-bash$ ls -ld /Volumes/SpotlightFS
dr-x------   2 arisawa  arisawa  0 Aug 20 11:58 /Volumes/SpotlightFS
-bash$ ls -l /Volumes/SpotlightFS
total 0
dr-x------   2 arisawa  arisawa  0 Aug 20 11:58 SmarterFolder
-bash$

chmod も効かない!

-bash$ chmod 700  /Volumes/SpotlightFS
-bash$ ls -ld /Volumes/SpotlightFS
dr-x------   2 arisawa  arisawa  0 Aug 20 12:08 /Volumes/SpotlightFS
-bash$
これは使い方の説明が悪いのだ。ネット上の次の記事を見つけて解決:

正しい SpotlightFS の使い方

(以下の記事は古くなっている可能性がある)

まず SpotlightFS を立ち上げておいて

Finder ⇒ ファイル ⇒ 新規スマートフォルダ
によって検索する。それを「保存済みの検索条件」に名前を付けて保存する。するとその結果が
/Volumes/SpotlightFS/
に反映する。

macwiki http://macwiki.sourceforge.jp/wiki/index.php/MacFUSE の説明

SporlightFS を起動すると、「SpotlightFS」というボリュームがマウントされます。このボリューム内にディレクトリを作成すると、作成したディレクトリ名を使って Spotlight の検索がおこなわれ、その結果がディレクトリ中にファイルとして表示されるようになります。
が悪い! 次のように書き換えるべきであろう。
SporlightFS を起動すると、「SpotlightFS」というボリュームがマウントされます。ファインダーから新規スマートフォルダを実行し Spotlight の検索を行い、その結果を「保存済みの検索条件」に名前を付けて保存すると、その名前が「SpotlightFS」に生成されます。

References

Plan9port

2017/05/24

インストール

Mac の FUSE を使って Plan 9 のファイルシステムをマウントするには MacFUSE(OSXFUSE) の他に Plan9port が必要である。
Plan9port は PowerPC Mac、intel Mac 共にサポートしている。

Plan9port のコードは以下のサイトに置かれている。(いた)

Plan9port の作者は Russ Cox で、最初は彼の個人サイト swtch.com に Plan9port を置いていたが、彼が Bell-Labs から Google に移ってしばらくして code.google に移した。(彼は Google のコードサーチの作者でもある。) そして現在は GITHUB にコードを移して共同作業の体制をとってる。

GITHUB 版の Plan9port のインストールに関しては別ページに解説する。→ http:/p9p/index.html

Plan9port には Plan9 の使いやすいライブラリやコマンドが多数含まれており、特に rc は、unix 系の分かり難くて継ぎ接ぎの貧弱なシェルに比べると天地の違いであり、きっと好きになると思う。なお rc はスクリプト言語に特化しているので、コマンド環境として使うには rlwrap との組み合わせが良いと思う(コマンド履歴が使えるようになる)。

また Linux や FreeBSD のテキストエディタや xterm は貧弱で使いにくい。Plan9port の acme や 9term はきっと作業効率を大幅に高めると思う。

rc については以下の筆者の記事が参考になる。

9PFUSE

2021/10/03 大幅に書き換え

ネットの記事を見ていると FUSE の能力を示すデモとして sshfs が注目されているようだ。確かに sshfs は UNIX ユーザにとっては驚きであろう。しかし僕としてはこのようなまがい物ではなく、リモートファイルシステムとの本物のリンクが欲しい。Plan 9 の 9P2000 は本物だ。

9PFUSE を使う場合にはバグの修正が必要

2021/10/03 訂正

筆者の実験では

FreeBSD ではそもそも FUSE がまともに動かない1

Russ の Plan9port には認証に関するバグが含まれている。さらに Mac の場合、リモートホストにアップロードできない問題がある。
必要な修正に関しては、 http:/p9p/ に解説されている。

コマンドでの操作に関しては以上の修正で(現在のところ) Mac、Linux、FreeBSD で実用になっている。


注1. 次の記事を見つけた。まともに動かなかった理由も書かれている。新しいドライバの使い心地は後で、どこかでレポートしますからね
FUSE Driver Update
https://freebsdfoundation.org/blog/fuse-driver-update/
September 16, 2019

ndb/local

我が家のシステムではホスト hebe がファイルサーバー、認証サーバー、HTTP サーバーを兼ねている。僕が文房具代わりに使っているのは MacBook Pro であり、Plan9port はこれにインストールされている。以下、$PLAN9 をインストールディレクトリとする。

$PLAN9/ndb/localの設定:

# ndb - only used for authdial right now

# database - would add extra file= lines here
# probably need some kind of syntax to avoid hard-coding paths.

database
	file=root-servers

# authentication domains

authdom=outside.plan9.bell-labs.com
	auth=sources.cs.bell-labs.com
authdom=hebe.local

dom=local
	# we need this entry for non Plan9 client
	# the ns value is the name server for dom=local
	ns=hebe.local	# for speed up
	auth=hebe

#
#	--- WARNING ---
#	ipv4 must be first, then ipv6
#	otherwise ndb/ipquery does not work!
#

#	plan9port does not support il protocol
#	look $plan9/src/lib9/_p9dialparse.c
#

ipnet=local ip=192.168.0.0 ipmask=255.255.255.0
	ipgw=192.168.0.1
	proto=tcp
	auth=hebe
	fs=hebe
	dns=io
	# these values are advertised by DHCP or BOOTP. (look dhcpd(8))
	# we assume that dhcpd is running on the same ip. look /cfg/common/cpurc
	# search domains are given by dnsdomain
	# if query is ar, then ar.local and then ar.aichi-u.ac.jp is looked
	# they are not advertised by DHCP server
	# therefore DHCP client should add (if unix):
	#	search local
	#	search aichi-u.ac.jp
	#  are used only for ndb/dnsquery
	dnsdomain=local

sys=router
	dom=router.local
	# the IPs below are LAN side
	# ether=1066820ced19	# WAN
	# ether=1066820ced18	# LAN
	ip=192.168.0.1

sys=hebe
	dom=hebe.local
	ip=192.168.0.6
	# proto=il	# il is not supported in p9p

Plan9 ホスト

9front

Bell-Labs 純正の Plan9 は(チームが Google に移ったために)現在はメンテされていない。ここから派生した OS が2つある。9tom と 9front である。筆者は 9front を推奨する。推奨する理由は、
(a) Cinap の存在である。Cinap の能力は素晴らしく、僕のような凡人100人以上の力を発揮する。多分天才なのだろう。(それでいて謙虚であると言うか、優しくて親切なんだね)
(b) 9front を推奨する他の理由はファイルシステムに Ken Thompson の CWFS が採用されていることにある。こんなことを言うと Fossil のコードを書いた Russ には悪いが、Plan9 の Fossil は回避した方が良い。理由は(Venti との組み合わせで使うために)仕組みが複雑すぎる点にある。Ventiの設定が難しく性能が出にくい。僕が CWFS に移った時点では Fossil にはバグが残っていた。そのバグはまだ残っているかも知れない。Fossil を使う場合には Venti スコアの管理が重要である。このデータを失うと全てを失うことになる。僕が Fossil を使っていた時には、過去10回分のスコアを安全な場所に保管しており、それによって全滅を免れた経験がある1
(c) 9front が採用しているブートプロセスが素晴らしい。これは Cinap がいたから出来たのであろう。Plan9 のブートプロセスが抱えている問題点は、Bell-Labs にチームが存在すした時代から問題視されていたが、これが 9front で見事に解決されたわけである。Cinap は Rob Pike, Russ Cox に並ぶ天才である。


注1. この問題は現在では解決されているようだ (2021/11/23 追記)

CWFS

CWFS(Cached WORM FS) は WORM(Write Once Read Many) と、その cache の組み合わせで動く。この FS(File System) は Ken Thompson の設計とコーディングである。Ken Thompson のものは FS 専用に1つのコンピュータが要求されたが、Geoff によってユーザーランドのファイルシステムとして再設計された。

Plan9 のファイルシステムの最大の特徴は WORM をベースにしていることだろう。どの OS でもファイルは断片に分けて管理されるが、Unix などで採用されている普通のファイルシステムは(メデイアの価格が高価だった時代に設計されたこともあり)断片を再利用する。そのために断片の繋がりを示す情報を失うと致命的な問題を引き起こす。WORM では断片を再利用しない。1度作られた断片は消さないで残す。それによって過去のファイルシステムの履歴を残せるようになった。また断片はデバイスのパーティション上に積み上げ方式で作られていく。ファイルは1日の内で何度も修正されたり、作られたり、消されたりする。そうした1日の中で発生する全ての変化を WORM が直接扱う訳ではない。それらは WORM cache が処理する。 WORM cache は普通のファイルシステムであり cache の中のファイルは必要に応じて1日単位で WORM にダンプ(バックアップ)されると言う仕組みである。

CWFS は僕が全面的に信頼している唯一のファイルシステムである。僕は Plan9 を使うようになってから無停電源装置を入れたことがない。突然の電源OFFの場合に発生するダメッジは高々 cache にしか及ばない。cache が潰れても前日の状態には回復可能である。(業務用はともかく、個人用にはそれで十分である) WORM への書き込みは数分で終わるが、その間に電源 OFF になったらどうか? WORM には正常にダンプされたことを示すマークが積み上げのトップに書き込まれる。ダンプ失敗なら(多分)もう一度ダンプすれば良いだけであろう。推測でしか言えないのは、経験が無いからである。Ken Thompson のことだ、そこまで考えていると思う。

ハードディスクのような機械装置はやがては壊れる。従って結局は WORM のバックアップが欠かせないであろう。実際に僕もバックアップを取っていた。しかし最近はそれも止めた。理由は大容量 SSD が安価に手に入るようになったからである。SSD では可能な上書き回数はハードディスクに比べて少ないので unix などではサーバーには使われないのであるが WORM では上書きが発生しない。コストの面を別にすれば SSD は WORM に最適である。安くなったから僕は WORM のために1TBの SSD を使っている。多分使い切れないであろう。もちろん cache には小容量の SSD を別に割り当てている。

fscons

僕は記憶力が悪く(母によれば僕の子供の頃の病気が原因なのだそうだ) CWFS のコンソールへのアクセス方法が分からなくなるので覚えやすいコマンドを持っている。

fscons:

#!/bin/rc
if(test -e /srv/fscons)
	exec con /srv/fscons
if(test -e /srv/cwfs.cmd)
	exec con -C /srv/cwfs.cmd
echo 'no fscons'
ls /srv

ここで fscons を取り上げるのは、認証問題に関係しているからである。

CWFS は次のオプションを持っている。

これらはコンソールから noauthnonone で制御できる。僕にとって理解し難いのは、こうしたセキュリティセンシティブなコマンドがトグルになっていることだ。打ってみて初めてどうなったかが理解できる。(この問題は簡単なパッチで解決は可能である)

noauth

nonone

Plan9 をやっていて感じる難しさは認証に絡む問題である。認証プロセスを外すオプションは、認証以外の部分が正しく働いていることを確認する上で役に立つ。このオプションを使う場合には、もちろん、ルーターなどによって外部からのアクセスを遮断しておく必要がある1


注1. あるいはその他のユーザーとは world wide ユーザーであると割り切って管理することであろう

認証プロトコル

9front では新しい認証プロトコルが追加された。dp9ik である。これは p9sk1 の代替えである。p9sk1 は現在では古く、インターネットレベルで使用するには危険である。 Plan9port を使って Plan9 ホストに接続するには以下の点に注意を払う必要がある。

つまりインターネット環境から家庭などの Plan9 ホストに cpu コマンドなどによるアクセスを許し、かつ p9sk1 を使いたくない場合にはそれ用に認証サーバが必要になると言うことである。僕はそのためにもう一つの認証サーバーとして Raspi を使っている。

9front の標準設定では /rc/bin/service.auth/tcp567p9sk1 を禁止している。僕は Unix 環境からのアクセスを必要としているので家庭内ネットワーク用の認証サーバ(ファイルサーバーと兼用)で次のように古いプロトコルも(p9sk1)を許している。

#!/bin/rc
#exec /bin/auth/authsrv -N $3 	# -N disables old des key
exec /bin/auth/authsrv $3

ファイルサーバーの factotum キー:

key proto=p9sk1 dom=local user=arisawa !password=XXXXXX
key proto=dp9ik dom=local user=arisawa !password=XXXXXX
...

マウント

準備 (one time action)

筆者のコンピューターライフは殆どが居間で使う MacBook Pro である。(以下 mbook とする)
mbook からアクセスする Plan9 サーバーは hebe である。hebe はインターネットからは様々な名前で呼ばれる。例えば ar.nyx.link とか p9.nyx.link である。家庭内のパソコンのブラウザからもアクセスしたいので、そのために ar.local とか p9.local のような名前でも呼ばれる。かなり複雑なのであるが、以下では複雑な部分を省いて、関係していることだけを説明する。もちろん Plan9port がインストールされている必要がある。

mbook から hebe をマウントするために、以下のディレクトリが mbook に追加されている。

この構成にしたのは Plan9 のやり方に合わせたからである。Unix の教義によると、個人用のディレクトリは $HOME 以下に置くべきであって、そうした教義を信じる人から言えばクレームがつくであろうが、mbook は完全に個人使用であるので便利さを優先して構わない。
/n はホストのマウントポイントである。

hebe のマウントポイントを作ると仮定して、ユーザー(例えば arisawa)から

sudo mkdir /n /srv /mnt
sudo chown arisawa /n /srv /mnt
chmod 700 /n /srv /mnt
mkdir /mnt/factotum
mkdir /n/hebe
を実行しておく。(one time action)
/n の下に置くホストに関しては、後からいくつでも追加できる。筆者は sshfs でマウントする他の unix ホストの名前もここに登録している。その方が楽。

環境変数 NAMESPACE の設定が必要である。

NAMESPACE=/srv ; export NAMESPACE
これは $HOME/.profile にでも設定しておけばよい。

Plan9port のインストール時に $HOME/.profile

PLAN9=/usr/local/plan9 export PLAN9
PATH=$PATH:$PLAN9/bin export PATH
追加されたと思うが、ついでに確認しておく。$PLAN9は、Plan9port の置き場所で、ここでコンパイルしなくてはならない。(他の場所でコンパイルしてもよいが SYMLINK が必要になる)

/srv には Plan9 ホストとの接続が成功すれば、自動的に /srv/hebe などが生成される。

/mnt は認証エージェント factotum が使う。

接続実験 (認証なし)

初めてトライする人は CWFS を認証なしの設定にし、接続の確認をする。9p コマンドが役に立つ。

9p -a hebe ls
これで hebe 側の FS root が見えれば接続成功。もちろんパスワードは聞かれない。

成功したら以下のコマンドを順に実行してみよう。

-bash$ srv hebe
-bash$ ls /srv
hebe
-bash$ 9 mount /srv/hebe /n/hebe
-bash$ ls /n/hebe

/n/hebe へのマウントに成功しているはずである。

接続実験 (認証あり)

サーバーの設定を「認証あり、none お断り」モードにすると Plan9 port の mount は拒否される。この mount は内部で 9pfuse を使っている。既に述べたように、この問題は 9pfuse のバグが原因であり、必要な修正に関しては、
http:/p9p/index.html
に解説されている。

なお、

9 mount /srv/hebe /n/hebe
の先頭の 9 は 環境変数の PATH に依存しないで Plan9port のコマンドを明示的に指定して呼び出すのに使われる。同様に unix のコマンドを呼び出すには u を先頭につければよい。Plan9 の mount コマンドはシェルスクリプトで、内部では結局 9pfuse コマンドが実行されている。つまり
9pfuse /srv/hebe /n/hebe
としてもよい。

Plan9port の 9p コマンドは 9P サーバーとの接続のデバッグにおいて非常に役に立つ。このコマンドの機能は ftp の 9p プロトコル版だと思ってよい。通信状態の基礎が分かるのである。特に認証が正しく働いているか否かの判断が可能である。 9p コマンドは FUSE には関係していない。 Russ の mount のコードは FUSE に強く依存しており、FUSE が抱えている問題点がそのまま Russ の mount に反映される。Russ が FUSE のコードに問題を感じていてもままならない面があるのである。その点で、9p は 100% Russ であり、信頼性は高い。

クリーンな状態から出発すれば上記の通りになるはずだか、しばしは途中からになる。例えば factotum が認証データを得るのは one time action に近い。
他方、1日の内に何回でも サーバーへの mount や unmount が発生する。そうした場合には発生しがちなエラーを整理する。

Address already in use:

-bash$ srv -a -k 'dom=local' hebe
9pserve: announce unix!/srv/hebe: Address already in use
srv: post9p: 9pserve failed
-bash$ rm /srv/hebe 	# and retry

Address already in use:

-bash$ factotum -a hebe
9pserve: announce unix!/srv/factotum: Address already in use
factotum: post9pservice factotum: 9pserve failed
-bash$
このケースでは認証ずみの場合である。

mount point /n/hebe is itself ...:

-bash$ 9 mount /srv/hebe /n/hebe
mount_osxfusefs: mount point /n/hebe is itself on a OSXFUSE volume
-bash$ unmount /n/hebe 	# and retry
なお unmount は Plan9port のコマンドである。

Connection refused:

-bash$ 9 mount /srv/hebe /n/hebe
9pfuse: dial /srv/hebe: connect /srv/hebe: Connection refused
認証されないとか...

診断とクリーンアップ

僕の診断プログラム
http:p9p_chk
http:me
中身を見て、各自の環境に合わせてください。
うまく行かないときのヒントになるかも知れません。

またクリーンアップしてやり直ししたいこともあろう。
http:un9fs
one time action の部分は残している。

9pfs

2017/06/08

9pfuse に代わって

ネットを検索していると、9pfs と言うのに出会った[1]。これは Russ の 9pfuse の置き換えを狙っているらしい。こののサイトによると、9pfuse に比べて相当に速いらしい。(キャッシュのお陰だと思う)

Russ は FUSE のライブラリを使用せずに、FUSE のカーネルだけを直接的に利用してコードを書いている。他人の書いたコードに依存したくないのであろう。Russ ほどの力量があればこそ可能な事である。実際に Russ のコードはシンプルで良くわかる。他方 FUSE のライブラリのコードを見ていると、何で... と思う部分が多い。

9pfs の方は FUSE のライブラリを利用している。少々手を加えればコンパイルは成功する1


注 1: 現在は少しでは済まない。もはや Linux ではコンパイルできない。これは本質的であって 9pfs で使う fuse.h が手に入らない。しかし Linux の場合には 9mount で代用できて、この方がずっと良い。Mac は1行の追加で済む。"#undef MSIZE" を入れればよい。FreeBSD ではかなり変更が発生するが、コンパイルは可能である。しかし肝心の FUSE がダメである。(2021-11-17)

コードの修正

libc.h

 typedef uint32_t u32int;
 typedef int32_t s32int;
 typedef unsigned char uchar;
+typedef unsigned long ulong;
 typedef unsigned long long uvlong;
 typedef long long vlong;

9pfs.c

 		size = CACHECTLSIZE;
 		if(off >= size)
 			return 0;
-		memcpy(buf, "cleared\n" + off, size - off);
+		memcpy(buf, &("cleared\n"[off]), size - off);
 		clearcache(path);
 		return size;

9p.c

つまらない GNU 拡張が使われているために数10行の修正が必要になっている。

問題の部分は

char *calls2str[] = {
  [Tversion]	"Tversion",
  [Tauth]	"Tauth",
  [Tattach]	"Tattach",
  ...

これは clang で蹴られる。この部分は

char *calls2str[] = {
  [Tversion] =	"Tversion",
  [Tauth] =	"Tauth",
  [Tattach] =	"Tattach",
  ...
で書き換えれば解決する。

それにしても GNU は、こんなに詰まらない(酷い)拡張をするのだね~~~
拡張というのは、常に副作用を伴う。従って、拡張が許されるのは相当な理由(合理性)が無くてはならない。例えば、論理的、必然的にあるべき姿が実現していない場合は許されるだろう。しかし、この場合には、文法エラーになって当然の書き方を、1文字の入力の節約のために許してしまおうとする拡張であって、コンパイラのバグと見なして良いものだ。

9pfs.tgz

コードを修正してパッケージにしたものを次に置く。
http:9pfs.tgz

Makefile_osxMakefile_bsdMakefile_linux を新たに含めた。
MacOS、FreeBSD、Linux でコンパイルできる事が確認されている。

FreeBSD ではマウントが NG である。(何しろ FUSE が NG)

MacOS と Linux ではマウントは OK。しかし、僕はまだ使い込んでいない。

使い込めば、修正が必要な箇所が他に発見されるかも知れない。

使い方

マウントは 9pfs で統一したいと思っても、factotum とミスマッチがあるらしい。

筆者の環境では

-bash$ factotum -a hebe
-bash$ 9 mount /srv/factotum /mnt/factotum
-bash$ export FACTOTUM=/mnt/factotum
-bash$ 9pfs -a hebe /n/hebe
!adding key: role=client proto=p9sk1 dom=local
user[arisawa]:
password:

ここに

あるいは、譜の最後の 9 mount に代わって

9pfs -U /srv/$1 /n/$1
としてもよい。

追加コメント

使ってみて

FUSE API の限界

FUSE では setattr が使えると思っていたが、fuse-2.9.7 のコードを見ている限り、使えるのは FUSE kernel との low level interface みのであって、普通のプログラマが使う API レベルではサポートされていない。

9pfs では API レベルを使っているので setattr がサポートされていない。そのために local のファイルをホスト側にコピーしたときに、元のファイルが持っていた時刻情報(atimematimeなど)まで含めてコピーできない。この事が問題なら 9pfs は使えない事となる。

Russ が 9pfuse で FUSE API を使わなかった理由の1つかも知れない。

その内に解決される可能性は高いのだが...

u9fs がマウントできる

Russ の 9pfuse は unix ホストの u9fs をマウントできないが1、9pfs だとマウントできる。
もっとも unix から unix ホストのマウントは、現在では sshfs で間に合うだろう。

注1: 可能かもしれないが、筆者はまだ成功していない。成功しました(2021)

いろいろな「9pfs」

ところで「9pfs」と言うのはいろいろあるらしい。
記事[1]のコードは Mischief のもの。(コードを見る限り、Mischief は几帳面だね...)
記事[2]から推測すると py9p プロジェクトの副産物としての 9pfs。これは、Saveliev と Mirtchovski による開発である。

前者では

Usage: 9pfs [-anU] [-A aname] [-p port] [-u user] service mtpt
で、これはクライアント仕様。

後者では

Usage: 9pfs [-dDw] [-c mode] [-p port] [-r root] [-a address] [user [domain]]
これはサーバー仕様。

また記事[3]によると、「9pfs」は 9P プロトコルの別名としても使われているらしい。

なお記事[4]には、9P の実装が多数紹介されている。(いつの間にか、こんなに...)

[1] 9pfs
https://github.com/mischief/9pfs

[2] 9pfs man page
https://www.mankier.com/1/9pfs

[3] Xen transport for 9pfs version 1
https://xenbits.xen.org/docs/unstable/misc/9pfs.html

[4] 9P Implementations
http://9p.cat-v.org/implementations

v9fs

2021/10/29

これは残念ながら Mac の話ではなく Linux の話である。
何年か前から v9fs が Linux のカーネルに標準装備されていて mount コマンドの "-t 9p" でマウントできるようになっている。v9fs は Plan9 ホストとの本物のリンクである1。このことに気付いたのは Linux の plan9port を更新したあとに mount コマンドの様子が違っていたからである。コードを見るとで、Linux では

/bin/mount -t 9p ....
が実行されるようになっている。

残念ながら v9fs を利用した mount は root 特権を要する。この問題はやがては改善されるだろうが、今のところ我慢である。しかし root 特権を使うことと、plan9port の mount コマンドは両立し難い。(非常に使いにくくなる)

幸い誰かが 9mount コマンドを準備してくれた。これは

sudo apt install 9mount
でインストールできる。マニュアルは[2]から手に入る。

これを使うと

9mount -i hebe /n/hebe
で簡単に、僕のサーバー hebe/n/hebe にマウントできる。
実際に 9p でマウントされていることは
maia$ /bin/mount
...
192.168.0.6 on /n/hebe type 9p (rw,relatime,sync,dirsync,uname=root,access=any,trans=tcp,noextend)
maia$
で確認できる。maia は Linux クライアントである。

なお sudo が不要だったのは

maia$ ls -l /usr/bin/9*
-rwsr-xr-x 1 root root 14328  9月  5  2018 /usr/bin/9bind
-rwsr-xr-x 1 root root 18584  9月  5  2018 /usr/bin/9mount
-rwsr-xr-x 1 root root 14328  9月  5  2018 /usr/bin/9umount
maia$
だからである。

オプション "-i" を添えないと、uid, gid のマッピングがひどい状態になり、書き込みができなくなるはずである。9mount 自体は認証に関わらない。従ってこのままでは高々 user none としてしかマウントされない。この問題に関して 9mount の著者(sqweek さん)に問い合わせたら、返事があって解決の方法が示された。maia で次のコマンドを実行すればよい。

srv -a hebe
9mount 'unix!/srv/hebe' /n/hebe

"src" は Plan9port のプログラムである。"srv -a hebe" で hebe と認証付きのコネクションを張ってくれ、接続口を /srv/hebe に作ってくれる。これを 9mount でマウントすればよいとのこと。昔、このことが話題になったことがあったとのことで、次のアドレスを示してくれた。
https://groups.google.com/g/comp.os.plan9/c/0WPz3Iwl3tc?pli=1
実験すると、srv コマンドは factotum を参照するように作られているので使いやすい。(Russ の作だから当然!)

残念ながら macFuse は plan9port の mount とは相性が悪いらしく、不安定である。Linux を経由して我が hebe にマウントすれば気持ちよく使える。Mac においても v9fs がサポートされる日が早く来るのを期待したい。Windows にすら v9fs が組み込まれているらしいから。

追記: macOS でも 9P が正式に使えるようになった[4]。 しかし僕の MacBook は古くて、OS のバージョンアップができない... 僕は20年間も Mac の 9P を追い求めてきたにも関わらずである。
これで OS 分野の Big three が 9P を公式にサポートすることになったのである。従って file service に関しては間違いなく 9P で統一される。現在様々な file service protocol 例えば cifs, nfs, webdav などがまだ使われているが近い将来には全て廃止されるであろう。(2021)

[1] v9fs: Plan 9 Resource Sharing for Linux
https://www.kernel.org/doc/html/latest/filesystems/9p.html

[2] 9mount
http://manpages.ubuntu.com/manpages/jammy/man1/9mount.1.html

[3] Windows 10 WSL: mount creates 9p filesystem instead of drvfs
https://superuser.com/questions/1643551/windows-10-wsl-mount-creates-9p-filesystem-instead-of-drvfs

[4] mount_9p(8) [mojave man page]
https://www.unix.com/man-page/mojave/8/mount_9p

評価

2021/11/17

Plan9port の 9pfuse は2つの問題を抱えている:
(1) 認証プロセスをサボっている
(2) サーバーのファイルスペースの残り容量を0にしてしまっている

これらはいずれも簡単に解決できる。( http://p9.nyx.link/p9p/ を見よ)

Linux では 9Pfuse は安定していて文句は無い。Mac では Linux 程安定していない。原因は(多分) 9Pfuse が作られた環境にあるのだろう。FreeBSD では全くダメである。9pfuse どころか FUSE もまともに動かない。

Mac 付属のテキストエディタ TextEdit.app や Xcode.app では、(拡張属性が邪魔をして)編集した結果を保存できない1。Plan9port の acme は OK である。他に mi.app や atom.app などが問題なく使える。

ところで最近の TextEdit.app は(僕にとっては)非常に使いにくくなっている

なお僕は edit コマンドを作って持っており、TextEdit.app で読み取る前に xattr を削除することとした。
関係するコードは次の通りである。(rc で書かれている)

xa=`{xattr $e}	# extended attribute
if(~ $xa ?*)
	xattr -d $xa $e
open -a $EDITOR $e || echo $usage
ここに、$e は編集の対象となっているファイルである。

macOS の 9P プロトコルの公式サポートは、このページに書いた記事を完全に過去のものにするだろう。苦労せずに他の OS のファイル空間を Mac 側に取り込める時代になったのだ。もっとも僕の MacBook は古くて、新しい macOS をインストールさせて貰えない。


注1: TextEdit.app はファイルの保存時に必ず拡張属性も合わせて保存する。不思議なことに、9pfuse でも 9pfs でも拡張属性の上書きができない。その場合には、TextEdit.app はファイルの上書き(つまり保存)を拒否するようだ。

References

9PFUSE の古い記事 (参考程度に)

実験環境

クライアントは Mac のノートブック。僕は Mac のノートブックを2つ持っている。PowerBook と MacBook である。いずれも OSX 10.4 環境下で動いている。以下それらを各々 pbookmbook と呼ぶ。どちらで行っても動作に違いはない。そこで、ここでは pbook での実験のみを示す。

マウントするリモートホストは 3 つを試した。

pc
自宅のデスクトップの Plan 9 端末で、端末と言っても実際にはサーバと同様なサービスを行っている。認証サーバを持たずに、単体で動いている。Factotum と venti を備えている。
ar
大学の Plan 9 の CPU サーバー
pmac
自宅のデスクトップの Mac で u9fs が動いている。
太字で示したのはマシン名であり、以下この名前で説明する。

pbook のディレクトリ構成

ここでは Plan 9 端末風にディレクトリを構成する。メリットは
注意: X11 は intel Mac ではサポートされていない。また X11 のユーザーインターフェースは Mac ユーザにとっては使いやすいとは言えない。

逆にデメリットは、

事にある。最後に述べたデメリットり関しては、ノートパソコンであるから問題にはならない。

pc のマウント

実験した日には研究室にある認証サーバ hera は停電のためにダウンしていた。しかし pc は認証サーバーと関係なく動いているので問題はない。

pc に接続するためには、pc の factotum には次の内容が必要である。

key dom=pc proto=p9sk1 user=arisawa !password=xxxxxxxx
xxxxxxxx はパスワードである。

以下にマウントに至るまでの pbook で実行するコマンド手順を示す。

-bash$ mkdir /srv   # needs only once
-bash$ mkdir -p /n/pc  # needs only once
-bash$ mkdir -p /mnt/factotum  # needs only once
-bash$ NAMESPACE=/srv
-bash$ export NAMESPACE
-bash$ factotum
# it may be required to execute here (added 2016)
# -bash$ 9 mount /srv/factotum /mnt/factotum
-bash$ 9fs pc

!adding key: role=client proto=p9sk1 dom=pc
user[arisawa]:
password:
!
-bash$ 9 mount /srv/pc /n/pc
kextload: /System/Library/Filesystems/fusefs.fs/Support/fusefs.kext loaded successfully
-bash$ ls /n/pc
386             NOTICE          cfg             lp              rc
68000           acme            cron            mail            sparc
68020           adm             dist            mips            sys
LICENSE         alpha           env             mnt             tmp
LICENSE.afpl    amd64           fd              n               update
LICENSE.gpl     arm             lib             power           usr
-bash$

ディレクトリ /srv/n/pc はあらかじめ作成しておく。また NAMESPACE の設定と export.profile で行うのが良いであろう。

9 コマンドは Plan9port のコマンド名が UNIX のコマンド名と衝突する場合に Plan9port のコマンドを実行してくれる。

factotum を実行すると /srv/factotum が生成される。"9fs pc" を実行すると /srv/pc が生成される。/srv に生成されたものはソケットである。

Plan 9 の 9fs はマウントまでやってくれるが、Plan9port の 9fs はやらない。9fs は rc スクリプトで内部で srv を実行している。また、Plan9port の mount も rc スクリプトで、ソースを見るに BSD 系の OS に対しては 9pfuse を実行している。

以下にマウントされた時の Mac の Finder を示す。

Finder に反映された MacFUSE

Factotum の ctl にアクセスする。

-bash$ mkdir -p /mnt/factotum     # needs only onece
-bash$ 9 mount /srv/factotum /mnt/factotum
-bash$ ls /mnt/factotum
confirm conv    ctl     log     needkey proto   rpc
-bash$ cat /mnt/factotum/ctl
key dom=pc proto=p9sk1 role=client user=arisawa !password?
-bash$

factotum にデータを追加するには

echo key 'dom=aichi-u.ac.jp proto=p9sk1 role=client user=arisawa !password=xxxxxxxx' >> /mnt/factotum/ctl
のように ">>" を使う必要がある。(Plan 9 の factotum の場合には ">" で構わない。)

削除するときにも同様である。

問題点

ls -l を実行してみると UNIX の限界がよく分かる。

-bash$ ls -l /n/pc
total 85
drwxrwxr-x   1 arisawa  arisawa      0 Jun 27 17:24 386
drwxrwxr-x   1 arisawa  arisawa      0 Jan 31  2007 68000
drwxrwxr-x   1 arisawa  arisawa      0 Jan 31  2007 68020
-r--r--r--   1 arisawa  arisawa  13006 Jul 13  2005 LICENSE
-rw-rw-r--   1 arisawa  arisawa  14333 Jun 29  2003 LICENSE.afpl
-rw-rw-r--   1 arisawa  arisawa  15081 Jun 26  2003 LICENSE.gpl
-r--r--r--   1 arisawa  arisawa     63 Apr 15  2002 NOTICE
drwxrwxr-x   1 arisawa  arisawa      0 Jan 31  2007 acme
...
オーナーやグループはどれも arisawa になっているが、本来は sys である。UNIX ではファイルシステム毎にファイルのユーザとグループを決める事ができないので、リモートファイルをマウントした時にローカルファイルシステムのユーザとグループで適当にマッピングする他ない。ここでは全て arisawa にマッピングされているのだ。その場合にはファイルに対する arisawa の本来のアクセス権を知る事ができない。

コマンドでファイルにアクセスする限り、実際にアクセスして拒否されれば知らせてくれる。しかし Mac の Finder を通じてマウスでクリックしていると状況が異なる。Finder は余計な親切をしているのだ。それがあだになって読み取れるはずのファイルが読み取れない事もある。(Finder は正しいメッセージを出していない!)

このような問題は UNIX と Plan 9 と言う異質な OS を結んだから発生したのではない。 UNIX 相互でも管理者ドメインが異なれば同じ問題が発生する。UNIX がネットワーク環境に適合しないと言われる根拠の一つになっている。

参考のために Plan 9 端末から u9fs を使って UNIX (Mac OSX) をマウントした場合の ls -l を示す

--rwxrwxrwx M 29 arisawa staff    6148 Apr 24 22:05 .DS_Store
d-rw------- M 29 root    ???       272 Aug 29 06:34 .Spotlight-V100
d--wx-wx-wx M 29 root    admin     170 Feb 23  2006 .Trashes
[中略]
d-rwxr-xr-x M 29 arisawa staff    1360 Jan 26  2003 システムフォルダ
d-rwxrwxr-x M 29 root    admin     340 Sep 13  2002 書類
d-rwxr-xr-x M 29 arisawa admin      68 Jan 26  2003 起動時に消去する項目
グループ名の欄の "???" は元は数字であった。この変更以外は本来のユーザ名とグループ名が正しく表示される。Plan 9 の場合にはマッピングの必要はないのである。

ar のマウント

ar は研究室に置かれている Plan 9 システムの CPU サーバである。ファイルサーバーの /lib/ndb/local で、ar の認証サーバーとして hera が指定されている。また ar の factotum は
key dom=aichi-u.ac.jp proto=p9sk1 user=arisawa !password=xxxxxxxx
である。(xxxxxxxx はパスワード)

ar の認証ドメインは aichi-u.ac.jp であるが、factotum には認証サーバーに関する情報が含まれていない。従って pbook から ar をマウントするには ar の認証サーバーが何であるかを知らせる必要がある。この事は $PLAN9/ndb/local で行える。僕のケースでは

authdom=aichi-u.ac.jp
	auth=hera.aichi-u.ac.jp
を追加した。これを追加すれば、マウントまでの手順は pc と同じである。
hera.aichi-u.ac.jp は NetInfo に登録しておかなくてはならない。

pmac のマウント

これは unix (like) から unix (like) へのマウントである。

pmac は自宅の PowerMac G4 で、ここでは u9fs が動いている。pmac は Plan 9 端末からはマウントできる。しかし不思議な事に pbook からは(pmac からも)マウントできない。
この問題は現在においても解決できない。9fans ではマウントできるとの情報もある。(2016/02/17)

-bash$ 9fs pmac
authdial: Connection refused
原因不明

取り消し

mount

マウント
9 mount /srv/ar /n/ar
の効果は unmount
9 unmount /n/ar
で取り消せる。

9fs

9fs ar
の効果を取り消すには次のようにする。
-bash$ ps
  PID  TT  STAT      TIME COMMAND
24157  p1  S      0:00.46 -bash
24276  p1  S      0:00.51 factotum
24278  p1  S      0:02.51 9pserve -u unix!/srv/factotum
24289  p1  S      0:40.18 9pserve -u -M 8192 -A  0 unix!/srv/ar
24306  p1  S      0:11.60 9pserve -u -M 8192 -A  0 unix!/srv/pc
24198  p2  S+     0:00.07 -bash
-bash$ kill 24289
-bash$ ls /srv
ar              factotum        pc
-bash$ rm /srv/ar
-bash$
Plan 9 の場合には /srv/ar だけを消せば良かったが、Plan9port ではプロセスも落とさなくてはならない。

factotum

factotum を取り消すには
-bash$ ps
  PID  TT  STAT      TIME COMMAND
24157  p1  S      0:00.53 -bash
24751  p1  S      0:00.01 factotum
24753  p1  S      0:00.01 9pserve -u unix!/srv/factotum
24198  p2  S+     0:00.07 -bash
-bash$ kill 24751
-bash$ rm /srv/factotum
-bash$

この後に

unmount /mnt/factotum
が必要かもしれない。

"9pserve -u unix!/srv/factotum" は factotum によって生成されたプロセスで factotum を落とせば自動的に落ちるが、/srv/factotum は削除しなくてはならない。

診断

以下に実験中に出会ったエラーについて解説と対処法を付ける。
なお、pc とか ar は実験当時に筆者が使用していたホスト名である。
また pmac は実験当時に僕が(Plan9port をインストールして)使っていた PowerBook の名称である。

実験では 9fs は Plan9port 付属のものをそのまま使用していた。譜を使えは、もっとスムーズに行く可能性がある。

unknown host

bash$ 9fs pc

!adding key: role=client proto=p9sk1 dom=home
user[arisawa]:
password:
!
authdial: unknown host home
bash$
原因: pc 側の factotum の誤設定
dom=home となっていた。$PLAN9/ndb/local の設定と一致していることを確認する。

unable to find common key

-bash$ factotum
-bash$ 9fs ar
srv: authproxy: auth_proxy rpc: p9any client ask for keys: unable to find common key
-bash$
この問題は $PLAN9/ndb/local の設定を行う事で解決したはずである。

Result too large

-bash$ echo key 'dom=aichi-u.ac.jp proto=p9sk1 user=arisawa !password=xxxxxxxx'>/mnt/factotum/ctl
-bash: /mnt/factotum/ctl: Result too large
この問題は ">>" を使う事によって解決する。

can't mount on Darwin

-bash$ 9 mount /srv/pc /n/pc
can't mount on Darwin
-bash$
これは pmac から pc をマウントするときに出た。原因は pmac の Plan9port が古い事による。最新の版をダウンロードしてインストールすれば解決する。

Connection refused (1)

2016/02/17

このメッセージはマウントするときに発生する。例えば

-bash$ 9 mount /srv/hebe /n/hebe
9pfuse: dial /srv/hebe: connect /srv/hebe: Connection refused

原因は認証されないままマウントを試みたからだろうと思われる。

参考のために、実行すべきコマンドと、その結果として生成されるファイル("→" で示してある)を以下に示しておく。
"*" はそこに名前が存在することを意味する。また"#" より右はコメントである。

  1. factotum # → /srv/factotum
  2. 9 mount /srv/factotum /mnt/factotum # → /mnt/factotum/*
  3. 9fs HOST # → /srv/HOST
  4. 9 mount /srv/HOST /n/HOST # → /n/HOST/*
認証は 9fs で行われているので、/mnt/factotum/ctl が存在すれば、(このケースでは)
9fs hebe
を実行してから、再度マウントを試みる。

なお譜だと "9fs HOST" でマウントまで進むはずである。

Connection refused (2)

2016/02/17

認証を求めようとして 9fs で次のメッセージに出会うことがある。

-bash$ 9fs nix
authdial: Connection refused

相手ホストは Linux で、こちらは Mac である。
今のところ筆者は unix 相互のマウントに成功したことがない。

注: Connection refused の発生要因として多いのは、閉じている port へのアクセス。(2017/06/13)

fid unknown or out of range

2016/02/17

-bash$ 9pfuse /srv/mmac /n/mmac
9pfuse: fsmount: fid unknown or out of range
-bash$

これは macbook から mac mini へのマウントで発生する。もっと一般的に言えば unix (like) から u9fs へのマウントで発生する。原因は認証が正しく行われていないからだろうと思えるが、「Connection refused」との違いが今のところ分からない。

mount point XXX is itself on a OSXFUSE volume

2016/03/03

既にマウントされている XXX にさらにマウントしようとした。

unmount XXX
で解決する。