内核编程中,操作的对象往往是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的内核设计是一种极其机智巧妙的艺术品,各位虾米在学习的时候要注意从整个设计思路上体会他的灵魂,切忌钻到某个细节而“走火入魔”啊~~
转帖请说明