分类: 服务器与存储
2010-08-16 22:09:29
fuse为开发者提供了两组接口,分别是fuse_lowlevel_ops以及fuse_operations,开发者只需要实现这两组接口的一种即可实现一个用户空间文件系统。
struct fuse_lowlevel_ops的成员如下所示,其中init方法在其它所有方法之前调用,用于初始化文件系统,fuse已经实现,destroy则是在文件系统被卸载时做一些清理工作。用于大多数请求的参数都是fuse_ino_t类型的ino,而文件系统提供给用户的视图是以文件名呈现的,故lookup是实现文件系统的关键,它在parent中查找名字name对应的文件,并返回相应的信息,可使用fuse_reply_entry或fuse_reply_err作为请求的返回。
接口中的方法对于了解过VFS的人应该都不难理解,只要按需实现这些接口,你就可以定制出属于自己的文件系统,这组接口的详细说明见fuse_lowlevel.h。
void(* | )(void *userdata, struct *conn) |
void(* | )(void *userdata) |
void(* | )( req, parent, const char *name) |
void(* | )( req, ino, unsigned long nlookup) |
void(* | )( req, ino, struct *fi) |
void(* | )( req, ino, struct stat *attr, int to_set, struct *fi) |
void(* | )( req, ino) |
void(* | )( req, parent, const char *name, mode_t mode, dev_t rdev) |
void(* | )( req, parent, const char *name, mode_t mode) |
void(* | )( req, parent, const char *name) |
void(* | )( req, parent, const char *name) |
void(* | )( req, const char *, parent, const char *name) |
void(* | )( req, parent, const char *name, newparent, const char *newname) |
void(* | )( req, ino, newparent, const char *newname) |
void(* | )( req, ino, struct *fi) |
void(* | )( req, ino, size_t size, off_t off, struct *fi) |
void(* | )( req, ino, const char *buf, size_t size, off_t off, struct *fi) |
void(* | )( req, ino, struct *fi) |
void(* | )( req, ino, struct *fi) |
void(* | )( req, ino, int datasync, struct *fi) |
void(* | )( req, ino, struct *fi) |
void(* | )( req, ino, size_t size, off_t off, struct *fi) |
void(* | )( req, ino, struct *fi) |
void(* | )( req, ino, int datasync, struct *fi) |
void(* | )( req, ino) |
void(* | )( req, ino, const char *name, const char *value, size_t size, int flags) |
void(* | )( req, ino, const char *name, size_t size) |
void(* | )( req, ino, size_t size) |
void(* | )( req, ino, const char *name) |
void(* | )( req, ino, int mask) |
void(* | )( req, parent, const char *name, mode_t mode, struct *fi) |
void(* | )( req, ino, struct *fi, struct flock *lock) |
void(* | )( req, ino, struct *fi, struct flock *lock, int sleep) |
void(* | )( req, ino, size_t blocksize, uint64_t idx) |
void(* | )( req, ino, int cmd, void *arg, struct *fi, unsigned *flagsp, const void *in_buf, size_t in_bufsz, size_t out_bufszp) |
void(* | )( req, ino, struct *fi, struct fuse_pollhandle *ph) |
用户实现的接口是如何跟这个结构关联起来的?
其实fuse中已经实现了一组接口,在fuse_lowlevel.c中,定义了一个静态的结构数组,该数组的元素为一组(函数,名字)的结构,但没做什么实际的工作,当fuse用户空间的daemon从/fuse/dev中读取到请求之后,它通过请求号来判别各个请求,并调用这里相应的处理函数,如读取到read调用时,会调用do_read进行处理。
static struct {
void (*func)(fuse_req_t, fuse_ino_t, const void *);
const char *name;
} fuse_ll_ops[] = {
//只列举了部分
[FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
[FUSE_OPEN] = { do_open, "OPEN" },
[FUSE_READ] = { do_read, "READ" },
[FUSE_WRITE] = { do_write, "WRITE" },
[FUSE_STATFS] = { do_statfs, "STATFS" },
[FUSE_FLUSH] = { do_flush, "FLUSH" },
[FUSE_INIT] = { do_init, "INIT" },
[FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
[FUSE_READDIR] = { do_readdir, "READDIR" },
[FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
[FUSE_DESTROY] = { do_destroy, "DESTROY" }
};
接下来看一下do_read的实现
static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
// 如果用户实现了read操作,则调用用户空间的read,否则以没有实现该调用为错误响应,这里的op就是用户实现文件系统时实现的,并传递给fuse。
if (req->f->op.read) {
struct fuse_file_info fi;
memset(&fi, 0, sizeof(fi));
fi.fh = arg->fh;
fi.fh_old = fi.fh;
req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
} else
fuse_reply_err(req, ENOSYS);
}
从这里的实现可以看出,这些操作是没有加任何锁的,如果开发者需要文件系统锁,需要在实现文件系统时自行考虑。
原文链接:http://blog.chinaunix.net/u2/87570/showart_2166461.html