免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1536 | 回复: 0
打印 上一主题 下一主题

fuse队列管理浅析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-02-03 13:46 |只看该作者 |倒序浏览

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.       用户的请求唤醒0中waitq,从waitq上移除一个请求进行处理,并在req的waitq上等待请求结果;
2.       fuse守护程序被唤醒,读取请求,处理请求,返回结果,唤醒对应req上的waitq队列。
3.       请求被唤醒,读取fuse守护程序返回的结果,返回给用户。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/87570/showart_2170133.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP