免费注册 查看新帖 |

ChinaUnix.net

  平台 论坛 博客 文库 频道自动化运维 虚拟化 储存备份 C/C++ PHP MySQL 嵌入式 Linux系统
最近访问板块 发新帖
查看: 2296 | 回复: 0

fuse_operations与fuse_lowlevel_ops [复制链接]

论坛徽章:
0
发表于 2010-02-01 13:48 |显示全部楼层

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这组操作使用的是读写锁,而不是互斥量,这样有利于提升文件系统执行效率。当读写锁是写加锁状态时,在它被解锁之前,所有试图对这个锁加锁的线程都会被阻塞。当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以获得访问权,但是如果线程希望以写模式对此锁加锁,它必须阻塞直到所有的线程释放读锁。在不同的系统上读写锁的实现可能各不相同,但当读写锁处于读模式锁住状态时,如果有另外线程试图以写模式加锁时,读写锁通常会阻塞接下来的读模式锁请求,以避免读模式锁被长期占用,导致写模式锁请求很长时间不能被满足。



本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/87570/showart_2166461.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

数据风云,十年变迁
DTCC 第十届中国数据库技术大会已启航!

2019年5月8日~5月10日,由IT168旗下ITPUB企业社区平台主办的第十届中国数据库技术大会(DTCC2019),将在北京隆重召开。大会将邀请百余位行业专家,就热点技术话题进行分享,是广大数据领域从业人士的又一次年度盛会和交流平台。与SACC2018类似,本届大会将采用“3+2”模式:3天传统技术演讲+2天深度主题培训。大会不仅提供超100场的主题演讲,还会提供连续2天的深度课程培训,深化数据领域的项目落地实践方案。
DTCC2019,一场值得期待的数据技术盛会,殷切地希望您报名参与!

活动入口>>
  

北京盛拓优讯信息技术有限公司. 版权所有 16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122
中国互联网协会会员  联系我们:huangweiwei@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP