📄 inode.c
字号:
}
/*
* This is called with the inode lock held. It searches
* the in-use for freeable inodes, which are moved to a
* temporary list and then placed on the unused list by
* dispose_list.
*
* We don't expect to have to call this very often.
*
* N.B. The spinlock is released during the call to
* dispose_list.
*/
/*宏定义判断一个inode是否是可以利用的未使用的inode*/
#define CAN_UNUSE(inode) \
((((inode)->i_state | (inode)->i_data.nrpages) == 0) && \
!inode_has_buffers(inode))
/*如果(inode)->i_state==0,且inode的地址空间总页数为0,
*且inode没有脏缓冲区,则inode是可用的未使用的inode
*/
/*宏定义从entry结构指针得到inode结构体的指针*/
#define INODE(entry) (list_entry(entry, struct inode, i_list))
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
/*
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
*/
/*按照目标要求剪除索引节点缓冲区*/
void prune_icache(int goal)
{
LIST_HEAD(list);
struct list_head *entry, *freeable = &list;/*声明list_head类型指针entry,freeable*/
int count;/*声明int型count*/
struct inode * inode;/*声明inode指针*/
spin_lock(&inode_lock);/*持有自旋锁inode_lock*/
count = 0;/*置count为0*/
entry = inode_unused.prev;/*entry指向inode_unused.prev*/
while (entry != &inode_unused)/*循环扫描节点*/
{
struct list_head *tmp = entry;/*声明list_head型指针tmp,指向entry*/
entry = entry->prev;/*置entry为entry->prev*/
inode = INODE(tmp);/*宏定义从tmp结构指针得到inode结构体的指针*/
if (inode->i_state & (I_FREEING|I_CLEAR|I_LOCK))/*inode正在释放、或已被清除、或被上锁*/
continue;/*跳过本次循环,继续执行下次循环*/
if (!CAN_UNUSE(inode))/*判断一个inode是否是可以利用的未使用的inode*/
continue;/*不能利用,则跳过本次循环,继续执行下次循环*/
if (atomic_read(&inode->i_count))/*原子操作读inode->i_count,判断其是否为0*/
continue;/*跳过本次循环,继续执行下次循环*/
list_del(tmp);/*将该 inode对象从tmp链表中删除*/
list_del(&inode->i_hash);/*将该 inode对象从哈希链表中删除*/
INIT_LIST_HEAD(&inode->i_hash);/*初始化哈希链表*/
list_add(tmp, freeable);/*并链入freeable链表中*/
inode->i_state |= I_FREEING;/*置inode标志为正在释放*/
count++;/*count值加一*/
if (!--goal)/*goal减一后值为0*/
break;/*跳出循环体*/
}
inodes_stat.nr_unused -= count;/*cache中未使用的inode个数=原未使用个数-count*/
spin_unlock(&inode_lock);/*释放自旋锁inode_lock*/
dispose_list(freeable);/*处理临时链表上的inode,
*删除inode的相关数据,销毁inode
*/
/*
* If we didn't freed enough clean inodes schedule
* a sync of the dirty inodes, we cannot do it
* from here or we're either synchronously dogslow
* or we deadlock with oom.
*/
if (goal)/*goal不为0*/
schedule_task(&unused_inodes_flush_task);/*并发执行进程上下文*/
/*schedule_task - schedule a function for subsequent execution in process context.*/
}
/*缩短inode缓存*/
int shrink_icache_memory(int priority, int gfp_mask)
{
int count = 0;/*声明int型count,置初值为0*/
/*
* Nasty deadlock avoidance..
*
* We may hold various FS locks, and we don't
* want to recurse into the FS that called us
* in clear_inode() and friends..
*/
/*避免死锁,我们尽可能持有各种文件系统锁
*避免递归的进入在clear_ionde及相关函数中调用我们的文件系统*/
if (!(gfp_mask & __GFP_FS))
return 0;
count = inodes_stat.nr_unused / priority;/*为count赋值*/
prune_icache(count);/*按照目标要求剪除索引节点缓冲区*/
kmem_cache_shrink(inode_cachep);/*缩短slab分配缓存*/
return 0;
}
/*
* Called with the inode lock held.
* NOTE: we are not increasing the inode-refcount, you must call __iget()
* by hand after calling find_inode now! This simplifies iunique and won't
* add any additional branch in the common code.
*/
/*在某个链表中查找由(sb,ino)唯一标识的inode对象
*调用find_inode()函数时一定要持有inode_lock锁
*/
static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
{
struct list_head *tmp;/*声明链表指针tmp*/
struct inode * inode;/*声明inode指针*/
tmp = head;/*tmp指向head*/
for (;;) {/*无条件循环*/
tmp = tmp->next;/*tmp指向其后继next*/
inode = NULL;/*赋值inode为空*/
if (tmp == head)/*如果tmp现指向head,说明搜索完整个队列,
*找不到需要的inode,返回NULL*/
break;/*跳出循环体*/
inode = list_entry(tmp, struct inode, i_hash);/*从list_head类型的域找到inode类型的域*/
if (inode->i_ino != ino)/*inode的节点号与参数中的ino不同*/
continue;/*跳过循环剩下的部分,直接进入下次循环*/
if (inode->i_sb != sb)/*inode的相关超块与参数中的超块不符*/
continue;/*跳过循环剩下的部分,直接进入下次循环*/
if (find_actor && !find_actor(inode, ino, opaque))/*用参数组成的find_actor(inode, ino, opaque)
*与参数给定的find_actor不符
*/
/*typedef int (*find_inode_t)(struct inode *, unsigned long, void *);*/
continue;/*跳过循环剩下的部分,直接进入下次循环*/
break;/*跳出循环体*/
}
return inode;/*返回由(sb,ino)唯一标识的inode对象*/
}
/*
* This just initializes the inode fields
* to known values before returning the inode..
*
* i_sb, i_ino, i_count, i_state and the lists have
* been initialized elsewhere..
*/
/*初始化部分inode对象成员域*/
/*将一个刚从inode_cachep slab分配器中分配得到的inode对象中的某些成员初始化
为已知的值(通常为0),但是有一个例外,即链接数i_nlink被初始化为1。
这是一个静态的静态内部函数,因此它只能被inode.c中的其他函数所调用,
如:get_empty_inode()和get_new_inode()。
*/
static void clean_inode(struct inode *inode)
{
static struct address_space_operations empty_aops;/*声明对地址空间操作的结构体empty_aops*/
static struct inode_operations empty_iops;/*声明对索引节点操作的结构体empty_iops*/
static struct file_operations empty_fops;/*声明对文件操作的结构体empty_fops*/
memset(&inode->u, 0, sizeof(inode->u));/*用给定的值填充一块内存区域,即用0填充inode->u*/
inode->i_sock = 0;/*初始化不是套接字*/
inode->i_op = &empty_iops;/*初始化索引节点操作表指向empty_iops*/
inode->i_fop = &empty_fops;/*初始化文件操作表指向empty_fops*/
inode->i_nlink = 1;/*i初始化硬链接数为1*/
atomic_set(&inode->i_writecount, 0);/*原子操作初始化写者使用计数为0*/
inode->i_size = 0;/*初始化以字节为单位的文件大小为0*/
inode->i_blocks = 0;/*初始化文件的块数为0*/
inode->i_generation = 0;/*初始化索引节点版本号为0*/
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));/*用给定的值填充一块内存区域,
*即用0填充节点的磁盘限额inode->i_dquot
*/
inode->i_pipe = NULL;/*初始化管道信息为空*/
inode->i_bdev = NULL;/*初始化块设备驱动为空*/
inode->i_cdev = NULL;/*初始化字符设备为空*/
inode->i_data.a_ops = &empty_aops;/*初始化设备地址空间的相应操作表指向empty_aops*/
inode->i_data.host = inode;/*初始化设备地址空间的拥有者为inode*/
inode->i_data.gfp_mask = GFP_HIGHUSER;/* 初始化设备地址空间的分配页方式为GFP_HIGHUSER*/
inode->i_mapping = &inode->i_data;/*初始化备份地址空间i_mapping 指向inode的设备地址空间i_data*/
}
/**
* get_empty_inode - obtain an inode
*
* This is called by things like the networking layer
* etc that want to get an inode without any inode
* number, or filesystems that allocate new inodes with
* no pre-existing information.
*
* On a successful return the inode pointer is returned. On a failure
* a %NULL pointer is returned. The returned inode is not on any superblock
* lists.
*/
/*从slab分配器中分配一个空的inode对象*/
/*
该函数通过调用alloc_inode宏从slab分配器中分配一个inode对象,
然后把除了i_count引用计数和链接计数i_nlink之外的所有域
都初始化为NULL(部分域的初始化通过调用clean_inode()函数来完成),
并将这个inode对象链入inode_in_use链表中。
Linux内核模块通常并不会调用这个函数来分配一个inode对象。
那些想获取一个没有索引节点号的inode对象的内核模块(如网络层等),
以及那些没有任何已知信息的fs,通常会用这个函数来获取一个新的inode对象。
*/
struct inode * get_empty_inode(void)
{
static unsigned long last_ino;/*声明unsigned long型的last_ino*/
struct inode * inode;/*声明inode指针*/
spin_lock_prefetch(&inode_lock);/*预取持有自旋锁inode_lock*/
inode = alloc_inode();/*调用alloc_inode宏从slab分配器中分配一个inode对象*/
if (inode)/*inode分配成功*/
{
spin_lock(&inode_lock);/*持有自旋锁inode_lock*/
inodes_stat.nr_inodes++;/*inode对象总数加一*/
list_add(&inode->i_list, &inode_in_use);/*将inode->i_list链入到inode_in_use链表中*/
inode->i_sb = NULL;/*初始化相关超块为空*/
inode->i_dev = 0;/*初始化设备标识符为0*/
inode->i_blkbits = 0;/*初始化以位为单位的块大小为0*/
inode->i_ino = ++last_ino;/*将last_ino先加一,再赋值给节点号inode->i_ino */
inode->i_flags = 0;/*初始化文件系统标志为0*/
atomic_set(&inode->i_count, 1);/*原子操作初始化引用计数为1*/
inode->i_state = 0;/*初始化状态标志为0*/
spin_unlock(&inode_lock);/*释放自旋锁inode_lock*/
clean_inode(inode); /*初始化部分inode对象成员域*/
}
return inode; /*返回分配的一个空inode对象*/
}
/*
* This is called without the inode lock held.. Be careful.
*
* We no longer cache the sb_flags in i_flags - see fs.h
* -- rmk@arm.uk.linux.org
*/
/*用于得到一个新的inode对象*/
static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
{
struct inode * inode;/*声明一个inode指针对象*/
inode = alloc_inode();/*调用alloc_inode宏从inode_cachep这个slab分配器缓存中分配一个新的inode对象*/
if (inode) {/*若分配了inode对象*/
struct inode * old;/*声明一个inode指针对象old*/
spin_lock(&inode_lock);/*持有自旋锁,实现对inode缓存链表的互斥访问*/
/* We released the lock, so.. */
/*由于在调用get_new_inode函数时,调用者已经释放了inode_lock锁,
*因此在inode_lock被释放到调用 get_new_inode函数期间,
*其他内核模块有可能已经创建了(sb,ino)所确定的索引节点。
*所以,get_new_inode函数必须重新调用find_inode()函数,
*以再一次在哈希链表中查找是否已存在相应的inode对象。
*/
old = find_inode(sb, ino, head, find_actor, opaque);/*在哈希链表中查找是否已存在相应的inode对象*/
if (!old) {/*如果find_inode()返回NULL,则对先前所分配的inode对象进行初始化*/
inodes_stat.nr_inodes++;/*inode对象总数加一*/
list_add(&inode->i_list, &inode_in_use);/*将inode->i_list链入到inode_in_use链表中*/
list_add(&inode->i_hash, head);/*将inode->i_hash链入到参数所给的head链表中*/
inode->i_sb = sb;/*初始化相关超块为参数所给的超块sb*/
inode->i_dev = sb->s_dev;/*初始化设备标识符i_dev 为参数所给超块的设备标识符s_dev*/
inode->i_blkbits = sb->s_blocksize_bits;/*初始化inode的以位为单位的块大小
*为参数所给超块以位为单位的块大小s_blocksize_bits
*/
inode->i_ino = ino;/*初始化节点号为参数ino的值 */
inode->i_flags = 0;/*初始化文件系统标志为0*/
atomic_set(&inode->i_count, 1);/*原子操作初始化引用计数为1*/
inode->i_state = I_LOCK;/*初始化状态标志为I_LOCK,即已上锁*/
spin_unlock(&inode_lock); /*释放自旋锁inode_lock*/
/*调用clean_inode()函数和超级块的 s_op->read_inode()方法,
以从块设备上读取磁盘索引节点的内容
*/
clean_inode(inode); /*初始化部分inode对象成员域*/
/* reiserfs specific hack right here. We don't
** want this to last, and are looking for VFS changes
** that will allow us to get rid of it.
** -- mason@suse.com
*/
if (sb->s_op->read_inode2) {/*如果sb->s_op->read_inode2函数存在*/
sb->s_op->read_inode2(inode, opaque) ;/*以inode->i_ino为索引,
*从磁盘上读取索引节点,
*并填充内存中对应的inode结构的剩余部分
*/
} else {/*如果sb->s_op->read_inode2函数不存在*/
sb->s_op->read_inode(inode);/*以inode->i_ino为索引,
*从磁盘上读取索引节点,
*并填充内存中对应的inode结构的剩余部分
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -