The main role of dentry and inode in the file system

In the previous article, we briefly discussed the role of struct super_block, we know that the root directory of our file system can be found in struct super_block, with this root directory we You can create a new file below, but we did not discuss how the root directory is generated, because we need to use the concepts of dentry and inode, today we will continue this discuss

Directories and files

We know that almost everything in a Linux system is a file

The function of inode is to represent a file on the file system, no matter how big the file is or what type it is

But the name of the file is not stored in the inode. In fact, the name of the file is stored in a special file. This special file is the directory (yes, the directory is also a file), each entry in directory points to a file, and this entry is called dentry

dentry and struct dentry

In the Linux kernel we use struct dentry to represent a directory entry

struct dentry {<!-- -->
    struct inode *d_inode; /* inode corresponding to directory entry */
    struct dentry *d_parent; /* the directory entry of the parent directory */
    struct qstr d_name; /* the name of the directory entry */
    unsigned int d_count; /* reference count of directory entry */
    // ... other member variables
};

Among them, d_name is the name of inode (that is, the file name), and d_inode is the associated with the directory item >inode

The following figure can roughly describe the relationship between dentry and inode

 + --------------- + + ----------------- +
| | | |
| inode |<--- | dentry |
| | | | |
|---------------| | |-----------------|
| i_mode | | | d_name --------|> The name of the file pointed to by the inode
| i_uid | |--<|-d_inode |
| i_gid | | d_parent -------|> Dentry object of the parent directory
| i_size | | ... |
| ... | | |
 + --------------- + + ----------------- +

It can be simply understood as, inode points to a specific file, and dentry points to this inode, so from dentry You can find any file when you start. In fact, the kernel has made a series of optimizations to dentry, making the process of finding files very fast

inode and struct inode

In the Linux kernel we use struct inode to represent inode on the file system

struct inode {<!-- -->
    umode_t i_mode; /* file type and access rights */
    uid_t i_uid; /* User ID */
    gid_t i_gid; /* group ID */
    dev_t i_rdev; /* device number */
    loff_t i_size; /* file size */
    struct timespec i_atime; /* last access time */
    struct timespec i_mtime; /* last modification time */
    struct timespec i_ctime; /* creation time */
    unsigned long i_ino; /* inode number */
    unsigned int i_count; /* reference count of index node */
    // ... other member variables
};

As mentioned above, inode is used to represent a file/directory, and each file or directory has a unique inode, which stores all information about the file or directory Metadata information, such as creation time, modification time, size, belonging user and group, etc. Additionally, an inode stores information about the physical location of a file or directory, the file type, and permissions. When we read or write a file, the kernel uses inode to locate and manipulate the actual file content.

How the root directory of the file system is generated

We know that the root directory of the file system (s_root field) is stored in struct super_block, now we can discuss how this directory is generated

For simplicity, let’s use ramfs as an example to see how this root directory is generated

ramfs is also called memory file system, it should be the simplest file system in Linux kernel, all files in this file system are stored in memory, no need to write to disk, so the implementation is very simple, use This file system is very suitable as an example to understand the basic logic of the file system

In ramfs, the root directory is generated in the ramfs_fill_super() function, the code is as follows, for the convenience of understanding, I deleted the irrelevant code

int ramfs_fill_super(struct super_block *sb, void *data, int silent)
{<!-- -->
    // ...other code
    
    // 1. Get the inode of the root directory
inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0);
    // 2. Generate the dentry of the root directory
sb->s_root = d_make_root(inode);
    
    // ...other code
return 0;
}

Let’s take a look at these two key steps

ramfs_get_inode

ramfs_get_inodeThe code is as follows, for the convenience of understanding, I deleted the irrelevant code

struct inode *ramfs_get_inode(struct super_block *sb,
const struct inode *dir, umode_t mode, dev_t dev)
{<!-- -->
    // new an inode
struct inode * inode = new_inode(sb);
\t
// ...other code
\t
// fill operation function
inode->i_op = & amp; ramfs_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
\t
// ...other code
\t
return inode;
}

Since ramfs is a memory file system, there is no need to read inode information from the disk. Here, new_inode() allocates a inode in the memory directly. Then set the operation function of inode, and it’s done

d_make_root

The d_make_root code is as follows, for the convenience of understanding, I deleted the irrelevant code

struct dentry *d_make_root(struct inode *root_inode)
{<!-- -->
    // new a dentry
struct dentry *res = __d_alloc(root_inode->i_sb, NULL);
\t
// Associate root_inode with our new dentry
d_instantiate(res, root_inode);
\t
return res;
}

The logic here is also very simple, first create a new dentry, and then associate the inode of the root directory with this dentry to complete, of course the specific There are still some details about how it is related, but we will not discuss it here, interested readers can see these details in the reference materials

So far, the root directory has been created. With the root directory, we can also create files on this file system. We will discuss the process of creating files in subsequent articles

References

struct dentry structure
struct inode structure
https://elixir.bootlin.com/linux/v4.8/source/fs/ramfs
https://elixir.bootlin.com/linux/v4.8/source/fs/ext2/super.c
https://blog.51cto.com/liangchaoxi/5422262
https://elixir.bootlin.com/linux/v4.8/source/fs/dcache.c#L1846