使用用戶空間的文件系統

http://bbs.chinaunix.net/thread-2125342-1-1.html

使用用戶空間的文件系統(FUSE),您無需理解文件系統的內幕,也不用學習內核模塊編程的知識,就可以開發用戶空間的文件系統框架。本文是一篇簡單的逐步介紹的指南,內容包括安裝、定製和啓用 FUSE 和 AFS,這樣您就可以在 Linux® 的用戶空間中創建自己的功能完備的文件系統了。

文件系統是一種用來存儲和組織計算機文件、目錄及其包含的數據的方法,它使文件、目錄以及數據的查找和訪問得到簡化。如果您正在使用一臺計算機,很可能使用了多個文件系統。文件系統能提供豐富的擴展能力。它可以編寫成底層文件系統的一個封裝程序,從而對其中的數據進行管理,並提供一個增強的、具有豐富特性的文件系統(例如 cvsfs-fuse,它爲 CVS 提供了一個文件系統的接口;或 Wayback 文件系統,它提供了一種用於保留原始數據文件的文件備份機制)。
在用戶空間的文件系統出現之前,文件系統的開發曾是內核開發人員的工作。創建文件系統需要了解內核編程和內核技術(例如 vfs)方面的知識。調試則需要 C 和 C++ 方面的專業技能。但是其他開發人員需要熟練地操作文件系統以添加個性化特性(例如添加歷史記錄或轉發緩存)及對其改進。
FUSE 簡介
使用 FUSE 您可以開發功能完備的文件系統:其具有簡單的 API 庫,可以被非特權用戶訪問,並可以安全的實施。更重要的是,FUSE 以往的表現充分證明了其穩定性。
使用 FUSE,您可以像可執行二進制文件一樣來開發文件系統,它們需要鏈接到 FUSE 庫上 —— 換言之,這個文件系統框架並不需要您瞭解文件系統的內幕和內核模塊編程的知識。
就文件系統來說,用戶空間的文件系統就不再是新奇的設計了。用戶空間文件系統的商業實現與學術實現的實例包括:

  • LUFS 是一個混合用戶空間的文件系統框架,它對用於任何應用程序無數的文件系統提供透明支持。大部分LUFS 包括一個內核模塊和一個用戶空間的守護進程。從根本上來說,它將大部分 VFS 調用都委託給一個專用的守護進程來處理。 
  • UserFS 讓用戶進程可以像普通的文件系統一樣進行加載。這種概念性的原型提供了 ftpfs,這可以使用文件系統接口提供匿名 FTP 訪問。 
  • Ufo Project 是爲 Solaris 提供的一個全局文件系統,它允許用戶將遠程文件真正當作本地文件一樣對待。 
  • OpenAFS 是 Andrew FileSystem 的一個開源版本。 
  • CIFS 是 Common Internet FileSystem 的簡稱。

與這些商業實現和學術實現不同,FUSE 將這種文件系統的設計能力帶到了 Linux 中來。由於 FUSE 使用的是可執行程序(而不像 LUFS 一樣使用的是共享對象),因此可以簡化程序的調試和開發。FUSE 可以在 2.4.x 和 2.6.x 的內核上使用,現在可以支持 Java™ 綁定,因此您可以不必限定於使用 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
在 fuse-2.2 目錄中運行 configure 腳本: ./configure。這會創建所需要的 makefile 等內容。
運行 ./make 來編譯庫、二進制文件和內核模塊。查看 kernel 目錄中的文件 ./kernel/fuse.ko —— 這是內核模塊文件。還要查看 lib 目錄中的 fuse.o、mount.o 和 helper.o。
運行 ./make install 完成 FUSE 的安裝。 
另外一種選擇:如果您希望使用 insmod 自己將這個模塊安裝到內核中,就可以跳過這個步驟。例如:/usr/local/sbin/insmod ./kernel/fuse.ko 或 /sbin/insmod ./kernel/fuse.ko。記住要使用 root 特權才能安裝所需要的模塊。 
如果希望,只在一個步驟中就可以完成上面的步驟。在 fuse-2.2 目錄中,運行 ./configure; make; make install;。 
重要提示:在編譯 FUSE 時,系統中需要有內核頭文件或源代碼。爲了簡單起見,請確保將內核源代碼放到 /usr/src/ 目錄中。 
定製文件系統
現在讓我們來創建一個文件系統,這樣就可以使用一個較舊的 Linux 內核來訪問一個具有最新內核的 Linux 系統上的 AFS 空間了。您需要兩個進程:一個是在較舊的 Linux 內核上運行的服務器進程,另外一個是在具有最新內核的 Linux 系統上運行的一個 FUSE 客戶機進程。不論何時請求到達您的 FUSE 客戶機進程上時,它都會與遠程服務器進程進行聯繫。爲了進行通信,這個文件系統使用了 RX RPC 代碼,這是 AFS 的一部分,因此您需要編譯 OpenAFS。(圖 1 給出了對這個 AFS 文件系統的概述。)
圖 1. AFS-FUSE 文件系統概述


編譯 OpenAFS
下載 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。
運行 ./make,然後運行 ./make dest。檢查在編譯過程中出現的錯誤。 
如果編譯過程一切順利,那麼 AFS 源代碼樹就可以使用了。現在,您需要準備一個開發目錄 afsfuse。在這個目錄中,創建另外兩個目錄: 

  • include 目錄包括 OpenAFS 和 FUSE 的 include 目錄的頭文件。 
  • lib 目錄包含 OpenAFS 和 FUSE 的庫文件。

拷貝頭文件和庫文件。 
首先從 OpenAFS 目錄中拷貝 AFS 的頭文件,方法是將 dest\i386_linux24\include 中的目錄和文件全部拷貝到 include 目錄中。然後將 fuse-2.2 目錄中的 FUSE 的 include 目錄拷貝到這個目錄中。對庫文件也重複相同的步驟,將它們全部拷貝到 lib 目錄中。 
創建應用程序的結構。 
對於這兩組進程,您需要使用兩組文件。使用命名規則 afsfuse_client.* 來命名客戶機進程的文件;使用命名規則 afsfuse_server.* 來命名服務器進程的文件。 
這樣您就有了一個 afsfuse_client.c 文件,其中包含了 FUSE 進程的代碼;一個 afsfuse_server.c 文件,其中包含了在遠程機器上運行的進程使用的服務器代碼;一個 makefile;一個 rxgen 文件,用來創建 RPC 頭文件(例如 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 域都可以忽略。st_ino 域也會被忽略,除非在執行 mount 時指定了 use_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() 序列。對於每個目錄項來說,都應該調用 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 *);
    這 4 個函數分別用來修改文件的權限位、屬主和用戶、大小以及文件的訪問/修改時間。 
  • open: int (*open) (const char *, struct fuse_file_info *);
    這是文件的打開操作。對 open() 函數不能傳遞創建或截斷標記(O_CREAT、O_EXCL、O_TRUNC)。這個函數應該檢查是否允許執行給定的標記的操作。另外,open() 也可能在 fuse_file_info 結構中返回任意的文件句柄,這會傳遞給所有的文件操作。 
  • read: int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *);
    這個函數從一個打開文件中讀取數據。除非碰到 EOF 或出現錯誤,否則 read() 應該返回所請求的字節數的數據;否則,其餘數據都會被替換成 0。一個例外是在執行 mount 命令時指定了 direct_io 選項,在這種情況中 read() 系統調用的返回值會影響這個操作的返回值。 
  • write: int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *);
    這個函數將數據寫入一個打開的文件中。除非碰到 EOF 或出現錯誤,否則 write() 應該返回所請求的字節數的數據。一個例外是在執行 mount 命令時指定了 direct_io 選項(這於 read() 操作的情況類似)。 
  • statfs: int (*statfs) (const char *, struct statfs *);
    這個函數獲取文件系統的統計信息。f_type 和 f_fsid 域都會被忽略。 
  • flush: int (*flush) (const char *, struct fuse_file_info *);
    這表示要刷新緩存數據。它並不等於 fsync() 函數 —— 也不是請求同步髒數據。每次對一個文件描述符執行 close() 函數時,都會調用 flush();因此如果文件系統希望在 close() 中返回寫錯誤,並且這個文件已經緩存了髒數據,那麼此處就是回寫數據並返回錯誤的好地方。由於很多應用程序都會忽略 close() 錯誤,因此這通常用處不大。

注意:我們也可以對一個 open() 多次調用 flush() 方法。如果由於調用了 dup()、dup2() 或 fork() 而產生多個文件描述符指向一個打開文件的情況,就可能會需要這種用法。我們無法確定哪個 flush 操作是最後一次操作,因此每個 flush 都應該同等地對待。多個寫刷新序列相當罕見,因此這並不是什麼問題。

  • release: int (*release) (const char *, struct fuse_file_info *);
    這個函數釋放一個打開文件。release() 是在對一個打開文件沒有其他引用時調用的 —— 此時所有的文件描述符都會被關閉,所有的內存映射都會被取消。對於每個 open() 調用來說,都必須有一個使用完全相同標記和文件描述符的 release() 調用。對一個文件打開多次是可能的,在這種情況中只會考慮最後一次 release,然後就不能再對這個文件執行更多的讀/寫操作了。release 的返回值會被忽略。 
  • fsync: int (*fsync) (const char *, int, struct fuse_file_info *);
    這個函數用來同步文件內容。如果 datasync 參數爲非 0,那麼就只會刷新用戶數據,而不會刷新元數據。 
  • 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      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 
%#include 
%#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, IN int dummy) split = 1;
rxc_getdirWrapper(IN string path, OUT bulkmydirhandles *handles) = 2;
rxc_read(IN string path;, IN afs_uint32 size, IN afs_uint32 offset,
         IN struct my_file_info *fi) split = 3;
rxc_open(IN string path, IN int flags, OUT u_int *hd) = 4;
rxc_write(IN string path,IN afs_uint32 size, IN afs_uint32 offset,
          IN struct my_file_info *fi) split = 5;
rxc_chmod(IN string path, IN afs_uint32 mode) = 6;
rxc_chown(IN string path, IN afs_uint32 uid, IN afs_uint32 gid) = 7;
rxc_utime(IN string path, IN afs_uint32 at,IN afs_uint32 mt) = 8;
rxc_mknod(IN string path, afs_uint32 mode, afs_uint32 rdev) = 9 ;
rxc_mkdir(IN string path, IN afs_uint32 mode) = 10;
rxc_unlink(IN string path) = 11 ;
rxc_rmdir(IN string path) = 12;
rxc_rename(IN string from, IN string to) = 13;
rxc_truncate(IN string path, IN afs_uint32 size) = 14;
rxc_release(IN string path, IN struct my_file_info *fi) = 15;
rxc_readlink(IN string path, IN afs_uint32 size,OUT string
             data) = 16;
rxc_symlink(IN string from, IN string to) = 17;
rxc_link(IN string from, IN string to) = 18;
rxc_statfs(IN string path, OUT struct mystatfs *stbuf) = 19;
rxc_fsync(IN string path , IN int isdatasync, IN struct my_file_info
          *fi) = 20 ;
rxc_flush(IN string path , IN struct my_file_info *fi) = 21 ;
在定義 RX RPC 層時,注意以下幾點: 

  • 在 statfs、stat 和 fuse_file_info 基礎上定義了 mystatfs、mystat 和 my_file_info 的封裝程序。它們都會使用所生成的 XDR 代碼進行轉換。(XDR(External Data Representation,外部數據表示)允許採用一種與體系結構無關的方式進行封裝,這樣就可以在異構計算機系統之間傳輸數據了。) 
  • 您幾乎要爲 fuse_operations 結構的每個成員都定義一個函數,它們幾乎具有相同的參數,因爲 afsfuse_client 的工作就是負責接管 FUSE 文件系統中的調用,並將這些調用傳遞給 afsfuse_server。 
  • 您已經硬編碼了一些值,例如 MYMAXPATH,這應該從系統中獲得 —— 硬編碼是爲了簡單性起見而這樣做的。

創建客戶機和存根文件
接下來使用 rxgen 編譯 afsfuse.xg 文件,從而創建客戶機和存根文件。從包含 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)&
        //
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)& //
簡單地,您可以在其他函數中添加代碼來對文件系統進行增強。 
您需要創建一個 makefile 來編譯代碼。記住在編譯 afsfuse_client 的代碼時包括以下選項:-D_FILE_OFFSET_BITS=64 和 -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 文件系統的兩個關鍵概念:如何安裝和配置 FUSE 內核模塊,以及如何充分利用 FUSE 庫和 API 的功能。
下載
描述
名字
大小
下載方法
AFSFuse filesystem sample code
l-fuse.zip
9KB
HTTP


關於下載方法的信息


Get Adobe® Reader®
參考資料 
學習

獲得產品和技術

關於作者


Sumit Singh 是 IBM 企業文件系統組的一名軟件工程師。他的主要工作是爲 AFS 提供 L3 支持。


本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u/30686/showart_288029.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章