fuse相关流程.docx
《fuse相关流程.docx》由会员分享,可在线阅读,更多相关《fuse相关流程.docx(18页珍藏版)》请在冰豆网上搜索。
fuse相关流程
1Fuse系统架构
图1系统架构
整体上分2个部分:
a)用户态libfuse
b)内核fuse:
◆Fuse文件系统
◆/dev/fuse设备驱动
2Fuse的结构
Fuse包括三个模块:
用户空间库,内核模块以及mount工具
(1)用户库(2.9.2)
提供编程接口,程序员通过实现fuse提供的两组接口fuse_lowlevel_ops,fuse_operations之一即可实现一个用户空间文件系统。
(2)内核模块(3.10.X):
实现了一个完整文件系统的框架。
(3)mount工具fusermount(这个代码由用户库提供,fusermount.c):
用于挂载基于fuse的文件系统。
3Fuse下write的整体流程(用户空间和kernel)
图2fuse下write流程
在基于FUSE的用户空间文件系统中执行write操作的流程如图2所示
流程说明:
(1)客户端在mount目录下,对一个file调用write,这一步是在用户空间执行;
(2)Write内部会调用vfs提供的一致性接口vfs_write;
(3)根据fuse模块注册的file_operations信息,vfs_write会调用fuse_file_aio_write,将写请求放入到requestpendingqueue,随后进入睡眠等待应用程序reply。
见kernel中fs/fuse/dev.c中的fuse_request_send:
●将请求加入到pending队列
●唤醒等待队列(wake_up(&fc->waitq)),这时fuse_dev_do_read中request_wait就会被唤醒,fuse_session_loop就会从pending队列中取数据
(4)用户空间的libfuse的fuse_session_loop轮询设备/dev/fuse,一旦requestqueue有请求即通过fuse_kern_chan_receive接收;
(5)Fuse_kern_chan_receive通过read读取requestqueue中的内容,read系统调用实际上是调用的/dev/fuse设备驱动接口fuse_dev_read;
(6)用户空间读取分析数据,执行用户定义的wirte操作,将状态通过fuse_reply_write返回给kernel;
(7)fuse_reply_write调用vfs提供的一致性接口vfs_write
(8)vfs_write最终调用fuse_dev_wirte将执行结果返回给第3步中等待在waitq的进程,此进程得到reply后,write返回
注意:
fuse文件系统和/dev/fuse的注册在kernelfs/fuse/inode.c的fuse_init中,分别初始化了fuse_init_inode和fuse_dev_init
4fuse在用户空间工作的流程图
图3libfuse的工作流程
关键点说明:
(1)fusermount会调用kernel的fuse_mount,fuse_fill_super中file->private_data=fuse_conn_get(fc)是一个关键的部分,file就是/dev/fuse。
(2)fuse_session_loop会不停的调用fuse_session_receive_buf,最终调用fuse_dev_read,然后request_wait等待requestqueue中有数据并被唤醒,然后从queue中取出数据返回给用户空间
(3)fuse_session_proc中完成libfuse注册的api接口,见附录一的代码,fuse_session_proc中会调用sfs_write来完成相应的工作(有可能会调用其他的接口),一个posix对应1或多个libfuse中注册的api
5Fusewrite的详细流程
客户端在mount目录下,对一个file调用write,这一步是在用户空间执行,Write内部会调用vfs提供的一致性接口vfs_write,根据fuse文件系统注册的接口,最终会调用fuse_file_aio_write
图4
图5
关键说明:
(1)图5中的fuse_write_fill完成fuse数据的填充,如操作码等
(2)fuse_request_send是关键部分:
●将request插入到pending队列,并将req的状态置为FUSE_REQ_PENDING
●唤醒等待队列wake_up(&fc->waitq)
●异步通知用户进程数据到达kill_fasync(&fc->fasync,SIGIO,POLL_IN)
●调用request_wait_answer,进程休眠,等待请求完成wait_event(req->waitq,req->state==FUSE_REQ_FINISHED)。
用户进程处理完请求,它会replay,休眠的进程(request_wait_answer)被唤醒,request_wait_answer返回,向上层返回结果。
用户态的进程在fuse_session_loop中循环read(读取/dev/fuse),read最终调用fuse_dev_read。
图6
关键说明:
(1)fuse_dev_read首先通过fuse_get_conn获取structfuse_conn(它是在fuse_mount是就完成实例化的)
(2)request_wait等待请求到达:
(3)fuse_copy_one将数据拷贝到structfuse_copy_state的buf中(此buf指向应用层的void*buf)
用户态进程读取上面的数据,然后做相应的处理,以write为例,这是会调用sfs_write(附录一),sfs_write处理完后,调用fuse_lib_write_buf,然后调用fuse_reply_write回复,最终调用/dev/fuse注册的fuse_dev_write
图7
关键流程说明:
request_end:
请求处理完成,设置req->state=FUSE_REQ_FINISHED,唤醒等待在waitq的进程wake_up(&req->waitq),最终唤醒图5中的request_wait_answer
附录一
下面是基于fuse开发的文件系统
#defineFUSE_USE_VERSION29
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
intg_debug=1;
staticchar*rootdir;
staticvoidfullpath(charfpath[PATH_MAX],constchar*path)
{
strcpy(fpath,rootdir);
strncat(fpath,path,PATH_MAX);
}
voidsfs_usage()
{
fprintf(stderr,"usage:
sfsrootDirmountPoint\n");
abort();
}
staticintsfs_getattr(constchar*path,structstat*statbuf)
{
if(g_debug)
printf("-->sfs_getattr%s\n",path);
intret=0;
charfpath[PATH_MAX];
fullpath(fpath,path);
ret=lstat(fpath,statbuf);
if(ret!
=0)
{
if(g_debug)
printf("sfs_getattrlstaterror\n");
return-errno;
}
return0;
}
staticintsfs_open(constchar*path,structfuse_file_info*fi)
{
if(g_debug)
printf("-->sfs_open%s\n",path);
intfd;
charfpath[PATH_MAX];
fullpath(fpath,path);
fd=open(fpath,fi->flags);
if(fd==-1)
return-errno;
fi->fh=fd;
return0;
}
staticintsfs_read(constchar*path,char*buf,size_tsize,off_toffset,
structfuse_file_info*fi)
{
if(g_debug)
printf("-->sfs_read%s\n",path);
intret;
ret=pread(fi->fh,buf,size,offset);
if(ret==-1)
ret=-errno;
returnret;
}
staticintsfs_create(constchar*path,mode_tmode,structfuse_file_info*fi)
{
if(g_debug)
printf("-->sfs_create%s\n",path);
intfd;
charfpath[PATH_MAX];
fullpath(fpath,path);
fd=open(fpath,fi->flags,mode);
if(fd==-1)
return-errno;
fi->fh=fd;
return0;
}
staticintsfs_write(constchar*path,constchar*buf,size_tsize,off_toffset,structfuse_file_info*fi)
{
if(g_debug)
printf("-->sfs_write%s\n",path);
intret=0;
ret=pwrite(fi->fh,buf,size,offset);
if(ret<0)
{
return-errno;
}
returnret;
}
staticintsfs_unlink(constchar*path)
{
if(g_debug)
printf("-->sfs_unlink%s\n",path);
intret=0;
charfpath[PATH_MAX];
fullpath(fpath,path);
ret=unlink(fpath);
if(ret<0)
return-errno;
return0;
}
staticintsfs_fsync(constchar*path,intisdatasync,
structfuse_file_info*fi)
{
if(g_debug)
printf("-->sfs_fsync%s\n",path);
intret;
(void)path;
ret=fsync(fi->fh);
if(ret==-1)
return-errno;
return0;
}
staticintsfs_truncate(constchar*path,off_tnewsize)
{
if(g_debug)
printf("-->sfs_truncate%s\n",path);
intret=0;
charfpath[PATH_MAX];
fullpath(fpath,path);
ret=truncate(fpath,newsize);
if(ret<0)
return-errno;
return0;
}
staticintsfs_flush(constchar*path,structfuse_file_info*fi)
{
if(g_debug)
printf("-->sfs_flush%s\n",path);
intres;
(void)path;
res=close(dup(fi->fh));
if(res==-1)
return-errno;
return0;
}
staticintsfs_release(constchar*path,structfuse_file_info*fi)
{
if(g_debug)
printf("-->sfs_release%s\n",path);
(void)path;
close(fi->fh);
return0;
}
staticintsfs_mkdir(constchar*path,mode_tmode)
{
if(g_debug)
printf("-->sfs_mkdir%s\n",path);
intres;
charfpath[PATH_MAX];
fullpath(fpath,path);
res=mkdir(fpath,mode);
if(res==-1)
return-errno;
return0;
}
intsfs_opendir(constchar*path,structfuse_file_info*fi)
{
if(g_debug)
printf("-->sfs_opendir%s\n",path);
DIR*dp;
charfpath[PATH_MAX];
fullpath(fpath,path);
dp=opendir(fpath);
if(dp==NULL)
return-errno;
fi->fh=(uintptr_t)dp;
return0;
}
staticintsfs_readdir(constchar*path,void*buf,fuse_fill_dir_tfiller,off_toffset,
structfuse_file_info*fi)
{
if(g_debug)
printf("-->sfs_readdir%s\n",path);
DIR*dp;
structdirent*de;
dp=(DIR*)(uintptr_t)fi->fh;
de=readdir(dp);
if(de==0)
{
return-errno;
}
do
{
//printf("-->sfs_readdir%s\n",de->d_name);
if(filler(buf,de->d_name,NULL,0)!
=0)
{
return-ENOMEM;
}
}while((de=readdir(dp))!
=NULL);
return0;
}
staticintsfs_releasedir(constchar*path,structfuse_file_info*fi)
{
if(g_debug)
printf("-->sfs_releasedir%s\n",path);
closedir((DIR*)(uintptr_t)fi->fh);
return0;
}
staticintsfs_utime(constchar*path,structutimbuf*ubuf)
{
if(g_debug)
printf("-->sfs_utime%s\n",path);
intret=0;
charfpath[PATH_MAX];
fullpath(fpath,path);
ret=utime(fpath,ubuf);
if(ret<0)
return-errno;
returnret;
}
staticintsfs_rmdir(constchar*path)
{
if(g_debug)
printf("-->sfs_rmdir%s\n",path);
intret=0;
charfpath[PATH_MAX];
fullpath(fpath,path);
ret=rmdir(fpath);
if(ret<0)
return-errno;
return0;
}
staticstructfuse_operationssfs_oper={
//.init=sfs_init,
.getattr=sfs_getattr,
.open=sfs_open,
.read=sfs_read,
.create=sfs_create,
.write=sfs_write,
.unlink=sfs_unlink,
.fsync=sfs_fsync,
.truncate=sfs_truncate,
.flush=sfs_flush,
.release=sfs_release,
.mkdir=sfs_mkdir,
.opendir=sfs_opendir,
.readdir=sfs_readdir,
.releasedir=sfs_releasedir,
.utime=sfs_utime,
.rmdir=sfs_rmdir,
};
intmain(intargc,char*argv[])
{
umask(0);
fprintf(stderr,"Fuselibraryversion%d.%d\n",FUSE_MAJOR_VERSION,FUSE_MINOR_VERSION);
if((argc<3)||(argv[argc-2][0]=='-')||(argv[argc-1][0]=='-'))
{
sfs_usage();
}
rootdir=malloc(sizeof(char)*1024);
if(rootdir==NULL)
{
perror("Unabletoallocatememoryforrootdirname\n");
abort();
}
rootdir=realpath(argv[argc-2],NULL);
argv[argc-2]=argv[argc-1];
argv[argc-1]=NULL;
argc--;
fprintf(stderr,"rootdir:
%s\n",rootdir);
structfuse_argsargs=FUSE_ARGS_INIT(argc,argv);
if(fuse_opt_parse(&args,NULL,NULL,NULL)==-1)
{
sfs_usage();
}
returnfuse_main(argc,argv,&sfs_oper,rootdir);
}
OS:
Centos7
●安装依赖包:
Yuminstallfuse-devel
●编译:
gccsfs.c-osfs`pkg-configfuse--cflags--libs`
●运行:
./sfs/root/fuse/root/root/fuse/mount
然后再/root/fuse/mount文件操作