FUSE隊列管理淺析

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


代碼片段1

static ssize_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 */

static void request_wait(struct fuse_conn *fc)

{

    //定義一個隊列節點變量wait,其與當前進程相關聯

    DECLARE_WAITQUEUE(wait, current);


//將wait加入到fc->waitq等待隊列中,當有請求發到fuse文件系統時(通過request_send),這個等待隊列上的進程會被喚醒,某一個進程會被賦予CPU使用權

    add_wait_queue_exclusive(&fc->waitq, &wait);


    //不斷的檢查fc的pending隊列及interrupts隊列,看是否有請求,沒有請求會一直while循環

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

    }

    //有請求,將進程設爲TASK_RUNNING狀態

    set_current_state(TASK_RUNNING);

    //將wait從等待隊列中移除

    remove_wait_queue(&fc->waitq, &wait);

}


static int request_pending(struct fuse_conn *fc)

{

    return !list_empty(&fc->pending) || !list_empty(&fc->interrupts);

}


request_send是用戶請求經過vfs,再到fuse operation中被調用的,它向/dev/fuse發送請求

代碼片段2

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)

{

//將請求加入到pending隊列

list_add_tail(&req->list, &fc->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. */

static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)

{

     //該調用會在req的waitq上睡眠,fuse守護程序處理完請求後,會將其喚醒

}


fuse守護程序處理完請求,最終通過fuse_dev_writev寫回/dev/fuse,它將喚醒相應req中waitq的等待隊列元素,從而讓文件系統請求完成request_wait_answer,獲取到結果。


/*

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)

{

//喚醒req上的等待隊列

wake_up(&req->waitq);

}


fuse設備其的主要工作其實就是進行隊列的管理,對fuse設備的讀(寫)其實就是從相應的隊列移除(添加)請求(或響應),request_send將請求加入pending隊列,喚醒fuse守護程序,並在req的waitq上等待請求結果,守護程序通過fuse_dev_readv從pending隊列中移除請求並處理,處理完成後,守護程序喚醒req的waitq上的進程,該進程讀取結果,並返回給用戶。總的來說,一個請求從發起到完成會經過4步:

0.   fuse守護程序在fc的waitq上等待請求;

1.  用戶的請求喚醒fc的waitq,從該waitq上移除一個請求進行處理,並在req的waitq上等待請求結果;

2.  fuse守護程序被喚醒,讀取請求,處理請求,返回結果,喚醒對應req上的waitq隊列。

3.  請求被喚醒,讀取fuse守護程序返回的結果,返回給用戶。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章