在做一个在内核态下分布式的文件系统,想知道在内核中,没有后备存储介质写入的时候,目录项dentry是如何管理的,所以,一直想知道怎么就可以得到子文件的目录项,并把名字打印出来看看。
第一次,沿着open函数不断深入,发现和lookup_one_len一样,创造dentry的过程中,查找是否有同名的dentry的时候都是调用的是d_lookup。但是,尝试了好久,由于采用的是hash策略,然而那个d_hash函数无法外部调用,其中的参数也需要内部定义并初始化,无奈,最后放弃,linux 为了效率做得很好,但是很难理解并采用。
第二次,关于dentry的介绍中,linux 2.32.21内核介绍是这样子的:
struct dentry {
atomic_t d_count;
unsigned int d_flags; /* protected by d_lock */
spinlock_t d_lock; /* per dentry lock */
int d_mounted;
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
/*
* The next three fields are touched by __d_lookup. Place them here
* so they all fit in a cache line.
*/
struct hlist_node d_hash; /* lookup hash list */
struct dentry *d_parent; /* parent directory */
struct qstr d_name;
struct list_head d_lru; /* LRU list */
/*
* d_child and d_rcu can share memory
*/
union {
struct list_head d_child; /* child of parent list */
struct rcu_head d_rcu;
} d_u; //在这个地方谁都会认为这就是子文件目录项的起始地址吧,根据双向循环链表的读取规则可以得到子文件目录项的指针
struct list_head d_subdirs; /* our children */
struct list_head d_alias; /* inode alias list */unsigned long d_time; /* used by d_revalidate */const struct dentry_operations *d_op;struct super_block *d_sb; /* The root of the dentry tree */void *d_fsdata; /* fs-specific data */unsigned char d_iname[DNAME_INLINE_LEN_MIN];
/* small names */};
就是在这个地方,并不是这么回事,尝试无数次无果之后,我决定研究源码:
创建一个新的dentry,在函数d_alloc中:
struct dentry *d_alloc(struct dentry * parent, 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;
dentry->d_name.len = name->len;
dentry->d_name.hash = name->hash;
memcpy(dname, name->name, name->len);
dname[name->len] = 0;
atomic_set(&dentry->d_count, 1);
dentry->d_flags = DCACHE_UNHASHED;
spin_lock_init(&dentry->d_lock);
dentry->d_inode = NULL;
dentry->d_parent = NULL;
dentry->d_sb = NULL;
dentry->d_op = NULL;
dentry->d_fsdata = NULL;
dentry->d_mounted = 0;
INIT_HLIST_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
INIT_LIST_HEAD(&dentry->d_alias);
if (parent) {
dentry->d_parent = dget(parent);
dentry->d_sb = parent->d_sb;
} else {
INIT_LIST_HEAD(&dentry->d_u.d_child);
}
spin_lock(&dcache_lock);
if (parent)
list_add(&dentry->d_u.d_child, &parent->d_subdirs); //在这个地方的时候被惊艳到了,合计插入的并不是d_subdirs啊
dentry_stat.nr_dentry++;
spin_unlock(&dcache_lock);
return dentry;
}
深入理解linux内核这部经典著作是这么写的:
d_subdirs :对目录而言,子目录项链表的头
d_child: 对目录而言,用于同一父目录中的目录项链表的指针
现在想想,说的很对,然而书上就这么写的,一点额外注释都木有,可是光看书,这怎么可能理解到原来是这么回事,只能说内核真是博大精深,光看书是肯定不够的了
得到一个目录项dentry之后,获取到目录中子目录项的代码就要变化一下子了:
printk("a dentry name : %s\n",a_dentry->d_name.name);
struct dentry *a_parent_dentry = a_dentry->d_parent;
printk(KERN_EMERG"根目录名称 %s\n",a_parent_dentry->d_name.name);
struct list_head *plist;
struct dentry *sub_dentry;
list_for_each(plist, &(a_parent_dentry->d_subdirs))
{
sub_dentry = list_entry(plist, struct dentry, d_u.d_child);
if(sub_dentry)
{
printk(KERN_EMERG"subdirs_dentry %s\n",sub_dentry->d_name.name);
printk(KERN_EMERG"sub_dentry %ld\n",sub_dentry);
}
}
然后就得到了正常的,本该出现的信息。