fuse_loop_mt.c 中fuse_do_work函数使用while循环在后台不断运行,每一个while循环中,主要有两个操作。

1. fuse_session_receive_buf(mt->se, &fbuf, &ch);  fuse_session.c

2. fuse_session_process_buf(mt->se, &fbuf, ch);

操作1使用 se->receive_buf(se, buf, chp)读取buffer内容。

操作2使用se->process_buf(se->data, buf, ch);处理buffer内容。

receive_buf和process_buf是两个函数指针,属于fuse_i.h的struct fuse_session的成员。

搜索整个源文件,只发现在fuse_lowlevel.c中的struct fuse_session *fuse_lowlevel_new_common有一句

    se->receive_buf = fuse_ll_receive_buf; //fuse_ll_receive_buf函数也在该源文件中。

经过打印发现,就是这个函数在处理接受。

//////fuse_ll_receive_buf函数有个重要的操作是创建pipe, 调用 llp = fuse_ll_get_pipe(f);

////static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_ll *f)函数使用

////  res = pipe(llp->pipe);

/////创建pipe。

这个函数会转到fallback标签,因为 !(f->conn.want & FUSE_CAP_SPLICE_READ) 为真,一个是16,一个是512,与以后为0,取反为真。

于是调用 fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size 函数。该函数在fuse_session.c中。

在一开始的两个操作中,都有if语句,else是进入 fuse_chan_recv函数,但是那里都没有进入else,而最终还是在这里进入了该函数。

然后调用int res=ch->op.receive(chp, buf, size);

其中ch是struct fuse_chan **类型,定义在fuse_session.c中。op是struct fuse_chan_ops类型,定义在fuse_lowlevel.h中。

但是无法得知receive函数定义在哪,这需要追中ch及op在哪里被赋值。

追踪:

1. ch 在fuse_chan_recv(fuse_session.c)中没有被修改,因此其值从fuse_ll_receive_buf(fuse_lowlevel.c)传递来.

2. 在fuse_ll_receive_buf中仍然没有被修改。

    此处发现,struct fuse_session在fuse_i.h中声明,在fuse_lowlevel.c中给其成员函数指针赋值。

  因此,值从fuse_session_receive_buf(fuse_session.c )中传来。

3.  fuse_session_receive_buf是被fuse_do_work(fuse_loop_mt.c )调用的。

现在来看在fuse_do_work中 ch的赋值过程。

1.  回溯 struct fuse_chan *ch = mt->prevch;

    struct fuse_mt *mt = w->mt;

      struct fuse_worker *w = (struct fuse_worker *) data;

  data是由pthread_create(thread_id, &attr, func, arg)   (fuse_loop_mt.c )传递来的。

    追溯到fuse_loop_mt.c 中的fuse_start_thread,这里也是没改变 arg的值,

再追溯到fuse_loop_start_thread(fuse_loop_mt.c )中的 w,这个变量就是元凶。其类型为fuse_worker。以参数形式传递到fuse_do_work中的w。

我们关心的是 w->mt->prevch.

2.

struct fuse_worker {
  struct fuse_worker *prev;
  struct fuse_worker *next;
  pthread_t thread_id;
  size_t bufsize;
  char *buf;
  struct fuse_mt *mt;
};

这里的mt由fuse_session_loop_mt(fuse_loop_mt.c )函数中传入。在该函数中有mt.prevch = fuse_session_next_chan(se, NULL);

struct fuse_session {//se
  struct fuse_session_ops op;

  int (*receive_buf)(struct fuse_session *se, struct fuse_buf *buf, struct fuse_chan **chp);

  void (*process_buf)(void *data, const struct fuse_buf *buf, struct fuse_chan *ch);

  void *data;

  volatile int exited;

  struct fuse_chan *ch;
};

struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, struct fuse_chan *ch)
{
  assert(ch == NULL || ch == se->ch);
  if (ch == NULL)
    return se->ch;
  else
    return NULL;
}

而se是由函数fuse_loop_mt(struct fuse *f) 中传入。res = fuse_session_loop_mt(fuse_get_session(f));

struct fuse_session *fuse_get_session(struct fuse *f)
{
  return f->se;
}

而f是由fuse_main_common(helper.c)中传入。

struct fuse {
  struct fuse_session *se;
  struct node_table name_table;
  struct node_table id_table;
  struct list_head lru_table;
  fuse_ino_t ctr;
  unsigned int generation;
  unsigned int hidectr;
  pthread_mutex_t lock;
  struct fuse_config conf;
  int intr_installed;
  struct fuse_fs *fs;
  int nullpath_ok;
  int utime_omit_ok;
  struct lock_queue_element *lockq;
  int pagesize;
  struct list_head partial_slabs;
  struct list_head full_slabs;
  pthread_t prune_thread;
};

3. fuse_main_common函数中创建struct fuse *fuse;但是由fuse_setup_common)(helper.c)赋值。又由fuse_new_common(fuse.c)赋值 。

    其中f->se = fuse_lowlevel_new_common(args, &llop, sizeof(llop), f);该函数在(fuse_lowlevel.c)中。

我们要找se->ch的赋值。

  

4. 重点来了。

    在fuse.c的fuse_new_common中,fuse_session_add_chan(f->se, ch);给se赋了值。

      那么,这里的ch是哪里来的?

  是fuse_new_common(fuse.c)传来的。并由fuse_mount_common(helper.c)构建,这里使用ch = fuse_kern_chan_new(fd);构建。

在fuse_kern_chan.c中:

struct fuse_chan *fuse_kern_chan_new(int fd)
{
  struct fuse_chan_ops op = {
    .receive = fuse_kern_chan_receive,
    .send = fuse_kern_chan_send,
    .destroy = fuse_kern_chan_destroy,
  };
  size_t bufsize = getpagesize() + 0x1000;
  bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;
  return fuse_chan_new(&op, fd, bufsize, NULL);
}

  终于名了,最终.receive 函数指针指向的是 fuse_kern_chan_receive函数,在fuse_kern_chan.c中。

现在的问题变为,fuse_kern_chan_receive中的read系统调用的fd,即fuse_chan_fd(ch)是从哪里打开的。

1. 我们在回溯一下调用过程。

    fuse_kern_chan_receive

        fuse_mount_common

原来是在fuse_mount_common中调用fuse_mount_compat25打开的。

    fuse_mount_compat25调用 fuse_kern_mount, fuse_kern_mount调用fuse_mount_sys或fuse_mount_fusermount。

以fuse_mount_sys为例,他会打开/dev/fuse,并返回文件描述符。/dev/fuse是一个字符设备。

至此,终于清晰了。

后台while收发过程的更多相关文章

  1. SpringMVC中,前台jsp封装参数,绑定参数,传递参数到后台controller的过程详解

    前台到后台的流程:前台jsp->后台:controller控制器层->service业务层->DAO数据访问层->数据库model模型层. 从上面流程可知,前台jsp的数据,想 ...

  2. 后台程序编译过程报错PCC-F-02104, Unable to connect to Oracle

    偶然重新编译了一下后台程序,发现编译过程报错无法连接数据库.但通过sqlplus登录数据库是正常的.后台程序改动中也做了详细的分析,没有改动相关数据库的参数和配置. 最后通过浏览器查看了很多相关问题的 ...

  3. [INet] WebSocket 协议中的数据收发过程

    WebSocket 和 HTTP 相似,只是一个应用层协议,对下层透明,所以不涉及 TCP/IP. 由于浏览器支持了 WebSocket,所以在用 JS 写客户端的时候,是无需考虑数据的编码解码的. ...

  4. 使用js获取复选框的值,并把数组传回后台处理,过程使用的是Ajax异步查询

    这是界面代码: ​ function shua(){             var id_array=new Array();         $('input[id="checkAll& ...

  5. 记一次用WireShark抓包摆脱Si服后台限制的过程

    背景:闲着无聊找了个小众的手游,因为手游都是比较吃金的,所以就找了个Si服,鉴于小时候宝可梦的情怀,就TB买了个GM后台.谁知这玩意有限制,到了100级之后升级超级难,最多只能发送99999W点经验, ...

  6. [na]mail收发过程

    以前老记不住这smtp和pop3谁收谁发. 简单邮件传输协议(SMTP),用来发送或中转发出的电子邮件,       占用tcp 25端口. 第三版邮局协议(POP3),用于将服务器上把邮件存储到本地 ...

  7. Socket的双网卡收发(C#)

    最近的一个项目中需要同时使用两块网卡收发UDP组播数据包,并且要求使用Socket的方式接收和发送网络数据包(我不会告诉你们我之前是直接使用SharpPcap来实现的).在C#中Socket接触的比较 ...

  8. node学习笔记(二)(ajax方式向node后台提交数据)

    通过ajax向node后台提交数据过程(附手写前后台代码),并总结post与get的区别 POST 前台代码 //CSS简单给点样式 <style> form{ width: 200px; ...

  9. C++后台服务崩溃堆栈日志

    C++后台服务崩溃堆栈日志 C/C++后台服务运行过程中总会出现一些不容易重现的崩溃故障,由于重现频率低,同时运行在服务器上,导致无法调试,此外服务直接崩溃,常规日志无法截获到有用信息,这时如果能够保 ...

随机推荐

  1. iOS7 毛玻璃效果

    转自:http://prolove10.blog.163.com/blog/static/138411843201391401054305/ 原图:  效果图:  实现:首先需要导入Accelerat ...

  2. mongodb的入门CURD

    mongodb的入门CURD #查看所有数据库show dbs;show databases; #有些版本可能不行 #使用数据库use 数据库名 #查看集合(集合即mysql的表)show table ...

  3. Maven实战:Pom.xml详解

    什么是pom?    pom作为项目对象模型.通过xml表示maven项目,使用pom.xml来实现.主要描述了项目:包括配置文件:开发者需要遵循的规则,缺陷管理系统,组织和licenses,项目的u ...

  4. Struts2的值栈和OGNL牛逼啊

    Struts2的值栈和OGNL牛逼啊 一 值栈简介: 值栈是对应每个请求对象的一套内存数据的封装,Struts2会给每个请求创建一个新的值栈,值栈能够线程安全的为每个请求提供公共的数据存取服务. 二 ...

  5. BZOJ——2096: [Poi2010]Pilots

    http://www.lydsy.com/JudgeOnline/problem.php?id=2096 Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: ...

  6. hadoop+yarn+hbase+storm+kafka+spark+zookeeper)高可用集群详细配置

    配置 hadoop+yarn+hbase+storm+kafka+spark+zookeeper 高可用集群,同时安装相关组建:JDK,MySQL,Hive,Flume 文章目录 环境介绍 节点介绍 ...

  7. MD5进行文件完整性校验的操作方法

    我组产品包含大量音频和图片资源,MD5主要就用来检测这些资源文件的完整性.主要思路是:先计算出所有资源文件的MD5值,存到一个xml文件中,作为标准的MD5值.然后把这个xml文件放到我们的产品中,每 ...

  8. influxDB的安装和简单使用

    单机的influxdb免费,集群的是收费的 1.安装,参考官方文档 https://portal.influxdata.com/downloads RedHat & CentOS: wget ...

  9. 【转】C语言中整型运算取Ceiling问题

    原文:http://blog.csdn.net/laciqs/article/details/6662472 --------------------------------------------- ...

  10. Override和Overload差别,Overloaded的方法能否够改变返回值的类型?

    Overload是重载的意思, Override是覆盖的意思,也就是重写. 重载Overload表示同一个类中能够有多个名称同样的方法,但这些方法的參数列表各不同样(即參数个数或类型不同). 重写Ov ...