内核fuse实现中的一个隐患--基于centos 3.10.0-693.11

一次项目中,我们用的基于fuse的文件系统进程出core挂掉了,排查发现,这并不是个BUG,算是个缺陷吧。出core表现是这样的,libfuse从/dev/fuse中调用read读取内容,读返回成功了,但缓冲区只更新了部分内容,还有部分内容是旧的,导致libfuse执行了旧的命令,而我们实现的fuse文件系统,某些命令重复执行是会出core的,也幸亏会出core才能暴露这个bug,不然某些命令重复执行,造成数据丢失就玩大发了
当排查到是read系统调用有问题的时候,我是不愿意相信的,堂堂centos 3.10.0 的内核还会有这种bug嘛?当然,事实这不算是bug,只是一个缺陷,用户层在多线程里fork,并使用非对齐到页的内存时,就会触发这个缺陷。下面我们来探下究竟。

fuse的原理还是比较简单易懂的,在用户层有个设备名为/dev/fuse,用户层(libfuse)就是通过这个来和内核的fuse通信。当用户层读写fuse实现的文件系统的时候,内核就会产生一个请求挂到队列里等待libfuse的读取,而libfuse读/dev/fuse来读取请求并执行相应操作后写回/dev/fuse。问题就在这个/dev/fuse的读实现里。

/dev/fuse是个混杂设备,其的最终的读函数是fuse_dev_read,我们分析下它的代码:

static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
			      unsigned long nr_segs, loff_t pos)
{
   
	struct fuse_copy_state cs;
	struct file *file = iocb->ki_filp;
	struct fuse_conn *fc = fuse_get_conn(file);
	if (!fc)
		return -EPERM;

	fuse_copy_init(&cs, fc, 1, iov, nr_segs);

	return fuse_dev_do_read(fc, file, &cs, iov_length(iov, nr_segs));
}

//fuse_copy_state 初始化, 这个结构体用于维护copy一个请求的状态。
static void fuse_copy_init(struct fuse_copy_state *cs, struct fuse_conn *fc,
			   int write,
			   const struct iovec *iov, unsigned long nr_segs)
{
   
	memset(cs, 0, sizeof(*cs));
	cs->fc = fc;	//fc连接
	cs->write = write;	//读写方向,1为读
	cs->iov = iov;	//用户地址iov,一般一个
	cs->nr_segs = nr_segs; //一般为1
}

fuse_copy_init初始化fuse_copy_state 这个结构体,这个结构体是维护fuse拷贝请求的,fuse_dev_do_read进行具体的读。

 //读取一个请求到用户空间的缓存里,这个调用会阻塞。 当一个请求不需要回复(FORGET)或者被abort或发生
 //错误,它会调用request_end来结束。其它情况下,这个请求被读取后会被挂载到processing 链表,然后设置 sent 标记
static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file,
				
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值