FUSE FS的实现(fuse_operations接口的抽象)
来源:互联网 发布:怎样删除kingroot软件 编辑:程序博客网 时间:2024/05/19 02:26
http://blog.chinaunix.net/uid-20196318-id-28822.html
fuse提供两种类型的操作接口,fuse lowlevel operations类似于内核文件系统的接口,以inode号作为访问的关键字,而更高级的fuse operations则提供以路径名作为关键字的访问形式,这样即使fuse用户对内核文件系统并不了解,也能编写文件系统程序。
高级的接口,其实是对fuse lowlevel operations的一个封装(相当于实现了一个用户空间文件系统fuse_fs,但其数据都放在内存中),它实现了一组lowlevel operations,并通过hash表来组织目录项,实现inode关键字向路径名关键字的转换(逆向路径名查找,索引节点中需要记录父节点的nodeid),封装的实现在fuse源代码包中fuse.c中实现。
2011年11月23日补充:
以访问/a/b/c为例,在路径名解析的过程中(根node在初始化时加载),能得到各级目录项的nodeid(递增)及node信息,并将这些信息加入node哈希表及名字哈希表,再根据c的nodeid访问c时(fuse_lowlevel_ops),可以反向解析出c的绝对路径,然后将c的绝对路径传递给外部实现的接口(fuse_operations),从而实现低级接口到高级接口的转换。
两个主要的数据结构
/* fuse fs 全局信息 */
struct fuse {
struct fuse_session *se;
struct node **name_table;/* 路径名hash表 */
size_t name_table_size;/* 路径名hash表的长度 */
struct node **id_table;/* nodeid hash表 */
size_t id_table_size;/* nodeid hash表的长度 */
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; /* 文件系统ops信息 */
int nullpath_ok;
int curr_ticket;
struct lock_queue_element *lockq;
};
/* 每个目录项的信息 */
struct node {
struct node *name_next;/* 名字hash链表 */
struct node *id_next;/* 索引节点hash链表 */
fuse_ino_t nodeid; /* 索引节点号 */
unsigned int generation;/* 用于扩展节点数,inode数可到2^64 */
int refctr;
struct node *parent;/* 父目录项信息 */
char *name;/* 本目录项的名称 */
uint64_t nlookup;
int open_count;
struct timespec stat_updated;
struct timespec mtime;
off_t size;
struct lock *locks;
unsigned int is_hidden: 1;
unsigned int cache_valid: 1;
int treelock;
int ticket;
};
与路径名查找(fuse_lib_lookup)实现相关的一些函数
/* fuse fs的hash函数 */
static unsignedint name_hash(struct fuse*f, fuse_ino_t parent,
const char *name)
{
unsigned int hash= *name;
if (hash)
for (name+= 1;*name !='\0'; name++)
hash = (hash << 5)- hash + *name;
return (hash+ parent) % f->name_table_size;
}
/* 通过名字hash查找node信息*/
static struct node*lookup_node(struct fuse*f, fuse_ino_t parent,
const char *name)
{
size_t hash = name_hash(f, parent, name);
struct node *node;
for (node= f->name_table[hash]; node!= NULL; node = node->name_next)
if (node->parent->nodeid== parent &&
strcmp(node->name, name)== 0)
return node;
return NULL;
}
/* 通过nodeid查找node信息*/
static struct node*get_node_nocheck(struct fuse*f, fuse_ino_t nodeid)
{
size_t hash = nodeid% f->id_table_size;
struct node *node;
for (node= f->id_table[hash]; node!= NULL; node = node->id_next)
if (node->nodeid== nodeid)
return node;
return NULL;
}
/* 通过某一个目录项,你想递归获取全局路径 */
static int try_get_path(struct fuse*f, fuse_ino_t nodeid,const char *name,
char **path,struct node **wnodep,int ticket)
{
unsigned bufsize= 256;
char *buf;
char *s;
struct node *node;
struct node *wnode= NULL;
int err;
*path =NULL;
buf = malloc(bufsize);
if (buf== NULL)
return -ENOMEM;
s = buf +bufsize - 1;
*s = '\0';
if (name!= NULL) {
s = add_name(&buf,&bufsize, s, name);
err = -ENOMEM;
if (s== NULL)
goto out_free;
}
if (wnodep){
assert(ticket);
wnode = lookup_node(f, nodeid, name);
if (wnode){
if (wnode->treelock!= 0 ||
(wnode->ticket&& wnode->ticket!= ticket)){
if (!wnode->ticket)
wnode->ticket= ticket;
err = -EAGAIN;
goto out_free;
}
wnode->treelock= -1;
wnode->ticket= 0;
}
}
/* 逆向遍历目录树,获取目录项的全局路径 */
err = 0;
for (node= get_node(f, nodeid); node->nodeid!= FUSE_ROOT_ID;
node = node->parent){
err = -ENOENT;
if (node->name== NULL || node->parent== NULL)
goto out_unlock;
err = -ENOMEM;
/* 长度不够将自动扩张,默认申请长度为256 */
s = add_name(&buf,&bufsize, s, node->name);
if (s== NULL)
goto out_unlock;
if (ticket){
err = -EAGAIN;
if (node->treelock== -1 ||
(node->ticket&& node->ticket!= ticket))
goto out_unlock;
node->treelock++;
node->ticket= 0;
}
}
if (s[0])
memmove(buf, s,bufsize - (s - buf));
else
strcpy(buf,"/");
*path = buf;
if (wnodep)
*wnodep = wnode;
return 0;
out_unlock:
if (ticket)
unlock_path(f, nodeid, wnode, node, ticket);
out_free:
free(buf);
return err;
}
/* 获取下一个nodeid */
static fuse_ino_t next_id(struct fuse*f)
{
do {
f->ctr= (f->ctr+ 1) & 0xffffffff;
if (!f->ctr)
f->generation++;/* 如果32bit数以用完,将generation加1 */
} while(f->ctr== 0 || f->ctr== FUSE_UNKNOWN_INO||
get_node_nocheck(f, f->ctr)!= NULL);
return f->ctr;
}
/* 获取目录项的fuse_entry_param信息,如果目录项不存在则新建,并加入hash表
lookup、mknod、create等都调用了该方法 */
static int lookup_path(struct fuse*f, fuse_ino_t nodeid,
const char*name, const char *path,
struct fuse_entry_param *e, struct fuse_file_info*fi)
{
int res;
memset(e, 0,sizeof(struct fuse_entry_param));
/* 从这里可以看出 如果getattr接口返回错误,则整个过程将会出现问题,故在实现getattr时,即使获取不到文件的信息,也要填充entry的信息 */
if (fi)
res = fuse_fs_fgetattr(f->fs, path,&e->attr, fi);
else
res = fuse_fs_getattr(f->fs, path,&e->attr);
if (res== 0){
struct node *node;
node = find_node(f, nodeid, name);
if (node== NULL)
res = -ENOMEM;
else {
/* 如果分配子目录项不成功,则返回父目录的信息 */
e->ino= node->nodeid;
e->generation= node->generation;
e->entry_timeout= f->conf.entry_timeout;
e->attr_timeout= f->conf.attr_timeout;
if (f->conf.auto_cache){
pthread_mutex_lock(&f->lock);
update_stat(node,&e->attr);
pthread_mutex_unlock(&f->lock);
}
set_stat(f, e->ino,&e->attr);
if (f->conf.debug)
fprintf(stderr," NODEID: %lu\n",
(unsignedlong) e->ino);
}
}
return res;
}
static struct node*find_node(struct fuse*f, fuse_ino_t parent,
const char *name)
{
struct node *node;
pthread_mutex_lock(&f->lock);
if (!name)
node = get_node(f, parent);
else
node = lookup_node(f, parent, name);
if (node== NULL) {
node = (struct node*) calloc(1,sizeof(struct node));
if (node== NULL)
goto out_err;
if (f->conf.noforget)
node->nlookup= 1;
node->refctr= 1;
node->nodeid= next_id(f);/* 选择下一个使用的nodeid */
node->generation= f->generation;
node->open_count= 0;
node->is_hidden= 0;
node->treelock= 0;
node->ticket= 0;
if (hash_name(f, node, parent, name)== -1) {/* 加入路径名hash表 */
free(node);
node = NULL;
goto out_err;
}
hash_id(f, node);/* 加入nodeid hash表 */
}
node->nlookup++;
out_err:
pthread_mutex_unlock(&f->lock);
return node;
}
创建fuse_fs环境的函数
struct fuse *fuse_new(struct fuse_chan*ch, struct fuse_args *args,
const struct fuse_operations*op, size_t op_size,
void *user_data)
{
return fuse_new_common(ch, args, op, op_size, user_data, 0);
}
/* 创建fuse文件系统的全局环境的内部接口 */
struct fuse *fuse_new_common(struct fuse_chan*ch, struct fuse_args *args,
const struct fuse_operations *op,
size_t op_size,void *user_data,int compat)
{
struct fuse *f;
struct node *root;
struct fuse_fs *fs;
struct fuse_lowlevel_ops llop = fuse_path_ops;
if (fuse_create_context_key()== -1)
goto out;
f = (struct fuse*) calloc(1,sizeof(struct fuse));
if (f == NULL){
fprintf(stderr,"fuse: failed to allocate fuse object\n");
goto out_delete_context_key;
}
fs = fuse_fs_new(op, op_size, user_data);/* 申请fuse fs的空间 */
if (!fs)
goto out_free;
fs->compat= compat;
f->fs = fs;
f->nullpath_ok= fs->op.flag_nullpath_ok;
/* Oh f**k, this is ugly! */
if (!fs->op.lock){
llop.getlk = NULL;
llop.setlk = NULL;
}
f->conf.entry_timeout= 1.0;
f->conf.attr_timeout= 1.0;
f->conf.negative_timeout= 0.0;
f->conf.intr_signal= FUSE_DEFAULT_INTR_SIGNAL;
if (fuse_opt_parse(args,&f->conf, fuse_lib_opts,
fuse_lib_opt_proc) == -1)
goto out_free_fs;
if (f->conf.modules){
char *module;
char *next;
for (module= f->conf.modules; module; module= next) {
char *p;
for (p= module; *p &&*p !=':'; p++);
next = *p ? p + 1: NULL;
*p ='\0';
if (module[0]&&
fuse_push_module(f, module, args)== -1)
goto out_free_fs;
}
}
if (!f->conf.ac_attr_timeout_set)
f->conf.ac_attr_timeout= f->conf.attr_timeout;
#ifdef __FreeBSD__
/*
* In FreeBSD, we always use these settings as inode numbers
* are needed to make getcwd(3) work.
*/
f->conf.readdir_ino= 1;
#endif
if (compat&& compat <= 25){
if (fuse_sync_compat_args(args)== -1)
goto out_free_fs;
}
/* 注册fuse fs的llop到lowlevel ops */
f->se = fuse_lowlevel_new_common(args,&llop, sizeof(llop), f);
if (f->se== NULL) {
if (f->conf.help)
fuse_lib_help_modules();
goto out_free_fs;
}
fuse_session_add_chan(f->se, ch);
if (f->conf.debug)
fprintf(stderr,"nullpath_ok: %i\n", f->nullpath_ok);
/* Trace topmost layer by default */
f->fs->debug= f->conf.debug;
f->ctr = 0;
f->generation= 0;
/* hash表长度,空间分配 */
/* FIXME: Dynamic hash table */
f->name_table_size= 14057;
f->name_table= (struct node**)
calloc(1,sizeof(struct node*) * f->name_table_size);
if (f->name_table== NULL) {
fprintf(stderr,"fuse: memory allocation failed\n");
goto out_free_session;
}
f->id_table_size= 14057;
f->id_table= (struct node**)
calloc(1,sizeof(struct node*) * f->id_table_size);
if (f->id_table== NULL) {
fprintf(stderr,"fuse: memory allocation failed\n");
goto out_free_name_table;
}
fuse_mutex_init(&f->lock);
/* 根节点的信息加入hash表,因不会根据名字查找根,故根只加入nodeid hash表
在find_node中,如果name为空,则返回父目录的信息 */
root = (struct node*) calloc(1,sizeof(struct node));
if (root== NULL) {
fprintf(stderr,"fuse: memory allocation failed\n");
goto out_free_id_table;
}
root->name= strdup("/");
if (root->name== NULL) {
fprintf(stderr,"fuse: memory allocation failed\n");
goto out_free_root;
}
if (f->conf.intr&&
fuse_init_intr_signal(f->conf.intr_signal,
&f->intr_installed)== -1)
goto out_free_root_name;
root->parent= NULL;
root->nodeid= FUSE_ROOT_ID;
root->generation= 0;
root->refctr= 1;
root->nlookup= 1;
hash_id(f, root);
return f;
out_free_root_name:
free(root->name);
out_free_root:
free(root);
out_free_id_table:
free(f->id_table);
out_free_name_table:
free(f->name_table);
out_free_session:
fuse_session_destroy(f->se);
out_free_fs:
/* Horrible compatibility hack to stop the destructor from being
called on the filesystem without init being called first */
fs->op.destroy= NULL;
fuse_fs_destroy(f->fs);
free(f->conf.modules);
out_free:
free(f);
out_delete_context_key:
fuse_delete_context_key();
out:
return NULL;
}
struct fuse_fs *fuse_fs_new(conststruct fuse_operations *op, size_t op_size,
void *user_data)
{
struct fuse_fs *fs;
if (sizeof(struct fuse_operations)< op_size) {
fprintf(stderr,"fuse: warning: library too old, some operations may not not work\n");
op_size = sizeof(struct fuse_operations);
}
fs = (struct fuse_fs*) calloc(1,sizeof(struct fuse_fs));
if (!fs){
fprintf(stderr,"fuse: failed to allocate fuse_fs object\n");
return NULL;
}
fs->user_data= user_data;
if (op)
memcpy(&fs->op, op, op_size);
return fs;
}
- FUSE FS的实现(fuse_operations接口的抽象)
- 实现接口的抽象类的用处
- 抽象接口的简单实现(纯虚类)
- 接口的重实现与抽象类
- 抽象类实现接口的意义
- 抽象类、抽象方法、接口的区别及实现
- FUSE用户态文件系统中自己实现的highlevel接口函数从注册到调用完全追踪
- Java中接口的定义与实现接口抽象方法
- Java中接口的定义与实现接口抽象方法
- Java中接口定义及实现接口的抽象方法
- java 的接口可以实现接口吗?抽象类呢?
- FUSE 程序的编译
- fuse的direct_io
- fuse的作用
- 抽象接口的作用
- 抽象类的接口
- 抽象类、接口的区别 和 抽象类可以不实现接口的全部方法
- 抽象类、接口的区别 和 抽象类可以不实现接口的全部方法
- 1.总览--JUC框架
- linux下编译x264,生成lib库
- Random随机类&Math数学类
- 三遍读书法
- OCP 1Z0 053 241
- FUSE FS的实现(fuse_operations接口的抽象)
- 点点滴滴
- java中round()与floor的区别
- App列表之圆角ListView
- qsort函数、sort函数 (精心整理篇)
- eclipse配置总结
- [html] 关于overflow 的用法
- 蕾丝欧美连衣裙
- 对exists用法的祥述