Linux文件系统,硬链接、软链接、iNode、dentry

时间:2021-07-13 05:16:17

http://daoluan.net/blog/inode-vnode-dentry/

传统的Unix既有v节点(vnode)也有i节点(inode),vnode的数据结构中包含了inode信息。但在Linux中没有使用vnode,而使用了通用inode。“实现虽不同,但在概念上是一样的。” vnode (“virtual node”)仅在文件打开的时候,才出现的;而inode定位文件在磁盘的位置,它的信息本身是存储在磁盘等上的,当打开文件的时候从磁盘上读入内存。 Linux文件系统,硬链接、软链接、iNode、dentryinode信息就存储在磁盘的某个分区上。下图是上图的一个扩展:inode指示了文件在数据块中的物理位置。所以仅仅存在inode无法描述一个完整的文件系统,比如:目录与目录的树状结构,这一点在inode上无法体现。 延伸:

  • 如果多个 inode 指向同一个数据块的时候,是不是就可以实现熟悉的链接了?!这就是软连接的原理,新建一个文件(一个符号链接文件,文件的属性中有明确说明它是一个符号链接文件),为需要链接的文件分配一个新的 inode ,然后指向同一个文件。所以删除软连接文件不会真正删除源文件,而删除源文件过后,软连接文件将失效。
  • 多个文件共用一个 inode ,同样可以实现链接?!这就是硬链接的原理, inode 中有链接计数器,当增加一个文件指向这个 inode 时,计数器增1。特别的,当计数器为 0 时候,即所有的文件都删除,文件才真正从磁盘删除;当然,修改其中任何一个文件,都会作用在其他硬链接文件上。

Linux文件系统,硬链接、软链接、iNode、dentry

ext3_inode上的数据结构如下:它记录了很多关于文件的信息,比如文件长度,文件所在的设备,文件的物理位置,创建、修改和更新时间等等,特别的,它不包含文件名!

?
Code Sample
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
struct ext3_inode {
     __le16 i_mode; File mode
     __le16 i_uid; Low 16 bits of Owner Uid
     __le32 i_size; Size in bytes
     __le32 i_atime; Access time
     __le32 i_ctime; Creation time
     __le32 i_mtime; Modification time
 
     __le32 i_dtime; Deletion Time
     __le16 i_gid; Low 16 bits of Group Id
     __le16 i_links_count; Links count
     ......
     __le32 i_block[EXT2_N_BLOCKS]; Pointers to blocks
     ......
};

引入vnode:早期版本的Unix是这样做的,但是Linux并没有。vnode一般包含了文件类型和对此文件进行各种操作的函数的指针。

Linux文件系统,硬链接、软链接、iNode、dentry

Linux上有dentry,中文的意思就是目录项,它粘合了内存中文件和磁盘中文件,同时它保存是经常访问的目录信息。

http://unix.stackexchange.com/questions/4402/what-is-a-superblock-inode-dentry-and-a-fileA dentry is the glue that holds inodes and files together by relating inode numbers to file names. Dentries also play a role in directory caching which, ideally, keeps the most frequently used files on-hand for faster access. File system traversal is another aspect of the dentry as it maintains a relationship between directories and their files.下面是一副很有趣的图片:

Linux文件系统,硬链接、软链接、iNode、dentry

?
Code Sample
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
struct dentry {
     atomic_t d_count; 目录项对象使用计数器
     unsigned int d_flags; 目录项标志
     struct inode * d_inode; 与文件名关联的索引节点
     struct dentry * d_parent; 父目录的目录项对象
     struct list_head d_hash; 散列表表项的指针
     struct list_head d_lru; 未使用链表的指针
     struct list_head d_child; 父目录中目录项对象的链表的指针
     struct list_head d_subdirs;对目录而言,表示子目录目录项对象的链表
     struct list_head d_alias; 相关索引节点(别名)的链表
     int d_mounted; 对于安装点而言,表示被安装文件系统根项
     struct qstr d_name; 文件名
     unsigned long d_time; // used by d_revalidate
     struct dentry_operations *d_op; 目录项方法
     struct super_block * d_sb; 文件的超级块对象
     vunsigned long d_vfs_flags;
     void * d_fsdata;与文件系统相关的数据
     unsigned char d_iname [DNAME_INLINE_LEN]; 存放短文件名
};

诸如文件名,父目录等。dentry可以描述目录的树状结构。 ps:本文只对inode,vnode和dentry作简单的介绍,具体的实现还有深入的原理并未做详细的解释。欢迎斧正!

本文完

http://linuxgazette.net/105/pitcher.html

Q & A: The difference between hard and soft links

By Lew Pitcher

 

I participate in about 30 usenet newsgroups, and in a virtual LUG, and a number of questions keep coming up. I've answered a few of these questions often enough to have 'canned' an answer, which I modify, depending on the circumstances.

Here's one, now...

Q: Can someone give me a simple explanation of the difference between a soft link and a hard link? The documentation I've read mention these links but make no strong explanations of their meaning and how/when to use them. Thanks!

A: OK, I'll give it a try...

Unix files consist of two parts: the data part and the filename part.

The data part is associated with something called an 'inode'. The inode carries the map of where the data is, the file permissions, etc. for the data.

                               .---------------> ! data ! ! data ! etc
                              /                  +------+ !------+
        ! permbits, etc ! data addresses !
        +------------inode---------------+

The filename part carries a name and an associated inode number.

                         .--------------> ! permbits, etc ! addresses !
                        /                 +---------inode-------------+
        ! filename ! inode # !
        +--------------------+

More than one filename can reference the same inode number; these files are said to be 'hard linked' together.

        ! filename ! inode # !
        +--------------------+
                        \
                         >--------------> ! permbits, etc ! addresses !
                        /                 +---------inode-------------+
        ! othername ! inode # !
        +---------------------+

On the other hand, there's a special file type whose data part carries a path to another file. Since it is a special file, the OS recognizes the data as a path, and redirects opens, reads, and writes so that, instead of accessing the data within the special file, they access the data in the file named by the data in the special file. This special file is called a 'soft link' or a 'symbolic link' (aka a 'symlink').

        ! filename ! inode # !
        +--------------------+
                        \
                         .-------> ! permbits, etc ! addresses !
                                   +---------inode-------------+
                                                      /
                                                     /
                                                    /
    .----------------------------------------------'
   ( 
    '-->  !"/path/to/some/other/file"! 
          +---------data-------------+
                  /                      }
    .~ ~ ~ ~ ~ ~ ~                       }-- (redirected at open() time)
   (                                     }
    '~~> ! filename ! inode # !
         +--------------------+
                         \
                          '------------> ! permbits, etc ! addresses !
                                         +---------inode-------------+
                                                            /
                                                           /
     .----------------------------------------------------'
    (
     '->  ! data !  ! data ! etc.
          +------+  +------+ 

Now, the filename part of the file is stored in a special file of its own along with the filename parts of other files; this special file is called a directory. The directory, as a file, is just an array of filename parts of other files.

When a directory is built, it is initially populated with the filename parts of two special files: the '.' and '..' files. The filename part for the '.' file is populated with the inode# of the directory file in which the entry has been made; '.' is a hardlink to the file that implements the current directory.

The filename part for the '..' file is populated with the inode# of the directory file that contains the filename part of the current directory file. '..' is a hardlink to the file that implements the immediate parent of the current directory.

The 'ln' command knows how to build hardlinks and softlinks; the 'mkdir' command knows how to build directories (the OS takes care of the above hardlinks).

There are restrictions on what can be hardlinked (both links must reside on the same filesystem, the source file must exist, etc.) that are not applicable to softlinks (source and target can be on seperate file systems, source does not have to exist, etc.). OTOH, softlinks have other restrictions not shared by hardlinks (additional I/O necessary to complete file access, additional storage taken up by softlink file's data, etc.)

In other words, there's tradeoffs with each.

Now, let's demonstrate some of this...

ln in action

Let's start off with an empty directory, and create a file in it

~/directory $ ls -lia 
total 3
  73477 drwxr-xr-x   2 lpitcher users        1024 Mar 11 20:16 .
  91804 drwxr-xr-x  29 lpitcher users        2048 Mar 11 20:16 ..

~/directory $ echo "This is a file" >basic.file

~/directory $ ls -lia 
total 4
  73477 drwxr-xr-x   2 lpitcher users        1024 Mar 11 20:17 .
  91804 drwxr-xr-x  29 lpitcher users        2048 Mar 11 20:16 ..
  73478 -rw-r--r--   1 lpitcher users          15 Mar 11 20:17 basic.file

~/directory $ cat basic.file
This is a file

Now, let's make a hardlink to the file

   
~/directory $ ln basic.file hardlink.file

~/directory $ ls -lia 
total 5
  73477 drwxr-xr-x   2 lpitcher users        1024 Mar 11 20:20 .
  91804 drwxr-xr-x  29 lpitcher users        2048 Mar 11 20:18 ..
  73478 -rw-r--r--   2 lpitcher users          15 Mar 11 20:17 basic.file
  73478 -rw-r--r--   2 lpitcher users          15 Mar 11 20:17 hardlink.file

~/directory $ cat hardlink.file
This is a file

We see that:

  1. hardlink.file shares the same inode (73478) as basic.file
  2. hardlink.file shares the same data as basic.file

If we change the permissions on basic.file:

~/directory $ chmod a+w basic.file

~/directory $ ls -lia 
total 5
  73477 drwxr-xr-x   2 lpitcher users        1024 Mar 11 20:20 .
  91804 drwxr-xr-x  29 lpitcher users        2048 Mar 11 20:18 ..
  73478 -rw-rw-rw-   2 lpitcher users          15 Mar 11 20:17 basic.file
  73478 -rw-rw-rw-   2 lpitcher users          15 Mar 11 20:17 hardlink.file

then the same permissions change on hardlink.file.

The two files (basic.file and hardlink.file) share the same inode and data, but have different file names.

Let's now make a softlink to the original file:

~/directory $ ln -s basic.file softlink.file

~/directory $ ls -lia 
total 5
  73477 drwxr-xr-x   2 lpitcher users        1024 Mar 11 20:24 .
  91804 drwxr-xr-x  29 lpitcher users        2048 Mar 11 20:18 ..
  73478 -rw-rw-rw-   2 lpitcher users          15 Mar 11 20:17 basic.file
  73478 -rw-rw-rw-   2 lpitcher users          15 Mar 11 20:17 hardlink.file
  73479 lrwxrwxrwx   1 lpitcher users          10 Mar 11 20:24 softlink.file -> basic.file

~/directory $ cat softlink.file
This is a file

Here, we see that although softlink.file accesses the same data as basic.file and hardlink.file, it does not share the same inode (73479 vs 73478), nor does it exhibit the same file permissions. It does show a new permission bit: the 'l' (softlink) bit.

If we delete basic.file:

~/directory $ rm basic.file

~/directory $ ls -lia 
total 4
  73477 drwxr-xr-x   2 lpitcher users        1024 Mar 11 20:27 .
  91804 drwxr-xr-x  29 lpitcher users        2048 Mar 11 20:18 ..
  73478 -rw-rw-rw-   1 lpitcher users          15 Mar 11 20:17 hardlink.file
  73479 lrwxrwxrwx   1 lpitcher users          10 Mar 11 20:24 softlink.file -> basic.file

then we lose the ability to access the linked data through the softlink:

~/directory $ cat softlink.file
cat: softlink.file: No such file or directory

However, we still have access to the original data through the hardlink:

~/directory $ cat hardlink.file
This is a file

You will notice that when we deleted the original file, the hardlink didn't vanish. Similarly, if we had deleted the softlink, the original file wouldn't have vanished.

A further note with respect to hardlink files

When deleting files, the data part isn't disposed of until all the filename parts have been deleted. There's a count in the inode that indicates how many filenames point to this file, and that count is decremented by 1 each time one of those filenames is deleted. When the count makes it to zero, the inode and its associated data are deleted.

By the way, the count also reflects how many times the file has been opened without being closed (in other words, how many references to the file are still active). This has some ramifications which aren't obvious at first: you can delete a file so that no "filename" part points to the inode, without releasing the space for the data part of the file, because the file is still open.

Have you ever found yourself in this position: you notice that /var/log/messages (or some other syslog-owned file) has grown too big, and you

     rm /var/log/messages
     touch /var/log/messages

to reclaim the space, but the used space doesn't reappear? This is because, although you've deleted the filename part, there's a process that's got the data part open still (syslogd), and the OS won't release the space for the data until the process closes it. In order to complete your space reclamation, you have to

     kill -SIGHUP `cat /var/run/syslogd.pid`

to get syslogd to close and reopen the file.

You can use this to your advantage in programs: have you ever wondered how you could hide a temporary file? Well, you could do the following:

     {
        FILE *fp;

        fp = fopen("some.hidden.file","w");
        unlink("some.hidden.file"); /* deletes the filename part */

        /* some.hidden.file no longer has a filename and is truely hidden */
        fprintf(fp,"This data won't be found\n"); /* access the data part */
        /*etc*/
        fclose(fp); /* finally release the data part */
     }

http://www.elmerzhang.com/2012/12/suerblock-inode-dentry-file-of-filesystem/

关于 Linux 文件系统的 Superblock, Inode, Dentry 和 File

首先,Superblock, Inode, Dentry 和 File 都属于元数据(Metadata),根据*中的解释,所谓元数据,就是描述数据的数据(data about data),主要是描述数据属性(property)的信息,用来支持如指示存储位置、历史数据、资源查找、文件纪录等功能。Linux/Unix 文件系统的元数据以多级结构保存。

Superblock 是文件系统最基本的元数据,它定义了文件系统的类似、大小、状态,和其他元数据结构的信息(元数据的元数据)。Superblock 对于文件系统来说是非常关键的,因此对于每个文件系统它都冗余存储了多份。Superblock对于文件系统来说是一个非常“高等级”的元数据结构。例如,如果 /var 分区的 Superblock 损坏了,那么 /var 分区将无法挂载。在这时候,一般会执行 fsck 来自动选择一份 Superblock 备份来替换损坏的 Superblock,并尝试修复文件系统。主 Superblock 存储在分区的 block 0 或者 block 1 中,而 Superblock 的备份则分散存储在文件系统的多组 block 中。当需要手工恢复时,我们可以使用 dumpe2fs /dev/sda1 | grep -i superblock 来查看 sda1 分区的 superblock 备份有哪一份是可用的。我们假设 dumpe2fs 输出了这样一行:Backup superblock at 163840, Group descriptors at 163841-163841 ,通过这条信息,我们就可以尝试使用这个 superblock 备份:/sbin/fsck.ext3 -163840 -1024/dev/sda1。请注意,这里我们假设 block 的大小为 1024 字节。

Inode 中包含了一个文件的元数据。为清晰起见,Linux/Unix 系统中的所有对象均为文件:实际的文件、目录、设备等等。请注意,在 Inode 所包含的元数据中,并没有文件名。一个 Inode 包含的基本信息有:所有权(用户,组),访问模式(读、写、执行权限)和文件类型。

Dentry 是将 Inode 和 文件联系在一起的”粘合剂”,它将 Inode number 和文件名联系起来。Dentry 也在目录缓存中扮演了一定的角色,它缓存最常使用的文件以便于更快速的访问。Dentry 还保存了目录及其子对象的关系,用于文件系统的遍历。

File 即文件,其实只是一些逻辑上相关的数据,相对而言没什么好说的。

参考:
http://zh.wikipedia.org/wiki/%E5%85%83%E6%95%B0%E6%8D%AE
http://unix.stackexchange.com/questions/4402/what-is-a-superblock-inode-dentry-and-a-file