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. 使用javaconfig方式配置spring工程的单元测试

    添加@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {MoveModelSpringTestConfig ...

  2. MySql的架构和历史

    1.1.mysql的逻辑架构 架构为如下: 存储引擎:负责数据的储存和提取,供了几十个API供服务层进行调用.各个存储引擎之间不会进行交互,只是供服务层进行调用.事务控制和锁的管理也是在存储引擎里面进 ...

  3. [BOI2007] Mokia

    题目描述 摩尔瓦多的移动电话公司摩基亚(Mokia)设计出了一种新的用户定位系统.和其他的定位系统一样,它能够迅速回答任何形如“用户C的位置在哪?”的问题,精确到毫米.但其真正高科技之处在于,它能够回 ...

  4. centos 安装php缓存 apc或zend-opcode

    去官方下载apc:pecl.php.net 搜索apc,安装最新的. #wget http://pecl.php.net/get/APC# tar -xzvf APC-3.1.9.tgz#cd  AP ...

  5. 机器学习优化方法总结比较(SGD,Adagrad,Adadelta,Adam,Adamax,Nadam)

    SGD: 此处的SGD指mini-batch gradient descent,关于batch gradient descent, stochastic gradient descent, 以及 mi ...

  6. insserv: warning: script 'lampp' missing LSB tags and overrides

    https://ubuntuforums.org/showthread.php?t=2327011 1.方法一,编辑rc.loacl脚本 Ubuntu开机之后会执行/etc/rc.local文件中的脚 ...

  7. [CSS3] Understand CSS Selector Specificity

    It is hard to explain css selector specificty, to easy way to understand it is by playing around wit ...

  8. SolidEdge 工程图中如何控制是否显示爆炸图组装线

    右击视图,点击性质,取消勾选"显示流线"   即可取消爆炸视图的装配线              

  9. 谜题 之 C语言

    本篇文章展示了14个C语言的迷题以及答案.代码应该是足够清楚的,并且我也相信有相当的一些样例可能是我们日常工作可能会见得到的.通过这些迷题,希望你能更了解C语言.假设你不看答案.不知道是否有把握回答各 ...

  10. 零基础学python-5.9 集合set

    今天我们来说说set 集合:是一些唯一的.不可变的对象(数值和字符串等)的一个无序的集合(collection).而且这些对象支持与数学集合理论相相应的操作. 特点: 1.一个项仅仅可以出现一次 2. ...