您的位置:首页 > 运维架构 > Linux

Linux内核查找文件操作函数的过程

2017-06-07 11:32 288 查看
先根据路径找到父目录项,然后找到对应的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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: