xattr on jffs2

ひとまず、EBS(Erase Block Summary)を有効にした状態で、SELinuxのセキュリティコンテキストを格納して安定的に動作するのには上手くいった。

先日のSELinuxユーザ会の集まりで、何人かにJFFS2のXATTRサポートについて質問されたし、David Woodhouseもマージしたいとは言ってるので頑張って作らないと。

ただ、現状ではPOSIX-ACLの動作でちょっとおかしいところが見受けられるので調査中。パッチの公開にはもう少し時間がかかるか…。
ACLを設定したファイルに対して上書きオープンを行おうとすると、-EINVALが返却される。EINVALというのが意味不明

[追記]
ファイル hoge にACLを設定した場合

% cat 1KB >> hoge    → こっちはOK
% cp /root/1KB hoge
cp: cannot create regular file `hoge': Invalid argument

となってしまう。
調べてみたところ、open()に O_TRUNC フラグを付けて呼び出した場合に、既存ファイルに対するTruncate処理(do_truncate)が実行され、その延長でinode_operationsのsetattrが呼び出される。
ファイルのUID/GIDが変更になった場合、POSIX-ACLの内容も書き換えられるために、setattrのJFFS2実装であるjffs2_setattr()からはACL処理のためjffs2_acl_chmod()が呼び出されるが、ここで何らかの理由で -EINVAL を返却している。

さて、やっと問題箇所が絞り込めた…。

[解決]
結局、自分の作ったデータ整合性チェックを行う関数で弾かれてました。orz
jffs2_acl_chmod()の呼び出し前後でACLが変化しない場合、ACLのコードは現在のname/valueペアと同じ値でXATTRを更新しようとする。
この様な場合、jffs2のxattrの実装では共有可能なname/valueペアが存在するかどうかを検索し、存在した場合はそのオブジェクトをinodeから参照させる。
しかしこの時、全く同一のname/valueペアを複数回参照しないようにチェックを行っており(create_xattr_ref()関数)、ここで -EINVAL を返却していた。
そもそもcreate_xattr_ref()を呼び出すのはdo_jffs2_setxattr()関数のみであり、inodeに対して同じnameが複数のvalueを持つことはないというのはこの関数が保証しているため、この冗長なチェックは外すことに。

さすがに、更新前後で値が変わらなくて、キャッシュに乗っている自分自身を参照するケースというのは考えが及ばなかった。うむむ…。

ちなみに、jffs2のACLのコードはExt2/3を参考にして作っているが、いつの間にかExt2/3側のコードはこんな風になっていた。

fs/ext2/inode.c: ext2_setattr()
if (!error && (iattr->ia_valid & ATTR_MODE))
error = ext2_acl_chmod(inode);

確かにこれなら、今の実装のように不必要な更新は避けられるということで、怪我の功名的にjffs2のACLにも追加。