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

全部博文(72)

文章存档

2013年(1)

2012年(17)

2011年(51)

2010年(3)

分类: LINUX

2011-05-22 17:19:33


sshfs采用了fuse的高级开发模式,整体流程

用户输入相关参数之后,根据输入的数据,进行初始化sshfs结构体,其中ssh结构体非常庞大,类似于session,大致的内容如下:

  1. struct sshfs
  2. {
  3.     //连接的端口,主机
  4.     char *directport;
  5.     char *host;
  6.     ….
  7.     //每一次发送,接受的数据包大小
  8.     unsigned max_read;
  9.     unsigned max_write;
  10.     //是否为前台进程,否则将错误进行重定位/dev/null
  11.     int foreground;
  12.     //这些workaround,没有弄明白
  13.     int rename_workaround;
  14.     char* workaround;
  15.     int nodelay_workaround;
  16.     int nodelaysrv_workaround;
  17.     int truncate_workaround;
  18.     …....
  19.     //请求数据包相关的信息
  20.     //其中reqtab非常重要,每次ssh中的请求都会进入该表
  21.     GhashTable *reqtab;
  22.     pthread_mutex_t lock;
  23.     pthread_mutex_t lock_write;
  24.     ….....
  25.     //网络通信fd,伪终端
  26.     int fd;
  27.     int ptyfd;
  28.     int ptyslavefd;
  29.     //在预取数据时,判断是否一致性
  30.     long modifver;
  31.     //用户id相关
  32.     unsigned remote_uid;
  33.     unsigned local_uid;
  34.     int remote_uid_detected;
  35.     …......
  36. }

这里最为重要的就是GHashTable reqtab,所有的请求在发送时都会进入该表,在返回之后,通过请求的性质(是否回复,是否回掉等)来处理,才能删除。

数据包的请求如下:

  1. struct request {
  2.   unsigned int want_reply; //是否需要回复
  3.   sem_t ready;//这个很重要,请求如果是阻塞情况,就发送命令直到出现回复为止
  4.   uint8_t reply_type;//通过调用程序,指定想要回复类型,进行判断
  5.   int replied;
  6.   int error;
  7.   struct buffer reply;
  8.   struct timeval start;
  9.   void *data;
  10.   request_func_end end_func;//异步回调函数
  11.   size_t len;
  12.   struct list_head list;
  13. }

协议请求数据包格式为:

数据包长度(4字节)

请求包命令类型(1字节)

Hash key(4字节)

数据

全局接收线程只有一个,调用函数如下:

  1. static int process_one_request(void)
  2. {
  3.           ………….
  4.     //这里有些疑惑,缓冲区长度为0,如何下面还能读取?
  5.     buf_init(&buf,0);
  6.     //读取数据包类型
  7. req = .sftp_read(&type,&buf);
  8. //读取数据包的hash id
  9. if(buf_get_uint32(&buf,&id)==-1) return -1;
  10. ……..
  11. //接下来,就是查看通过获取到的key来查询hashtab,
  12. req = (struct request*)g_hash_lookup(sshfs.reqtab,GUINT_TO_POINTER(id));
  13. g_hash_table_remove(sshfs.reqtab,GUINT_TO_POINTER(id));
  14. //初始化回复包中的数据
  15.      req->reply = buf;
  16.      req->reply_type = type;
  17. req->replied = 1;
  18. //
  19. if(req->want_reply) sem_post(req->ready);
  20. else
  21. {
  22.     //异步回调函数的实现方式
  23.     if(req->end_func){
  24.     pthread_mutex_lock(&sshfs.lock);
  25.     req->end_func(req);
  26.     pthread_mutex_unlock(&sshfs.lock);
  27. }
  28. ………..
  29. }

  30. }

至此请求过来的数据就会处理完毕!

而基于此上面的方法主要是发送,请求,阻塞式请求方式等等。

文件部分

  1. //整体文件
  2. struct sshfs_file
  3. {
  4. //这个对于客户端而言,没什么作用,但对于服务器而言,这里就是服务器区分不同文件的
  5. //凭证了
  6.   struct buffer handle;
  7.   struct list_head write_reqs;
  8. //实现阻塞式写
  9.   pthread_cond_t write_finished;
  10.   int write_error;
  11. //提前预读取数据部分,每次读时,都要提前读取下一部分的数据
  12.  struct read_chunk *readahead;
  13. //用来判断是否命中,作为readahead标志
  14.  off_t next_pos;
  15.  int is_seq;
  16. //ssh是否连接成功
  17.  int connver;
  18. //是否修改位,判断命中的标志
  19.  int modifver;
  20. //文件引用计数
  21.  int refs;
  22. }

我认为设计上面不是很合理,文件信息最好与描述信息(stat),数据块连接起来,而且这里也没有进行数据块的缓存,该结构体最为重要的与fuse中描述体fuse_file_info中的选项联系起来,fuse_file_info.fh,在文件打开时候,就会绑定起来:

fi->fh = (unsigned long)sf;

这里就是以后所有的操作关键所在,以后所有的文件操作就会和fuse的接口进行关联。

文件块信息

  1. struct read_chunk
  2. {
  3. //非阻塞方式已经细化到具体的数据块
  4.   sem_t ready;
  5. //文件偏移量和大小
  6.   off_t offset;
  7.   size_t size;
  8. //具体数据
  9.   struct buffer data;
  10. //引用计数
  11.    int refs;
  12. //脏位标志
  13.    long modifver;
  14. }

相关方法就是搜索。

阅读(4000) | 评论(0) | 转发(0) |
0

上一篇:C++类型转换

下一篇:sshfs分析心得(二)

给主人留下些什么吧!~~