Chinaunix首页 | 论坛 | 博客
  • 博客访问: 491878
  • 博文数量: 72
  • 博客积分: 1851
  • 博客等级: 上尉
  • 技术积分: 1464
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-16 17:50
文章分类

全部博文(72)

文章存档

2013年(1)

2012年(17)

2011年(51)

2010年(3)

分类: LINUX

2011-06-20 16:23:39

ino(nodeid)缓存

数据结构

nodeid具体包含在fuse请求的包头中:

  1. //用户读取包头
  2. struct fuse_in_header{
  3.     __u32 len;//包含数据头包长度
  4.     __u32 opcode;//包的请求操作码
  5.     __u64 unique;//请求id
  6.     __u64 nodeid;//与操作相关的节点id
  7.     __u32 uid;//请求用户的user id
  8.     __u32 gid;//请求用户所在组id
  9.     __u32 pid;//请求的进程id
  10.     __u32 pidding;//填充字符

  11. }

fuse中用于缓存的对象定义如下:

  1. struct node {
  2.     struct node *name_next;//按name进行hash
  3.     struct node *id_next;//按nodeid(ino)进行hash
  4.     fuse_ino_t nodeid;//索引节点号
  5.     unsigned int generation;
  6.     int refctr;//!!是否删除该节点的关键所在
  7.     struct node *parent;//父节点(ino)形式产生
  8.     char *name;//文件名
  9.     uint64_t nlookup;//查看次数,每find一次自增,unlink一次自减
  10.     int open_count;//打开次数,open,create自增,release自减
  11.     struct timespec stat_updated;//mtime修改,更新时间
  12.     struct timespec mtime;//每次有关文件属性操作时都将该文件属性设置为属性修改时间参数
  13.     off_t size;//相关联文件的大小
  14.     struct lock*locks;//文件锁,具体到起始位置,偏移量,配合操作setlk,getlk
  15.     unsigned int is_hidden:1;//当节点被重命名或者删除时,需要使用此项
  16.     unsigned int cache_valid:1;//是否缓存有效
  17.     //同步访问标志
  18.     int treelock;
  19.     int ticket;
  20. }

内核inode分配

fuse内核模块中,当需要分配一个索引节点时,就会出现nodeid初始化(VFS需要分配索引节点时,就会调用此函数):

  1. static struct inode *fuse_alloc_inode(struct super_block* sb)
  2. {
  3.     struct inode *inode;
  4.     struct fuse_inode *fi;
  5.     //通过slab分配器获取一个inode节点(大小实际为fuse_inode)
  6.     inode = kmem_cache_alloc(fuse_inode_cachep,GFP_KERNEL);
  7.     if(!node)
  8.      return NULL;
  9.     //获取fuse_inode
  10.     fi = get_fuse_inode(inode);
  11.     //文件属性有效的时间
  12.     fi->i_time = 0;
  13.     //用于区别inode,全局唯一
  14.     fi->nodeid = 0;
  15.     //在该索引节点查看的次数
  16.     fi->nlookup = 0;
  17.     //上一次版本修改时间
  18.     fi->attr_version = 0;
  19.     //文件数据页
  20.     LIST_INIT_HEAD(&fi->write_files);
  21.     fi->forget_req = fuse_request_alloc();
  22.     if(!fi->forget_req) {
  23.      kmem_cache_free(fuse_inode_cachep,inode);
  24.      return NULL;
  25.     }
  26.     return inode;
  27. }

其实这里只是进行最低级的初始化,具体的赋值操作还需要等到客户端去完成,在fuse挂载时,服务器需要生成root索引节点,VFS通过函数fuse_fill_super实现:

  1. static int fuse_fill_super(struct super_block *sb,void *data,int silent)
  2. {
  3.     struct inode *root;
  4.     …............
  5.     //分配根节点:root.ino = FUSE_ROOT_ID
  6.     root = get_root_inode(sb,d.rootmate);
  7.     if(!root)
  8.         goto err;
  9.     //将根节点存入缓存
  10.     root_dentry = d_alloc_root(root);
  11.     if(!root_dentry) {
  12.      iput(root);
  13.      goto err;
  14.     }
  15.     sb->s_root = root_dentry;
  16.     …....
  17.     //向客户端发送初始化请求
  18.     fuse_send_init(fc,init_req);
  19. }

客户端nodeid

客户端方向在新建一个fuse对象(运行程序时就进行创建),通过调用函数 fuse_new_common实现:

  1. struct fuse *fuse_new_common(/*参数省略*/)
  2. {
  3.     …......
  4.     root = (struct node *)calloc(1,sizeof(struct node));
  5.     ….......
  6.     root ->name = strdup(/);
  7.     …......
  8.     //进行初始化,同时写入缓存中
  9.     root ->parent = NULL;
  10.     root ->nodeid = FUSE_ROOT_ID;
  11.     root ->generation = 0;
  12.     root -> refctr = 1;
  13.     root -> nlookup = 1;
  14.     hash_id(f,root);
  15.     return f;
  16. }

添加nodeid

当内核出现调用lookup调用请求时lookup请求时,就生成nodeid,并进入缓存中:

op():session调用op

   --->do_lookup:fuse_lowlevel.c do_lookup

       ---->fuse_lib_lookup:fuse.c

原型如下:

  1. //在父节点parent中查找文件name
  2. static void fuse_lib_lookup(fuse_req_t req,fuse_ino_t parent,const char* name)
  3. {
  4.     //从req中提取出fuse文件结构
  5.     struct fuse *f = req_fuse_prepare(req);
  6.     struct fuse_entry_param e;//用于回复的数据
  7.     char *path;
  8.     int err;
  9.     struct node *dot = NULL;
  10.     if(name[0]=='.') {//指向本身,parent则表示文件本身
  11.      int len = strlen(name);
  12.      if(len ==1|| (name[1]=='.'&&len==2)) { //或者指向父文件夹,parent则表示文件本身
  13.     pthread_mutex_lock(&f->lock);
  14.     if(len==1) {
  15.     //如果指向的是本身
  16.      …...
  17.     //在本身节点nodeid中查找node
  18.      dot = get_node_nocheck(f,parent);
  19.      if(dot==NULL) {
  20.      pthread_mutex_unlock(&f->lock);
  21.      reply_entry(req,&e,-ESTALE);
  22.      return;
  23.     }
  24.      //引用自增
  25.      dot->refctr++;
  26.     } else {
  27.      …..
  28.      //获取该节点的父节点nodeid
  29.      parent = get_node(f,parent)->parent->nodeid;
  30.     }
  31.      pthread_mutex_unlock(&f->lock);
  32.      name = NULL;
  33.     }}
  34.     //通过在父索引节点parent中查找name文件,并返回绝对路径
  35.      err = get_path_name(f,parent,name,&path);
  36.      if(!err) {
  37.      struct fuse_intr_data d;
  38.      ….....
  39.      //检查是否产生中断并注册中断回调处理函数
  40.      fuse_prepare_interrupt(f,req,&d);
  41.      //获取name属性,并加入两个缓存中
  42.      err = lookup_path(f,parent,name,path,&e,NULL);
  43.      …....
  44.      //同样检查是否产生中断,处理回调,不同的是,一个没有在完成之前,一个完成之后
  45.      fuse_finish_interrupt(f,req,&d);
  46.      free_path(f,parent,path);
  47.     }
  48.     if(dot) {
  49.      pthread_mutex_lock(&f->lock);
  50.     //上面计数增加,现在计数自减,如果为0从缓存中删除该节点,这里删除只是假设assert(!node->name),这个
  51.     //用于保证unhash_name必须在这之前调用
  52.      unref_node(f,dot);
  53.      pthread_mutex_unlock(&f->lock);
  54.     }
  55.     //回复至内核
  56.      reply_entry(req,&e,err);
  57. }

查找节点

静态查找node节点:static struct node* lookup_node(struct fuse* f,fuse_ino_t parent,const char* name);

动态查找node节点(查找失败就装入缓存):static struct node* find_node(struct fuse* f,fuse_ino_t parent,const char* name);同时写入两个缓存name_table,id_table

修改节点

nodeid部分:

增加引用(使用)计数:

hash_name(struct fuse* f,struct node* node,fuse_ino_t parentid,const char* name)

减少引用(使用)计数:

unref_node(struct fuse*f,struct node*node)//如果计数为0,删除该节点

name_table删除节点(调用unhash_name实现)

static void unlink_node(struct fuse *f,struct node* node)

node父节点中删除该node选项

unhash_name(struct fuse *f,struct node *node);

生成nodeid

static fuse_ino_t nexid(struct fuse *f)

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