在上文对操作的跟踪中,对于vfs提供的接口。fuse填充的静态情形知道了。其中主要是针对inode。那么inode初始化的整个情景如何.首先跟踪到直接相关的初始化函数。
static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
{
inode->i_mode = attr->mode & S_IFMT;
inode->i_size = attr->size;
if (S_ISREG(inode->i_mode)) {
fuse_init_common(inode);
fuse_init_file_inode(inode);
} 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();
}
|
以上代码很清楚的表明针对inode的不同类型进行各种不同的初始化化过程。
有一般文件,目录,链接,其他文件(字符设备,块设备,管道,套接字)
可以看到基本上包含了我们一般使用的文件。
fuse_init_file_inode(inode) 和
fuse_init_dir(inode); 上文已经介绍过。
可以看出。该部分的初始化实际上是对inode操作接口的实例化。
函数被唯一调用
struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
int generation, struct fuse_attr *attr)
{
struct inode *inode;
struct fuse_inode *fi;
struct fuse_conn *fc = get_fuse_conn_super(sb);
retry:
inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
if (!inode)
return NULL;
if ((inode->i_state & I_NEW)) {
inode->i_flags |= S_NOATIME|S_NOCMTIME;
inode->i_generation di;
fuse_init_inode(inode, attr);
unlock_new_inode(inode) = generation;
inode->i_data.backing_dev_info = &fc->b ;
} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
/* Inode has changed type, any I/O on the old should fail */
make_bad_inode(inode);
iput(inode);
goto retry;
}
fi = get_fuse_inode(inode);
spin_lock(&fc->lock);
fi->nlookup ++;
spin_unlock(&fc->lock);
fuse_change_attributes(inode, attr);
return inode;
|
顺序分析:
fuse_conn 是对fuse整个系统的一个控制结构。它把地址存放于super_block中。
用这种方式来把用户的某些数据存放到系统提供的结构中。可以在很多地方使用。
static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb)
{
return sb->s_fs_info;
}
|
是系统内核的函数,用于从挂载的文件系统获取一个inode节点。
static inline struct fuse_inode *get_fuse_inode(struct inode *inode)
{
return container_of(inode, struct fuse_inode, inode);
}
|
container_of() 通过该宏可以获取到指向inode 结构的fuse_inode地址。
spin_lock(&fc->lock);
fi->nlookup ++;
spin_unlock(&fc->lock);
该处是典型的引用计数的增加。代表在该节点上搜索的次数。那么这是否可以代表该节点增在被使用。
fuse_change_attributes,该函数是对inode节点属性的填充,如节点号,用户id,组id等。
分析fuse_lookup
该函数应该是相当关键的。该函数如何作用,要从vfs的调用来看。借助某位仁兄对vfs的分析一起来看该处的作用,先看:。然后就明白该函数在系统中的位置了。这样vfs 和fuse就对应起来了。首先弄清楚fuse_lookup 使用的上下文情景。
从
static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
struct nameidata *nd)
{
int err;
struct fuse_entry_out outarg;
struct inode *inode = NULL;
struct dentry *newent;
struct fuse_conn *fc = get_fuse_conn(dir);
struct fuse_req *req;
struct fuse_req *forget_req;
if (entry->d_name.len > FUSE_NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
req = fuse_get_req(fc);
if (IS_ERR(req))
return ERR_PTR(PTR_ERR(req));
forget_req = fuse_get_req(fc);
if (IS_ERR(forget_req)) {
fuse_put_request(fc, req);
return ERR_PTR(PTR_ERR(forget_req));
}
fuse_lookup_init(req, dir, entry, &outarg);
request_send(fc, req);
err = req->out.h.error;
fuse_put_request(fc, req);
/* Zero nodeid is same as -ENOENT, but with valid timeout */
if (!err && outarg.nodeid &&
(invalid_nodeid(outarg.nodeid) ||
!fuse_valid_type(outarg.attr.mode)))
err = -EIO;
if (!err && outarg.nodeid) {
inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
&outarg.attr);
if (!inode) {
fuse_send_forget(fc, forget_req, outarg.nodeid, 1);
return ERR_PTR(-ENOMEM);
}
}
fuse_put_request(fc, forget_req);
if (err && err != -ENOENT)
return ERR_PTR(err);
if (inode && S_ISDIR(inode->i_mode)) {
mutex_lock(&fc->inst_mutex);
newent = fuse_d_add_directory(entry, inode);
mutex_unlock(&fc->inst_mutex);
if (IS_ERR(newent)) {
iput(inode);
return newent;
}
} else
newent = d_splice_alias(inode, entry);
entry = newent ? newent : entry;
entry->d_op = &fuse_dentry_operations;
if (!err)
fuse_change_timeout(entry, &outarg);
else
fuse_invalidate_entry_cache(entry);
return newent;
}
|
fuse_get_req
dentry = d_lookup(parent, name);
if (!dentry) {
struct dentry *new;
/* Don't create child dentry for a dead directory. */
dentry = ERR_PTR(-ENOENT);
if (IS_DEADDIR(dir))
goto out_unlock;
new = d_alloc(parent, name);
dentry = ERR_PTR(-ENOMEM);
if (new) {
dentry = dir->i_op->lookup(dir, new, nd);
if (dentry)
dput(new);
else
dentry = new;
}
out_unlock:
mutex_unlock(&dir->i_mutex);
if (IS_ERR(dentry))
goto fail;
goto done;
}
|
阅读(1455) | 评论(0) | 转发(0) |