2021SC@SDUSC
inode(2)
We've talked about inodes, so what are we doing here.After reading some blogs from several great coders, I finally notice that I am far from ultimately understand such structure, so I would like to start with inodes again about some new information.
One senior write in his blog that inode is actually the core of vfs, which means almost every operations to files are connected to this structure.One of the reason is that a inode directly map to single file, and you will have to access inode first before really started to read or write a file.One of the very important thing that ralated to inode is page cache.
Our cpu and ram runs a lot quicker than disks, and if we go to storage to get files every time we use them, it will be very slow than you ever expected, that is why all os realize their cache, so is linux kernal.So when you use a file which is recently used, the system will firstly check the cache for such file, if exsited, it won't go to hard disk for files again, instead they get file from cache.If the file being used is not in cache, the system will find it in disk and save it to the cache.Be aware that cache are quite smaller than any hardware so it is not possible to store all the files in cache, otherwise you won't need disks at all.So when we find the Cache full, we need an operational way to replace some pages to get available space for newly accessed files, such page replacement algorithm we've learnt in lessons about Operating System(even thought I almost forgot all about it,I surely did some experiment on my own), and linux kernal are doing similar things.
So how does our OS even know if a file is already in cache so we don't need to go any further?Inode play an important role in such operation. One status in inode called i_mapping are pointing at structure address_space, which is also very important node in Cache storage.
struct inode {
umode_t i_mode;
unsigned short i_opflags;
kuid_t i_uid;
kgid_t i_gid;
unsigned int i_flags;
struct posix_acl *i_acl;
struct posix_acl *i_default_acl;
const struct inode_operations *i_op;
struct super_block *i_sb;
struct address_space *i_mapping;
One inode now map to a single address_space which also means a file has a address_space,so how does such structure functioning?An address space is a mapping from struct node to struct page, so kernal can use it to bind data of a file with it's address in ram.And address_space_operations of course has the operations for address_space which can read files or write data into cache space.With an address in ram and an offset we can easily locate certain pages in page cache.
Member page_tree shows radix tree of all pages.So what is radix tree?
struct address_space {
struct inode *host; /* owner: inode, block_device拥有它的节点 */
struct radix_tree_root page_tree;/* radix tree of all pages包含全部页面的radix树 */
rwlock_t tree_lock; /* and rwlock protecting it保护page_tree的自旋锁 */
unsigned int i_mmap_writable;/* count VM_SHARED mappings共享映射数 VM_SHARED记数*/
struct prio_tree_root i_mmap; /* tree of private and shared mappings 优先搜索树的树根*/
struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings 非线性映射的链表头*/
spinlock_t i_mmap_lock; /* protect tree, count, list 保护i_mmap的自旋锁*/
unsigned int truncate_count; /* Cover race condition with truncate 将文件截断的记数*/
unsigned long nrpages; /* number of total pages 页总数*/
pgoff_t writeback_index;/* writeback starts here 回写的起始偏移*/
struct address_space_operations *a_ops; /* methods 操作函数表*/
unsigned long flags; /* error bits/gfp mask ,gfp_mask掩码与错误标识 */
struct backing_dev_info *backing_dev_info; /* device readahead, etc预读信息 */
spinlock_t private_lock; /* for use by the address_space 私有address_space锁*/
struct list_head private_list; /* ditto 私有address_space链表*/
struct address_space *assoc_mapping; /* ditto 相关的缓冲*/
} __attribute__((aligned(sizeof(long))));
Radix Tree
Radix tree should not be topic for our discussion, but the more I dive deeply into Linux Kernal, the more I notice that I know little about it.So it's a good opportunity to learn about radix tree. With address_space and an offset, we are able to locate the pages in such tree for a file.
What is a radix tree?
Radix tree is an n-ary tree and a special kind of trie-tree which uses binary bits as its trie.
It might be a binary tree but only if one point has one bit on it like shown above.It's also haffmantree-like because they are both trie tree anyway.Origin trie has a-z as it's value of a point, but in radix tree, they are organized binary bits and it's actually part of the key we are searching for.A trie is easilly gets too deep for we might imput some strings that might be very long.But it's able to caculate some keys out of a string(more like a hash) and make'em build a radix tree.
A radix tree could be a 4-ary tree if each point has two bits as its value and 2^x-ary tree if each has x bits as value.Though we can make a radix tree wide enough, making it too large will greately reduce its efficiency, so we usually use 2-4 bits.
Insert
Search for a key in radix tree.If the route is not provided yet, we build new nodes for it.It also means that if a node was never being used, it will not be created so the space will be saved.
Delete
Mark it if a node is leaf.When we delete it, we just delete the leaf node and keep those in route alive for further use.
Usage in Linux
Radix tree is used for searching pages for a file.Like we talked earlier in this article, address_space leads a radix tree for each file, and the pointers for pages are stored in such trees.While page_tree point at the root of the radix tree, an offset is used as binary key for searching the page in radix tree that related to this file.We might say that hash-map could do the same thing by hash a page's number and use it to search for mappers.But hash are lacking efficiency than a radix tree.