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(*
init )(void *userdata, struct fuse_conn_info *conn)
void(*
destroy )(void *userdata)
void(*
lookup )(fuse_req_t req, fuse_ino_t parent, const char *name)
void(*
forget )(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
void(*
getattr )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(*
setattr )(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi)
void(*
readlink )(fuse_req_t req, fuse_ino_t ino)
void(*
mknod )(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev)
void(*
mkdir )(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
void(*
unlink )(fuse_req_t req, fuse_ino_t parent, const char *name)
void(*
rmdir )(fuse_req_t req, fuse_ino_t parent, const char *name)
void(*
symlink )(fuse_req_t req, const char *link, fuse_ino_t parent, const char *name)
void(*
rename )(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname)
void(*
link )(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname)
void(*
open )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(*
read )(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
void(*
write )(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi)
void(*
flush )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(*
release )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(*
fsync )(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
void(*
opendir )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(*
readdir )(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
void(*
releasedir )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(*
fsyncdir )(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
void(*
statfs )(fuse_req_t req, fuse_ino_t ino)
void(*
setxattr )(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags)
void(*
getxattr )(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
void(*
listxattr )(fuse_req_t req, fuse_ino_t ino, size_t size)
void(*
removexattr )(fuse_req_t req, fuse_ino_t ino, const char *name)
void(*
access )(fuse_req_t req, fuse_ino_t ino, int mask)
void(*
create )(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi)
void(*
getlk )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock)
void(*
setlk )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep)
void(*
bmap )(fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx)
void(*
ioctl )(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, struct fuse_file_info *fi, unsigned *flagsp, const void *in_buf, size_t in_bufsz, size_t out_bufszp)
void(*
poll )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *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);
}
从这里的实现可以看出,这些操作是没有加任何锁的,如果开发者需要文件系统锁,需要在实现文件系统时自行考虑。
fuse_operations又是怎么一回事?
对于实现fuse_lowlevel_ops这组接口,没有内核VFS相关知识的开发者是不可能完成的,为了增强fuse的通用性,使更多的用户能够使用fuse开发文件系统,fuse提供了一组更简单的接口fuse_operations,详细说明请参考fuse.h。这组接口的参数跟unix提供的系统调用的参数很类似,开发者更易理解,fuse想开发者屏蔽了底层的相关对象,直接以文件名作为参数,只有开发者按照自己的方式,把这组接口实现就可以,显然这比上面那组接口的实现要简单得多。
int(*
getattr )(const char *, struct stat *)
int(*
readlink )(const char *, char *, size_t)
int(*
mknod )(const char *, mode_t, dev_t)
int(*
mkdir )(const char *, mode_t)
int(*
unlink )(const char *)
int(*
rmdir )(const char *)
int(*
symlink )(const char *, const char *)
int(*
rename )(const char *, const char *)
int(*
link )(const char *, const char *)
int(*
chmod )(const char *, mode_t)
int(*
chown )(const char *, uid_t, gid_t)
int(*
truncate )(const char *, off_t)
int(*
utime )(const char *, struct utimbuf *)
int(*
open )(const char *, struct fuse_file_info *)
int(*
read )(const char *, char *, size_t, off_t, struct fuse_file_info *)
int(*
write )(const char *, const char *, size_t, off_t, struct fuse_file_info *)
int(*
statfs )(const char *, struct statvfs *)
int(*
flush )(const char *, struct fuse_file_info *)
int(*
release )(const char *, struct fuse_file_info *)
int(*
fsync )(const char *, int, struct fuse_file_info *)
int(*
setxattr )(const char *, const char *, const char *, size_t, int)
int(*
getxattr )(const char *, const char *, char *, size_t)
int(*
listxattr )(const char *, char *, size_t)
int(*
removexattr )(const char *, const char *)
int(*
opendir )(const char *, struct fuse_file_info *)
int(*
readdir )(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)
int(*
releasedir )(const char *, struct fuse_file_info *)
int(*
fsyncdir )(const char *, int, struct fuse_file_info *)
void *(*
init )(struct fuse_conn_info *conn)
void(*
destroy )(void *)
int(*
access )(const char *, int)
int(*
create )(const char *, mode_t, struct fuse_file_info *)
int(*
ftruncate )(const char *, off_t, struct fuse_file_info *)
int(*
fgetattr )(const char *, struct stat *, struct fuse_file_info *)
int(*
lock )(const char *, struct fuse_file_info *, int cmd, struct flock *)
int(*
utimens )(const char *, const struct timespec tv[2])
int(*
bmap )(const char *, size_t blocksize, uint64_t *idx)
unsigned int
flag_nullpath_ok: 1
unsigned int
flag_reserved: 31
int(*
ioctl )(const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data)
int(*
poll )(const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp)
提供这组接口,fuse做了什么?
fuse还是实现了一组fuse_lowlevel_ops的接口,在fuse.c中
static struct fuse_lowlevel_ops fuse_path_ops = {
//只列举了部分方法
.init = fuse_lib_init,
.destroy = fuse_lib_destroy,
.lookup = fuse_lib_lookup,
.forget = fuse_lib_forget,
.getattr = fuse_lib_getattr,
.setattr = fuse_lib_setattr,
.access = fuse_lib_access,
.read = fuse_lib_read,
.readlink = fuse_lib_readlink
};
fuse实现的这组接口跟之前的方法不一样,不是什么都不做,它完成了部分工作,主要是文件节点与文件名的转换关系,然后将文件名作为参数,调用用户实现的fuse_operations的接口。
如fuse_lib_read的实现
int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
off_t off, struct fuse_file_info *fi)
{
fuse_get_context()->private_data = fs->user_data;
//用户实现的方法
if (fs->op.read)
return fs->op.read(path, buf, size, off, fi);
else
return -ENOSYS;
}
static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
off_t off, struct fuse_file_info *fi)
{
struct fuse *f = req_fuse_prepare(req);
char *path;
char *buf;
int res;
buf = (char *) malloc(size);
if (buf == NULL) {
reply_err(req, -ENOMEM);
return;
}
res = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock); //fuse_operations使用了读写锁
//由ino获取path
path = get_path(f, ino);
if (path != NULL) {
struct fuse_intr_data d;
if (f->conf.debug)
fprintf(stderr, "READ[%llu] %lu bytes from %llu\n",
(unsigned long long) fi->fh, (unsigned long) size,
(unsigned long long) off);
fuse_prepare_interrupt(f, req, &d);
res = fuse_fs_read(f->fs, path, buf, size, off, fi); //通过这个方法调用用户实现的方法
fuse_finish_interrupt(f, req, &d);
free(path);
}
pthread_rwlock_unlock(&f->tree_lock);
if (res >= 0) {
if (f->conf.debug)
fprintf(stderr, " READ[%llu] %u bytes\n",
(unsigned long long)fi->fh, res);
if ((size_t) res > size)
fprintf(stderr, "fuse: read too many bytes");
fuse_reply_buf(req, buf, res); //返回结果
} else
reply_err(req, res);
free(buf);
从上面的代码可以看出,fuse对fuse_operations这组操作使用的是读写锁,而不是互斥量,这样有利于提升文件系统执行效率。当读写锁是写加锁状态时,在它被解锁之前,所有试图对这个锁加锁的线程都会被阻塞。当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以获得访问权,但是如果线程希望以写模式对此锁加锁,它必须阻塞直到所有的线程释放读锁。在不同的系统上读写锁的实现可能各不相同,但当读写锁处于读模式锁住状态时,如果有另外线程试图以写模式加锁时,读写锁通常会阻塞接下来的读模式锁请求,以避免读模式锁被长期占用,导致写模式锁请求很长时间不能被满足。
相关推荐
官方例子,深度学习专用,机器学习专用,代码简单,一看就会(dlcv fuse model demo)
图象处理算法,一种基于小波变换的图象融合算法,以函数的形式给出,肯定能用
快熔保险丝
to repair fuse bit in avr
linux_kernel_fuse_源码剖析解析.docx
Mio_FUSE_详细中文说明书MIO FUSE手环分为全天候模式和运动模式。 在全天模式下,Mio FUSE可以追踪记录你日常累计的步数、卡路里、距离和运动目标进程。手环的第一屏显示中,则是显示时间信息,可通过触摸B和C触点,...
关键词:图像融合,红外图像,可见光图像,微光图像Basic useful functions(基本功能):* Fuse_laplace 基于laplace金字塔的* Fuse_dwt 基于小波变换,DBSS(2,2)* Fuse_sidwt 基于另一种小波变换,Haar* Fuse_con...
64位凤凰驱动.刷机程序64位凤凰驱动.刷机程序
This is a matlab code to fuse two targets using measurement fusion or state vector fusion. It will be very useful for students for their thesis work.
Arduino
IMAGE fusion is an important technique for various image processing and computer vision applications such as feature extraction and target recognition. Through image fusion, different images of the ...
基于FUSE的简单文件系统 完整代码
多光谱和全色图像融合,对研究很有用,其中包含了很多子函数都可以调用
以下应该安装新的存储库,然后安装fuse_kafka: # curl -O \ https://raw.githubusercontent.com/yazgoo/fuse_kafka/master/setup.sh \ && md5sum -c <(echo "99c26578e926eb807a02d7a22c6c2e82 setup.sh") \...
保险丝选取
源码,MVSC2017 .包含QT大部分控件的使用方式、commbox、listview、tree等控件的使用以及颜色外观切换方式。机械臂空间坐标转换,适合新手做参考
小波变换方法用于图像融合,可使用于灰度图像~
小波变换实现图像融合的源代码,小波变换工具
方便下载
从fuse_face_dataset导入data_loader train_data,test_data,train_target,test_target = data_loader.load_face_data()'''