推广 热搜: 天涯  求购acf  收购ACF  回收acf  耐磨缓冲床  架桥机出租  气动卧闸  幅度  战地  迫击炮 

dcache 、dcache flush

   日期:2023-04-10     浏览:46    评论:0    
核心提示:arm为什么要关闭icache和dcache从两个方面来回答: 一个cache的行为,Icache大多都是顺序取指,碰到分支指令也会跳转, 而Dcache访问的模式变化比较大.也就是前者所说的patt

arm为什么要关闭icache和dcache

从两个方面来回答: 一个cache的行为,Icache大多都是顺序取指,碰到分支指令也会跳转, 而Dcache访问的模式变化比较大.也就是前者所说的pattern的问题. 指令只有读和refill没有写,而数据有读也有写. 最重要的是冯氏的结构是指令和数据分离.I和D在一。

dcache文件夹是什么?

dentry_cache简称dcache,中文名称是目录项高速缓存,是Linux为了提高目录项对象的处理效率而设计的。

这个没关系

虚拟文件是什么啊?

虚拟文件系统

虚拟文件系统

作 者: difeijing

Richard Gooch

23-APR-1999

翻译:difeijing

本文档中的惯例用法

==================

文档中的每一节标题的右边都有一个字符串""。

每个小节都会有个""在右边。

这些字符串是为了在文档中查询更容易而设的。

注意:本文档的最新更新可在下面找到:

它到底是什么?

=============

Virtual File System(或者被称为Virtual Filesystem Switch)是Linux内核中的一个软件层,用于给用户空间的程序提供文件系统接口。它也提供了内核中的一个抽象功能,允许不同的文件系统共存。

它的工作方式的概览

==================

在这一节里,在讲解细节问题之前,我会简单扼要的介绍一下VFS是如何工作的。首先,介绍一下当用户程序打开或者操作文件时发生了些什么,然后看看一个文件系统是如何被支持的。

打开一个文件

------------

VFS实现了open(2)系统调用。路径参数被VFS用来在目录入口缓存(dentry cache or "dcache")。这提供了一个将路径名转化为特定的dentry的一个快的查找机制。

一个单独的dentry通常包含一个指向i节点(inode)的指针。i节点存在于磁盘驱动器上,它可以是一个规则文件,目录,FIFO文件,等等。 Dentry存在于RAM中,并且永远不会被存到磁盘上:它们仅仅为了提高系统性能而存在。i节点存在于磁盘上,当需要时被拷入内存中,之后对它的任何改变将被写回磁盘。存在于RAM中的i节点就是VFS的i节点,dentry所包含的指针指向的就是它。

dcache是你的整个文件空间的观察点。跟Linus不同,我们中的大多数人不可能有足够的RAM空间来放我们的文件空间的所有文件的目录入口缓存 (dentry),所以我们的dcache会有缺少的项。为了将路径名转换为一个dentry,VFS不得不采取创建dentry的方式,并在创建 dentry时将指针指向相应的i节点。这是通过对i节点的查找完成的。

为了查找一个文件的i节点(通常从磁盘上读),VFS需要调用该文件的父目录的lookup()方法,此方法是特定的文件系统所设置的。后面对此将会有更详尽的描述。

一旦VFS得到了所需要的dentry(同时也得到了相应的i节点),我们就能够对文件做想要的操作:打开文件,或者用stat(2)来看i节点中的数据。stat(2)的操作非常简单:在VFS得到dentry之后,它取得inode中的一些数据并将其中的一部分送回用户空间。打开一个文件需要其它的操作:分配一个struct file(定义于linux/fs.h,这是内核中的文件描述)结构。新分配的struct file结构被指向dentry的指针和对文件进行操作的函数集合所初始化,这些都是从i节点中得到的。通过这种方式,特定的文件系统实现才能起作用。

文件结构(struct file)被放在进程的文件描述符表中。

读,写和关闭文件(或者其它的VFS操作)是通过使用用户空间的文件描述符找到相应的文件结构(struct file),然后调用所需要的方法函数来实现的。

当文件处于打开状态时,系统保持相应的dentry为"open"状态(正在使用),这表示相应的i节点在被使用。

注册和安装一个文件系统

----------------------

如果你想在内核中支持一种新的文件系统的话,你所需要做的仅仅是调用函数register_filesystem().你向内核中传递一个描述文件系统实现的结构(struct filesystem), 此结构将被加入到内核的支持文件系统表中去。你可以运行下面的命令:

% cat /proc/filesystems

这样可以看到你的系统支持哪些文件系统。

当一个mount请求出现时,VFS将会为特定的文件系统调用相应的方法。安装点的dentry结构将会被改为指向新文件系统的根i节点。

现在是看看细节的时候了,nice to look!

struct file_system_type

=======================

此结构描述了文件系统。在内核2.1.99中,此结构的定义如下:

(注:在2.2的内核中,此结构也没有变化)

struct file_system_type {

const char *name;

int fs_flags;

struct super_block *(*read_super) (struct super_block *, void *, int);

struct file_system_type * next;

};

其中各个域的意义:

name:文件系统的类型名称,如"vfat","ext2",等等。

fs_flags:变量标志,如FS_REQUIRES_DEV, FS_NO_DCACHE,等等.

read_super:当此种文件系统的一个新的实例要被安装时,此方法会被调用。

next:被内部的VFS实现所使用,你只需要将其初试化为NULL。

函数read_super具有以下的参数:

struct super_block ****:超级块结构。此结构的一部分被VFS初始化,余下的部分必须被函数read_super初始化。

void * data:任意的安装选项,通常是ASCII的字符串。

int silent:表示当出现错误时是否保持安静。(不报警?)

read_super方法必须确定指定的块设备是否包含了一个所支持的文件系统。当成功时返回超级块结构的指针,错误时返回NULL。

read_super方法填充进超级块结构(struct super_block)的最有用的域是"s_op"域。这是一个指向struct super_operations的指针,此结构描述了文件系统实现的下一层细节。

struct super_operations

=======================

此结构描述了VFS对文件系统的超级块所能进行的操作。

在内核2.1.99中,此结构的定义如下:

(注:在2.2的内核中,此结构已经有了改变)

struct super_operations {

void (*read_inode) (struct inode *);

void (*write_inode) (struct inode *);

void (*put_inode) (struct inode *);

void (*delete_inode) (struct inode *);

int (*notify_change) (struct dentry *, struct iattr *);

void (*put_super) (struct super_block *);

void (*write_super) (struct super_block *);

int (*statfs) (struct super_block *, struct statfs *, int);

int (*remount_fs) (struct super_block *, int *, char *);

void (*clear_inode) (struct inode *);

};

除非特别提出,所有的方法都在未加锁的情况下被调用,这意味着大多数方法都可以安全的被阻塞。所有的方法都仅仅在进程空间被调用(例如,在中断处理程序和底半部中不能调用它们)

read_inode:从一个文件系统中读取一个特定的i节点时调用此方法。i节点中的域"i_ino"被VFS初始化为指向所读的i节点,其余的域被此方法所填充。

write_inode:当VFS需要向磁盘上的一个i节点写时调用。

put_inode:当VFS的i节点被从i节点缓冲池移走时被调用。此方法是可选的。

delete_inode:当VFS想删除一个i节点时调用次方法。

notify_change:当VFS的i节点的属性被改变时调用。若此域为NULL则VFS会调用rite_inode.此方法调用时需要锁住内核。

put_super:当VFS要释放超级块时调用(umount一个文件系统).此方法调用时需要锁住内核。

write_super:当VFS超级块需要被写入磁盘时被调用。此方法为可选的。

statfs:当VFS需要得到文件系统的统计数据时调用。此方法调用时需要锁住内核。

remount_fs:当文件系统被重新安装时调用。此方法调用时需要锁住内核。

clear_inode:当VFS清除i节点时调用。可选项。

以上方法中,read_inode需要填充"i_op"域,此域为一个指向struct inode_operations结构的指针,它描述了能够对一个单独的i节点所能进行的操作。

struct inode_operations

=======================

此结构描述了VFS能够对文件系统的一个i节点所能进行的操作。

在内核2.1.99中,此结构的定义如下:

(注:在2.2的内核中,此结构已经有了少许改变)

struct inode_operations {

struct file_operations * def***lt_file_ops;

int (*create) (struct inode *,struct dentry *,int);

int (*lookup) (struct inode *,struct dentry *);

int (*link) (struct dentry *,struct inode *,struct dentry *);

int (*unlink) (struct inode *,struct dentry *);

int (*symlink) (struct inode *,struct dentry *,const char *);

int (*mkdir) (struct inode *,struct dentry *,int);

int (*rmdir) (struct inode *,struct dentry *);

int (*mknod) (struct inode *,struct dentry *,int,int);

int (*rename) (struct inode *, struct dentry *,

struct inode *, struct dentry *);

int (*readlink) (struct dentry *, char *,int);

struct dentry * (*follow_link) (struct dentry *, struct dentry *);

int (*readpage) (struct file *, struct page *);

int (*writepage) (struct file *, struct page *);

int (*bmap) (struct inode *,int);

void (*truncate) (struct inode *);

int (*permission) (struct inode *, int);

int (****ap) (struct inode *,int);

int (*updatepage) (struct file *, struct page *, const char *,

unsigned long, unsigned int, int);

int (*revalidate) (struct dentry *);

};

def***lt_file_ops:这是一个指向struct file_operations的指针,包含了对一个打开的文件所能进行的操作。

create:被open(2)和creat(2)所调用,仅仅在你要支持普通文件时才需要。参数中的dentry不应该包含有i节点的指针(即应该为一个negative dentry)。这里你可能需要对传入的dentry和i节点调用函数d_instantiate.

lookup:当VFS要在一个父目录中查找一个i节点时调用。待查找的文件名在dentry中。此方法必须调用d_add函数把找到的i节点插入到 dentry中,i节点的"i_count"域要加一。若指定的i节点不存在的话,一个NULL的i节点指针将***入到dentry中去(这种情况的 dentry被称为negative dentry)。Returning an error code from this routine must only be done on a real error, otherwise creating inodes with system calls like create(2), mknod(2), mkdir(2) and so on will fail.If you wish to overload the dentry methods then you should initialise the "d_dop" field in the dentry; this is a pointer to a struct "dentry_operations".This method is called with the directory semaphore held。

link:被link(2)所调用。仅在你需要支持hard link时才需要它。跟create方法相同的原因,你可能在此方法中也需要调用d_instantiate()函数来验证。

unlink:被unlink(2)所调用。仅在你要支持对i节点的删除时才需要它。

symlink:被symlink(2)调用。仅在需要支持符号链接时才需要它。通上面两处,你需要对传入的参数进行验证,要调用d_instantiate()函数。

mkdir:被mkdir(2)调用。仅在你要支持建立子目录时才需要它。同上,你需要调用d_instantiate()函数进行验证。

rmdir:被rmdir(2)所调用。仅在你要支持对子目录的删除时才需要它。

mknod:被mknod(2)所调用,用于建立一个设备i节点,或者FIFO,或socket.仅当你需要支持对这些类型的i节点的建立时才需要此方法。同上面几个,你可能也需要调用_instantiate来验证参数。

readlink:被readlink(2)调用。仅当你要支持对符号链接的读取才需要它。

follow_link:被VFS调用,用以从一个符号链接找到相应的i节点。仅当你需要支持符号链接时才需要此方法。

struct file_operations

======================

结构file_operations包含了VFS对一个已打开文件的操作。

在内核2.1.99中,此结构的定义如下:

(注:在2.2的内核中,此结构已经有了少许改变)

struct file_operations {

loff_t (*llseek) (struct file *, loff_t, int);

ssize_t (*read) (struct file *, char *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char *, size_t, loff_t *);

int (*readdir) (struct file *, void *, filldir_t);

unsigned int (*poll) (struct file *, struct poll_table_struct *);

int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

int (*mmap) (struct file *, struct vm_area_struct *);

int (*open) (struct inode *, struct file *);

int (*release) (struct inode *, struct file *);

int (*fsync) (struct file *, struct dentry *);

int (*fasync) (struct file *, int);

int (*check_media_change) (kdev_t dev);

int (*revalidate) (kdev_t dev);

int (*lock) (struct file *, int, struct file_lock *);

};

llseek:当VFS需要移动文件指针的位置时调用。

read:被read(2)所调用。

write:被write(2)所调用。

readdir:当VFS需要读取目录中的内容时被调用。

poll: called by the VFS when a process wants to check if there is activity on this file and (optionally) go to sleep until there is activity.

(注:这里我怎么想都翻不好,所以就把原文放在这里了,poll就是相当于select的东西)

ioctl:被ioctl(2)所调用。

mmap:被mmap(2)所调用。

open:当VFS要打开一个i节点时调用它。当VFS打开一个文件时,它建立一个新的struct file结构,并用i节点中的"def***lt_file_ops"来初始化其中的f_op域,然后对新分配的文件结构调用open方法。你可以认为 open方法实际上属于struct inode_operations。I think its done the w*** it is bec***se it makes filesystems simpler to implement.open方法是一个很好的初始化文件结构中的"private_data"域的的地方。

release:当没有对被打开文件的引用时调用此方法。

fsync:被fsync(2)所调用。

fasync:当用fcntl(2)激活一个文件的异步模式时此方法被调用。

这些文件操作是由i节点所在的特定文件系统所实现的。当打开一个设备节点时(字符或块设备特殊文件),大多数文件系统会调用VFS中的特定支持例程,由此来找到所需要的设备驱动信息;

这些支持例程用设备驱动程序的方法来代替文件系统的文件操作,然后继续对文件调用新的open方法。这就是为什么当你打开文件系统上的一个设备特殊文件时,最后被调用的却是设备驱动程序的open方法。另外,devfs(Device Filesystem)有一个从设备节点到设备驱动程序的更直接的方式(这是非官方的内核补丁)

struct dentry_operations

========================

This describes how a filesystem can overload the standard dentry

operations.Dentries和dcache是属于VFS和单个文件系统实现的,设备驱动与此无关。

在内核2.1.99中,此结构的定义如下:

(注:在2.2的内核中,此结构没有改变)

struct dentry_operations {

int (*d_revalidate)(struct dentry *);

int (*d_hash) (struct dentry *, struct qstr *);

int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);

void (*d_delete)(struct dentry *);

void (*d_release)(struct dentry *);

void (*d_iput)(struct dentry *, struct inode *);

};

d_revalidate:当VFS要使一个dentry重新生效时被调用。

d_hash:当VFS向哈希表中加入一个dentry时被调用。

d_compare:当指向一个dentry的最后的引用被去除时此方法被调用,因为这意味这没有人在使用此dentry;当然,此dentry仍然有效,并且仍然在dcache中。

d_release: 当一个dentry被清除时调用此方法。

d_iput:当一个dentry释放它的i节点时(在dentry被清除之前)此方法被调用。The def***lt when this is NULL is that the VFS calls iput(). If you define this method, you must call iput() yourself.

每个dentry都有一个指向其父目录dentry的指针,一个子dentry的哈希列表。子dentry基本上就是目录中的文件。

dget:为一个已经存在的dentry打开一个新的句柄(这仅仅增加引用计数)

dput:关闭一个dentry的句柄(减少引用计数).如果引用计数减少为0,d_delete方法将会被调用;并且,如果此dentry仍然在其父目录的哈希列表中的话,此dentry将被放置于一个未被使用的列表中。将dentry放置于未使用表中意味着当系统需要更多的RAM时,将会遍历未使用的 dentry的列表,并回收其内存空间。假如当detry的引用计数为0时,它已经没有在父目录的哈希表中的话,在d_delete方法被调用之后系统就会回收起内存空间。

d_drop: 此方法将一个dentry从其父目录的哈希列表中去掉。如果被去掉的dentry的引用计数降为0的话,系统会马上调用d_put来去掉此dentry.

d_delete:删除一个dentry.如果没有别的对此dentry的打开引用的话,此dentry会变成一个negative dentry(d_iput方法会被调用);如果有别的对此dentry的引用的话,将会调用d_drop.

d_add:向父目录的哈希列表中加入一个dentry,然后调用d_instantiate().

d_instantiate:把一个dentry加入别名哈希列表中,并更新其d_inode域为所给的i节点。i节点中的i_count域加一。假如i 节点的指针为NULL,此dentry就被称为"negative dentry".此函数通常在为一个已存在的negative dentry建立i节点时被调用。

为什么要增加Cache?Cache有什么优点?

减少数据库访问压力,加快速度,多模型应用一般都用分布式缓存,

比如一篇文章在数据库快还是内存快

dentry 和inode整理

dentry

dentry是一个内存实体,其中的d_inode成员指向对应的inode

struct dentry {

atomic_t d_count;

struct inode * d_inode; //指向一个inode结构。这个inode和dentry共同描述了一个普通文件或者目录文件

struct dentry * d_parent; //父目录的目录项对象

struct list_head d_hash; //链接到dentry cache的hash链表。

struct list_head d_lru; //未使用链表的指针

struct list_head d_child;//dentry自身的链表头,需要链接到父dentry的d_subdirs成员

struct list_head d_subdirs;//项(子项可能是目录,也可能是文件)的链表头,所有的子项都要链接到这个链表

int d_mounted;// 指示dentry是否是一个挂载点。如果是挂载点,该成员不为零。

struct qstr d_name;// 成员保存的是文件或者目录的名字。打开一个文件的时候,根据这个成员和用户输入的名字比较来搜寻目标文件

...

};

当移动文件的时候,需要把一个dentry结构从旧的父dentry的链表上脱离,然后链接到新的父dentry的d_subdirs成员。这样dentry结构之间就构成了一颗目录树

每个dentry都有一个指向其父目录的指针(d_parent),一个子dentry的哈希列表(d_child)。其中,子dentry基本上就是目录中的文件

dentry状态:

1.d_count=0,未使用(unused)状态,d_inode指向相关的的索引节点。该目录项仍然包含有效的信息,只是当前没有人引用他。这种dentry对象在回收内存时可能会被释放。

2.d_count0,正在使用(inuse)状态,d_inode指向相关的inode对象。这种dentry对象不能被释放。

3.d_count0,y负(negative)状态,inode对象不复存在可能被删除,dentry对象的d_inode指针为NULL。但这种dentry对象仍然保存在dcache中,以便后续对同一文件名的查找能够快速完成。这种dentry对象在回收内存时将首先被释放。

dentry与dentry_cache

dentry_cache(dcache,目录项高速缓存)由两个数据结构组成:

1、哈希链表dentry_hashtable:dcache中的所有dentry对象都通过d_hash指针域链到相应的dentry哈希链表中。

2、未使用的dentry对象链表dentry_unused:dcache中所有处于unused状态和negative状态的dentry对象都通过其d_lru指针域链入dentry_unused链表中。该链表也称为LRU链表。

dcache中的dentry对象控制着icache中的inode对象的生命期转换。无论何时,只要一个目录项对象存在于dcache中(非 negative状态),则相应的inode就将总是存在,因为 inode的引用计数i_count总是大于0。当dcache中的一个dentry被释放时,针对相应inode对象的iput()方法就会被调用。

inode(索引节点)

文件储存在硬盘上,硬盘的最小存储单位叫做”扇区”(Sector)。每个扇区储存512字节(相当于0.5KB)。操作系统读磁盘时会多个扇区组成一个块(block)一起读取,最常见大小为4kb,8个扇区组成一个块。inode储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等。inode对应于物理磁盘上的具体对象,一个inode可以在运行的时候链接多个dentry,d_count记录了这个链接的数量

struct ext3_inode {

__le16 i_mode;

__le16 i_uid;

__le32 i_size;

__le32 i_atime;

__le32 i_ctime;

__le32 i_mtime;

__le16 i_gid;

__le16 i_links_count;

......

__le32 i_block[EXT2_N_BLOCKS];

......

}

可以用stat命令,查看某个文件的inode信息:

stat example.txt

函数得到当前文件或目录的inode值后,进入dcache查找对应的dentry,然后顺着父目录指针d_parent得到父目录的dentry,这样逐级向上直到dentry= root,就得到全部目录名称。

inode的大小

inode会消耗硬盘空间,所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区,存放文件数据;另一个是inode区(inode table),存放inode所包含的信息。

查看每个硬盘分区的inode总数和已经使用的数量,可以使用df命令。

df -i

sudo dumpe2fs -h /dev/hda | grep “Inode size” //查看每个inode节点的大小

inode号码

每个inode都有一个号码,操作系统用inode号码来识别不同的文件。

移动文件或重命名文件,只是改变文件名,不影响inode号码。

打开一个文件以后,系统就以inode号码来识别这个文件,而系统无法从inode号码得知文件名。

ls -i a.cpp //查看文件名对应的inode号码

硬链接就是多个文件名指向同一个inode号码。可以用不同的文件名访问同样的内容;对文件内容进行修改,会影响到所有文件名;但是,删除一个文件名,不影响另一个文件名的访问。

ln 源文件 目标文件 //创建硬链接

两文件指向同一个inode。d_count加1。删除一个文件名,d_count减1。当这个值减到0,表明没有文件名指向这个inode,系统就会回收这个inode号码,以及其所对应block区域。

创建目录时,默认会生成两个目录项:”.”和”..”。前者的inode号码就是当前目录的inode号码,等同于当前目录的”硬链接”;后者的inode号码就是当前目录的父目录的inode号码,等同于父目录的”硬链接”。所以,任何一个目录的”硬链接”总数,总是等于2加上它的子目录总数(含隐藏目录),这里的2是父目录对其的“硬链接”和当前目录下的”.硬链接“。

软连接就像int a=b,虽然名字不一样,文件A的内容是文件B的路径。读取文件A时,系统会自动将访问者导向文件B。如果删除了文件B,打开文件A就会报错。文件A指向文件B的文件名,而不是文件B的inode号码,文件B的inode”链接数”不会因此发生变化。

ln -s 源文文件或目录 目标文件或目录  //创建软链接

1

文件名包含特殊字符,无法正常删除,直接删除inode节点,就能起到删除文件的作用。

1、根据文件名,通过Directory里的对应关系,找到文件对应的Inode number

2、再根据Inode number读取到文件的Inode table

3、再根据Inode table中的Pointer读取到相应的Blocks

谁能解释一下cach为什么分为i-cache和d-cache吗

从两个方面来回答:

一个cache的行为,Icache大多都是顺序取指,碰到分支指令也会跳转,

而Dcache访问的模式变化比较大.也就是前者所说的pattern的问题.

指令只有读和refill没有写,而数据有读也有写.

最重要的是冯氏的结构是指令和数据分离.I和D在一起只有相互干扰.

另外一个方面就是,物理设计上考虑.

一个union的cache,同时需要数据和指令的访问.端口上是很难实现的.

所以一般在流水线的主干上,都是采用分离的icache和dcache.

非主干的L2 cache,从容量的角度考虑采用union的方式.

当然早期的也有不分离icache和dcache.因为早期的结构也简单.

L1 i-cache因为只读不改,可以放在IFU(instructionfetch unit)一起,IFU可以直接读i-cache;

但是L1 d-cache因为可读写,控制复杂,IFU/EU访问d-cache需要通过bus-interface-bus,速度要比i-cache慢。

关于dcache和dcache flush的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

原文链接:http://www.yzhh2002.cn/news/show-16182.html,转载和复制请保留此链接。
以上就是关于dcache 、dcache flush全部的内容,关注我们,带您了解更多相关内容。
 
标签: 文件 节点 目录
打赏
 
更多>同类资讯
0相关评论

推荐资讯
网站首页  |  VIP套餐介绍  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  SITEMAPS  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报