1. 程式人生 > >【linux】核心中根據inode得到檔名

【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的核心設計是一種極其機智巧妙的藝術品,各位蝦米在學習的時候要注意從整個設計思路上體會他的靈魂,切忌鑽到某個細節而“走火入魔”啊~~

轉帖請說明