参考文章: https://yq.aliyun.com/articles/6371
inode 和 dentry 结构
在Linux下,所有的结构都是以文件形式存在的。不管是目录还是网络 socket 。每个文件在系统底层关联一个具体的文件结构,关联的key 就是 inode。
目录也是一个特殊的文件,不过目录本身存储的内容是文件名和inode信息的映射。
以下3个结构是为加强理解,模拟的3个结构体,可以描述文件,inode,目录之间的关系。
/*每个文件都映射一个 inode, 包括目录也是一种文件*/
struct Inode
{
/*inode 号, 通过 ls -i 可以看到*/
int inodenumber;
....
int filesize;
void* filedata;
}Inode;
/**
* 目录本身也是一个文件,也具有inode 信息,
* 同时目录的内容存的是,当前目录下各个文件的文件名和inode 的映射关系, 也就是 dentry
* 有了 dentry 就可以根据文件名找到文件对应的 inode
* */
struct dir
{
dentry **entry;
int n_entrys;
Inode *inode; // 目录本身的inode
}
//dentry 映射了文件名和 inode 的关系
struct dentry
{
char *filename;
Inode *inode;
}dentry;
通过以上的多级映射, dentry 以及 dentry中存储的文件名 和 inode,就完整的描述了一个文件。
执行 cp 命令的时候,发生了什么?
cp test1 test2
-
首先 test1 的文件名和inode 都不会变
-
要给 test2 生产 dentry 和 inode 信息,文件名已经有了,现在需要一个 inodenumber
- 如果 test2 是一个已存在文件,则直接服用已存在文件的 inodenumber
- 如果 test2 不存在, 则分配一个新的未使用的inode
/** * 生成文件A的Inode number * 如果 A文件已存在,则返回 inode number * 若不存在,则返回一个没有用过的新的 inode_number * */ get_inode_number(file A) { if (A.exists) return A.Inode.inodenumber; else return new_inode_number; }
-
将test1 对应的inode 的信息,覆盖到test2 所对应的inode 信息中。如果test2 是正在运行的程序,此时的 cp 是失败的,因为操作系统引用了 test2 的文件映像,相当于给 inode 加了一把锁,inode 所指向的文件信息是不可以随意改变的。
执行 mv 的时候发生了什么?
mv test1 test2
-
test1 不用管
-
要给 test2 生产 dentry 和 inode 信息,文件名已经有了, 现在需要一个 inodenumber。由于是 mv 操作,原来 test1 的 inode 肯定是不需要了,那么直接用 test1 的inode 作为 test2 的 inode 即可
如果test2 是正在运行的程序,此时的 mv 是成功的,因为改变 test2 的inode 信息只需要改变 dentry即可,不需要改变inode 本身的信息。
所以运行与否不影响 mv 操作的进行,但是执行之后,需要重启程序,因为操作系统内存中的程序依然是指向 test2 原先的 inode
重启之后,原来test2的 inode 节点就会被回收。