F2FS源码分析-6.6 [其他重要数据结构以及函数] F2FS的重命名过程-f2fs_rename函数
生活随笔
收集整理的這篇文章主要介紹了
F2FS源码分析-6.6 [其他重要数据结构以及函数] F2FS的重命名过程-f2fs_rename函数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
F2FS源碼分析系列文章
主目錄
一、文件系統布局以及元數據結構
二、文件數據的存儲以及讀寫
三、文件與目錄的創建以及刪除(未完成)
四、垃圾回收機制
五、數據恢復機制
六、重要數據結構或者函數的分析
F2FS的rename流程
rename流程介紹
sys_rename函數
sys_rename函數是一個系統調用,是rename函數進入內核層的第一個函數:
SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname) {// AT_FDCWD表示以相對路徑的方法找oldname和newname這個文件,flags=0return do_renameat2(AT_FDCWD, oldname, AT_FDCWD, newname, 0); }do_renameat2函數
do_renameat2函數比較長,考慮多個輸入flag的作用,這里只考慮sys_rename函數rename一個文件的情形,即flag=0,并以此精簡函數。
static int do_renameat2(int olddfd, const char __user *oldname, int newdfd,const char __user *newname, unsigned int flags) {struct dentry *old_dentry, *new_dentry;struct dentry *trap;struct path old_path, new_path;struct qstr old_last, new_last;int old_type, new_type;struct inode *delegated_inode = NULL;struct filename *from;struct filename *to;unsigned int lookup_flags = 0, target_flags = LOOKUP_RENAME_TARGET;bool should_retry = false;int error;retry:// 接下來兩個函數最重要的作用是根據oldname和newname找到父目錄的dentry結構// 這兩個dentry結構保存在old_path和new_path中(注意是父目錄的dentry)from = filename_parentat(olddfd, getname(oldname), lookup_flags,&old_path, &old_last, &old_type);to = filename_parentat(newdfd, getname(newname), lookup_flags,&new_path, &new_last, &new_type);retry_deleg:// 這個函數會觸發一個全局的rename的互斥鎖,然后鎖兩個父目錄inode結構trap = lock_rename(new_path.dentry, old_path.dentry);// 根據old path的父目錄找到需要被rename的文件的dentryold_dentry = __lookup_hash(&old_last, old_path.dentry, lookup_flags);// 根據new path的父目錄找到或創建新的dentrynew_dentry = __lookup_hash(&new_last, new_path.dentry, lookup_flags | target_flags);// 調用vfs_rename函數進行重命名// 傳入的是新舊兩個目錄的inode,以及需要重命名的兩個dentry, flags = 0error = vfs_rename(old_path.dentry->d_inode, old_dentry,new_path.dentry->d_inode, new_dentry,&delegated_inode, flags);dput(new_dentry);dput(old_dentry);// 解鎖全局rename互斥鎖,釋放兩個inode鎖unlock_rename(new_path.dentry, old_path.dentry);path_put(&new_path);putname(to);path_put(&old_path);putname(from); exit:return error; }vfs_rename函數
vfs_rename函數也會做簡化,簡化的情形是將文件A重命名到文件B (B可能已經存在,或者不存在),flags=0。
int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,struct inode *new_dir, struct dentry *new_dentry,struct inode **delegated_inode, unsigned int flags) {int error;bool is_dir = d_is_dir(old_dentry);struct inode *source = old_dentry->d_inode; // 舊文件inodestruct inode *target = new_dentry->d_inode; // 新文件inodebool new_is_dir = false;unsigned max_links = new_dir->i_sb->s_max_links;struct name_snapshot old_name;dget(new_dentry); // 對新文件的引用計數+1if (target)inode_lock(target); // 如果新文件已經存在,則上鎖error = old_dir->i_op->rename(old_dir, old_dentry,new_dir, new_dentry, flags);out:if (target)inode_unlock(target); // 如果新文件已經存在,則解鎖dput(new_dentry); // 對新文件的引用計數-1return error; }f2fs_rename函數
f2fs_rename函數也會做簡化,簡化的情形是將文件A重命名到文件B (B可能已經存在,或者不存在),flags=0。
static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,struct inode *new_dir, struct dentry *new_dentry,unsigned int flags) {struct f2fs_sb_info *sbi = F2FS_I_SB(old_dir);struct inode *old_inode = d_inode(old_dentry);struct inode *new_inode = d_inode(new_dentry);struct inode *whiteout = NULL;struct page *old_dir_page;struct page *old_page, *new_page = NULL;struct f2fs_dir_entry *old_dir_entry = NULL;struct f2fs_dir_entry *old_entry;struct f2fs_dir_entry *new_entry;bool is_old_inline = f2fs_has_inline_dentry(old_dir);int err;// 輸入顯然是// 舊的父目錄old_dir,舊的文件old_dentry// 新的父目錄new_dir,新的文件new_dentry// 根據舊文件的名字找到對應的f2fs_dir_entry,old_page保存的是磁盤上的dir_entry數據old_entry = f2fs_find_entry(old_dir, &old_dentry->d_name, &old_page);if (new_inode) { // 如果新文件已經存在// 根據新文件的名字找到對應的f2fs_dir_entry,new_page保存的是磁盤上的數據new_entry = f2fs_find_entry(new_dir, &new_dentry->d_name,&new_page);// F2FS獲取一個全局讀信號量f2fs_lock_op(sbi);// 在管理orphan inode的全局結構中,將orphan inode的數目+1。err = f2fs_acquire_orphan_inode(sbi);// 這里進行新舊inode的link的變化:// 將new_dentry所屬的inode指向old_inode// 因為rename的時候新inode是已經存在了,因此rename的操作就是將// 新路徑原來的inode無效掉,然后替換為舊路徑的inodef2fs_set_link(new_dir, new_entry, new_page, old_inode);new_inode->i_ctime = current_time(new_inode);down_write(&F2FS_I(new_inode)->i_sem); // 拿寫信號量// 減少新inode一個引用計數,因為被rename了f2fs_i_links_write(new_inode, false);up_write(&F2FS_I(new_inode)->i_sem); // 釋放寫信號量// 如果引用計數下降到0,則添加到orphan inode中,在checkpoint管理if (!new_inode->i_nlink)f2fs_add_orphan_inode(new_inode);elsef2fs_release_orphan_inode(sbi); // 否則管理結構將orphan inode的數目-1。} else {// 這個情況是新路徑的Inode不存在// F2FS獲取一個全局讀信號量f2fs_lock_op(sbi);// 由于新inode是不存在的,因此直接將舊inode添加到新的f2fs_dir_entry中err = f2fs_add_link(new_dentry, old_inode);}down_write(&F2FS_I(old_inode)->i_sem);if (!old_dir_entry || whiteout)file_lost_pino(old_inode); // 這個操作要保留著用于數據恢復elseF2FS_I(old_inode)->i_pino = new_dir->i_ino;up_write(&F2FS_I(old_inode)->i_sem);old_inode->i_ctime = current_time(old_inode);f2fs_mark_inode_dirty_sync(old_inode, false);// 新的數據已經加入到新的f2fs_dir_entry,因此舊entry就去去除掉f2fs_delete_entry(old_entry, old_page, old_dir, NULL);// F2FS釋放全局讀信號量f2fs_unlock_op(sbi);f2fs_update_time(sbi, REQ_TIME);return 0; }總結
以上是生活随笔為你收集整理的F2FS源码分析-6.6 [其他重要数据结构以及函数] F2FS的重命名过程-f2fs_rename函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图像调整亮度饱和度 c语言,数据增强-亮
- 下一篇: CISCO CCNA CCNP CCIE