linux VFS 之五:目录项dentry

一、理解进程与vfs对象之间的关系很重要



在存储介质中,每个文件对应唯一的inode结点,但是,每个文件又可以有多个文件名(ln建创链接)。即可以通过不同的文件名访问同一个文件。这里多个文件名对应一个文件的关系在数据结构中表示就是dentry和inode的关系。

VFS inode中没有与路径相关的信息,也没有文件名。文件名记录在它所属的目录项中。
一个目录是一个特殊的文件,其内容是该目录所包含的文件名和子目录名。
由于一个文件可以出现在多个目录中,因而一个文件可以有多个文件名、路径名,仅用VFS inode建立关系不现实,
因此,linux需要引入dentry结构描述目录与文件的关系树。
 Linux为每一个目录建立一个目录项结构,而且也为每个文件建立一个目录项结构。
目录项结构中包含很多信息:可以建立目录、子目录、文件之间的关系,利用目录项关系,加快文件的查找。
因此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值得到目录名?
函数得到当前文件或目录的inode值后,进入dcache查找对应的dentry,然后顺着父目录指针d_parent得到父目录的dentry,这样逐级向上直到找到。

};

struct dentry_operations {
int (*d_revalidate)(struct dentry *, struct nameidata *);
//把目录项对项转换为一个文件路径名之前,检查dentry cache中的dentry是否有效。缺省vfs该函数什么也不做。
int (*d_hash)(const struct dentry *, const struct inode *,struct qstr *);
//计算文件名的hash值,用于目录项散列表。第一个参数是父目录,第二个参数包含了预设的文件名。
int (*d_compare)(const struct dentry *, const struct inode *,
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

下面举例sdcardfs vnode interposition操作函数: sdcardfs_interpose
说明dentry中的inode是如何实例化的:即dentry与inode是如何关联起来的。
struct dentry {

。。。。。。
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;
}

下面看实例化dentry中的inode成员
static void __d_instantiate(struct dentry *dentry, struct inode *inode)
{
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);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值