sshfs采用了
fuse的高级开发模式
,整体流程
用户输入相关参数之后,根据输入的数据,进行初始化sshfs结构体,其中ssh结构体非常庞大,类似于session,大致的内容如下:
- struct sshfs
-
{
-
//连接的端口,主机
-
char *directport;
-
char *host;
-
….
-
//每一次发送,接受的数据包大小
-
unsigned max_read;
-
unsigned max_write;
-
//是否为前台进程,否则将错误进行重定位/dev/null
-
int foreground;
-
//这些workaround,没有弄明白
-
int rename_workaround;
-
char* workaround;
-
int nodelay_workaround;
-
int nodelaysrv_workaround;
-
int truncate_workaround;
-
…....
-
//请求数据包相关的信息
-
//其中reqtab非常重要,每次ssh中的请求都会进入该表
-
GhashTable *reqtab;
-
pthread_mutex_t lock;
-
pthread_mutex_t lock_write;
-
….....
-
//网络通信fd,伪终端
-
int fd;
-
int ptyfd;
-
int ptyslavefd;
-
//在预取数据时,判断是否一致性
-
long modifver;
-
//用户id相关
-
unsigned remote_uid;
-
unsigned local_uid;
-
int remote_uid_detected;
-
…......
-
}
这里最为重要的就是GHashTable
reqtab,所有的请求在发送时都会进入该表,在返回之后,通过请求的性质(是否回复,是否回掉等)来处理,才能删除。
数据包的请求如下:
- struct request {
-
unsigned int want_reply; //是否需要回复
-
sem_t ready;//这个很重要,请求如果是阻塞情况,就发送命令直到出现回复为止
-
uint8_t reply_type;//通过调用程序,指定想要回复类型,进行判断
-
int replied;
-
int error;
-
struct buffer reply;
-
struct timeval start;
-
void *data;
-
request_func_end end_func;//异步回调函数
-
size_t len;
-
struct list_head list;
-
}
协议请求数据包格式为:
数据包长度(4字节)
|
请求包命令类型(1字节)
|
Hash key(4字节)
|
数据
|
全局接收线程只有一个,调用函数如下:
- static int process_one_request(void)
-
{
-
………….
-
//这里有些疑惑,缓冲区长度为0,如何下面还能读取?
-
buf_init(&buf,0);
-
//读取数据包类型
-
req = .sftp_read(&type,&buf);
-
//读取数据包的hash id
-
if(buf_get_uint32(&buf,&id)==-1) return -1;
-
……..
-
//接下来,就是查看通过获取到的key来查询hashtab,
-
req = (struct request*)g_hash_lookup(sshfs.reqtab,GUINT_TO_POINTER(id));
-
g_hash_table_remove(sshfs.reqtab,GUINT_TO_POINTER(id));
-
//初始化回复包中的数据
-
req->reply = buf;
-
req->reply_type = type;
-
req->replied = 1;
-
//
-
if(req->want_reply) sem_post(req->ready);
-
else
-
{
-
//异步回调函数的实现方式
-
if(req->end_func){
-
pthread_mutex_lock(&sshfs.lock);
-
req->end_func(req);
-
pthread_mutex_unlock(&sshfs.lock);
-
}
-
………..
-
}
-
-
}
至此请求过来的数据就会处理完毕!
而基于此上面的方法主要是发送,请求,阻塞式请求方式等等。
文件部分
- //整体文件
-
struct sshfs_file
-
{
-
//这个对于客户端而言,没什么作用,但对于服务器而言,这里就是服务器区分不同文件的
-
//凭证了
-
struct buffer handle;
-
struct list_head write_reqs;
-
//实现阻塞式写
-
pthread_cond_t write_finished;
-
int write_error;
-
//提前预读取数据部分,每次读时,都要提前读取下一部分的数据
-
struct read_chunk *readahead;
-
//用来判断是否命中,作为readahead标志
-
off_t next_pos;
-
int is_seq;
-
//ssh是否连接成功
-
int connver;
-
//是否修改位,判断命中的标志
-
int modifver;
-
//文件引用计数
-
int refs;
-
}
我认为设计上面不是很合理,文件信息最好与描述信息(stat),数据块连接起来,而且这里也没有进行数据块的缓存,该结构体最为重要的与fuse中描述体fuse_file_info中的选项联系起来,fuse_file_info.fh,在文件打开时候,就会绑定起来:
fi->fh
= (unsigned long)sf;
这里就是以后所有的操作关键所在,以后所有的文件操作就会和fuse的接口进行关联。
文件块信息
- struct read_chunk
-
{
-
//非阻塞方式已经细化到具体的数据块
-
sem_t ready;
-
//文件偏移量和大小
-
off_t offset;
-
size_t size;
-
//具体数据
-
struct buffer data;
-
//引用计数
-
int refs;
-
//脏位标志
-
long modifver;
-
}
相关方法就是搜索。
阅读(4000) | 评论(0) | 转发(0) |