Android Fuse文件系统-6:fuse内核

867 阅读3分钟

以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);
    //...
}