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守护程序返回的结果,返回给用户。


你可能感兴趣的:(源码,linux,开发)