SimpleFs檔案系統初步四(Inode的建立過程)
阿新 • • 發佈:2018-11-24
我們在檔案系統下面建立一個檔案或者目錄,毫無疑問,檔案系統必須先去檢查這個檔案或者資料夾是否存在吧,隨後如果檔案系統檢查到檔案或者資料夾不存在才會為你新建,否則返回出錯。
1.檔案或者資料夾的檢查過程
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; }
2.檔案的建立過程
當我們檔案系統檢查完,該檔案不存在時,就會通過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; }