FUSEによる独自ファイルシステムの開発

カーネル・プログラミングは不要

FUSE(Filesystem in Userspace)を使用すると、ファイルシステムの内部を理解したりカーネル・モジュール・プログラミングを学習しなくても、ユーザー空間ファイルシステム・フレームワークを開発することができます。このシンプルなステップ・バイ・ステップのガイドに従い、FUSEとAFSのインストール、カスタマイズ、および有効化を行うことによって、完全に機能するユーザー独自のファイルシステムをLinux ® のユーザー空間に作成することができます。

Sumit Singh, Software Engineer, IBM

Sumit Singhは、IBMのエンタープライズ・ファイルシステム・グループのソフトウェア技術者です。主な業務として、AFS用のL3サポートがあります。



2006年 2月 28日

ファイルシステムは、コンピューター・ファイルおよびディレクトリーとそれらが含むデータを格納・編成して、検索とアクセスを容易にする手段です。コンピューターを使用している場合、おそらく2種類以上のファイルシステムを使用していることになります。ファイルシステムは、拡張機能を提供することができます。基盤のファイルシステムのデータを管理するラッパーとして作成して、豊富な拡張機能を備えたファイルシステムを提供することもできます(たとえば、cvsfs-fuseはCVS用のファイルシステム・インターフェースを提供し、Waybackファイルシステムは古いデータのコピーを保持するバックアップ・メカニズムを提供します)。

ユーザー空間ファイルシステム以前では、ファイルシステムの開発はカーネル開発者の仕事でした。ファイルシステムを作成するには、カーネル・プログラミングとカーネル・テクノロジー(vfsなど)の知識が必要でした。また、デバッグには、CおよびC++の高度な専門知識が必要でした。しかし、他の開発者もファイルシステムを操作(履歴の追加や転送キャッシングなどのカスタム機能や拡張機能を追加)する必要がありました。

FUSEについて

FUSEを使用すると、フル機能のファイルシステムを開発することができます。そのファイルシステムでは、シンプルなAPIライブラリーを備え、非特権ユーザーもアクセスでき、セキュア実装を提供できます。また、なにより、FUSEは安定性に実績があります。

FUSEでは、ファイルシステムをFUSEライブラリーにリンクされた実行可能バイナリーとして開発することができます。言い換えると、このファイルシステム・フレームワークでは、ファイルシステムの内部やカーネル・モジュール・プログラミングを学ぶ必要がありません。

ファイルシステムに関して言えば、ユーザー空間ファイルシステムは新しい設計ではありません。ユーザー空間ファイルシステムの商用および学術用の実装としては、次のようなものがあります。

  • LUFSは、あらゆるアプリケーションに対して無限数のファイルシステムをトランスペアレントにサポートするハイブリッドなユーザー空間ファイルシステム・フレームワークで、カーネル・モジュールとユーザー空間デーモンで構成されています。基本的に、VFS呼び出しの大部分を専用のデーモンに任せます。
  • UserFSでは、ユーザー・プロセスを通常のファイルシステムとしてマウントすることができます。この概念実証プロトタイプは、ファイルシステム・インターフェースによる匿名FTPが可能なftpfsを提供します。
  • Ufo ProjectはSolaris向けのグローバルなファイルシステムであり、リモート・ファイルをローカル・ファイルと同様に扱うことができます。
  • OpenAFSは、Andrew FileSystemのオープン・ソース版です。
  • CIFSは、Common Internet FileSystemです。

これらの商用および学術用の例と異なり、FUSEはこのファイルシステム設計の機能をLinuxにもたらします。FUSEは実行ファイルを使用するので(たとえばLUFSのように共有オブジェクトを使用するのではなく)、デバッグと開発が容易です。FUSEは両方のカーネル(2.4.xと2.6.x)で動作し、JavaTMバインディングもサポートするようになったので、ファイルシステムのプログラミングがCとC++に限定されません(FUSEを使用するユーザーランド・ファイルシステムの詳細については、「 参考文献 」を参照してください)。

FUSEでファイルシステムを作成するには、FUSEカーネル・モジュールをインストールし、FUSEライブラリーとAPIのセットを使用してファイルシステムを作成する必要があります。


FUSEの解凍

ファイルシステムを開発するには、まずFUSEソース・コードをダウンロードして(「 参考文献 」を参照)、パッケージを解凍します。tar -zxvf fuse-2.2.tar.gz。これによって、ソース・コードの入ったFUSEディレクトリーが作成されます。fuse-2.2ディレクトリーの内容は、次のとおりです。

  • ./docには、FUSE関連のドキュメンテーションが含まれています。現時点では、含まれているファイルはhow-fuse-worksだけです。
  • ./kernelには、FUSEカーネル・モジュールのソース・コードが含まれています(もちろん、FUSEでファイルシステムを開発するのにこの内容を知る必要はありません)。
  • ./includeには、ファイルシステムの作成に必要なFUSE APIヘッダーが含まれています。今のところ必要なのは、fuse.hだけです。
  • ./libには、FUSEライブラリーを作成するためのソース・コードが含まれています。これをバイナリーにリンクすることによってファイルシステムを作成します。
  • ./utilには、FUSEユーティリティー・ライブラリーのソース・コードがあります。
  • ./exampleには、もちろん、fusexmp、nullやhelloのファイルシステムなど、参考用のサンプルが含まれています。

FUSEのビルドとインストール

  1. fuse-2.2ディレクトリーから構成スクリプトを実行します。./configure。このスクリプトによって、必要なmakefileなどが作成されます。
  2. ./makeを実行して、ライブラリー、バイナリー、およびカーネル・モジュールをビルドします。kernelディレクトリーにファイル./kernel/fuse.koがあることを確認します。これがカーネル・モジュール・ファイルです。また、libディレクトリーにfuse.o、mount.o、およびhelper.oがあることを確認します。
  3. ./make installを実行して、FUSEのインストールを完了します。
別の手段 :insmodを使用して、自分でカーネル内のモジュールをインストールしたい場合は、このステップをスキップしてください。たとえば、/usr/local/sbin/insmod ./kernel/fuse.koまたは/sbin/insmod ./kernel/fuse.ko。必須モジュールはルート権限でインストールしてください。

必要な場合は、上記のステップを1ステップで実行できます。fuse-2.2ディレクトリーから、./configure; make; make install;を実行します。

重要 :FUSEを作成するときには、カーネル・ヘッダーまたはソース・コードが所定の場所になければなりません。作業を単純にするには、カーネル・ソース・コードを/usr/src/ディレクトリーに置いてください。


ファイルシステムのカスタマイズ

では、ファイルシステムを作成し、古いLinuxカーネルを使用して最新のカーネルがあるLinuxボックス上のAFS空間にアクセスできるようにしましょう。これには2つのプロセス、すなわち古いLinuxカーネル上で実行するサーバー・プロセスと、最新のカーネルがあるLinuxボックス上で実行するFUSEクライアント・プロセスが存在します。要求がFUSEクライアント・プロセスに到達すると、このプロセスがリモートのサーバー・プロセスに接続します。このファイルシステムは、通信にAFSの一部であるRX RPCコードを使用するので、OpenAFSをビルドする必要があります(図1に、このAFSファイルシステムの概要を示します)。

図 1.AFS-FUSEファイルシステムの概要
AFS-FUSEファイルシステムの概要

OpenAFSのビルド

  1. OpenAFS Linuxソースをダウンロードして、ソースを解凍します。
    ソースの解凍先ディレクトリーで、./make ./configure --enable-transarc-pathsを実行します。./configureがビルドするsysnameを認識できない場合は、--with-afs-sysnameオプションを使用して、適切なsysnameを指定してください。 Linux 2.4カーネルをビルドする場合は、次のコマンドを使用します。./configure --enable-transarc-paths --with-afs-sysname=i386_linux24。
  2. ./makeを実行して、次に、./make destを実行します。ビルド中にエラーがなかったかを確認します。 ビルドに問題がなければ、AFSソース・ツリーを使用することができます。この段階で、afsfuseという名前の開発用ディレクトリーを準備する必要があります。このディレクトリーに、さらに2つのディレクトリーを作成します。
    • includeディレクトリーには、OpenAFSとFUSEのincludeヘッダーを入れます。
    • libディレクトリーには、OpenAFSとFUSEのライブラリーを入れます。
  3. ヘッダーとライブラリーをコピーします。 まず、OpenAFSディレクトリーからAFSヘッダーをコピーします。すなわち、dest\i386_linux24\includeのディレクトリーとファイルをincludeディレクトリーにコピーします。次に、fuse-2.2ディレクトリーのFUSEヘッダーをこのディレクトリーにコピーします。ライブラリーについても同じステップを繰り返して、libディレクトリーにコピーします。
  4. アプリケーションの構造を作成します。
    2組のプロセスのために2組のファイルが必要です。クライアント・プロセス・ファイルには、 afsfuse_client. *という方式の名前を付けます。サーバー・プロセス・ファイルには、 afsfuse_server. *という名前を付けます。

このようにして、FUSEプロセス・コードを含んだafsfuse_client.cファイル、リモート・ボックス上で実行するプロセス用のサーバー・コードを含んだafsfuse_server.cファイル、makefile、およびRPCヘッダーを作成するためのrxgenファイル(afsfuse.xgなど)を用意します。

afsfuse_client.cファイルは、afsfuse_clientプロセス・コードを作成します。これはFUSEファイルシステムによって呼び出されて、独自ファイルシステムを作成します(このファイルの作成には、サンプルfuse-2.2/example/fusexmp.cを使用してください)。

必要な関数の定義

FUSEでファイルシステムを作成するには、fuse_operations型の構造体変数を宣言して、それをfuse_main関数に渡す必要があります。fuse_operations構造体は、適切な処置が必要なときに呼び出される関数のポインターを伝えます。リスト1にfuse_operations構造体を示します。

リスト1. fuse_operation構造体の必須関数
struct fuse_operations {
    int (*getattr) (const char *, struct stat *);
    int (*readlink) (const char *, char *, size_t);
    int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
    int (*mknod) (const char *, mode_t, dev_t);
    int (*mkdir) (const char *, mode_t);
    int (*unlink) (const char *);
    int (*rmdir) (const char *);
    int (*symlink) (const char *, const char *);
    int (*rename) (const char *, const char *);
    int (*link) (const char *, const char *);
    int (*chmod) (const char *, mode_t);
    int (*chown) (const char *, uid_t, gid_t);
    int (*truncate) (const char *, off_t);
    int (*utime) (const char *, struct utimbuf *);
    int (*open) (const char *, struct fuse_file_info *);
    int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
    int (*write) (const char *, const char *, size_t, off_t,struct fuse_file_info *);
    int (*statfs) (const char *, struct statfs *);
    int (*flush) (const char *, struct fuse_file_info *);
    int (*release) (const char *, struct fuse_file_info *);
    int (*fsync) (const char *, int, struct fuse_file_info *);
    int (*setxattr) (const char *, const char *, const char *, size_t, int);
    int (*getxattr) (const char *, const char *, char *, size_t);
    int (*listxattr) (const char *, char *, size_t);
    int (*removexattr) (const char *, const char *);
};

これらの操作は絶対不可欠というものではありませんが、その多くはファイルシステムが正常に機能するために必要です。特殊目的のメソッド.flush、.release、または.fsyncを備えたフル機能のファイルシステムを実行することができます(この記事では、xattr関数には触れません)。リスト1に示した関数を以下で説明します。

  • getattr: int (*getattr) (const char *, struct stat *); この関数は、stat()と同様です。st_devおよびst_blksizeフィールドは無視されます。use_inoマウント・オプションが指定されていない限り、st_inoフィールドは無視されます。
  • readlink: int (*readlink) (const char *, char *, size_t); この関数は、シンボリック・リンクのターゲットを読み取ります。バッファーは、null終了文字列で埋められます。バッファー・サイズ引数には、末尾のnull文字分のスペースも含まれます。リンク名が長すぎてバッファーに収まらない場合は、切り詰められます。成功の場合、リターン値は「0」です。
  • getdir: int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
    この関数は、ディレクトリーの内容を読み取ります。この操作は、opendir()、readdir()、...closedir()のシーケンスを1回の呼び出しで行います。ディレクトリー・エントリーごとにfilldir()関数が呼び出されます。
  • mknod: int (*mknod) (const char *, mode_t, dev_t);
    この関数は、ファイル・ノードを作成します。create()操作はありません。非ディレクトリー、非シンボリック・リンク・ノードの作成には、mknod()が呼び出されます。
  • mkdir: int (*mkdir) (const char *, mode_t);
    rmdir: int (*rmdir) (const char *);
    これらの関数は、それぞれディレクトリーを作成および削除します。
  • unlink: int (*unlink) (const char *);
    rename: int (*rename) (const char *, const char *);
    これらの関数は、それぞれファイルの削除とファイル名の変更を行います。
  • symlink: int (*symlink) (const char *, const char *);
    この関数は、シンボリック・リンクを作成します。
  • link: int (*link) (const char *, const char *);
    この関数は、ファイルのハード・リンクを作成します。
  • chmod: int (*chmod) (const char *, mode_t);
    chown: int (*chown) (const char *, uid_t, gid_t);
    truncate: int (*truncate) (const char *, off_t);
    utime: int (*utime) (const char *, struct utimbuf *);
    これらの関数は、それぞれ、ファイルの許可ビット、所有者、およびグループ、サイズ、アクセス/更新日時を変更します。
  • open: int (*open) (const char *, struct fuse_file_info *);
    この関数は、ファイル・オープン操作です。作成または切り詰めフラグ(O_CREAT、O_EXCL、O_TRUNC)は、open()には渡されません。この関数は、指定されたフラグに対して操作が許されるかどうかをチェックします。オプションで、open()はfuse_file_info構造体で任意のファイルハンドルを返すこともでき、それがすべてのファイル操作に渡されます。
  • read: int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
    この関数は、開いているファイルからデータを読み取ります。read()はEOFまたはエラーの場合を除き、要求されたバイト数を返します。そうでない場合、残りのデータはゼロに置き換えられます。direct_ioマウント・オプションが指定されたときは例外です。この場合、read()システム呼び出しのリターン値は、この操作のリターン値を反映します。
  • write: int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *);
    この関数は、開いているファイルにデータを書き込みます。write()はエラーの場合を除き、要求されたバイト数を返します。direct_ioマウント・オプションが指定された場合は例外です(read()操作と同様)。
  • statfs: int (*statfs) (const char *, struct statfs *);
    この関数は、ファイルシステム統計を取得します。f_typeおよびf_fsidフィールドは無視されます。
  • flush: int (*flush) (const char *, struct fuse_file_info *);
    この関数は、キャッシュ・データのフラッシュを行います。fsync()と同じではありません(ダーティー・データを同期する要求ではありません)。flush()はファイル記述子のclose()のたびに呼び出されるので、ファイルシステムがclose()で書き込みエラーを返したい場合、またはファイルにキャッシュされたダーティー・データがあった場合に、ここでデータを書き戻してエラーを返すとよいでしょう。多くのアプリケーションがclose()エラーを無視するので、常に使えるわけではありません。

:flush()メソッドは、1つのopen()に対して複数回呼び出すことができます。dup()、dup2()、またはfork()呼び出しのために、複数のファイル記述子が1つの開かれたファイルを参照している場合、このようになります。どのフラッシュが最後のフラッシュかを判断するのは不可能なので、すべてのフラッシュが平等に扱われます。書き込み/フラッシュのシーケンスが複数回行われるのは比較的まれなので、これが問題になることはないはずです。

  • release: int (*release) (const char *, struct fuse_file_info *);
    この関数は、開いているファイルを解放します。release()は呼び出されるのは、開いているファイルの参照がそれ以上ないとき、すなわち、すべてのファイル記述子がクローズされてすべてのメモリー・マッピングがアンマップされたときです。それぞれのopen()呼び出しにつき、同じフラグとファイル記述子を持つrelease()呼び出しが1つずつ存在することになります。ファイルが複数回オープンされることもあり、その場合は最後のreleaseだけがカウントされ、そのファイルに対してはそれ以上の読み取り/書き込みは行われません。releaseのリターン値は無視されます。
  • fsync: int (*fsync) (const char *, int, struct fuse_file_info *);
    この関数は、ファイルの内容を同期します。datasyncパラメーターが非ゼロの場合は、ユーザー・データだけがフラッシュされ、メタ・データはフラッシュされません。
  • setxattr: int (*setxattr) (const char *, const char *, const char *, size_t, int);
    getxattr: int (*getxattr) (const char *, const char *, char *, size_t);
    listxattr: int (*listxattr) (const char *, char *, size_t);
    removexattr: int (*removexattr) (const char *, const char *);
    これらの関数はそれぞれ、拡張属性を設定、取得、一覧表示、および削除します。

結果としてのファイルシステム

ファイルシステムは次のようになります。

afsfuse_client   <--RX[RPC]-->   afsfuse_server

afsfuse_clientは、渡されたファイルシステム呼び出しを別のマシン上のafsfuse_serverに転送します。afsfuse_serverはクライアントから送られたすべての要求を処理して、結果をクライアントに返します。必要な処理のすべてを行います。RPCの場合に使用されるメカニズムはRXです。データとメタ・データのいずれについても、キャッシュは行われません。


RX RPC層の定義

先へ進む前に、RX RPC層を定義する必要があります。そのためには、rxgenの.xgファイルを作成して、afsfuse_client.cとafsfuse_server.cにリンクされるプロキシおよびスタブ・コードを記述します。リスト2に、次のような内容のafsfuse.xgファイルを作成する方法を示します。

リスト2. afsfuse.xgファイルの作成
#define MYMAXPATH 512
%#include <rx/rx.h>
%#include </rx_null.h >
%#define SAMPLE_SERVER_PORT 5000
%#define SAMPLE_SERVICE_PORT 0
/* i.e. user server's port */
%#define SAMPLE_SERVICE_ID 4 /* Maximum number of requests that will be handled by this
                                service simultaneously */
/* This number will also be guaranteed to execute in parallel if no services' requests
   are being processed */
%#define SAMPLE_MAX 2 /* Minimum number of requests that are guaranteed to be handled
                         immediately */
%#define SAMPLE_MIN 1 /* Index of the "null" security class in the sample service. This
                         must be 0 (there are N classes, numbered from 0. In this case,
                         N is 1) */
%#define SAMPLE_NULL 0 /********************** fuse4_file_info taken from fuse.h the
                        rxgen does not understands fuse.h  mystat taken from man 2
                        mystat these are required again rxgen does not understand the
                        struct paras and will bump.. **********************/
struct my_file_info { /** Open flags. Available in open() and release() */
                     int flags; /** File handle. May be filled in by filesystem in
                                    open(). Available in all other file operations */
                     unsigned int fh; /** In case of a write operation indicates if
                                          this was caused by a writepage */
                     int writepage;
                    };
struct mystatfs {
                    afs_uint32 f_type; /* type of filesystem (see below) */
                    afs_uint32 f_bsize; /* optimal transfer block size */
                    afs_uint32 f_blocks; /* total data blocks in file system */
                    afs_uint32 f_bfree; /* free blocks in fs */
                    afs_uint32 f_bavail; /* free blocks avail to non-superuser */
                    afs_uint32 f_files; /* total file nodes in file system */
                    afs_uint32 f_ffree; /* free file nodes in fs */
                    afs_uint32 f_fsid1; /* file system id */
                    afs_uint32 f_fsid2; /* file system id */
                    afs_uint32 f_namelen; /* maximum length of filenames */
                    afs_uint32 f_spare[6]; /* spare for later */
                };
struct mystat {
                    afs_uint32 st_dev; /* device */
                    afs_uint32 st_ino; /* inode */
                    afs_uint32 st_mode; /* protection */
                    afs_uint32 st_nlink; /* number of hard links */
                    afs_uint32 st_uid; /* user ID of owner */
                    afs_uint32 st_gid;/* group ID of owner */
                    afs_uint32 st_rdev; /* device type (if inode device) */
                    afs_uint32 st_size; /* total size, in bytes */
                    afs_uint32 st_blksize; /* blocksize for filesystem I/O */
                    afs_uint32 st_blocks; /* number of blocks allocated */
                    afs_uint32 st_atim; /* time of last access */
                    afs_uint32 st_mtim; /* time of last modification */
                    afs_uint32 st_ctim; /* time of last change */
                };
struct my_dirhandle{
                    afs_uint32 type;
                    afs_uint32 inode;
                    char name[MYMAXPATH];
                };
typedef my_dirhandle bulkmydirhandles<>;
 /*********************phase 1 functions *********************************************/
rxc_getattr(IN string mypath<MYMAXPATH>, IN int dummy) split = 1;
rxc_getdirWrapper(IN string path<MYMAXPATH>, OUT bulkmydirhandles *handles) = 2;
rxc_read(IN string path<MYMAXPATH>;, IN afs_uint32 size, IN afs_uint32 offset,
         IN struct my_file_info *fi) split = 3;
rxc_open(IN string path<MYMAXPATH>, IN int flags, OUT u_int *hd) = 4;
rxc_write(IN string path<MYMAXPATH>,IN afs_uint32 size, IN afs_uint32 offset,
          IN struct my_file_info *fi) split = 5;
rxc_chmod(IN string path<MYMAXPATH>, IN afs_uint32 mode) = 6;
rxc_chown(IN string path<MYMAXPATH>, IN afs_uint32 uid, IN afs_uint32 gid) = 7;
rxc_utime(IN string path<MYMAXPATH>, IN afs_uint32 at,IN afs_uint32 mt) = 8;
rxc_mknod(IN string path<MYMAXPATH>, afs_uint32 mode, afs_uint32 rdev) = 9 ;
rxc_mkdir(IN string path<MYMAXPATH>, IN afs_uint32 mode) = 10;
rxc_unlink(IN string path<MYMAXPATH>) = 11 ;
rxc_rmdir(IN string path<MYMAXPATH>) = 12;
rxc_rename(IN string from<MYMAXPATH>, IN string to<MYMAXPATH>) = 13;
rxc_truncate(IN string path<MYMAXPATH>, IN afs_uint32 size) = 14;
rxc_release(IN string path<MYMAXPATH>, IN struct my_file_info *fi) = 15;
rxc_readlink(IN string path<MYMAXPATH>, IN afs_uint32 size,OUT string
             data<MYMAXPATH>) = 16;
rxc_symlink(IN string from<MYMAXPATH>, IN string to<MYMAXPATH>) = 17;
rxc_link(IN string from<MYMAXPATH>, IN string to<MYMAXPATH>) = 18;
rxc_statfs(IN string path<MYMAXPATH>, OUT struct mystatfs *stbuf) = 19;
rxc_fsync(IN string path <MYMAXPAT>, IN int isdatasync, IN struct my_file_info
          *fi) = 20 ;
rxc_flush(IN string path <MYMAXPATH>, IN struct my_file_info *fi) = 21 ;

RX RPC層を定義するときには、次の点に注意してください。

  • mystatfs、mystat、およびmy_file_infoをstatfs、stat、およびfuse_file_info構造体のラッパーとして定義しました。これらは、生成されたXDRコードを使用して、回線経由で変換されます。(XDR(External Data Representation)では、アーキテクチャーに依存しない方法でデータをラップできるので、異種混在のコンピューター・システム間でデータを転送できます。)
  • afsfuse_clientの仕事は、FUSEファイルシステムから呼び出しを受け取って、それをafsfuse_serverに渡すだけなので、構造体fuse_operationsのすべてのメンバーについて、ほとんど同じパラメーターを持つ関数をほぼ1つずつ定義しました。
  • MYMAXPATHなど、システムから取得する値をハードコーディングしました。ハードコーディングは、単純化が目的です。

クライアントおよびスタブ・ファイルの作成

次に、afsfuse.xgファイルをrxgenでコンパイルして、クライアントおよびスタブ・ファイルを作成します。afsfuse_serverとafsfuse_clientがあるディレクトリーから、コマンドopenafs-1.2.13/i386_linux24/dest/bin/rxgen afsfuse.xgを実行します。次のようなファイルが作成されます。

  • afsfuse.cs.cは、afsfuse_client.cにリンクされるクライアント・スタブ・コードです。
  • afsfuse.hは、FUSE RXコードのさまざまな定義を含んでいるヘッダーです。
  • afsfuse.ss.cは、afsfuse_serverコードにリンクされるサーバー・スタブ・コード(プロキシ・コード)です。
  • afsfuse.xdr.cは、afsfuse.xgで定義した3つの構造体を整列するコードを含んでいます。

次に、実際の作業を行うためのコードをafsfuse_client.cとafsfuse_server.cに追加します。ほとんどの呼び出しは、次のようになります。

  • Our_call_in_afs_fuse_client()。パラメーターを整列して、RPCの準備をします。RX [RPC]経由でafsfuse_serverアプリケーションを呼び出します。パラメーターを整列解除します。この関数に渡された正式なパラメーターに値をコピーします。
  • Our_call_in_afs_fuse_server()。パラメーターを整列解除します。ローカル・ファイルシステムまたはAFS固有の関数を呼び出します。パラメーターを整列して、RPCの準備をします。RX RPC呼び出しを行います。

afsfuse_client.cの呼び出しは、次のようになります。

int afsfuse_readlink(const char *path, char *buf, size_t size){
    rx_connection *local& int ret& char *buffer = malloc (512)&
    memset(buffer,0,512)& memset(buf,0,size)& local = getconnection()&
    ret = rxc_rxc_readlink(local,path,512,&buffer) // rpc call
         relconnection(local)&
         strncpy(buf,buffer,512-1)&
        //<- demarshall the parametrs
        return ret&
    }

afsfuse_server.cの呼び出しは、次のようになります。

リスト3. afsfuse_server.cの呼び出し
int rxc_rxc_readlink( struct rx_call *call, char * path, afs_uint32 size, char**data)
    { int ret& char lbuff[512] ={0}&
    translatePath(path,lbuff)& //<- make filesystem call
     *data = malloc(512)&
     res = readlink(lbuff, *data, 512-1)&
     if(res == -1) return -errno& (*data)[res] = '\0'& return 0&
    }

同様に、ファイルシステムを拡張するためのコードをその他の関数に追加することができます。

やはり、makefileを作成して、コードをコンパイルする必要があります。afsfuse_clientのコードをコンパイルするときには、次のオプションを含めるのを忘れないでください。-D_FILE_OFFSET_BITS=64 and -DFUSE_USE_VERSION=22。

リスト4. クライアント・コードをコンパイルするためのmakefileの生成
SRCDIR=./ LIBRX=${SRCDIR}lib/librx.a
LIBS=${LIBRX} ${SRCDIR}lib/liblwp.a
#CC = g++
CFLAGS=-g -I. -I${SRCDIR}include -I${SRCDIR}include/fuse/ -DDEBUG ${XCFLAGS}
    -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=22
afsfuse_client: afsfuse_client.o afsfuse.xdr.o ${LIBS} bulk_io.o afsfuse.cs.o
    ${CC} ${CFLAGS} -o afsfuse_client afsfuse_client.o ${SRCDIR}lib/fuse/fuse.o
    ${SRCDIR}lib/fuse/mount.o ${SRCDIR}lib/fuse/helper.o
    ${SRCDIR}lib/fuse/fuse_mt.o bulk_io.o afsfuse.cs.o afsfuse.xdr.o ${LIBS}
afsfuse_server: afsfuse_server.o afsfuse.xdr.o afsfuse.ss.o bulk_io.o ${LIBS}
    ${CC} ${CFLAGS} -o afsfuse_server afsfuse_server.o bulk_io.o afsfuse.ss.o
    afsfuse.xdr.o ${LIBS}
#afsfuse_client.o: afsfuse.h
#afsfuse_server.o: afsfuse.h
bulk_io.o: ${CC} -c -g -I${SRCDIR}include bulk_io.c afsfuse.cs.c afsfuse.ss.c
    afsfuse.er.c afsfuse.h afsfuse.xdr.c: afsfuse.xg rxgen afsfuse.xg
afsfuse.xdr.o: afsfuse.xdr.c ${CC} -c -g -I{SRCDIR}include afsfuse.xdr.c
all: afsfuse_server afsfuse_client
clean: rm *.o rm afsfuse_client rm afsfuse_server

やはり、librx.aとliblwp.aを使用して、RXおよびRX用LWPコードにリンクする必要があります。また、fuse/fuse.o、fuse/helper.o、およびfuse/mount.oは、コードをリンクするために必要なFUSEライブラリーです。


まとめ

この記事では、FUSEとOpenAFSをインストールする方法と、これらを使用して独自のユーザー空間ファイルシステム、Linuxで完全に機能する安定したファイルシステムを作成してカスタマイズする方法を学びました。これには、アクティブ・カーネルのパッチや再コンパイルの必要がなく、カーネル・モジュール・プログラマーである必要もありません。FUSEファイルシステムの有効化における2つの重要な概念の詳細を述べました。すなわち、FUSEカーネル・モジュールをインストールして構成する方法と、FUSEライブラリーおよびAPIのパワーを利用する方法です。


ダウンロード

内容ファイル名サイズ
AFSFuse filesystem sample codel-fuse.zip09KB

参考文献

学ぶために

製品や技術を入手するために

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux
ArticleID=228240
ArticleTitle=FUSEによる独自ファイルシステムの開発
publish-date=02282006