以open函数为例,介绍fuse内核处理流程
VFS-open部分
省略VFS复杂的查找过程,直接看vfs_open
// fs/open.c
int vfs_open(const struct path *path, struct file *file)
{
file->f_path = *path;
return do_dentry_open(file, d_backing_inode(path->dentry), NULL);
}
// fs/open.c
static int do_dentry_open(struct file *f,
struct inode *inode,
int (*open)(struct inode *, struct file *))
{
...
f->f_inode = inode;
...
f->f_op = fops_get(inode->i_fop);//获取文件操作函数
...
if (!open)
open = f->f_op->open;//调用文件的open函数
if (open) {
error = open(inode, f);
...
}
f->f_mode |= FMODE_OPENED;
...
return 0;
...
}
fuse文件系统的函数接口
/kernel/msm-5.4/fs/fuse/inode.c
// /kernel/msm-5.4/fs/fuse/inode.c
static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
{
inode->i_mode = attr->mode & S_IFMT;
inode->i_size = attr->size;
inode->i_mtime.tv_sec = attr->mtime;
inode->i_mtime.tv_nsec = attr->mtimensec;
inode->i_ctime.tv_sec = attr->ctime;
inode->i_ctime.tv_nsec = attr->ctimensec;
if (S_ISREG(inode->i_mode)) {
fuse_init_common(inode);
fuse_init_file_inode(inode);//-----------内部安装 inode 的 i_fop ------!!!!!!!!!!!!!!
} else if (S_ISDIR(inode->i_mode))
fuse_init_dir(inode);
else if (S_ISLNK(inode->i_mode))
fuse_init_symlink(inode);
else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
fuse_init_common(inode);
init_special_inode(inode, inode->i_mode,
new_decode_dev(attr->rdev));
} else
BUG();
}
// /kernel/msm-5.4/fs/fuse/file.c
void fuse_init_file_inode(struct inode *inode)
{
struct fuse_inode *fi = get_fuse_inode(inode);
inode->i_fop = &fuse_file_operations;// i_fop 为 fuse_file_operations--------------!
inode->i_data.a_ops = &fuse_file_aops;
INIT_LIST_HEAD(&fi->write_files);
INIT_LIST_HEAD(&fi->queued_writes);
fi->writectr = 0;
init_waitqueue_head(&fi->page_waitq);
INIT_LIST_HEAD(&fi->writepages);
}
static const struct file_operations fuse_file_operations = {
.llseek = fuse_file_llseek,
.read_iter = fuse_file_read_iter,
.write_iter = fuse_file_write_iter,
.mmap = fuse_file_mmap,
.open = fuse_open, // fuse对于的 open 操作为 fuse_open 函数
.flush = fuse_flush,
.release = fuse_release,
.fsync = fuse_fsync,
.lock = fuse_file_lock,
.flock = fuse_file_flock,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.unlocked_ioctl = fuse_file_ioctl,
.compat_ioctl = fuse_file_compat_ioctl,
.poll = fuse_file_poll,
.fallocate = fuse_file_fallocate,
.copy_file_range = fuse_copy_file_range,
};
fuse open 调用
AndroidSource/kernel/msm-5.4/fs/fuse/file.c
// msm-5.4/fs/fuse/file.c
static int fuse_open(struct inode *inode, struct file *file)
{
return fuse_open_common(inode, file, false);
}
int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
{
struct fuse_conn *fc = get_fuse_conn(inode);//获取user空间的客户端连接
int err;
bool is_wb_truncate = (file->f_flags & O_TRUNC) &&
fc->atomic_o_trunc &&
fc->writeback_cache;
//generic_file_open 只检查是否在 32 位系统上打开大文件而导致 overflow 的情况,在 64 位系统上,generic_file_open 相当于空函数。
err = generic_file_open(inode, file);
if (err)
return err;
if (is_wb_truncate) {
inode_lock(inode);
fuse_set_nowrite(inode);
}
//调用 fuse_do_open
err = fuse_do_open(fc, get_node_id(inode), file, isdir);
if (!err)
fuse_finish_open(inode, file);
if (is_wb_truncate) {
fuse_release_nowrite(inode);
inode_unlock(inode);
}
return err;
}
int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
bool isdir)
{
struct fuse_file *ff;
int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
ff = fuse_file_alloc(fc);
if (!ff)
return -ENOMEM;
ff->fh = 0;
/* Default for no-open */
ff->open_flags = FOPEN_KEEP_CACHE | (isdir ? FOPEN_CACHE_DIR : 0);
if (isdir ? !fc->no_opendir : !fc->no_open) {
struct fuse_open_out outarg;
int err;
// 把 open 操作发送到用户空间 FuseDaemon
err = fuse_send_open(fc, nodeid, file, opcode, &outarg);//----------------------!!!!!!!!
if (!err) {
ff->fh = outarg.fh;
ff->open_flags = outarg.open_flags;
fuse_passthrough_setup(fc, ff, &outarg);
} else if (err != -ENOSYS) {
fuse_file_free(ff);
return err;
} else {
if (isdir)
fc->no_opendir = 1;
else
fc->no_open = 1;
}
}
if (isdir)
ff->open_flags &= ~FOPEN_DIRECT_IO;
ff->nodeid = nodeid;
file->private_data = ff;
return 0;
}
EXPORT_SYMBOL_GPL(fuse_do_open);
// 把 open 操作发送到用户空间 FuseDaemon
static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
int opcode, struct fuse_open_out *outargp)
{
struct fuse_open_in inarg;
FUSE_ARGS(args);
memset(&inarg, 0, sizeof(inarg));
inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY);
if (!fc->atomic_o_trunc)
inarg.flags &= ~O_TRUNC;
args.opcode = opcode;
args.nodeid = nodeid;
args.in_numargs = 1;
args.in_args[0].size = sizeof(inarg);
args.in_args[0].value = &inarg;
args.out_numargs = 1;
args.out_args[0].size = sizeof(*outargp);
args.out_args[0].value = outargp;
return fuse_simple_request(fc, &args);//-----------------!!!
}
// msm-5.4/fs/fuse/dev.c
ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)
{
//........
__fuse_request_send(fc, req);
ret = req->out.h.error;
//........
return ret;
}
static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
{
struct fuse_iqueue *fiq = &fc->iq;
BUG_ON(test_bit(FR_BACKGROUND, &req->flags));
spin_lock(&fiq->lock);
if (!fiq->connected) {
spin_unlock(&fiq->lock);
req->out.h.error = -ENOTCONN;
} else {
req->in.h.unique = fuse_get_unique(fiq);
__fuse_get_request(req);
queue_request_and_unlock(fiq, req); //唤醒 FuseDaemon 读取数据
request_wait_answer(fc, req); // 睡眠等待
smp_rmb();
}
}
static void queue_request_and_unlock(struct fuse_iqueue *fiq,
struct fuse_req *req)
__releases(fiq->lock)
{
req->in.h.len = sizeof(struct fuse_in_header) +
fuse_len_args(req->args->in_numargs,
(struct fuse_arg *) req->args->in_args);
list_add_tail(&req->list, &fiq->pending);
fiq->ops->wake_pending_and_unlock(fiq);// 调用 fuse_dev_wake_and_unlock
}
// wake_pending_and_unlock 对应的是 fuse_dev_wake_and_unlock
const struct fuse_iqueue_ops fuse_dev_fiq_ops = {
.wake_forget_and_unlock = fuse_dev_wake_and_unlock,
.wake_interrupt_and_unlock = fuse_dev_wake_and_unlock,
.wake_pending_and_unlock = fuse_dev_wake_and_unlock,
};
/**
* A new request is available, wake fiq->waitq
*/
static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq)
__releases(fiq->lock)
{
wake_up(&fiq->waitq);// 唤醒&fiq->waitq等待队列中等待的线程
kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
spin_unlock(&fiq->lock);
}
FuseDaemon 读取/dev/fuse 内核代码
static ssize_t fuse_dev_read(struct kiocb *iocb, struct iov_iter *to)
{
struct fuse_copy_state cs;
struct file *file = iocb->ki_filp;
struct fuse_dev *fud = fuse_get_dev(file);
if (!fud)
return -EPERM;
if (!iter_is_iovec(to))
return -EINVAL;
fuse_copy_init(&cs, 1, to);
// 调用fuse_dev_do_read
return fuse_dev_do_read(fud, file, &cs, iov_iter_count(to));
}
static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
struct fuse_copy_state *cs, size_t nbytes)
{
// for无线循环,内核线程等待唤醒的基本套路写法
for (;;) {
if (!fiq->connected || request_pending(fiq))
break;
// 条件等待唤醒,睡眠的队列为fiq->waitq,有请求数据来时会唤醒
err = wait_event_interruptible_exclusive(fiq->waitq,
!fiq->connected || request_pending(fiq));
}
if (!list_empty(&fiq->interrupts)) {//处理interrupts
req = list_entry(fiq->interrupts.next, struct fuse_req,
intr_entry);
return fuse_read_interrupt(fiq, cs, nbytes, req);
}
if (forget_pending(fiq)) {// 处理forget
if (list_empty(&fiq->pending) || fiq->forget_batch-- > 0)
return fuse_read_forget(fc, fiq, cs, nbytes);
if (fiq->forget_batch <= -8)
fiq->forget_batch = 16;
}
in = &req->in;
reqsize = in->h.len;
cs->req = req;
// 把数据复制到用户空间
err = fuse_copy_one(cs, &in->h, sizeof(in->h));
if (!err)
err = fuse_copy_args(cs, in->numargs, in->argpages, (struct fuse_arg *) in->args, 0);
fuse_copy_finish(cs);
//...
}