Chinaunix首页 | 论坛 | 博客
  • 博客访问: 200663
  • 博文数量: 55
  • 博客积分: 2330
  • 博客等级: 大尉
  • 技术积分: 504
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-20 22:55
文章分类

全部博文(55)

文章存档

2013年(6)

2012年(7)

2011年(7)

2010年(35)

我的朋友

分类: 服务器与存储

2010-08-16 22:00:53

Kernel Version: 2.6.8.1
Fuse Version: fuse-2.5.3
以fuse/example/hello_ll进行分析

重要的数据结构

struct fuse_req: 表示fuse发往fuse上层具体文件系统的的请求.
struct fuse_session: 进行具体文件系统会话管理
struct fuse_chan: 实现具体文件系统与内核(fuse)的交互,主要通过/dev/fuse或者/dev/misc/fuse

工作流程

首先编译Fuse,将kernel文件夹下面编译好的Module insmod.
执行命令: $./hello_ll /tmp/ddd/ 其作用是利用fuse建立一个文件系统, 并将这个文件系统挂载到/tmp/ddd/下面.


执行过程

执行上述命令后,具体的执行过程如下:
1. fuse_mount(char *mount_point, struct fuse_args *args)
实现文件系统的挂载,其最终会调用fusermount来执行文件系统的挂载.
在fuse_mount里面,在执行fusermount前通过socketpair创建全双工通信管道,也就是创建两个进程,并将两个进程的套口文件
描述符返回,其作用是实现父子进程间全双工通信。fusermount就是在其子进程中完成的。
在fuse_mount的最后,会执行receive_fd(子进程描述符),从子程接收数据并把接收到数据附属数据缓冲区中所读到的文件描述符
返回。这个值也是fuse_mount的返回值。
2. fusermount
fusermount -o fsname=hello_ll -- /tmp/ddd/
mount parameter: fsname=hello_ll mnt=/tmp/ddd type=fuse flags=6
optbuf=fd=4,rootmode=40000,user_id=0,group_id=0
3. 在fuse_mount结束之后,fuse_lowlevel_new会被调用,这个函数是用来建立fuse session的。在这个函数里面,会把
fuse_ll_process这个函数初始化给新创那的session,所挂载文件系统所有会话都会通过这个函数来完成。
另外, fuse_lowlevel_new也会把文件系统所定义的操作赋给新创建的session(通过struct fuse_ll->op,最终
由se->data=fuse_ll完成),这些操作最终决定文件系统的Feature.
4. fuse_kern_chan_new(fd)
这个部分为创建新的channel,并将channel实例返回。包括初始化channel op, fd, bufsize, and data. 其中op主要是通过
对channel的读写,实现userspace与Kernel的交互,由fuse_kern_chan_receive和fuse_kern_chan_send两个函数完成读
写功能。fd正是上面fuse_mount所返回的fd的值。也是channel进行交互所使用的文件描述符。
5. fuse_session_add_chan(se, ch), 把channel实例赋给session。
6. fuse_session_loop(se), 这个函数主要实现文件系统挂载后的Daemon。
fuse_chan_receive(ch, buf, bufsize),调用fuse_kern_chan_receive从Kernel里面读数据。
fuse_session_process(se, buf, res, ch), 对于上面读出的数据,在这里最终交给fuse_ll_process函数进行处理。

use_ll_process

从上面我们看到,程序最终通过fuse_ll_process这个函数完成了文件系统的大部分功能,下面我们看看它具体做了什么:

 首先,它从上面receive函数中读到的数据里面读出in->opcode,也就是所执行的命令具体执行的动作,然后,跟据相应的
opcode, 执行们们在创建session时所注册的文件系统的相关函数。下面以ls命令为例对其进行简单说明:
1. $cd /tmp/ddd
2. $ls
那么相应的它会执行:OPENDIR, GETATTR, READDIR, LOOKUP, READDIR, RELEASEDIR几个动作,详细的执行过
程请参考busybox中coreutils/ls.c源码。

FUSE Kernel Module

在上面的fuse_session_loop中我们提到两个函数:
(1)fuse_chan_receive(ch, buf, bufsize), 在这个函数里,会调用read(ch->fd, buf, size),从channel内读取信息,
也就是从Kernel中把对文件系统相应的请求信息读出来。
在Kernel里面,fuse module的fuse_dev_read(struct file *file, char __user *buf,size_t nbytes, loff_t *off)被
调用。
struct iovec iov. iov->iov_len = nbytes; iov->iov_base = buf;
最终通过使用fuse_dev_readv函数,这个函数作用是读取一个请求到文件系统的用户空间。这里也使用到我们上面提的

到的重要数据结构struct fuse_req req在这里也被使用,主要用来读出request in信息。接下来通过fuse_copy_one
把in->h的信息存放到iov->buf里面。在此之前,已经通过fuse_copy_init将iov初始化为iov->write=1,iov->req = req,
iov->iov=iov,cs->nr_segs = nr_segs;
read的最后,会执行fuse_copy_args(cp request argument to userspace buffer)-->fuse_copy_pages(cp pages in
the request to userspace buffer)
(2) int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],size_t count),这个函数是在对上
面的请求之后被调用的,它主要是调用writev来回应上面的request。在Kernel里面,writev所对应的函数为
fuse_dev_writev(struct file *file, const struct iovec *iov,unsigned long nr_segs, loff_t *off),它用来实现
写回一个前面request的应答.

when insmod fuse module.
1. call fuse_fs_init, in this function, it will register fuse file system, the fuse_fs_type vlue as follows:


flow:

new_conn()创建一个fuse_conn实例,其中包含10 fuse_req 的链表。
sb->s_fs_info = fc file->prive_data = fc
notes: 
container_of(ptr, type, member): 
The function of this macro is return the address of the "type" instance, ptr pointer to type->member.
fget(fd):
将文件对象与文件描述符连接起来,即fget根据参数指定的文件描述符,找出文件描述符所对应的文件结构,并将其在返回。
d_alloc_root:
根据得到的根 inode 分配超级块(super block)中的s_root 此字段是一个 struct dentry 结构。

Reference:
enum fuse_opcode {
        FUSE_LOOKUP        = 1,
        FUSE_FORGET        = 2,  /* no reply */
        FUSE_GETATTR       = 3,
        FUSE_SETATTR       = 4,
        FUSE_READLINK      = 5,
        FUSE_SYMLINK       = 6,
        FUSE_MKNOD         = 8,
        FUSE_MKDIR         = 9,
        FUSE_UNLINK        = 10,
        FUSE_RMDIR         = 11,
        FUSE_RENAME        = 12,
        FUSE_LINK          = 13,
        FUSE_OPEN          = 14,
        FUSE_READ          = 15,
        FUSE_WRITE         = 16,
        FUSE_STATFS        = 17,
        FUSE_RELEASE       = 18,
        FUSE_FSYNC         = 20,
        FUSE_SETXATTR      = 21,
        FUSE_GETXATTR      = 22,
        FUSE_LISTXATTR     = 23,
        FUSE_REMOVEXATTR   = 24,
        FUSE_FLUSH         = 25,
        FUSE_INIT          = 26,
        FUSE_OPENDIR       = 27,
        FUSE_READDIR       = 28,
        FUSE_RELEASEDIR    = 29,
        FUSE_FSYNCDIR      = 30,
        FUSE_ACCESS        = 34,
        FUSE_CREATE        = 35
};


阅读(988) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~