注意: この記事の内容はわりと危険な部分があります. 使いたくなってもよく注意して理解して使ってください
わたしもまだ大して実動テストしてません. Dropboxの中身が消失したり, FSがこわれたり, なんかおもしろいことになっても責任は一切とれません. 技術的な観賞用に留めるのが無難です
はじめに
Dropboxがext4しか対応しなくなるらしいですね. btrfs愛用者としてはハチャメチャめんどいです. ということで, なんとかしたくなりますね.
1つの方法として, 下の記事のようにbtrfs上にext4のイメージファイルを作ってあげるという方法があります.
ただこの方法だと, kernelの中で無駄にext4をDropboxのためだけに動かすことになりますね. ext4のmoduleなんか置いておきたくない. そう思いませんか
システムコールの結果を書きかえる
なんとかDropboxをだましてみましょう.
Dropboxは, statfs()システムコールを使ってファイルシステムの種類を取得しているようです. では, このシステムコールの結果を書きかえてやればDropboxをだませるんじゃない?
statfs()システムコールを呼ぶと, 以下のstruct statfsが返ってきます. このうち, f_typeにファイルシステムのマジックナンバーが書かれています. ここをext4のものに書きかえてやればいいわけです.
gist1b945b7172bf97560cf9bf15aa73f5ce
livepatchで書きかえる
こんな時にべんりなのがLinux kernelのLivepatchなんですよ*1.
この機能を使うと, カーネルのいろんな関数を自分の書いたものに差し換えられてべんりです
statfs()システムコールを呼ぶと, いろいろあってuser_statfs()関数にたどりつきます. このコードは下のようにvfs_statfs()を呼んでいます. vfs_statfs()がさらにファイルシステムごとのstatfsの関数を呼びます.
本当はvfs_statfs()を書きかえると, fstatfs()システムコールにも対応できていいんですが, シンボルの解決が面倒なのでこっちで済ませます.
gist261c74c6dfdf19f76bdc58e829d99ae5
これを書きかえて, こんなふうな関数を作ります. vfs_statfs()が正しく終了したら, st->f_type
に EXT4_SUPER_MAGIC を書いてるだけです
gist5b144de1e2396aab8e717a63c39561f8
これにlivepatchするためのなんやかんやを書いて, kernel moduleとしてビルドできるようにしたものが, 以下のファイル
動かしてみる
これでDropboxをだませるんでしょうか? やってみましょう
まずは比較用にbtrfs上のdropboxをvanilla kernelで動かします. わたしは通知を表示するのにdunstを使っていますが, dunst -printで実行してやると, 通知内容を表示してくれるのでべんりです. その上でdropboxを起動すると, 以下のようにうるさい身勝手な通知がとんできてます
$ dunst -print { appname: 'Dropbox' summary: 'Move Dropbox by Nov 2018' body: 'Dropbox is on a file system that will no longer be supported. Details...' icon: 'dialog-information' raw_icon set: false category: timeout: 10000 urgency: NORMAL transient: 0 formatted: '<strong>Move Dropbox by Nov 2018</strong> Dropbox is on a file system that will no longer be supported. Details...' fg: #ffffff bg: #285577 frame: #aaaaaa id: 2 actions: { [default,default] } actions_dmenu: #default [Dropbox] script: (null) }
ついでにコマンドでも確かめてやるとこんな感じ
$ stat -f ~/Dropbox/ File: "/home/naota/Dropbox/" ID: 546b23f0cd0e1903 Namelen: 255 Type: btrfs Block size: 4096 Fundamental block size: 4096 Blocks: Total: 116433920 Free: 103094488 Available: 102796532 Inodes: Total: 0 Free: 0
Type: btrfsで怒られてますね〜
ここでさっきのlivepatch moduleをロードします. ロードすると, user_statfs()関数が自分の書いたlivepatch_user_statfs()に置きかえられます.
すると, statコマンドの結果が"Type: ext2/ext3"と変わります. さらにここでdropboxを起動しても, (なにも出てこてないので見せようがないが)さっきのうるさい通知が出てきません.
$ sudo insmod module/fake-ext4-v0.ko $ stat -f /home/naota/Dropbox File: "/home/naota/Dropbox" ID: 546b23f0cd0e1903 Namelen: 255 Type: ext2/ext3 Block size: 4096 Fundamental block size: 4096 Blocks: Total: 116433920 Free: 103096727 Available: 102798307 Inodes: Total: 0 Free: 0
めでたくDropboxを黙らせることに成功しました. やったぜ
しかし, これは随分と大ざっぱなことをやっています. dropbox以外でも全てのstatfs()の結果がext4に書きかわっているわけです. 大丈夫なんでしょうか?
たとえば, うちはFSのrootからbtrfsなんですが…これもext4に見えています.
$ stat -f / File: "/" ID: 546b23f0cd0e1852 Namelen: 255 Type: ext2/ext3 Block size: 4096 Fundamental block size: 4096 Blocks: Total: 116433920 Free: 103093875 Available: 102795927 Inodes: Total: 0 Free: 0
ここでbtrfsコマンドでsubvolumeの一覧を見るコマンドをたたいてみると……なんということでしょう, コマンドが動かなくなってしまいました
$ sudo btrfs subvolume list / ERROR: not a btrfs filesystem: / ERROR: can't access '/'
Dropboxのディレクトリだけ書きかえる
さっきの方法だとあまりに大雑把でいろいろ影響が出てきそうです. やばくならないうちに, livepatchを解除しておきましょう.
$ echo 0 | sudo tee /sys/kernel/livepatch/fake_ext4_v0/enabled
$ rmmod fake_ext4_v0 # しばらくたたないとダメな時もある
なんとかDropboxのディレクトリだけext4に見せかけることができないでしょうか?
これにはstatfs()に指定されたパスを見ていくなどいくつか方法はあると思います. うちではDropboxのディレクトリが個別のbtrfsのsubvolumeになっているので, ファイルシステムID(FSID)で識別することにしました.
さきほどの"stat -f ~/Dropbox", "stat -f /"のIDの部分を見てください. "~/Dropbox"では"ID: 546b23f0cd0e1903"で, "/"では"ID: 546b23f0cd0e1852"になっています. これは作成したファイルシステム固有のIDで, btrfsではsubvolumeごとに別のIDになります. ここでDropboxディレクトリかどうか見分けてやりましょう.
"stat -f"で見たIDを定義して, さっきはエラーチェックだけしていた部分にFSIDの比較を追加します.
gist5579cbbdea96629710934be8e86e777f
ではこれで, livepatchしてみましょう. moduleをロードしてstatしてみると? ちゃんと/はbtrfsでありながら, Dropboxはext4に見えています. もちろんdropboxも変な通知をとばしてきませんし, btrfsコマンドも動いている感じです.
$ sudo insmod module/fake-ext4-v1.ko
$ stat -f / ~/Dropbox/ File: "/" ID: 546b23f0cd0e1852 Namelen: 255 Type: btrfs Block size: 4096 Fundamental block size: 4096 Blocks: Total: 116433920 Free: 103093043 Available: 102795175 Inodes: Total: 0 Free: 0 File: "/home/naota/Dropbox/" ID: 546b23f0cd0e1903 Namelen: 255 Type: ext2/ext3 Block size: 4096 Fundamental block size: 4096 Blocks: Total: 116433920 Free: 103093043 Available: 102795175 Inodes: Total: 0 Free: 0 $ sudo btrfs subvolume list / ID 260 gen 79047 top level 5 path var/log ID 261 gen 79050 top level 5 path home/naota ID 262 gen 79045 top level 5 path var/tmp ID 263 gen 79003 top level 5 path etc ID 265 gen 23700 top level 5 path srv ID 266 gen 493 top level 5 path var/lib/portables ID 267 gen 494 top level 5 path var/lib/machines ID 340 gen 79045 top level 261 path home/naota/Dropbox
終わりに
Dropboxの中がやばいことになる可能性はあるので特に覚悟がなければ片付けておきましょう.
$ echo 0 | sudo tee /sys/kernel/livepatch/fake_ext4_v1/enabled
$ rmmod fake_ext4_v1 # しばらくたたないとダメな時もある
コードはここにまとめておきます. 覚悟があれば livepatchしてdropboxを黙らせてみるのもいいでしょう. kernelの更新で, user_statfs()が書き変わったら追従するなどしないとすごいことになることもあると思います.
*1:本来こんなことに使うのではないと思うが