1. 程式人生 > >Linux核心查詢檔案操作函式的過程

Linux核心查詢檔案操作函式的過程

先根據路徑找到父目錄項,然後找到對應的i_node,i_ndoe的成員 file_operations  *  i_fop是指向檔案操作函式集的指標。

在建立檔案的i_node時會設定 file_operations  *  i_fop的值。一般預設使用init_special_inode()函式進行設定,其程式碼如下:

void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)           
{                                                                                
        inode->i_mode = mode;                                                    
        if (S_ISCHR(mode)) {                                                     
                inode->i_fop = &def_chr_fops;                                    
                inode->i_rdev = rdev;                                            
        } else if (S_ISBLK(mode)) {                                              
                inode->i_fop = &def_blk_fops;                                    
                inode->i_rdev = rdev;                                            
        } else if (S_ISFIFO(mode))                                               
                inode->i_fop = &pipefifo_fops;                                   
        else if (S_ISSOCK(mode))                                                 
                inode->i_fop = &bad_sock_fops;                                   
        else                                                                     
                printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"    
                                  " inode %s:%lu\n", mode, inode->i_sb->s_id,    
                                  inode->i_ino);                                 
}
這個函式會根據檔案的型別,給i_fop賦不同值。
def_chr_fops:  字元裝置檔案的操作函式。
def_blk_fops:  塊裝置檔案的操作函式。
pipefifo_fops: 管道檔案的操作函式
bad_sock_fops: 網路裝置檔案的操作函式
另外,對於字元裝置檔案和塊裝置檔案,i_node的成員i_rdev也會被賦值成rdev,這個rdev實際上是由主裝置號和從裝置號生成的裝置號。


當然,具體的檔案系統有可能會實現自己的初始化函式,比如sysfs就是使用自己的函式,如下:

static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)       
{                                                                                
        struct bin_attribute *bin_attr;                                          
                                                                                 
        inode->i_private = sysfs_get(sd);                                        
        inode->i_mapping->a_ops = &sysfs_aops;                                   
        inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;            
        inode->i_op = &sysfs_inode_operations;                                   
                                                                                 
        set_default_inode_attr(inode, sd->s_mode);                               
        sysfs_refresh_inode(sd, inode);                                          
                                                                                 
        /* initialize inode according to type */                                 
        switch (sysfs_type(sd)) {                                                
        case SYSFS_DIR:                                                          
                inode->i_op = &sysfs_dir_inode_operations;                       
                inode->i_fop = &sysfs_dir_operations;                            
                break;                                                           
        case SYSFS_KOBJ_ATTR:                                                    
                inode->i_size = PAGE_SIZE;                                       
                inode->i_fop = &sysfs_file_operations;                           
                break;                                                           
        case SYSFS_KOBJ_BIN_ATTR:                                                
                bin_attr = sd->s_bin_attr.bin_attr;                              
                inode->i_size = bin_attr->size;                                  
                inode->i_fop = &bin_fops;                                        
                break;                                                           
        case SYSFS_KOBJ_LINK:                                                    
                inode->i_op = &sysfs_symlink_inode_operations;                   
                break;                                                           
        default:                                                                 
                BUG();                                                           
        }                                                                        
                                                                                 
        unlock_new_inode(inode);                                                 
}     
該函式會根據檔案型別(ktype)給i_fop和i_op賦不同值。                                                                                      
而sysfs_type(sd)的定義如下:
static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
{
	return sd->s_flags & SYSFS_TYPE_MASK;
}
sysfs_dirent的成員變數sd->s_flags用於標識檔案的型別,該變數在建立目錄或檔案對應的sysfs_dirent時進行初始化:
(1)file:
    sysfs_create_file()--->sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR)--->sysfs_add_file_mode()--->sysfs_new_dirent()
 (2) dir:
    sysfs_create_dir()--->create_dir--->sysfs_new_dirent(name, mode, SYSFS_DIR)
	
  在建立檔案和目錄的過程中都會呼叫sysfs_new_dirent()去建立sysfs_dirent,其原始碼如下:
  
struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
{
	char *dup_name = NULL;
	struct sysfs_dirent *sd;

	if (type & SYSFS_COPY_NAME) {
		name = dup_name = kstrdup(name, GFP_KERNEL);
		if (!name)
			return NULL;
	}

	sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
	if (!sd)
		goto err_out1;

	if (sysfs_alloc_ino(&sd->s_ino))
		goto err_out2;

	atomic_set(&sd->s_count, 1);
	atomic_set(&sd->s_active, 0);

	sd->s_name = name;
	sd->s_mode = mode;
	sd->s_flags = type | SYSFS_FLAG_REMOVED;

	return sd;

 err_out2:
	kmem_cache_free(sysfs_dir_cachep, sd);
 err_out1:
	kfree(dup_name);
	return NULL;
}