一、理解进程与vfs对象之间的关系很重要
VFS inode中没有与路径相关的信息,也没有文件名。文件名记录在它所属的目录项中。
Linux为每一个目录建立一个目录项结构,而且也为每个文件建立一个目录项结构。
目录项结构中包含很多信息:可以建立目录、子目录、文件之间的关系,利用目录项关系,加快文件的查找。
Dentry中不包含“脏”域。VFS在遍历路径名的过程中现场将它们逐个地解析成目录项对象。为了加快文件的查找,每一个曾被读取的目录或文件都可能在目录高速缓存(directory cache)中。
二、目录项dendry重要成员及操作函数
struct dentry {struct qstr d_name; //目录项名(可快速查找)
struct inode *d_inode;与文件名关联的索引节点
unsigned char d_iname[DNAME_INLINE_LEN]; //存放短文件名
const struct dentry_operations *d_op; // 目录项操作方法
struct super_block *d_sb;/* 目录项树的根(即文件的超级块)*/
void *d_fsdata;/*具体文件系统的数据 */
struct dentry *d_parent;/* 父目录的目录项 */
struct list_head d_child;/*父目录的子目录项所形成的链表 */
struct list_head d_subdirs;/* 该目录项的子目录所形成的链表 */
函数得到当前文件或目录的inode值后,进入dcache查找对应的dentry,然后顺着父目录指针d_parent得到父目录的dentry,这样逐级向上直到找到。
};
int (*d_revalidate)(struct dentry *, struct nameidata *);
int (*d_hash)(const struct dentry *, const struct inode *,struct qstr *);
int (*d_compare)(const struct dentry *, const struct inode *,
unsigned int, const char *, const struct qstr *);
int (*d_delete)(const struct dentry *); //删除目录项对象(d_count 变为0时)
void (*d_release)(struct dentry *); // 释放一个目录项对象
void (*d_prune)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
int (*d_manage)(struct dentry *, bool);
} ____cacheline_aligned;
三、目录项对象申请
下面以sdcardfs的根目录项创建说明目录项申请过程:
static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb)
{
struct dentry *ret = NULL;
if (sb) {
static const struct qstr name = {
.name = "/",
.len = 1
};
ret = __d_alloc(sb, &name); //申请dentry,并作初始化
if (ret)
d_set_d_op(ret, &sdcardfs_dops); //设置dentry操作函数
}
return ret;
}
dcache.c 文件中__d_alloc()的实现如下:
/**
* __d_alloc -allocate a dcache entry
* @sb: filesystem it will belong to
* @name: qstr of the name
*
* Allocates a dentry. It returns %NULL if there is insufficient memory
* available. On a success the dentry is returned. The name passed in is
* copied and the copy passed in may be reused after this call.
*/
struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
{
struct dentry *dentry;
char *dname;
dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); //申请高速缓存
if (!dentry)
return NULL;
if (name->len > DNAME_INLINE_LEN-1) {
dname = kmalloc(name->len + 1, GFP_KERNEL);
if (!dname) {
kmem_cache_free(dentry_cache, dentry);
return NULL;
}
} else {
dname = dentry->d_iname;
}
dentry->d_name.name = dname;
// 初始化denry成员
dentry->d_name.len = name->len;
dentry->d_name.hash = name->hash;
memcpy(dname, name->name, name->len);
dname[name->len] = 0;
dentry->d_count = 1;
dentry->d_flags = 0;
spin_lock_init(&dentry->d_lock);
seqcount_init(&dentry->d_seq);
dentry->d_inode = NULL;
dentry->d_parent = dentry;
dentry->d_sb = sb;
dentry->d_op = NULL;
dentry->d_fsdata = NULL;
INIT_HLIST_BL_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
INIT_LIST_HEAD(&dentry->d_alias);
INIT_LIST_HEAD(&dentry->d_u.d_child);
d_set_d_op(dentry, dentry->d_sb->s_d_op); //利用根目录项操作方法初始化d_op
return dentry;
}
四、目录项对象实例化inode
。。。。。。
struct inode *d_inode; // 与文件名关联的索引节点
。。。。。
int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb,
struct path *lower_path)
{
int err = 0;
struct inode *inode;
struct inode *lower_inode;
struct super_block *lower_sb;
lower_inode = lower_path->dentry->d_inode;
lower_sb = sdcardfs_lower_super(sb);
/* check that the lower file system didn't cross a mount point */
if (lower_inode->i_sb != lower_sb) {
err = -EXDEV;
goto out;
}
/*
* We allocate our new inode below by calling sdcardfs_iget,
* which will initialize some of the new inode's fields
*/
/* inherit lower inode number for sdcardfs's inode */
inode = sdcardfs_iget(sb, lower_inode); //申请inode
d_add(dentry, inode); // 调用__d_instantiate, 对dentry 中的inode成员实例化,即dentry与inode关联
out:
return err;
}
{
spin_lock(&dentry->d_lock);
if (inode) {
if (unlikely(IS_AUTOMOUNT(inode)))
dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
list_add(&dentry->d_alias, &inode->i_dentry);
}
dentry->d_inode = inode;
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
fsnotify_d_instantiate(dentry, inode);
}