`

fuse调用流程分析

阅读更多
fuse处理请求的整个流程如下图所示,以unlink操作为例进行说明。其中“>”表示调用,”<”表示返回,[]表示调用中所做的工作。本人结合fuse的源代码,对整个流程进行了分析。









fuse通过fuse_session_loop(或对应多线程的方法)来启动fuse守护程序,守护程序不断的从/dev/fuse上读取请求,并处理。



代码片段1

int fuse_session_loop(struct fuse_session *se) //在fuse_main中会被调用,或其多线程版本

{

    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分配好缓冲区

    if (!buf) {

        fprintf(stderr, "fuse: failed to allocate read buffer\n");

        return -1;

    }



         //fuse daemon, loops

    while (!fuse_session_exited(se)) {

        struct fuse_chan *tmpch = ch;

//分析见代码片段2,从/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;

}



//代码片段2

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

        //由下面的一段代码可以发现,receive最终是通过fuse_kern_chan_receive实现的,代码片段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,

};

//设置bufsize大小

    size_t bufsize = getpagesize() + 0x1000;

    bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;

    return fuse_chan_new(&op, fd, bufsize, NULL);

}



代码片段3

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_fs获取到/dev/fuse的文件描述符,调用read系统调用从设备读取请求

res = read(fuse_chan_fd(ch), buf, size);

//根据fuse设备驱动程序file结构的实现(dev.c),read将调用fuse_dev_read,该方法最终通过fuse_dev_readv实现,根据代码中的注释,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.

   

    if no data: goto restart

    ………

}



以上的分析对应了fuse filesystem daemon做的第一部分工作。当用户从控制台输入"rm /mnt/fuse/file"时,通过VFS(sys_unlink),再到fuse(dir.c中实现的inode_operations,file.c中实现的file_operations中的方法都会最终调用request_send,后面会介绍),这个请求最终被发到了/dev/fuse中,该请求的到达会唤醒正在等待的fuse守护程序,fuse守护程序读取该请求并进行处理,接下来介绍处理请求所作的工作。




代码片段4

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中已经介绍过了,开发者实现了fuse_lowlevel_ops并传递给fuse_lowlevel_common

    struct fuse_ll *f;

    struct fuse_session *se;

struct fuse_session_ops sop = {

    //最终调用的处理方法

        .process = fuse_ll_process, //分析见代码片段5

        .destroy = fuse_ll_destroy,

    };



  …….

}





代码片段5                                  

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;



    //创建并初始化一个请求

    req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));

    if (req == NULL) {

        fprintf(stderr, "fuse: failed to allocate request\n");

        return;

    }



    req->f = f;

req->unique = in->unique;

……

//根据opcode调用fuse_ll_ops中相应的方法,fuse_ll_ops的介绍http://blog.chinaunix.net/u2/87570/showart_2166461.html

    fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);

    }

}



以上代码对应中流程中perform unlink的工作,实际上就是执行开发者实现的一组方法来完成相关的工作,接下来就是把执行完请求后需要的数据返回,最终是通过send_reply实现的,



代码片段6

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

        //将数据写到/dev/fuse上,最终会调用fuse_dev_write

        ssize_t res = writev(fuse_chan_fd(ch), iov, count);

    ……

    return 0;

}





另外fuse接收到VFS的请求时,通过request_send将请求发送到/fuse/dev,并调用request_wait_answer等待返回结果。至于fuse使用的队列的管理,在流程图中也做了简单的说明,下一篇文章将详细分析队列的管理。



代码片段7

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

        //等待结果

                   request_wait_answer(fc, req);

         }

         spin_unlock(&fc->lock);

}







  • 大小: 127.6 KB
分享到:
评论

相关推荐

    fuse文件系统源码

    通过学习和分析FUSE源码,不仅可以提升对Linux文件系统和内核编程的理解,还能为开发个性化文件系统打下坚实基础。总之,FUSE文件系统为Linux生态系统带来了无限的可能性,是开发者和研究人员不可多得的工具。

    fuse文件系统课程设计

    Fuse的核心思想是通过系统调用将内核中的文件系统操作映射到用户空间的函数,从而实现了用户空间文件系统。在Fuse中,开发者需要实现一系列回调函数,这些函数对应于标准文件系统操作,如open、read、write、mkdir等...

    SCUT fuse文件系统

    而“操作系统课设_fuse设计源码.tar”则包含了实际的源代码,可以通过阅读源码来深入理解文件系统的内部工作原理,包括函数调用流程、数据结构设计以及特定功能的实现。 **学习与实践** 对于操作系统课程设计而言,...

    linux_kernel_fuse_源码剖析解析.docx

    5. **执行用户定义的写操作**:用户空间读取并分析请求数据,执行用户自定义的`write`操作,并通过`fuse_reply_write`函数将结果返回给内核。 6. **结果反馈**:内核再次调用`vfs_write`,并通过`fuse_dev_write`将...

    qosfs-free:具有 QoS 的 FUSE 文件系统

    FUSE允许用户在用户空间编写文件系统,简化了开发流程,同时也使得QoSFS-Free能够灵活地实施定制化的QoS策略。 **FUSE** 是一种轻量级的机制,它允许非特权用户在用户空间实现自己的文件系统,而无需修改内核代码。...

    ntfs-3g源码

    通过FUSE,ntfs-3g避免了内核模块的复杂性和安全性问题,同时允许开发者在用户空间编写和调试代码,极大地简化了开发流程。了解FUSE的工作原理对于理解ntfs-3g至关重要,因为它涉及到I/O操作、系统调用、信号处理等...

    LINUX内核模块编程

    3. 文件系统:开发新的文件系统类型,如FUSE(Filesystem in Userspace)允许在用户空间实现文件系统。 六、调试内核模块 1. `dmesg`:查看内核消息,了解模块加载和运行情况。 2. `kernel log`:通过日志文件分析...

    CDH5Hadoop发行版离线安装手册.docx

    - **Impala内存数据库**: Impala是CDH中集成的一款内存数据库软件,能够在毫秒级响应时间内完成对大数据集的查询,极大地提高了数据分析的速度。 **1.3 解决的问题** 随着数据量的不断增长,传统的数据库管理系统...

    arm-linux-gcc_4.9.1

    5. **Linux ABI**:理解GNU/Linux ABI的重要性,包括调用约定、数据类型和内存布局,这对于确保编译的代码能在目标系统上正确运行至关重要。 6. **S3C2440处理器**:深入研究这款处理器的特点、性能和常见应用,...

    FreeBSD Handbooks 手册

    3. 系统管理:讲解系统服务的启动与停止、用户与权限管理、系统安全设置、性能监控和日志分析等。 **开发手册** 主要面向开发者和系统管理员,提供了FreeBSD下的程序开发、调试、测试和打包的详细信息: 1. 编程...

    monitor-expcs07.pdf

    - **全面的系统调用拦截**:由于 ptrace 可以拦截所有操作系统入口点(包括系统调用和信号),因此相比于其他原型设计技术(如 FUSE 或者用户级 NFS 服务器)提供了更多的功能。 #### 实例研究 文章中提到了几种...

    浅析主流商业和开源ESB产品

    本文旨在深入探讨当前主流的商业与开源ESB产品的特点和发展趋势,并分析它们的优点及存在的不足之处。主要涉及的产品包括:Oracle Service Bus (OSB)、WebSphere Message Broker (WMB)、Mule、ServiceMix/FUSE ESB ...

    Open Source ESBs In Action

    开源ESB项目如Apache CXF、MuleSoft Anypoint、Red Hat JBoss Fuse等,为开发者提供了强大的功能,包括服务发现、数据转换、事务管理、安全性以及性能优化等。 二、ESB的核心组件 1. **消息代理**:作为ESB的基础,...

    ceph知识树.pdf

    - **ftrace/strace**:跟踪系统调用和函数调用。 - **lttng/perf**:用于实时追踪和性能分析。 **Ceph性能分析:** - **ceph-w**:监控Ceph集群状态。 - **cephtellosd.*heapstats**:检查OSD堆内存状态。 - **ceph...

    HMPPWorkbench 用户手册

    - **功能特性:** 它提供了一套全面的工具链,包括编译器、调试器、性能分析器等,旨在简化并行程序的开发流程。 - **目标用户:** 主要面向需要利用高性能计算资源进行复杂计算任务的科研人员和工程师。 **HMPP ...

Global site tag (gtag.js) - Google Analytics