Refer to <

内核源代码情景分析

>> and <>

Having any problems, send mails to viloner@163.com

目录项缓存与散列表

所谓缓存,是指把存在于磁盘中的操作系统运行时频繁使用到的信息读取到内存中去,以提高

CPU

读取这些信息的速度。所以目录项的缓存就是指把存在于磁盘上的目录项信息读取到内存中去,而这些目录信息就是一个个的

dentry

结构。当某个进程运行时用到某个目录项,但在内存中却没有相应的

dentry

结构,就需要在内存中建立

(

所谓的建立实际是从磁盘上把相应的

dentry

结构读取到内存中去

)

一个与该目录项对应的

dentry

结构。由于在操作系统运行的过程中,用到的目录项很多,因此读入到内存中的

dentry

结构就非常多,故有必要对已读入到内存中的所有

dentry

结构进行管理,内核中的

dentry_hashtable

便是用于此目的的。

首先分析一下

dentry

的结构,便可知内核是如何在内存中管理

dentry

结构的。

Dentry

结构中有

6

list_head,

d_vfsmnt

d_hash

d_lru

d_child

d_subdirs

、和

d_alias

。注意,

list_head

既可以用来作为一个队列的头部,也可以用来将其所在的数据结构挂入到某个队列中。其中

d_vfsmnt

仅在该

dentry

结构为一个安装点时才使用。一个

dentry

结构一经建立就通过其

d_hash

挂入杂凑表

dentry_hashtable

中的某个队列里,当共享计数变为

0

时则通过

d_lru

挂入队列

dentyr_unused

中。同时,

dentry

结构通过

d_child

挂入到其父节点

(

上一层目录

)

d_subdirs

队列中,同时又通过指针

d_parent

指向父目录的

dentry

结构。而它自己各个子目录的

dentry

结构则在它本身的

d_subdirs

队列中。一个有效的

dentry

结构必定有一个相应的

inode

结构,这是因为一个目录项要么代表一个文件,要么就代表着一个目录,而目录实际上也是文件。所以,只要是有效的

dentry

结构,则其指针

d_inode

必定指向一个

inode

结构。可是,反过来一个

inode

却可能对应着不止一个

dentry

结构,也就是说,一个文件可以有不止一个文件名

(

或路径名

)

。这是因为一个已经建立的文件可以被连接

(link)

到其他文件名。所以,在

inode

结构中有个队列

i_dentry

,凡是代表着这个文件的所有目录项都通过其

dentry

结构中的

d_alias

挂入相应

inode

结构中的

i_dentry

队列。此外,

dentry

结构中还有指针

d_sb,

指向其所在设备的超级块

super_block

数据结构,以及指针

d_op,

指向特定文件系统

(

指文件格式

)

dentry_operations

结构。也许可以说,

dentry

结构是文件系统的核心数据结构,也是文件访问和为文件访问而做的文件路径搜索操作枢纽。

下面是一个简要的总结:

1、

每个

dentry

结构都通过队列头

d_hash

链入杂凑表

dentry_hashtable

中的某个队列里。

2、

共享计数为

0

dentry

结构都通过队列头

d_lru

链入

LRU

队列

dentry_unused

,在队列中等待释放或者“东山再起”。

3、

每个

dentry

结构都通过指针

d_inode

指向一个

inode

数据结构。但是多个

dentry

结构可以指向同一个

inode

数据结构。

4、

指向同一个

inode

数据结构的

dentry

结构都通过队列头

d_alias

链接在一起,都在该

inode

结构的

i_dentry

队列中。

5、

每个

dentry

结构都通过指针

d_parent

指向其父目录节点的

dentry

结构,并通过队列头

d_child

跟同一目录中的其他节点的

dentry

结构链接在一起,都在父目录节点的

d_subdirs

队列中。

6、

每个

dentry

结构都通过指针

d_sb

指向一个

super_block

数据结构。

7、

每个

dentry

结构都通过指针

d_op

指向一个

dentry_operations

数据结构。

8、

每个

dentry

结构都有个队列头

d_vfsmnt,

用于文件系统的安装,详见“文件系统的安装与拆卸”。

在分析完

dentry

数据结构以后,现在来看一下

dentry_hashtable

杂凑表的

散列算法。

dentry_hashtable

是由

list_head

组成的数组

,

它们与

dentry->d_hash

相环接

,

形成短链

,

散列表中的

dentry

将均分布于这些短链上

;

散列表的索引确定于父目录项地址和目录名的

hash

; dentry_hashtable

的尺寸由系统内存大小分配

,

4M

内存分配一个页面

,

每个页面具有

512

项索引

;

哈希链表

dentry_hashtable

定义在

dcache.c

文件中,如下:

static struct list_head *dentry_hashtable;

d_hash(dentry,hash)

为散列函数

,

它将

dentry

地址和

hash

值相组合

,

映射到

dentry_hashtable

表中

,

返回相应的散列链

;

d_rehash(dentry)

dentry

加入散列表

;

d_drop(dentry)

dentry

从散列表中删除

;

d_lookup(dentry,qstr)

在散列中找出以

dentry

作为父目录项

,

名称为

qstr

的目录项

.

下面分别介绍一下这几个函数:

一、

d_hash(dentry,hash)

每一个

dentry

对象都通过其父目录

dentry

对象的指针和其文件名的哈希值

hash

来唯一地确定它所属的哈希链表的表头指针,这是通过

d_hash

函数来完成的:

static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash)

{

hash += (unsigned long) parent / L1_CACHE_BYTES;

hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);

return dentry_hashtable + (hash & D_HASHMASK);

}

每个目录项文件名的哈希值是通过

full_name_hash()

函数(定义在

include/linux/dcache.h

文件中)来计算的,如下所示:

/* Compute the hash for a name string. */

static __inline__ unsigned int full_name_hash(const unsigned char * name, unsigned int len)

{

unsigned long hash = init_name_hash();

while (len--)

hash = partial_name_hash(*name++, hash);

return end_name_hash(hash);

}

可以看出,该函数又向下调用

partial_name_hash()

函数和

end_name_hash

()函数来完成哈希值的计算工作。

二、

d_rehash(dentry)

向哈希链表中增加一个

dentry

对象

函数

d_rehash()

实现这一功能,它首先通过

d_hash()

函数找到这个

dentry

对象应该挂到哪一个哈希链表中,然后设置

d_hash

指针。如下所示(

dcache.c

):

void d_rehash(struct dentry * entry)

{

struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash);

spin_lock(&dcache_lock);

list_add(&entry->d_hash, list);

spin_unlock(&dcache_lock);

}

三、

d_drop(dentry)

从哈希链表中摘除一个

dentry

对象

函数

d_drop

()实现这一点,如下所示(

dcache.h

):

static __inline__ void d_drop(struct dentry * dentry)

{

spin_lock(&dcache_lock);

list_del(&dentry->d_hash);

INIT_LIST_HEAD(&dentry->d_hash);

spin_unlock(&dcache_lock);

}

头文件

dcache.h

中还定义了一个函数

d_unhashed()

,用来测试一个

dentry

对象是否没有链接在哈希链表中,如下:

static __inline__ int d_unhashed(struct dentry *dentry)

{

return list_empty(&dentry->d_hash);

}

四、

d_lookup(dentry,qstr)

在散列中找出以

dentry

作为父目录项

,

名称为

qstr

的目录项

struct dentry * d_lookup(struct dentry * parent, struct qstr * name)

{

unsigned int len = name->len;

unsigned int hash = name->hash;

const unsigned char *str = name->name;

struct list_head *head = d_hash(parent,hash);

struct list_head *tmp;

spin_lock(

tmp = head->next;

for (;;) {

struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);

if (tmp == head)

break;

tmp = tmp->next;

if (dentry->d_name.hash != hash)

continue;

if (dentry->d_parent != parent)

continue;

if (parent->d_op  parent->d_op->d_compare) {

; 如果文件系统提供了目录名比较的方法

if (parent->d_op->d_compare(parent,  name))

continue;

} else {

if (dentry->d_name.len != len)

continue;

if (memcmp(dentry->d_name.name, str, len))

continue;

}

__dget_locked(dentry); 增加dentry的引用计数

dentry->d_flags |= DCACHE_REFERENCED;

spin_unlock(

return dentry;

}

spin_unlock(

return NULL;

)

java 解压ygb文件_文件系统-目录项缓存与散列表相关推荐

  1. Java解压Jar文件

    今天写点java解压jar文件的东西,以前项目中用到过,很简单... java中有专门的文件类型对应jar文件,那就是JarFile,用于从任何可以使用java.io.RandomAccessFile ...

  2. java 解压tgz文件

    java 解压tgz文件 pom 引入依赖 <dependency><groupId>org.apache.commons</groupId><artifac ...

  3. tar解压单个文件到特定目录_技术|如何解压 tar 文件到不同的目录中

    我想要解压一个tar文件到一个叫/tmp/data的指定目录.我该如何在Linux或者类Unix的系统中使用tar命令解压一个tar文件到不同的目录中? 你不必使用cd命令切换到其他的目录并解压.可以 ...

  4. Java解压zip文件(文本)压缩包

    2019独角兽企业重金招聘Python工程师标准>>> 说明:由于我们的日志收集到指定服务器上,会按天压缩成一个zip格式的压缩包,但是有时候需要对这些日志进行处理,人工解压在处理, ...

  5. java解压zip文件

    package com.chuangqi.tools;import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipFile ...

  6. java解压gz文件

    http://panshaobinsb.iteye.com/blog/1566231 下面是网上的代码 http://www.iteye.com/topic/894879 Java代码   impor ...

  7. 用Java解压lz文件

    可以使用 Apache Commons Compress 库来解压 lz 文件. 首先,需要在项目中导入这个库,可以使用 Maven 或者 Gradle 进行依赖管理. 然后,可以使用以下代码来解压 ...

  8. mac 命令行 解压7z文件_如何在Mac上快速压缩和解压文件?Mac上解压和压缩文件的方法...

    苹果mac电脑怎么压缩和解压文件?Mac电脑仅默认支持把文件压缩成zip格式,解压成zip.tar.gz,bz2等格式,有些操作需要安装第三方软件来完成,这篇文章为大家带来几种关于在Mac上解压和压缩 ...

  9. java解压zip文件,处理文件名不能为中文

    1.最近工作需要把压缩文件解压,经过测试有两种方法,一种是JDK自带的ZipFile,       另外一种是org.apache.tools.zip进行解压. 2.经测试,JDK自带的文件不能处理文 ...

  10. 你知道为什么手机qq解压压缩包文件会出现0项吗??

    常见的压缩包格式有两种:zip和rar,而我们手机qq上自带的解压软件目前只支持zip,而rar是有专利的,不会集成在任何系统上,这就需要我们去下载第三方软件来解压. 注: (但是有时候我们会发现qq ...

最新文章

  1. SQL 查询总是先执行SELECT语句吗?你们都错了!
  2. 杭电oj2035c语言答案,杭电oj 2035
  3. php 百度逆地理编码,百度逆地址解析
  4. 通过MATLAB将数据转化为mif文件,供Quartusii软件的ROM核读取调用
  5. TalkingData大规模机器学习的应用
  6. 前端基础21:正则基础
  7. boost::variant2模块实现默认构造相关的测试程序
  8. 如何处理错误消息Unable to install breakpoint due to missing line number attributes
  9. 深度思考的能力,决定了你能走多远
  10. 微服务跨数据库联合查询_数据库跨库查询
  11. idea2017+kemulator搭建J2ME开发环境
  12. Web前端:木兰花令网页案例设计
  13. vue3中导出excel表格
  14. Flink 的状态保存和恢复
  15. 附近的人实现(Redis 3.2 以上版本和es 性能比较)
  16. 微博html5版登录,新浪微博模拟登录 支持手动处理验证码
  17. Fitbit协助执法部门破获一起犯罪案件
  18. opencv接口那些不为人知的事!
  19. 求数组中最长递增子序列
  20. uni-app学习(一)

热门文章

  1. 【路径规划】基于matlab HybridA_Star算法机器人路径规划【含Matlab源码 1390期】
  2. 【数字信号】基于matlab GUI简易电子琴(英文版)【含Matlab源码 873期】
  3. 【数学建模】基于matlab计划生育政策调整对人口数量、结构及其影响的研究【含Matlab源码 749期】
  4. 【图像融合】基于matlab PCA图像融合【含Matlab源码 723期】
  5. 【优化算法】多目标粒子群优化算法(MOPSO)【含Matlab源码 033期】
  6. 【图像增强】基于matlab区域相似变换函数和蜻蜓算法灰度图像增强【含Matlab源码 089期】
  7. b站 前端构架_技术干货:哔哩哔哩(B站)功能框架图
  8. 数据库的根据当前id查询所有父级菜单
  9. 例2.3 日期差值 - 九度教程第6题(日期类问题)
  10. data标签怎么爬虫_scrapy爬虫笔记(1):scrapy基本使用