在应用fuse提供的库进行文件系统编写。前面讲一些接口的调用和处理都完成。但是对于后面多线程的环境却有许多困扰的地方。
单独的来说多线程本身有一定的困难。当不同的资源使用到共享的资源时。这里需要进行更多的分析。需要保证数据不会被错误的同步使用。之前使用线程的较少,而且使用的情况,资源也会较为简单清楚。
但是现在整个的编程环境不是自己设计。而是通过实现系统的调用来达到一定的要求。这样多线程环境不是自己清楚知晓的。这给资源的同步设计带来了难度。
先说明一下项目的情况。目的是做一个文件系统,使用开源的fuse项目。熟悉vfs的人应该一个文件系统的设计实现方法应该了解。fuse把其中可能重复出现的部分给实现了,不需要再重新开发相同的部分。另外一个就是把底层的请求又发回到了用户层。这样就给数据的来源提供了充足的扩展空间,可以是本地的。也可以是网络的。
其中curlftpfs,sshfs就是网络的,基于不同的协议。自己所编写的也是基于网络的。从模块的角度来看,网络部分实际上就和其他的网络数据信息传输是完全一样的了。
回到现在要说的问题。前面虽然有众多的难点问题。但是都在对其他类似项目的借鉴参考。对他人研究成果的学习中完成了。但是到了多线程的环境,自己所面临的场景和他人就有不同了。于是这一块的问题就需要更多对现有环境信息的收集和分析。
从libfuse 到fuse kernel 。从fuse kernel 到vfs 。一路逆向的跟踪。把libfuse 和fuse kernel
中的问题算是清楚了。但是vfs这一块的多线程依然停留在理论上面。对于其中多线程的源码了解较少。
系统的整体运行过程:用户空间对文件操作后,会发起vfs调用。vfs调用的具体实现在fuse kernel。fuse kernel通过读写设备文件来进行信息和数据的传递 这些传输的另外一端就是用户空间的libfuse。最终libfuse中的操作最终由用户实现。如下图:
可以把fuse kernel 和 libfuse 看做是通信环节。最终实际的数据就是由用户提供了。当然这是从数据的角度来看,把其中的模块忽略了。但如果从控制的角度看。主要的工作实际上就是通信了。
如何把内核的信息发送到用户空间。这是fuse解决的一个重要问题。fuse采用了很巧妙的方式。之前自己
在没有深入了解kernel部分前,认为就是采用进程间的一般通信方式就可以了。但fuse 使用的读写设备文件的方式。fuse kernel 实现了文件系统模块 和设备驱动模块。二者都是在内核层的,通信自然就可以实现了。用户空间循环的通过vfs去读取调用信息。vfs把这些请求发送到了设备驱动模块。该模块把相关的内容传回。这样就把文件系统的请求发送到了用户空间。然后用户空间通过相同的写方式把信息发送回设备驱动。设备驱动再传回文件系统模块。这样信息通道就通畅了。相关的操作就都可以顺利的完成。
有了上面的整体认识后,对vfs 和fuse 中和多线程相关的问题进行分析。在自己编写的系统中有对文件树结构的保存和对文件内容的缓存。这和curlftpfs 和sshfs 不相同。这两个系统都是把从fuse接收来的请求发送到服务器。这样看来是一个较为单一的客户端。这样再客户端的涉及到的数据同步就较少。不需要维护相关的文件树结构。数据的同步在服务器端由相关的协议完成。
有了本地目录结构和文件内容后,同步的信息就较多了。这里和vfs在系统中所处的位置基本上是相同的。
所以vfs需要考虑的同步问题,这里也需要考虑。
这里就有了一个比较有意思的问题。请求是先经过vfs调用的。vfs对这些请求做了一定的同步处理。那么
经过fuse后,请求到了用户编码部分是否还是保持同步的。如果是同步的。那么在文件目录结构这一块就不需要再做同步操作了。
同步所要做的就是避免多个线程同时使用一个会产生冲突的资源。同步可以从不同的层次采用不同的锁来实现。如果vfs已经把对于某些目录结构上冲突的操作同步了。那么到了用户编码区域时,出现冲突的同步操作已经不存在了。因而用户编码区可以不对该部分进行同步设计。这是一种很好的情况。
如果是直接接口对应的就是vfs,那么问题就显而易见了。可是请求从vfs到用户编码部分。可谓是跋山涉水。这种同步是否被破坏了。在请求传输的过程中,是否打破了之前已经约束好的先后顺序。同步就是让多个会冲突的操作依次序完成。如果到了用户编码时,他们还是有次序的。就ok了。
于是不得不对中间的过程进行分析。这里就需要深入了解fuse对请求的处理。
先说点主要的信息,更为详细的需要根据代码来说明。
在fuse kernel 部分采用的是请求队列。也就是从vfs发送过来的请求到了fuse kernel会以队列的形式存储起来。等到某个请求有信息返回了再把请求唤醒。
而在libfuse 是采用循环的获取请求,对于每个请求分配一个线程进行处理。线程数量是有限制的。
这两种机制说明了有序发送过来的请求也会是有可能同步执行的。于是这就对vfs的同步有了一个要求。
发送完请求后如果采用的是继续等待的方式,那么同步的机制就依然有效。因为会冲突的操作是无法获取到锁这类的资源的。当然在vfs端也应该是多线程的处理环境。和已经占有锁,但是为完成的请求不冲突的其他请求可以继续的发送。
现在唯一的问题就是如果vfs中一个操作占有锁后,是否会一直等待。会一直等到操作完毕才会释放锁。如果那样。在目录结构这一个方面,底层的实现就都不需要再做同步了。当然底层的实现基本上没有再需要用到目录结构的。但是恰好请求发送到了用户端后,这样的情况就成为可能了。
好了,问题基本上明白了。剩下的就是探究vfs的锁机制了。其实对vfs 的锁也进行了一定程度的探索。理论上基本知道了。但是没有看到实际的源码,无法得出更准确的答案。前段时间一直分析各个系统的源码。有些疲倦了,不想再看了。等休息下再分析了。
阅读(1542) | 评论(0) | 转发(0) |