在文件系统中,有三大缓冲为了提升效率:inode缓冲区、dentry缓冲区、块缓冲。
(内核:2.4.37)
为什么这个缓冲区会存在,不好意思,我说了废话,当然和前面一样的,为了提升效率,例如我们写一个.c的helloworld文件,简单的过程是编辑,编译,执行。。。那么这个过程都是需要找到所在的文件位置的,如果每次都从根开始找并且还有构造相应的目录项对象,是很费时的,所以将目录项一般也都是缓存起来的~~~
Ps:dentry结构
67 struct dentry { 68 atomic_t d_count; 69 unsigned int d_flags; 70 struct inode * d_inode; /* Where the name belongs to - NULL is negative */ 71 struct dentry * d_parent; /* parent directory */ 72 struct list_head d_hash; /* lookup hash list */ 73 struct list_head d_lru; /* d_count = 0 LRU list */ 74 struct list_head d_child; /* child of parent list */ 75 struct list_head d_subdirs; /* our children */ 76 struct list_head d_alias; /* inode alias list */ 77 int d_mounted; 78 struct qstr d_name; 79 unsigned long d_time; /* used by d_revalidate */ 80 struct dentry_operations *d_op; 81 struct super_block * d_sb; /* The root of the dentry tree */ 82 unsigned long d_vfs_flags; 83 void * d_fsdata; /* fs-specific data */ 84 unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */ 85 };
和前面的一样,这个也涉及到几个相应的链表来管理,那么看看/fs/dcache.c中哪些链表被定义了。
52 static struct list_head *dentry_hashtable; 53 static LIST_HEAD(dentry_unused);
“未使用”链表:所有未使用 目录项对象都存放在一个LRU的双向链表。LRU链表的首元素和尾元素的地址存放在变量dentry_unused中的next 域和prev域中。目录项对象的d_lru域包含的指针指向该链表中相邻目录的对象。
简单的看一下dcache初始化过程:
1181 static void __init dcache_init(unsigned long mempages) 1182 { 1183 struct list_head *d; 1184 unsigned long order; 1185 unsigned int nr_hash; 1186 int i; 1187 1188 /* 1189 * A constructor could be added for stable state like the lists, 1190 * but it is probably not worth it because of the cache nature 1191 * of the dcache. 1192 * If fragmentation is too bad then the SLAB_HWCACHE_ALIGN 1193 * flag could be removed here, to hint to the allocator that 1194 * it should not try to get multiple page regions. 1195 */ 1196 dentry_cache = kmem_cache_create("dentry_cache", 1197 sizeof(struct dentry), 1198 0, 1199 SLAB_HWCACHE_ALIGN, 1200 NULL, NULL); 1201 if (!dentry_cache) 1202 panic("Cannot create dentry cache"); 1203 1204 #if PAGE_SHIFT < 13 1205 mempages >>= (13 - PAGE_SHIFT); 1206 #endif 1207 mempages *= sizeof(struct list_head); 1208 for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++) 1209 ; 1210 1211 do { 1212 unsigned long tmp; 1213 1214 nr_hash = (1UL << order) * PAGE_SIZE / 1215 sizeof(struct list_head); 1216 d_hash_mask = (nr_hash - 1); 1217 1218 tmp = nr_hash; 1219 d_hash_shift = 0; 1220 while ((tmp >>= 1UL) != 0UL) 1221 d_hash_shift++; 1222 1223 dentry_hashtable = (struct list_head *) 1224 __get_free_pages(GFP_ATOMIC, order); 1225 } while (dentry_hashtable == NULL && --order >= 0); 1226 1227 printk(KERN_INFO "Dentry cache hash table entries: %d (order: %ld, %ld bytes)\n", 1228 nr_hash, order, (PAGE_SIZE << order)); 1229 1230 if (!dentry_hashtable) 1231 panic("Failed to allocate dcache hash table\n"); 1232 1233 d = dentry_hashtable; 1234 i = nr_hash; 1235 do { 1236 INIT_LIST_HEAD(d); 1237 d++; 1238 i--; 1239 } while (i); 1240 }
下面看一下怎么分配一个目录项对象,涉及函数d_alloc:
580 /** 581 * d_alloc - allocate a dcache entry 582 * @parent: parent of entry to allocate 583 * @name: qstr of the name 584 * 585 * Allocates a dentry. It returns %NULL if there is insufficient memory 586 * available. On a success the dentry is returned. The name passed in is 587 * copied and the copy passed in may be reused after this call. 588 */ 589 590 struct dentry * d_alloc(struct dentry * parent, const struct qstr *name) 591 { 592 char * str; 593 struct dentry *dentry; 594 595 dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); /* 分配一个dentry空间 */ 596 if (!dentry) 597 return NULL; 598 599 if (name->len > DNAME_INLINE_LEN-1) { 600 str = kmalloc(NAME_ALLOC_LEN(name->len), GFP_KERNEL); 601 if (!str) { 602 kmem_cache_free(dentry_cache, dentry); 603 return NULL; 604 } 605 } else 606 str = dentry->d_iname; 607 /* 复制name */ 608 memcpy(str, name->name, name->len); 609 str[name->len] = 0; 610 /* 下面根据dentr的字段进行赋值,具体的字段意义见:http://blog.csdn.net/shanshanpt/article/details/38943731 */ 611 atomic_set(&dentry->d_count, 1); 612 dentry->d_vfs_flags = 0; 613 dentry->d_flags = 0; 614 dentry->d_inode = NULL; 615 dentry->d_parent = NULL; 616 dentry->d_sb = NULL; 617 dentry->d_name.name = str; 618 dentry->d_name.len = name->len; 619 dentry->d_name.hash = name->hash; 620 dentry->d_op = NULL; 621 dentry->d_fsdata = NULL; 622 dentry->d_mounted = 0; 623 INIT_LIST_HEAD(&dentry->d_hash); 624 INIT_LIST_HEAD(&dentry->d_lru); 625 INIT_LIST_HEAD(&dentry->d_subdirs); 626 INIT_LIST_HEAD(&dentry->d_alias); 627 if (parent) { 628 dentry->d_parent = dget(parent); 629 dentry->d_sb = parent->d_sb; 630 } else 631 INIT_LIST_HEAD(&dentry->d_child); 632 633 spin_lock(&dcache_lock); 634 if (parent) 635 list_add(&dentry->d_child, &parent->d_subdirs); 636 dentry_stat.nr_dentry++; 637 spin_unlock(&dcache_lock); 638 639 return dentry; 640 } 641
698 /** 699 * d_lookup - search for a dentry 700 * @parent: parent dentry 701 * @name: qstr of name we wish to find 702 * 703 * Searches the children of the parent dentry for the name in question. If 704 * the dentry is found its reference count is incremented and the dentry 705 * is returned. The caller must use d_put to free the entry when it has 706 * finished using it. %NULL is returned on failure. 707 */ 708 709 struct dentry * d_lookup(struct dentry * parent, struct qstr * name) 710 { 711 unsigned int len = name->len; 712 unsigned int hash = name->hash; 713 const unsigned char *str = name->name; 714 struct list_head *head = d_hash(parent,hash); /* 通过hash值计算得到目录项缓冲区位置的head */ 715 struct list_head *tmp; 716 717 spin_lock(&dcache_lock); 718 tmp = head->next; 719 for (;;) { /* 下面循环找到对应的dentry */ 720 struct dentry * dentry = list_entry(tmp, struct dentry, d_hash); 721 if (tmp == head) 722 break; 723 tmp = tmp->next; 724 if (dentry->d_name.hash != hash) 725 continue; 726 if (dentry->d_parent != parent) 727 continue; 728 if (parent->d_op && parent->d_op->d_compare) { 729 if (parent->d_op->d_compare(parent, &dentry->d_name, name)) 730 continue; 731 } else { 732 if (dentry->d_name.len != len) 733 continue; 734 if (memcmp(dentry->d_name.name, str, len)) 735 continue; 736 } 737 __dget_locked(dentry); 738 dentry->d_vfs_flags |= DCACHE_REFERENCED; /* 找到,那么添加引用就OK */ 739 spin_unlock(&dcache_lock); 740 return dentry; /* 返回找到的dentry。里面有我们需要的信息例如inode */ 741 } 742 spin_unlock(&dcache_lock); 743 return NULL; 744 }