我们在文件系统下面创建一个文件或者目录,毫无疑问,文件系统必须先去检查这个文件或者文件夹是否存在吧,随后如果文件系统检查到文件或者文件夹不存在才会为你新建,否则返回出错。
struct dentry *simplefs_lookup(struct inode *parent_inode,
struct dentry *child_dentry, unsigned int flags)
{
//从根节点的Inode获取在Mount的时候读取到的磁盘中Sb的信息
struct simplefs_inode *parent = SIMPLEFS_INODE(parent_inode);
struct super_block *sb = parent_inode->i_sb;
struct buffer_head *bh;
struct simplefs_dir_record *record;
int i;
//因为根节点中会包含Data Block的索引,通过这个索引获取根节点这个dentry中存放的内容
/* 根节点(Dentry)的内容如下:
* 文件名: "vanakkam"
* Inode号: 2
*/
bh = sb_bread(sb, parent->data_block_number);
BUG_ON(!bh);
//指向父目录Inode中内容头部
record = (struct simplefs_dir_record *)bh->b_data;
//先确定该目录下面有多少个Inode(这里是包含文件和目录的)
for (i = 0; i < parent->dir_children_count; i++) {
//如果遍历了整个目录后,都无法找到这个文件或者文件夹,那么直接返回NULL,让VFS为其新
//建一个Inode,child_dentry->d_name.name是希望创建的目标文件或者文件夹
if (!strcmp(record->filename, child_dentry->d_name.name)) {
/* FIXME: There is a corner case where if an allocated inode,
* is not written to the inode store, but the inodes_count is
* incremented. Then if the random string on the disk matches
* with the filename that we are comparing above, then we
* will use an invalid uninitialized inode */
/*
* 进入这个分支是一种比较极端的情况,意味着分配的Inode并没有被写入存储区,但是InodesCount确递增了
* 同时磁盘上的Inode的随机字符串和我们比较的字符串匹配上了,那么我们直接使用这个非法的未初始化的
* Inode即可
*/
struct inode *inode;
struct simplefs_inode *sfs_inode;
//使用这个未被写入存储区的Inode号,查询到具体的Inode信息结构
sfs_inode = simplefs_get_inode(sb, record->inode_no);
//使用SuperBlock分配一个空闲的Inode
inode = new_inode(sb);
//设置Inode号
inode->i_ino = record->inode_no;
//设置这个Inode归属于哪个父节点(Inode)下,同时设置其模式(例如:表明其是目录还是文件)
inode_init_owner(inode, parent_inode, sfs_inode->mode);
//该Inode指向的超级块指针需要设置
inode->i_sb = sb;
//设置该Inode的节点操作指针(因为有可能这个节点它是一个目录,那就需要支持mkdir,touch等操作)
inode->i_op = &simplefs_inode_ops;
//针对目录和常规文件的操作指针
if (S_ISDIR(inode->i_mode))
inode->i_fop = &simplefs_dir_operations;
else if (S_ISREG(inode->i_mode))
inode->i_fop = &simplefs_file_operations;
else
printk(KERN_ERR
"Unknown inode type. Neither a directory nor a file");
/* FIXME: We should store these times to disk and retrieve them */
//设置Inode的创建时间
inode->i_atime = inode->i_mtime = inode->i_ctime =
CURRENT_TIME;
//如前所述,i_private指针指向的是Inode具体信息(文件大小,属性,数据块的位置)
inode->i_private = sfs_inode;
//将该Inode加入到当前目录(Dentry)下
d_add(child_dentry, inode);
//由于我们使用的是之前分配的inode号(未写入存储区),因此并不需要再重新创建了,直接
//返回NULL即可
return NULL;
}
record++;
}
printk(KERN_ERR
"No inode found for the filename [%s]\n",
child_dentry->d_name.name);
return NULL;
}
当我们文件系统检查完,该文件不存在时,就会通过vfs创建一个文件
static struct inode_operations simplefs_inode_ops = {
.create = simplefs_create,
.lookup = simplefs_lookup,
.mkdir = simplefs_mkdir,
};
如上对于一个目录的Inode我们之前为其设置了simplefs_inode_ops的结构,其中有个成员就是create指针。如下
simplefs_create ->simplefs_create_fs_object
下面就是Inode的创建过程
static int simplefs_create_fs_object(struct inode *dir, struct dentry *dentry,
umode_t mode)
{
struct inode *inode;
struct simplefs_inode *sfs_inode;
struct super_block *sb;
struct simplefs_inode *parent_dir_inode;
struct buffer_head *bh;
struct simplefs_dir_record *dir_contents_datablock;
uint64_t count;
int ret;
if (mutex_lock_interruptible(&simplefs_directory_children_update_lock)) {
sfs_trace("Failed to acquire mutex lock\n");
return -EINTR;
}
//通过这个父Inode获取到这个文件系统的SuperBlock
sb = dir->i_sb;
//我们首先思考,我们如果想要创建一个Inode是不是应该看下该文件系统的Inode位置是否
//还有空余来允许我们创建呢,因此,我们先要得到当前文件系统已经使用的Inode总数。
ret = simplefs_sb_get_objects_count(sb, &count);
if (ret < 0) {
mutex_unlock(&simplefs_directory_children_update_lock);
return ret;
}
//先判断Inode总数是否超了,如果是,则返回用户,没有空间创建了
if (unlikely(count >= SIMPLEFS_MAX_FILESYSTEM_OBJECTS_SUPPORTED)) {
/* The above condition can be just == insted of the >= */
printk(KERN_ERR
"Maximum number of objects supported by simplefs is already reached");
mutex_unlock(&simplefs_directory_children_update_lock);
return -ENOSPC;
}
//该文件系统只支持目录和普通文件的创建,否则返回出错
if (!S_ISDIR(mode) && !S_ISREG(mode)) {
printk(KERN_ERR
"Creation request but for neither a file nor a directory");
mutex_unlock(&simplefs_directory_children_update_lock);
return -EINVAL;
}
//通过SuperBlock创建一个空的Inode
inode = new_inode(sb);
if (!inode) {
mutex_unlock(&simplefs_directory_children_update_lock);
return -ENOMEM;
}
//设置这个Inode指向的SuperBlock
inode->i_sb = sb;
//设置这个Inode的操作指针
inode->i_op = &simplefs_inode_ops;
//设置这个Inode的创建时间
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
//设置Inode的Inode号
inode->i_ino = (count + SIMPLEFS_START_INO - SIMPLEFS_RESERVED_INODES + 1);
//创建特定文件系统的Inode结构
sfs_inode = kmem_cache_alloc(sfs_inode_cachep, GFP_KERNEL);
//对该节点的Inode号赋值
sfs_inode->inode_no = inode->i_ino;
//将内核标准节点的私有指针指向当前特定文件系统的Inode结构
inode->i_private = sfs_inode;
//设置文件系统的属性
sfs_inode->mode = mode;
//对文件目录以及普通文件分别做设置,需要注意的是,如果创建的是一个目录,那么毫无疑问,当前目录下
//的Inode个数肯定还是为0的
if (S_ISDIR(mode)) {
printk(KERN_INFO "New directory creation request\n");
sfs_inode->dir_children_count = 0;
inode->i_fop = &simplefs_dir_operations;
} else if (S_ISREG(mode)) {
printk(KERN_INFO "New file creation request\n");
sfs_inode->file_size = 0;
//针对普通文件设置读写操作
inode->i_fop = &simplefs_file_operations;
}
/* First get a free block and update the free map,
* Then add inode to the inode store and update the sb inodes_count,
* Then update the parent directory's inode with the new child.
*
* The above ordering helps us to maintain fs consistency
* even in most crashes
*/
//从超级块中获取空闲的数据块
ret = simplefs_sb_get_a_freeblock(sb, &sfs_inode->data_block_number);
if (ret < 0) {
printk(KERN_ERR "simplefs could not get a freeblock");
mutex_unlock(&simplefs_directory_children_update_lock);
return ret;
}
//新建一个Inode需要更新Inode的数据区,并同步
simplefs_inode_add(sb, sfs_inode);
/*除了更新Inode的数据区,我们还需要做一件事:在父目录(Inode)下面,添加该Inode的信息*/
//既然要添加信息,必须首先取得当前父目录的结构信息,通过内核的标准Inode获取特定文件系统的Inode
//信息
parent_dir_inode = SIMPLEFS_INODE(dir);
//通过simplefs_inode中的成员从而获取到数据信息
bh = sb_bread(sb, parent_dir_inode->data_block_number);
BUG_ON(!bh);
//需要知道的是目录Inode中存放的内容结构都是固定的,因此做下强制转换
dir_contents_datablock = (struct simplefs_dir_record *)bh->b_data;
/* Navigate to the last record in the directory contents */
/*让DIR的内容指针指向空闲区域*/
dir_contents_datablock += parent_dir_inode->dir_children_count;
/*让DIR的内容inode_no以及文件名称更新到父目录中*/
dir_contents_datablock->inode_no = sfs_inode->inode_no;
strcpy(dir_contents_datablock->filename, dentry->d_name.name);
/*将父目录指向的数据块设置为dirty,并将其回写到磁盘,之后释放*/
mark_buffer_dirty(bh);
sync_dirty_buffer(bh);
brelse(bh);
if (mutex_lock_interruptible(&simplefs_inodes_mgmt_lock)) {
mutex_unlock(&simplefs_directory_children_update_lock);
sfs_trace("Failed to acquire mutex lock\n");
return -EINTR;
}
//将父目录中的dir_children_count也自增
parent_dir_inode->dir_children_count++;
//同理我们更改了Inode数据区,这个数据区自然也要同步下了
ret = simplefs_inode_save(sb, parent_dir_inode);
if (ret) {
mutex_unlock(&simplefs_inodes_mgmt_lock);
mutex_unlock(&simplefs_directory_children_update_lock);
/* TODO: Remove the newly created inode from the disk and in-memory inode store
* and also update the superblock, freemaps etc. to reflect the same.
* Basically, Undo all actions done during this create call */
return ret;
}
mutex_unlock(&simplefs_inodes_mgmt_lock);
mutex_unlock(&simplefs_directory_children_update_lock);
//将当前Inode和其父目录关联
inode_init_owner(inode, dir, mode);
//将当前文件加入到denrty下面
d_add(dentry, inode);
return 0;
}