【linux】核心中根據inode得到檔名
核心程式設計中,操作的物件往往是inode,但是如何根據inode得到檔名呢,或者找到對應於檔案系統的位置呢?
527 struct inode { 528 umode_t i_mode; 529 unsigned short i_opflags; 530 kuid_t i_uid; 531 kgid_t i_gid; 532 unsigned int i_flags; 533 534 #ifdef CONFIG_FS_POSIX_ACL 535 struct posix_acl *i_acl; 536 struct posix_acl *i_default_acl; 537 #endif 538 539 const struct inode_operations *i_op; 540 struct super_block *i_sb; 541 struct address_space *i_mapping; 542 543 #ifdef CONFIG_SECURITY 544 void *i_security; 545 #endif 546 547 /* Stat data, not accessed from path walking */ 548 unsigned long i_ino; 549 /* 550 * Filesystems may only read i_nlink directly. They shall use the 551 * following functions for modification: 552 * 553 * (set|clear|inc|drop)_nlink 554 * inode_(inc|dec)_link_count 555 */ 556 union { 557 const unsigned int i_nlink; 558 unsigned int __i_nlink; 559 }; 560 dev_t i_rdev; 561 loff_t i_size; 562 struct timespec i_atime; 563 struct timespec i_mtime; 564 struct timespec i_ctime; 565 spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ 566 unsigned short i_bytes; 567 unsigned int i_blkbits; 568 blkcnt_t i_blocks; 569 570 #ifdef __NEED_I_SIZE_ORDERED 571 seqcount_t i_size_seqcount; 572 #endif 573 574 /* Misc */ 575 unsigned long i_state; 576 struct mutex i_mutex; 577 578 unsigned long dirtied_when; /* jiffies of first dirtying */ 579 580 struct hlist_node i_hash; 581 struct list_head i_wb_list; /* backing dev IO list */ 582 struct list_head i_lru; /* inode LRU list */ 583 struct list_head i_sb_list; 584 union { 585 struct hlist_head i_dentry; 586 struct rcu_head i_rcu; 587 }; 588 u64 i_version; 589 atomic_t i_count; 590 atomic_t i_dio_count; 591 atomic_t i_writecount; 592 #ifdef CONFIG_IMA 593 atomic_t i_readcount; /* struct files open RO */ 594 #endif 595 const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ 596 struct file_lock *i_flock; 597 struct address_space i_data; 598 #ifdef CONFIG_QUOTA 599 struct dquot *i_dquot[MAXQUOTAS]; 600 #endif 601 struct list_head i_devices; 602 union { 603 struct pipe_inode_info *i_pipe; 604 struct block_device *i_bdev; 605 struct cdev *i_cdev; 606 }; 607 608 __u32 i_generation; 609 610 #ifdef CONFIG_FSNOTIFY 611 __u32 i_fsnotify_mask; /* all events this inode cares about */ 612 struct hlist_head i_fsnotify_marks; 613 #endif 614 615 void *i_private; /* fs or device private pointer */ 616 };
以上是inode結構體的定義,在linux/fs中,仔細看上n邊也沒有發現一個跟名字有關的東西,比如i_name【筆者意淫的】,為什麼沒有名稱呢,那如何才能找到名稱呢?
我覺得出現以上的問題,應該是對linux的檔案系統瞭解不夠,或者說不明白什麼是inode。inode是在linux的虛擬檔案系統之上統一出來的對任何檔案型別的記憶體中版本。什麼意思,就是說inode這個結構體是在記憶體中,對應的ext2檔案系統也有一個inode的硬碟版本ext2_inode。inode結構體用union記錄不同的檔案型別,但是他們總體抽象成inode,這是一種虛擬化的思想。這也是為什麼linux的vfs強大的原因。
檔案系統除了inode結構體外,還有個dentry結構體,翻譯一般叫目錄項,inode的i_dentry指向inode的目錄項,而dentry中的d_inode指向相應的inode結構。那麼他們是不是一一對應的呢?答案是,inode與dentry是多對一的關係,為什麼呢,因為一個inode可以對應多個不同位置【目錄項】的不同檔名的檔案,但是這些檔案在核心中的表現形式都是這個inode,現在應該能夠明白為什麼inode為什麼沒有記錄檔名和檔案位置了吧,因為這個多對一的關係。
dentry和inode是從不同的兩個角度描述檔案的屬性,dentry表示的是邏輯意義上的檔案【也就是我們看到的/usr/abc.txt】而inode表示的是物理意義上的檔案【也就是記憶體中的表示體】。那麼如何從inode得到正確的dentry?
核心為了設計一種適應所有型別的連結串列,使用了一種非常巧妙的機制,就是把一個固定型別的雙向連結串列list_head加入某一結構體中,這樣就通過該連結串列將某一結構體組織成連結串列形式,是不是很聰明?而且核心提供了針對連結串列的操作幾乎所有函式,使用巨集定義完成。這樣也減輕了核心設計人員的工作。
再回到上面問題,inode有一個list_head型別的雙向連結串列指向i_dentry,只要在裡面遍歷就能找到正確的dentry結構。
程式碼如下:
char *getfullpath(struct inode *inod,char* buffer,int len)
{
struct list_head* plist = NULL;
struct dentry* tmp = NULL;
struct dentry* dent = NULL;
struct dentry* parent = NULL;
char* name = NULL;
char* pbuf = buffer + PATH_MAX - 1;
struct inode* pinode = inod;
int length = 0;
buffer[PATH_MAX - 1] = '\0';
if(pinode == NULL)
return NULL;
list_for_each(plist,&pinode->i_dentry)
{
tmp = list_entry(plist,struct dentry,d_alias);
if(tmp->d_inode == pinode)
{
dent = tmp;
break;
}
}
if(dent == NULL)
{
return NULL;
}
name = (char*)(dent->d_name.name);
name = name + strlen(name) - 4;
if(!strcmp(name,".img"))
{
while(pinode && pinode ->i_ino != 2 && pinode->i_ino != 1)
{
if(dent == NULL)
break;
name = (char*)(dent->d_name.name);
if(!name)
break;
pbuf = pbuf - strlen(name) - 1;
*pbuf = '/';
memcpy(pbuf+1,name,strlen(name));
length += strlen(name) + 1;
if((parent = dent->d_parent))
{
dent = parent;
pinode = dent->d_inode;
}
}
printk(KERN_INFO "the fullname is :%s \n",pbuf);
}
return pbuf;
}
dentry結構中有一個d_name對應的就是檔名,d_parent指向目錄項的上一級目錄【/usr/src/linux中linux的parent就是src】所以一級級遍歷就能找到檔案的全路徑!
linux的核心設計是一種極其機智巧妙的藝術品,各位蝦米在學習的時候要注意從整個設計思路上體會他的靈魂,切忌鑽到某個細節而“走火入魔”啊~~
轉帖請說明