📄 inode.c
字号:
/*
* linux/fs/inode.c
*
* (C) 1997 Linus Torvalds
*/
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/dcache.h>
#include <linux/init.h>
#include <linux/quotaops.h>
#include <linux/slab.h>
#include <linux/cache.h>
#include <linux/swap.h>
#include <linux/swapctl.h>
#include <linux/prefetch.h>
#include <linux/locks.h>
/*
* New inode.c implementation.
*
* This implementation has the basic premise of trying
* to be extremely low-overhead and SMP-safe, yet be
* simple enough to be "obviously correct".
*
* Famous last words.
*/
/* inode dynamic allocation 1999, Andrea Arcangeli <andrea@suse.de> */
/* #define INODE_PARANOIA 1 */
/* #define INODE_DEBUG 1 */
/*
* Inode lookup is no longer as critical as it used to be:
* most of the lookups are going to be through the dcache.
*/
#define I_HASHBITS i_hash_shift/*宏定义哈希链表表头数组的位数*/
#define I_HASHMASK i_hash_mask/*宏定义哈希链表表头数组的位掩码*/
static unsigned int i_hash_mask;/*哈希链表表头数组的位掩码*/
static unsigned int i_hash_shift;/*哈希链表表头数组的位数*/
/*
* Each inode can be on two separate lists. One is
* the hash list of the inode, used for lookups. The
* other linked list is the "type" list:
* "in_use" - valid inode, i_count > 0, i_nlink > 0
* "dirty" - as "in_use" but also dirty
* "unused" - valid inode, i_count = 0
*
* A "dirty" list is maintained for each super block,
* allowing for low-overhead inode sync() operations.
*/
/*每一个inode对象都会存在于两个分离的双向链表中:
一个是inode哈希链表inode_hashtable,用来加快inode查找,
每个inode对象都通过i_hash指针链入哈希链表中。
另一个是inode的“类型”链表:
如果i_count>0、i_nlink>0,且该inode不脏,
则这个inode就通过其i_list指针链入系统全局的inode_in_use双向链表。
如果i_count>0、i_nlink>0,但是这个inode为脏(即i_state域中设置了I_DIRTY标志),
则这个inode通过i_list指针链入他所属的super_block对象的s_dirty链表。
如果i_count=0,则通过其i_list链入inode_unused链表。
对于那些不属于任何超级块对象(即i_sb=NULL)的匿名inode对象,
则通过i_hash指针链入系统全局的匿名inode哈希链表anon_hash_chain。
*/
static LIST_HEAD(inode_in_use);/*正在使用的未更改信息的节点链表*/
static LIST_HEAD(inode_unused);/*未使用的信息节点链表*/
static struct list_head *inode_hashtable;/*索引节点哈希链表*/
static LIST_HEAD(anon_hash_chain); /* for inodes with NULL i_sb *//*匿名索引节点哈希链表*/
/*每个超级块对象super_block中还有一条被修改过的、且正在使用的inode双向链表s_dirty*/
/*
* A simple spinlock to protect the list manipulations.
*
* NOTE! You also have to own the lock if you change
* the i_state of an inode while it is in use..
*/
/*定义了自旋锁inode_lock,来实现对所有inode缓存链表的互斥访问。
*任何访问任意一条inode缓存链表的代码段,
*都必须通过调用spin_lock()函数持有该自旋锁,
*并在结束访问后通过spin_unlock()释放该自旋锁。
*如果要改变一个正在使用的inode对象的i_state域,也必须先持有该自旋锁
*/
static spinlock_t inode_lock = SPIN_LOCK_UNLOCKED;/*定义静态自旋锁变量inode_lock*/
/*
* Statistics gathering..
*/
struct inodes_stat_t inodes_stat;
/*全局变量inodes_stat定义了inode cache的统计信息,
主要包括cache中的inode对象总数和其中未使用的inode个数,具体定义如下:
struct {
int nr_inodes;
int nr_unused;
int dummy[5];
} inodes_stat;
*/
/*索引节点的slab分配缓存由一个kmem_cache_t类型的指针变量inode_cachep来定义,
*这个slab分配器缓存是在inode cache的初始化函数inode_init()中
*通过kmem_cache_create()函数来创建的。
*/
static kmem_cache_t * inode_cachep;/*定义静态kmem_cache_t类型的指针变量inode_cachep,
*用来给inode的slab分配缓存
*/
/*宏定义分配索引节点*/
#define alloc_inode() \
((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
/*从inode_cachep slab分配器缓存中分配一个inode对象*/
/*释放inode指针指向的inode对象*/
static void destroy_inode(struct inode *inode)
{
if (inode_has_buffers(inode))/*如果i_dirty_buffers链表不空或i_dirty_data_buffers链表不空*/
BUG();/*调用BUG()*/
kmem_cache_free(inode_cachep, (inode)); /*将一个不再使用的inode对象释放给slab分配器*/
}
/*
* These are initializations that only need to be done
* once, because the fields are idempotent across use
* of the inode, so let the slab aware of that.
*/
/*只需要做一次的初始化函数*/
static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
{
struct inode * inode = (struct inode *) foo;
/*声明inode指针,指向foo的强制类型转换的inode*/
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR)/*判断构造器标志是否被设置过*/
{
memset(inode, 0, sizeof(*inode));/*用给定的值填充一块内存区域,即用0填充inode*/
/*
* memset - Fill a region of memory with the given value
* @s: Pointer to the start of the area.
* @c: The byte to fill the area with
* @count: The size of the area.*/
init_waitqueue_head(&inode->i_wait);/*初始化inode->i_wait等待队列为空*/
INIT_LIST_HEAD(&inode->i_hash);/*初始化inode->i_hash链表为空*/
INIT_LIST_HEAD(&inode->i_data.clean_pages);/*初始化inode->i_data.clean_pages链表为空*/
INIT_LIST_HEAD(&inode->i_data.dirty_pages);/*初始化inode->i_data.dirty_pages链表为空*/
INIT_LIST_HEAD(&inode->i_data.locked_pages);/*初始化inode->i_data.locked_pages链表为空*/
INIT_LIST_HEAD(&inode->i_dentry);/*初始化inode->i_dentry链表为空*/
INIT_LIST_HEAD(&inode->i_dirty_buffers);/*初始化inode->i_dirty_buffers链表为空*/
INIT_LIST_HEAD(&inode->i_dirty_data_buffers);/*初始化inode->i_dirty_data_buffers链表为空*/
INIT_LIST_HEAD(&inode->i_devices);/*初始化inode->i_devices链表为空*/
sema_init(&inode->i_sem, 1);/*初始化信号量inode->i_sem的count值为1,wait等待队列为空*/
sema_init(&inode->i_zombie, 1);/*初始化信号量inode->i_zombie的count值为1,wait等待队列为空*/
spin_lock_init(&inode->i_data.i_shared_lock);/*初始化inode->i_data.i_shared_lock自旋锁*/
}
}
/*
* Put the inode on the super block's dirty list.
*
* CAREFUL! We mark it dirty unconditionally, but
* move it onto the dirty list only if it is hashed.
* If it was not hashed, it will never be added to
* the dirty list even if it is later hashed, as it
* will have been marked dirty already.
*
* In short, make sure you hash any inodes _before_
* you start marking them dirty..
*/
/*对上面注释的翻译:
*把inode放到超块的dirty list上,标记脏是无条件的,
*但是只有当被散列后才可以将inode移到dirty list。
*如果没有被散列过,即使以后将被散列,
*也不能加到dirty list上,虽然它已经被标记为脏了
*总之,在标记inode为脏前要确认其已被散列
*/
/**
* __mark_inode_dirty - internal function
* @inode: inode to mark
* @flags: what kind of dirty (i.e. I_DIRTY_SYNC)
* Mark an inode as dirty. Callers should use mark_inode_dirty or
* mark_inode_dirty_sync.
*/
/*标记一个inode为脏,
*将一个位于inode_in_use中的一个脏inode转移到超块的s_dirty队列中
*/
void __mark_inode_dirty(struct inode *inode, int flags)
{
struct super_block * sb = inode->i_sb;/*声明一个超块指针,指向inode->i_sb*/
if (!sb)/*inode->i_sb为空*/
return;/*直接返回*/
/* Don't do this for I_DIRTY_PAGES - that doesn't actually dirty the inode itself *//*不需要判断I_DIRTY_PAGES */
if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {/*判断flags是否要设置为I_DIRTY_SYNC或I_DIRTY_DATASYNC*/
if (sb->s_op && sb->s_op->dirty_inode)/*判断sb->s_op 和sb->s_op->dirty_inode函数是否存在*/
sb->s_op->dirty_inode(inode);/*存在,调用函数将inode置脏*/
}
/* avoid the locking if we can */
if ((inode->i_state & flags) == flags)/*检测需要标志的flag是否已经在i_state上标记过*/
return;/*已标记过,则直接返回*/
spin_lock(&inode_lock);/*持有自旋锁inode_lock*/
if ((inode->i_state & flags) != flags) {/*需要标志的flag没有在i_state上标记过*/
inode->i_state |= flags;/*i_state与flag做按位或运算,结果赋值给i_state,
*即将需要标志的位置进行重新标志
*/
/* Only add valid (ie hashed) inodes to the dirty list */
if (!(inode->i_state & I_LOCK) && !list_empty(&inode->i_hash)) {/*i_state的I_LOCK位不为1,且inode->i_hash不为空*/
list_del(&inode->i_list);/*将该 inode对象从原来的“类型”链表中删除*/
list_add(&inode->i_list, &sb->s_dirty);/*并将其链入到sb->s_dirty链表中*/
}
}
spin_unlock(&inode_lock);/*释放自旋锁inode_lock*/
}
/*等待一个inode对象被解锁的函数*/
static void __wait_on_inode(struct inode * inode)
{
DECLARE_WAITQUEUE(wait, current);/*宏定义一个wait_queue_t,用当前的task_struct定义*/
add_wait_queue(&inode->i_wait, &wait);/*将wait_queue_t类型的wait添加到wait_queue_head_t型的inode->i_wait中 */
repeat:
set_current_state(TASK_UNINTERRUPTIBLE);/*设置当前进程的task_struct的state为不可中断*/
if (inode->i_state & I_LOCK) {/*如果i_state的I_LOCK位为1,即inode被加锁*/
schedule();/*执行调度程序函数*/
goto repeat;/*跳转到repeat程序段*/
}
remove_wait_queue(&inode->i_wait, &wait);/*将wait_queue_t类型的wait从wait_queue_head_t型的inode->i_wait中删除 */
current->state = TASK_RUNNING;/*设置当前进程的task_struct的state为运行态*/
}
/*测试一个inode对象是否已经被加锁,加锁则等待其被解锁的函数*/
static inline void wait_on_inode(struct inode *inode)
{
if (inode->i_state & I_LOCK)/*测试一个inode对象是否已经被加锁*/
__wait_on_inode(inode);/*被加锁,则调用__wait_on_inode()函数等待该inode被解锁*/
}
/*将指定inode对象写入设备*/
static inline void write_inode(struct inode *inode, int sync)
{
/*inode->i_sb存在,inode->i_sb->s_op存在,
*inode->i_sb->s_op->write_inode ()函数存在,且不是受损的inode
*/
if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->write_inode && !is_bad_inode(inode))
inode->i_sb->s_op->write_inode(inode, sync);/*调用write_inode ()函数把inode回写到磁盘
*更新某个文件系统的inode
*/
}
/*内联函数__iget()用来增加一个inode对象的引用计数*/
static inline void __iget(struct inode * inode)
{
if (atomic_read(&inode->i_count)) {/*判断inode->i_count的当前值*/
atomic_inc(&inode->i_count);/*如果不为0,则将i_count加1*/
return;/*直接返回*/
}
atomic_inc(&inode->i_count);/*如果为0,则先将i_count加1*/
if (!(inode->i_state & (I_DIRTY|I_LOCK))) {/*该inode对象不脏,也没有被上锁*/
list_del(&inode->i_list);/*将该 inode对象从原来的“类型”链表(应该在inode_unused链表中)中删除*/
list_add(&inode->i_list, &inode_in_use);/*并将其链入到inode_in_use链表中*/
}
inodes_stat.nr_unused--;/*将inode cache 统计信息中的未使用inode个数减1*/
}
/*将一个指定的脏inode同步写回块设备*/
static inline void __sync_one(struct inode *inode, int sync)
/*
Avoid looping in write_inode_now since the sync_one changes now ensure __sync_one
is called once the inode is unlocked.
*/
{
unsigned dirty;/*声明unsigned类型变量dirty*/
list_del(&inode->i_list);/*将该 inode对象从原来的“类型”链表中删除*/
list_add(&inode->i_list, &inode->i_sb->s_locked_inodes);/*并将其链入到inode->i_sb->s_locked_inodes链表中*/
if (inode->i_state & I_LOCK)/*inode被上锁*/
BUG();/*调用BUG()*/
/* Set I_LOCK, reset I_DIRTY */
dirty = inode->i_state & I_DIRTY;/*将i_state与I_DIRTY相与的结果赋值给dirty*/
inode->i_state |= I_LOCK;/*i_state与I_LOCK做按位或运算,结果赋值给i_state,
*即将需要标志的位置进行重新标志,标志为上锁
*/
inode->i_state &= ~I_DIRTY;/*清除脏位*/
spin_unlock(&inode_lock);/*释放自旋锁inode_lock*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -