日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

FUSE简介

發(fā)布時間:2024/6/21 综合教程 38 生活家
生活随笔 收集整理的這篇文章主要介紹了 FUSE简介 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

什么是FUSE

傳統(tǒng)的文件系統(tǒng)是操作系統(tǒng)的一部分,放在操作系統(tǒng)內(nèi)核里面實現(xiàn)。Fuse(Filesystem in Userspace), 一個用戶空間文件系統(tǒng)框架,提供給我們一組用于實現(xiàn)一個文件系統(tǒng)的API,使我們可以在用戶態(tài)實現(xiàn)自已的文件系統(tǒng)。

FUSE的優(yōu)缺點

1)傳統(tǒng)文件系統(tǒng)都是定義在操作系統(tǒng)內(nèi)核層面上的,要操作系統(tǒng)識別一種新的文件系統(tǒng),必需重寫內(nèi)核,而內(nèi)核態(tài)代碼難以調(diào)試,生產(chǎn)率較低;但是用戶空間編程和調(diào)試難度較小,有更多的語言可以選擇(目前FUSE已經(jīng)綁定了很多語言,比如c++、java等),還可以復(fù)用已有的庫),從而能夠大幅提高生產(chǎn)率,極大地簡少了為操作系統(tǒng)提供新的文件系統(tǒng)的工作量。

2)一些服務(wù)可以通過統(tǒng)一的文件系統(tǒng)接口來進行訪問,比如說ftp、sftp、samba

3)可以把非文件的服務(wù)當(dāng)做文件來實現(xiàn),比如把gmail提供的巨大的空間用來進行文件存儲的Gmail Filesystem

4)在用戶態(tài)實現(xiàn)文件系統(tǒng)必然會引入額外的內(nèi)核態(tài)/用戶態(tài)切換帶來的開銷,對性能會產(chǎn)生一定影響。

FUSE的結(jié)構(gòu)

fuse包括三個模塊:用戶空間庫,內(nèi)核模塊以及mount工具

1)用戶空間庫給程序員提供編程接口,程序員通過實現(xiàn)fuse提供的兩組接口fuse_lowlevel_ops,fuse_operations之一即可實現(xiàn)一個用戶空間文件系統(tǒng)

2)內(nèi)核模塊實現(xiàn)了一個完整文件系統(tǒng)的框架,但具體操作沒有實現(xiàn)(由程序員在用戶空間實現(xiàn))

3)mount工具fusermount用于掛載基于fuse的文件系統(tǒng)

定義FUSE需要的函數(shù)

fuse為開發(fā)者提供了兩組接口,分別是fuse_lowlevel_ops以及fuse_operations,開發(fā)者只需要實現(xiàn)這兩組接口的一種即可實現(xiàn)一個用戶空間文件系統(tǒng)。

struct fuse_lowlevel_ops的成員如下所示,其中init方法在其它所有方法之前調(diào)用,用于初始化文件系統(tǒng),fuse已經(jīng)實現(xiàn),destroy則是在文件系統(tǒng)被卸載時做一些清理工作。用于大多數(shù)請求的參數(shù)都是fuse_ino_t類型的ino,而文件系統(tǒng)提供給用戶的視圖是以文件名呈現(xiàn)的,故lookup是實現(xiàn)文件系統(tǒng)的關(guān)鍵,它在parent中查找名字name對應(yīng)的文件,并返回相應(yīng)的信息,可使用fuse_reply_entry或fuse_reply_err作為請求的返回。

接口中的方法對于了解過VFS的人應(yīng)該都不難理解,只要按需實現(xiàn)這些接口,你就可以定制出屬于自己的文件系統(tǒng),這組接口的詳細說明見fuse_lowlevel.h。

void(* init )(void *userdata, struct fuse_conn_info *conn)
void(* destroy )(void *userdata)
void(* lookup )(fuse_req_t req, fuse_ino_t parent, const char *name)
void(* forget )(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
void(* getattr )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* setattr )(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi)
void(* readlink )(fuse_req_t req, fuse_ino_t ino)
void(* mknod )(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev)
void(* mkdir )(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
void(* unlink )(fuse_req_t req, fuse_ino_t parent, const char *name)
void(* rmdir )(fuse_req_t req, fuse_ino_t parent, const char *name)
void(* symlink )(fuse_req_t req, const char *link, fuse_ino_t parent, const char *name)
void(* rename )(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname)
void(* link )(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname)
void(* open )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* read )(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
void(* write )(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, structfuse_file_info *fi)
void(* flush )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* release )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* fsync )(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
void(* opendir )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* readdir )(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
void(* releasedir )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* fsyncdir )(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
void(* statfs )(fuse_req_t req, fuse_ino_t ino)
void(* setxattr )(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags)
void(* getxattr )(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
void(* listxattr )(fuse_req_t req, fuse_ino_t ino, size_t size)
void(* removexattr )(fuse_req_t req, fuse_ino_t ino, const char *name)
void(* access )(fuse_req_t req, fuse_ino_t ino, int mask)
void(* create )(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info*fi)
void(* getlk )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock)
void(* setlk )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep)
void(* bmap )(fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx)
void(* ioctl )(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, struct fuse_file_info *fi, unsigned *flagsp, const void *in_buf, size_t in_bufsz, size_t out_bufszp)
void(* poll )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph)

用戶實現(xiàn)的接口是如何跟這個結(jié)構(gòu)關(guān)聯(lián)起來的?

其實fuse中已經(jīng)實現(xiàn)了一組接口,在fuse_lowlevel.c中,定義了一個靜態(tài)的結(jié)構(gòu)數(shù)組,該數(shù)組的元素為一組(函數(shù),名字)的結(jié)構(gòu),但沒做什么實際的工作,當(dāng)fuse用戶空間的daemon從/fuse/dev中讀取到請求之后,它通過請求號來判別各個請求,并調(diào)用這里相應(yīng)的處理函數(shù),如讀取到read調(diào)用時,會調(diào)用do_read進行處理。

static struct {
    void (*func)(fuse_req_t, fuse_ino_t, const void *);
    const char *name;
} fuse_ll_ops[] = {
    //只列舉了部分
    [FUSE_LOOKUP]      = { do_lookup,      "LOOKUP"      },
    [FUSE_OPEN]        = { do_open,        "OPEN"        },
    [FUSE_READ]        = { do_read,        "READ"        },
    [FUSE_WRITE]       = { do_write,       "WRITE"       },
    [FUSE_STATFS]      = { do_statfs,      "STATFS"      },
    [FUSE_FLUSH]       = { do_flush,       "FLUSH"       },
    [FUSE_INIT]        = { do_init,        "INIT"        },
    [FUSE_OPENDIR]     = { do_opendir,     "OPENDIR"     },
    [FUSE_READDIR]     = { do_readdir,     "READDIR"     },
    [FUSE_RELEASEDIR]  = { do_releasedir,  "RELEASEDIR"  },
    [FUSE_DESTROY]     = { do_destroy,     "DESTROY"     }
};

接下來看一下do_read的實現(xiàn)

static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
    struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
    // 如果用戶實現(xiàn)了read操作,則調(diào)用用戶空間的read,否則以沒有實現(xiàn)該調(diào)用為錯誤響應(yīng),這里的op就是用戶實現(xiàn)文件系統(tǒng)時實現(xiàn)的,并傳遞給fuse。
    if (req->f->op.read) {
        struct fuse_file_info fi;
        memset(&fi, 0, sizeof(fi));
        fi.fh = arg->fh;
        fi.fh_old = fi.fh;
        req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
    } else
        fuse_reply_err(req, ENOSYS);
}

從這里的實現(xiàn)可以看出,這些操作是沒有加任何鎖的,如果開發(fā)者需要文件系統(tǒng)鎖,需要在實現(xiàn)文件系統(tǒng)時自行考慮。

fuse_operations又是怎么一回事?

對于實現(xiàn)fuse_lowlevel_ops這組接口,沒有內(nèi)核VFS相關(guān)知識的開發(fā)者是不可能完成的,為了增強fuse的通用性,使更多的用戶能夠使用fuse開發(fā)文件系統(tǒng),fuse提供了一組更簡單的接口fuse_operations,詳細說明請參考fuse.h。這組接口的參數(shù)跟unix提供的系統(tǒng)調(diào)用的參數(shù)很類似,開發(fā)者更易理解,fuse想開發(fā)者屏蔽了底層的相關(guān)對象,直接以文件名作為參數(shù),只有開發(fā)者按照自己的方式,把這組接口實現(xiàn)就可以,顯然這比上面那組接口的實現(xiàn)要簡單得多。

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 *);
};

這些操作并非都是必需的,但是一個文件系統(tǒng)要想正常工作,就需要其中的很多函數(shù)。

提供這組接口,fuse做了什么?

fuse還是實現(xiàn)了一組fuse_lowlevel_ops的接口,在fuse.c中

static struct fuse_lowlevel_ops fuse_path_ops = {
    //只列舉了部分方法
    .init = fuse_lib_init,
    .destroy = fuse_lib_destroy,
    .lookup = fuse_lib_lookup,
    .forget = fuse_lib_forget,
    .getattr = fuse_lib_getattr,
    .setattr = fuse_lib_setattr,
.access = fuse_lib_access,
.read = fuse_lib_read,
    .readlink = fuse_lib_readlink
};

fuse實現(xiàn)的這組接口跟之前的方法不一樣,不是什么都不做,它完成了部分工作,主要是文件節(jié)點與文件名的轉(zhuǎn)換關(guān)系,然后將文件名作為參數(shù),調(diào)用用戶實現(xiàn)的fuse_operations的接口。

如fuse_lib_read的實現(xiàn)

int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
                 off_t off, struct fuse_file_info *fi)
{
fuse_get_context()->private_data = fs->user_data;
//用戶實現(xiàn)的方法
    if (fs->op.read)
        return fs->op.read(path, buf, size, off, fi);
    else
        return -ENOSYS;
}
 
static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
                          off_t off, struct fuse_file_info *fi)
{
    struct fuse *f = req_fuse_prepare(req);
    char *path;
    char *buf;
    int res;
 
    buf = (char *) malloc(size);
    if (buf == NULL) {
        reply_err(req, -ENOMEM);
        return;
    }
 
    res = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock); //fuse_operations使用了讀寫鎖
//由ino獲取path
    path = get_path(f, ino);
    if (path != NULL) {
        struct fuse_intr_data d;
        if (f->conf.debug)
            fprintf(stderr, "READ[%llu] %lu bytes from %llun",
                    (unsigned long long) fi->fh, (unsigned long) size,
                    (unsigned long long) off);
 
        fuse_prepare_interrupt(f, req, &d);
        res = fuse_fs_read(f->fs, path, buf, size, off, fi); //通過這個方法調(diào)用用戶實現(xiàn)的方法
        fuse_finish_interrupt(f, req, &d);
        free(path);
    }
    pthread_rwlock_unlock(&f->tree_lock);
 
    if (res >= 0) {
        if (f->conf.debug)
            fprintf(stderr, "   READ[%llu] %u bytesn",
                    (unsigned long long)fi->fh, res);
        if ((size_t) res > size)
            fprintf(stderr, "fuse: read too many bytes");
        fuse_reply_buf(req, buf, res); //返回結(jié)果
    } else
        reply_err(req, res);
 
    free(buf);

FUSE 流程

通過這幅圖可以看到三個模塊在fuse工作時所起的作用

fuse_main() (lib/helper.c)——fuse用戶空間主函數(shù),用戶程序調(diào)用它時,fuse_main()函數(shù)解析相關(guān)參數(shù)(如mountpoint,multithreaded),并調(diào)用fuse_mount()函數(shù),接著調(diào)用fuse_new()函數(shù),為fuse文件系統(tǒng)數(shù)據(jù)分配存儲空間。最后調(diào)用fuse_loop()函數(shù)實現(xiàn)會話的接受與處理。

fuse_mount() (lib/mount.c)——創(chuàng)建UNIX本地套接口,創(chuàng)建并運行子進程fusermount。

fusermount (util/fusermount.c)——確保fuse模塊已經(jīng)加載,通過UNIX套接口返回fuse模塊的文件fd給fuse_mount()函數(shù)。

fuse_new() (lib/fuse.c)——為fuse創(chuàng)建數(shù)據(jù)結(jié)構(gòu)空間,用來存儲文件系統(tǒng)數(shù)據(jù)。

fuse_loop() (lib/fuse.c)( fuse_loop_mt() (lib/fuse_mt.c))——從/dev/fuse (/dev 設(shè)備文件存儲目錄)讀取文件系統(tǒng)調(diào)用,調(diào)用fuse_operations或fuse_lowlevel_ops結(jié)構(gòu)中的處理函數(shù),返回調(diào)用結(jié)果給/dev/fuse

FUSE Kernel模塊由兩部分組成:

第一部分——proc文件系統(tǒng)組件:Kernel/dev.c——回應(yīng)io請求到/dev/fuse。fuse_dev_read()函數(shù)負責(zé)讀出文件,并將來自“l(fā)ist of request”結(jié)構(gòu)體的命令返回到調(diào)用函數(shù)。fuse_dev_write ()負責(zé)文件寫入,并將寫入的數(shù)據(jù)置放到“req→out”數(shù)據(jù)結(jié)構(gòu)中。

第二部分——文件系統(tǒng)調(diào)用部分:kernel/file.c,kernel/inode.c,kernel/dir.c——調(diào)用request_send(),將請求加入到“l(fā)ist of request”結(jié)構(gòu)體中,等待回復(fù)(reply)。

Fuse調(diào)用流程

在shell里輸入命令,請求通過vfs到達fuse,然后通過用戶實現(xiàn)的fuse給出的API返回調(diào)用。

Fuse處理請求的核心工作就是進行隊列管理

兩個重要的數(shù)據(jù)結(jié)構(gòu) fc, req

/* A Fuse connection.
 * This structure is created, when the filesystem is mounted, and is destroyed, when the
 * client device is closed and the filesystem is unmounted. 
*/
Struct  fuse_conn
 {
/** Readers of the connection are waiting on this */
    wait_queue_head_t waitq; // 等待執(zhí)行請求的進程的隊列
    /** The list of pending requests */
    struct list_head pending;  // 被掛起的請求 的隊列
    /** The list of requests being processed */
    struct list_head processing; // 正在被處理的請求的 隊列
/** Pending interrupts */
 struct list_head interrupts;  // 執(zhí)行中被中斷的請求的 隊列
...
}
/*  
*A request to the client
 */
struct fuse_req
{
/** Used to wake up the task waiting for completion of request*/
    wait_queue_head_t waitq;  // 請求的等待隊列
…
}

fuse通過fuse_session_loop來啟動守護程序,守護程序最終會調(diào)用fuse_dev_readv, fuse_dev_readv調(diào)用request_wait,使得進程在fc的waitq隊列上睡眠。

Static  size_t  fuse_dev_readv(struct file *file, const struct iovec *iov,  unsigned long nr_segs, loff_t *off)                              
{
     ….
     request_wait(fc);
 ….
}
* Wait until a request is available on the pending list 
 *當(dāng)前進程一直等待,直到掛起隊列中有一個請求
*/
static void request_wait(struct fuse_conn *fc)
{
DECLARE_WAITQUEUE(wait, current);  //定義一個隊列節(jié)點變量wait,其與當(dāng)前進程相關(guān)聯(lián)
        add_wait_queue_exclusive(&fc->waitq, &wait);  //將wait加入到fc->waitq等待隊列中
        //不斷的檢查fc的pending隊列及interrupts隊列,看是否有請求,沒有請求一直while循環(huán)
         while (fc->connected && !request_pending(fc))
 {
             set_current_state(TASK_INTERRUPTIBLE);
             if (signal_pending(current)) break;
             spin_unlock(&fc->lock);
             schedule();  //選擇一個進程運行
             spin_lock(&fc->lock);
         } 
        // 有請求,將進程設(shè)為TASK_RUNNING狀態(tài)(被喚醒,被賦予CPU使用權(quán))
        set_current_state(TASK_RUNNING); 
        remove_wait_queue(&fc->waitq, &wait); // 將wait(當(dāng)前進程)從等待隊列中移除
}

③// fc的pending隊列及interrupts隊列,看是否有請求
static int request_pending(struct fuse_conn *fc)
{
return !list_empty(&fc->pending) || !list_empty(&fc->interrupts);
}

request_send是用戶請求經(jīng)過vfs(如上面的圖),再到fuse operation中被調(diào)用的,它向/dev/fuse發(fā)送請求

void  request_send(struct fuse_conn *fc, struct fuse_req *req)
{
    ……
    queue_request(fc, req); 
 request_wait_answer(fc, req);
……
}

⑤static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
{
    list_add_tail(&req->list, &fc->pending);  //將請求加入到pending隊列
    req->state = FUSE_REQ_PENDING;
   if (!req->waiting)
 {
  req->waiting = 1;
  atomic_inc(&fc->num_waiting);
    }
wake_up(&fc->waitq);  //喚醒等待等列
    kill_fasync(&fc->fasync, SIGIO, POLL_IN);
}
/* Called with fc->lock held.  Releases, and then reacquires it. */
//該調(diào)用會在req的waitq上睡眠,fuse守護程序處理完請求后,會將其喚醒
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
{
	     if (!fc->no_interrupt) 
{
		    /* Any signal may interrupt this */
		    wait_answer_interruptible(fc, req);
		   if (req->aborted)
			   goto aborted;
		   if (req->state == FUSE_REQ_FINISHED)
			   return; 
		   req->interrupted = 1;
		   if (req->state == FUSE_REQ_SENT)
			   queue_interrupt(fc, req);
	     }
	     if (req->force) {
		spin_unlock(&fc->lock);
		wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
		spin_lock(&fc->lock);
	     } else {
		   sigset_t oldset;
		/* Only fatal signals may interrupt this */
		block_sigs(&oldset);
		wait_answer_interruptible(fc, req);
		restore_sigs(&oldset);
	     }
	    if (req->aborted)
		    goto aborted;
	    if (req->state == FUSE_REQ_FINISHED)   return;
	req->out.h.error = -EINTR;
	req->aborted = 1;
aborted:
	if (req->locked) {
		/* This is uninterruptible sleep, because data is
		   being copied to/from the buffers of req.  During
		   locked state, there mustn't be any filesystem
		   operation (e.g. page fault), since that could lead
		   to deadlock */
		spin_unlock(&fc->lock);
		wait_event(req->waitq, !req->locked);
		spin_lock(&fc->lock);
	}
	if (req->state == FUSE_REQ_PENDING) {
		list_del(&req->list);
		__fuse_put_request(req);
	} else if (req->state == FUSE_REQ_SENT) {
		spin_unlock(&fc->lock);
		wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
		spin_lock(&fc->lock);
	}
}
}

 (左列七行)fuse守護程序處理完請求,最終通過fuse_dev_writev寫回/dev/fuse,它將喚醒相應(yīng)req中waitq的等待隊列元素,從而讓文件系統(tǒng)請求完成request_wait_answer,獲取到結(jié)果。
⑦/**Write a single reply to a request.  First the header is copied from the write buffer.  The request is then *searched on the processing list by the unique ID found in the header.  If found, then remove it from the list *and copy the rest of the buffer to the request. The request is finished by calling request_end()
 */
static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,  unsigned long nr_segs, loff_t *off)                                                  
{
   ……..
req = request_find(fc, oh.unique);
   request_end(fc, req);
   ….
}
⑧/* * This function is called when a request is finished.  Either a reply has arrived or it was aborted (and not yet *sent) or some error occurred during communication with userspace, or the device file was closed.  The *requester thread is woken up (if still waiting), the 'end' callback is called if given, else the reference to the *request is released Called with fc->lock, unlocks it 
*/
static void request_end(struct fuse_conn *fc, struct fuse_req *req)
{
   ….
   wake_up(&req->waitq);  //喚醒req上的等待隊列
   ……
}

fuse通過fuse_session_loop(或?qū)?yīng)多線程的方法)來啟動fuse守護程序,守護程序不斷的從/dev/fuse上讀取請求,并處理。

int fuse_session_loop(struct fuse_session *se) //在fuse_main中會被調(diào)用,或其多線程版本
{
    int res = 0;
    struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
    size_t bufsize = fuse_chan_bufsize(ch);
    char *buf = (char *) malloc(bufsize); //為channel分配好緩沖區(qū)
    if (!buf) {
        fprintf(stderr, "fuse: failed to allocate read buffer
");
        return -1;
}
//fuse daemon, loops
    while (!fuse_session_exited(se)) {
        struct fuse_chan *tmpch = ch;
// 從/dev/fuse讀請求,會等待一直到有請求為止
        res = fuse_chan_recv(&tmpch, buf, bufsize);
        if (res == -EINTR)   continue;
        if (res <= 0)       break;
        fuse_session_process(se, buf, res, tmpch);   //處理讀到的請求
    }
free(buf);
fuse_session_reset(se);
return res < 0 ? -1 : 0;
}
②int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size)
{
    struct fuse_chan *ch = *chp;
    if (ch->compat)
        return ((struct fuse_chan_ops_compat24 *) &ch->op)->receive(ch, buf, size);
    else
        return ch->op.receive(chp, buf, size); //由下面的一段代碼可以發(fā)現(xiàn),receive最終是通過
// fuse_kern_chan_receive實現(xiàn)的,代碼片段3分析該請求
}
③#define MIN_BUFSIZE 0x21000
struct fuse_chan *fuse_kern_chan_new(int fd)
{
    //channel的讀寫方法
    struct fuse_chan_ops op = {
        .receive = fuse_kern_chan_receive,
        .send = fuse_kern_chan_send,
        .destroy = fuse_kern_chan_destroy,
};
//設(shè)置bufsize大小
    size_t bufsize = getpagesize() + 0x1000;
    bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;
    return fuse_chan_new(&op, fd, bufsize, NULL);
}
static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,  size_t size)
{
    struct fuse_chan *ch = *chp;
    int err;
    ssize_t res;
    struct fuse_session *se = fuse_chan_session(ch);
    assert(se != NULL);
    // 一直輪詢,直到讀到請求為止
 restart:
    //fuse_chan_fd獲取到/dev/fuse的文件描述符,調(diào)用read系統(tǒng)調(diào)用從設(shè)備讀取請求
res = read(fuse_chan_fd(ch), buf, size); 
//根據(jù)fuse設(shè)備驅(qū)動程序file結(jié)構(gòu)的實現(xiàn)(dev.c),read將調(diào)用fuse_dev_read,該方法最終通過fuse_dev_readv
//實現(xiàn),根據(jù)代碼中的注釋,fuse_dev_read做了如下工作:
// Read a single request into the userspace filesystem's buffer.  This function waits until a request is available, 
// then removes it from the pending list and copies request data to userspace buffer.
// 而fuse_dev_read又調(diào)用request_wait,使得進程在fc->waitq上睡眠
    if no data: goto restart
    ………
}

以上的分析對應(yīng)了fuse filesystem daemon做的第一部分工作。當(dāng)用戶從控制臺輸入"rm /mnt/fuse/file"時,通過VFS(sys_unlink),再到fuse(dir.c中實現(xiàn)的inode_operations,file.c中實現(xiàn)的file_operations中的方法都會最終調(diào)用request_send,后面會講到),這個請求最終被發(fā)到了/dev/fuse中,該請求的到達會喚醒正在等待的fuse守護程序,fuse守護程序讀取該請求并進行處理,接下來介紹處理請求所作的工作。

⑤struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, 
                                      const struct fuse_lowlevel_ops *op,
                                       size_t op_size, void *userdata)
{
//fuse_lowlevel_ops在之前的文章
http://blog.chinaunix.net/u2/87570/showart_2166461.html中已經(jīng)介紹//過了,開發(fā)者實現(xiàn)了fuse_lowlevel_ops并傳遞給fuse_lowlevel_common
    struct fuse_ll *f;
    struct fuse_session *se;
struct fuse_session_ops sop = {
    //最終調(diào)用的處理方法
        .process = fuse_ll_process, //分析見代碼片段5
        .destroy = fuse_ll_destroy,
    };
  …….
}
⑥static void fuse_ll_process(void *data, const char *buf, size_t len, struct fuse_chan *ch)
{
    struct fuse_ll *f = (struct fuse_ll *) data;
    struct fuse_in_header *in = (struct fuse_in_header *) buf;
    const void *inarg = buf + sizeof(struct fuse_in_header);
struct fuse_req *req;
    //創(chuàng)建并初始化一個請求
    req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
    if (req == NULL) {
        fprintf(stderr, "fuse: failed to allocate request
");
        return;
    }
    req->f = f;
req->unique = in->unique;
……
//根據(jù)opcode調(diào)用fuse_ll_ops中相應(yīng)的方法,fuse_ll_ops的介紹
// http://blog.chinaunix.net/u2/87570/showart_2166461.html
    fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
    }
}

以上代碼對應(yīng)中流程中perform unlink的工作,實際上就是執(zhí)行開發(fā)者實現(xiàn)的一組方法來完成相關(guān)的工作,接下來就是把執(zhí)行完請求后需要的數(shù)據(jù)返回,最終是通過send_reply實現(xiàn)的

⑦static int send_reply(fuse_req_t req, int error, const void *arg, size_t argsize)
{
    struct iovec iov[2];
    int count = 1;
    if (argsize) {
        iov[1].iov_base = (void *) arg;
        iov[1].iov_len = argsize;
        count++;
    }
    return send_reply_iov(req, error, iov, count);
}
⑧static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, int count)
{
    ……
    res = fuse_chan_send(req->ch, iov, count);
    free_req(req);
    return res;
}
⑨static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],  size_t count)
{
    if (iov) {
        //將數(shù)據(jù)寫到/dev/fuse上,最終會調(diào)用fuse_dev_write
        ssize_t res = writev(fuse_chan_fd(ch), iov, count);
    ……
    return 0;
}

另外fuse接收到VFS的請求時,通過request_send將請求發(fā)送到/fuse/dev,并調(diào)用request_wait_answer等待返回結(jié)果。至于fuse使用的隊列的管理,在流程圖中也做了簡單的說明,下一篇文章將詳細分析隊列的管理。

void request_send(struct fuse_conn *fc, struct fuse_req *req)
{
         req->isreply = 1;
         spin_lock(&fc->lock);
         if (!fc->connected)
                   req->out.h.error = -ENOTCONN;
         else if (fc->conn_error)
                   req->out.h.error = -ECONNREFUSED;
         else {
        //將請求加入請求隊列
                   queue_request(fc, req);
                   /* acquire extra reference, since request is still needed after request_end() */
                   __fuse_get_request(req);
        //等待結(jié)果
                   request_wait_answer(fc, req);
         }
         spin_unlock(&fc->lock);
}

  

總結(jié)

以上是生活随笔為你收集整理的FUSE简介的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。