FUSE 内核实现代码分析(二) 队列管理
2014-09-09 14:19
363 查看
fuse处理的请求和操作非常多,代码里有相当多的函数,分析起来很容易陷入函数调用泥潭里,所以要抓住关键分析。
fuse的关键是对请求队列的处理,所以搞清楚fuse如何管理请求队列是基础。先上一张关系图
这里一共有两个进程等待队列:一个是用户空间fuse库对/dev/fuse读写的进程等待队列,一个是发起VFS调用请求的进程的等待队列
一个请求pending队列:需要处理的请求都挂在这个队列上
下面再看相关数据结构
1. fuse守护进程在fuse_session_loop中一直read设备-->内核中fuse_dev_read-->fuse_dev_do_read-->request_wait
将进程睡眠在fc->waitq上
/* Wait until a request is available on the pending list */
static void request_wait(struct fuse_conn *fc)
__releases(fc->lock)
__acquires(fc->lock)
{
DECLARE_WAITQUEUE(wait, current);
add_wait_queue_exclusive(&fc->waitq, &wait);
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);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&fc->waitq, &wait);
}
判断进程是否睡眠的条件是request_pending()
static int request_pending(struct fuse_conn *fc)
{
return !list_empty(&fc->pending) || !list_empty(&fc->interrupts) ||
forget_pending(fc);
}
看三个请求队列是不是为空,为空则睡眠,不为空则处理
2. VFS文件系统操作请求使用fuse_request_send向fuse守护进程发送请求
static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
{
BUG_ON(req->background);
spin_lock(&fc->lock);
if (!fc->connected)
req->out.h.error = -ENOTCONN;
else if (fc->conn_error)
req->out.h.error = -ECONNREFUSED;
else {
req->in.h.unique = fuse_get_unique(fc);
queue_request(fc, req); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/* acquire extra reference, since request is still needed
after request_end() */
__fuse_get_request(req);
request_wait_answer(fc, req); <<<<<<<<<<<<<<<<<<<<<<<<<<<
}
spin_unlock(&fc->lock);
}
void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
{
req->isreply = 1;
__fuse_request_send(fc, req);
}
EXPORT_SYMBOL_GPL(fuse_request_send);
首先调用queue_request将请求放入fc->pending队列并唤醒用户空间fuse守护进程处理请求,
static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
{
req->in.h.len = sizeof(struct fuse_in_header) +
len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
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);
}
然后调用rquest_wait_answer睡眠在req->waitq上等待处理完成
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
__releases(fc->lock)
__acquires(fc->lock)
{
... ...
/*
* Either request is already in userspace, or it was forced.
* Wait it out.
*/
spin_unlock(&fc->lock);
wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
spin_lock(&fc->lock);
... ...
}
3. fuse守护进程被唤醒,处理完成后,将结果写回fuse设备,并唤醒req->waitq上等待进程来取回结果,fuse_dev_write-->fuse_dev_do_write
static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct fuse_copy_state cs;
struct fuse_conn *fc = fuse_get_conn(iocb->ki_filp);
if (!fc)
return -EPERM;
fuse_copy_init(&cs, fc, 0, iov, nr_segs);
return fuse_dev_do_write(fc, &cs, iov_length(iov, nr_segs));
}
4. VFS文件系统操作请求被唤醒,取回处理结果
/*
* 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)
__releases(fc->lock)
{
... ...
req->state = FUSE_REQ_FINISHED;
wake_up(&req->waitq);
... ...
}
下面以一个删除文件操作展示一下具体流程:>为调用,<为返回
到此可以看清fuse和用户空间交互的过程,fuse用户态库和内核代码对请求处理的细节待后续分析。
fuse的关键是对请求队列的处理,所以搞清楚fuse如何管理请求队列是基础。先上一张关系图
这里一共有两个进程等待队列:一个是用户空间fuse库对/dev/fuse读写的进程等待队列,一个是发起VFS调用请求的进程的等待队列
一个请求pending队列:需要处理的请求都挂在这个队列上
下面再看相关数据结构
struct fuse_conn { /** Readers of the connection are waiting on this */ wait_queue_head_t waitq; /** 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; ...... };
struct fuse_req { /** This can be on either pending processing or io lists in fuse_conn */ struct list_head list; /** Entry on the interrupts list */ struct list_head intr_entry; /** Used to wake up the task waiting for completion of request*/ wait_queue_head_t waitq; ...... };
1. fuse守护进程在fuse_session_loop中一直read设备-->内核中fuse_dev_read-->fuse_dev_do_read-->request_wait
将进程睡眠在fc->waitq上
/* Wait until a request is available on the pending list */
static void request_wait(struct fuse_conn *fc)
__releases(fc->lock)
__acquires(fc->lock)
{
DECLARE_WAITQUEUE(wait, current);
add_wait_queue_exclusive(&fc->waitq, &wait);
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);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&fc->waitq, &wait);
}
判断进程是否睡眠的条件是request_pending()
static int request_pending(struct fuse_conn *fc)
{
return !list_empty(&fc->pending) || !list_empty(&fc->interrupts) ||
forget_pending(fc);
}
看三个请求队列是不是为空,为空则睡眠,不为空则处理
2. VFS文件系统操作请求使用fuse_request_send向fuse守护进程发送请求
static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
{
BUG_ON(req->background);
spin_lock(&fc->lock);
if (!fc->connected)
req->out.h.error = -ENOTCONN;
else if (fc->conn_error)
req->out.h.error = -ECONNREFUSED;
else {
req->in.h.unique = fuse_get_unique(fc);
queue_request(fc, req); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
/* acquire extra reference, since request is still needed
after request_end() */
__fuse_get_request(req);
request_wait_answer(fc, req); <<<<<<<<<<<<<<<<<<<<<<<<<<<
}
spin_unlock(&fc->lock);
}
void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
{
req->isreply = 1;
__fuse_request_send(fc, req);
}
EXPORT_SYMBOL_GPL(fuse_request_send);
首先调用queue_request将请求放入fc->pending队列并唤醒用户空间fuse守护进程处理请求,
static void queue_request(struct fuse_conn *fc, struct fuse_req *req)
{
req->in.h.len = sizeof(struct fuse_in_header) +
len_args(req->in.numargs, (struct fuse_arg *) req->in.args);
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);
}
然后调用rquest_wait_answer睡眠在req->waitq上等待处理完成
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
__releases(fc->lock)
__acquires(fc->lock)
{
... ...
/*
* Either request is already in userspace, or it was forced.
* Wait it out.
*/
spin_unlock(&fc->lock);
wait_event(req->waitq, req->state == FUSE_REQ_FINISHED);
spin_lock(&fc->lock);
... ...
}
3. fuse守护进程被唤醒,处理完成后,将结果写回fuse设备,并唤醒req->waitq上等待进程来取回结果,fuse_dev_write-->fuse_dev_do_write
static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct fuse_copy_state cs;
struct fuse_conn *fc = fuse_get_conn(iocb->ki_filp);
if (!fc)
return -EPERM;
fuse_copy_init(&cs, fc, 0, iov, nr_segs);
return fuse_dev_do_write(fc, &cs, iov_length(iov, nr_segs));
}
/* * 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_do_write(struct fuse_conn *fc, struct fuse_copy_state *cs, size_t nbytes) { ... ... req = request_find(fc, oh.unique); ... ... request_end(fc, req); ... ... }
4. VFS文件系统操作请求被唤醒,取回处理结果
/*
* 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)
__releases(fc->lock)
{
... ...
req->state = FUSE_REQ_FINISHED;
wake_up(&req->waitq);
... ...
}
下面以一个删除文件操作展示一下具体流程:>为调用,<为返回
到此可以看清fuse和用户空间交互的过程,fuse用户态库和内核代码对请求处理的细节待后续分析。
相关文章推荐
- FUSE 内核实现代码分析(一) 初始化
- 基于Visual C++之Windows核心编程代码分析(2)实现Windows用户管理
- 用内核定时器来实现的按键驱动代码分析以及测试代码
- 螺旋队列---最简分析及代码实现
- 黑马程序员:交通灯管理系统分析及代码实现
- 应用框架的设计与实现——.NET平台(9 消息队列服务代码分析)
- 通过内嵌汇编实现模拟时间片轮转多道程序的内核代码分析
- 内核内存池管理技术实现分析【转】
- 基于Linux的消息队列及多线程编程实现的聊天室(二)代码分析
- 数据结构:队列Queue的实现与代码分析
- Ascent代码分析4-World之地图管理及实现结构
- 实现挂号管理窗体功能代码分析(三)
- Linux RCU队列(3)树形RCU队列实现代码分析
- 内核内存池管理技术实现分析
- 基于Visual C++之Windows核心编程代码分析(2)实现Windows用户管理
- CVE-2014-0038内核漏洞原理与本地提权利用代码实现分析 作者:seteuid0
- 简单SNMP管理程序的VC++代码实例实现
- 代码分析-DataGrid实现自增列、单选、多选
- [网际参考]权限管理设计、分析、实现
- 用.net实现远程获取其他网站页面内容!(核心代码分析)