linux 虚拟文件系统 源码,Linux内核源代码情状分析-虚拟文件系统

Linux内核源代码情景分析-虚拟文件系统

我们先来看两张图:

第一张是VFS与具体文件系统的关系示意图:

114159319

第二张是Linux文件系统的层次结构:

114159320

特殊文件:用来实现”管道“的文件,特别是"命名管道"的FIFO文件,还有Unix域的socket,也都属于特殊文件;还有在/proc目录下的一系列文件。

磁盘文件:就是存在硬盘上的文件。

设备文件:sudo mount -t ext2 /dev/sdb1 /mnt/sdb,这里的/dev/sdb1就是设备文件。如果硬盘上的节点raw_inode->i_block[block],如果得到是目录节点的inode,那么i_block[]存储着目录项的位置。如果是文件节点的inode,那么i_block[]存储着真正数据的位置,现在设备节点的inode存储着设备号(包含了主设备号和次设备号)。

区别的他们的代码如下,ext2_read_inode代码如下:

if (inode->i_ino == EXT2_ACL_IDX_INO ||

inode->i_ino == EXT2_ACL_DATA_INO)

/* Nothing to do */ ;

else if (S_ISREG(inode->i_mode)) {//硬盘文件,普通文件

inode->i_op = &ext2_file_inode_operations;

inode->i_fop = &ext2_file_operations;

inode->i_mapping->a_ops = &ext2_aops;

} else if (S_ISDIR(inode->i_mode)) {//硬盘文件,目录文件

inode->i_op = &ext2_dir_inode_operations;

inode->i_fop = &ext2_dir_operations;

} else if (S_ISLNK(inode->i_mode)) {//硬盘文件,链接文件

if (!inode->i_blocks)

inode->i_op = &ext2_fast_symlink_inode_operations;

else {

inode->i_op = &page_symlink_inode_operations;

inode->i_mapping->a_ops = &ext2_aops;

}

} else

init_special_inode(inode, inode->i_mode,

le32_to_cpu(raw_inode->i_block[0]));void init_special_inode(struct inode *inode, umode_t mode, int rdev)

{

inode->i_mode = mode;

if (S_ISCHR(mode)) {//设备文件,字符设备

inode->i_fop = &def_chr_fops;

inode->i_rdev = to_kdev_t(rdev);

} else if (S_ISBLK(mode)) {//设备文件,块设备

inode->i_fop = &def_blk_fops;

inode->i_rdev = to_kdev_t(rdev);

inode->i_bdev = bdget(rdev);

} else if (S_ISFIFO(mode))//特殊文件,命名管道

inode->i_fop = &def_fifo_fops;

else if (S_ISSOCK(mode))//特殊文件,socket文件

inode->i_fop = &bad_sock_fops;

else

printk(KERN_DEBUG "init_special_inode: bogus imode (%o)\n", mode);

}

一、我们对比下open对特殊文件,命名管道和硬盘文件,普通文件来做对比。

特殊文件,命名管道的打开请参考Linux内核源代码情景分析-进程间通信-命名管道。

硬盘文件,普通文件的打开请参考Linux内核源代码情景分析-文件的打开。f->f_op已经指向了ext2_file_operations。

两者不同之处在于dentry_open()时,f->f_op->open,普通文件指向ext2_open_file;而命名管道指向fifo_open。

f->f_op = fops_get(inode->i_fop);//f->f_op被赋值为inode_i_fop

if (inode->i_sb)

file_move(f, &inode->i_sb->s_files);//将其从中间队列脱链而挂入该文件所在设备的super_block结构中的file结构队列s_files

if (f->f_op && f->f_op->open) {

error = f->f_op->open(inode,f);//普通文件指向ext2_open_file;而命名管道指向fifo_open

if (error)

goto cleanup_all;

}另外在open中调用path_walk指向的过程中也会因为dentry->d_op和inode->i_op的不同执行的代码也不同。

二、对比普通文件的读和管道文件的读的不同。

普通文件的读,read映射到内核是sys_read,代码如下:

asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)

{

ssize_t ret;

struct file * file;

ret = -EBADF;

file = fget(fd);

if (file) {

if (file->f_mode & FMODE_READ) {

ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,

file, file->f_pos, count);

if (!ret) {

ssize_t (*read)(struct file *, char *, size_t, loff_t *);

ret = -EINVAL;

if (file->f_op && (read = file->f_op->read) != NULL)

ret = read(file, buf, count, &file->f_pos);//generic_file_read

}

}

if (ret > 0)

inode_dir_notify(file->f_dentry->d_parent->d_inode,

DN_ACCESS);

fput(file);

}

return ret;

}    硬盘文件,普通文件的打开请参考Linux内核源代码情景分析-文件的打开。f->f_op已经指向了ext2_file_operations。所以file->f_op->read指向generic_file_read。

管道文件的读请参考Linux内核源代码情景分析-进程间通信-管道。f->f_op指向pipe_read。

三、不同文件系统super_block结构中的指针s_op指向具体的super_operations数据结构。

参考Linux内核源代码情景分析-从路径名到目标节点,get_new_inode相关代码:

static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)

{

struct inode * inode;

inode = alloc_inode();

if (inode) {

struct inode * old;

spin_lock(&inode_lock);

/* We released the lock, so.. */

old = find_inode(sb, ino, head, find_actor, opaque);//再一次在杂凑表队列中寻找

if (!old) {//如果没有找到

inodes_stat.nr_inodes++;

list_add(&inode->i_list, &inode_in_use);

list_add(&inode->i_hash, head);//加入到对应的hash表

inode->i_sb = sb;//超级块结构

inode->i_dev = sb->s_dev;//设备号

inode->i_ino = ino;//节点号

inode->i_flags = 0;

atomic_set(&inode->i_count, 1);

inode->i_state = I_LOCK;

spin_unlock(&inode_lock);

clean_inode(inode);

sb->s_op->read_inode(inode);//根据不同的文件系统指向不同的代码

/*

* This is special! We do not need the spinlock

* when clearing I_LOCK, because we're guaranteed

* that nobody else tries to do anything about the

* state of the inode when it is locked, as we

* just created it (so there can be no old holders

* that haven't tested I_LOCK).

*/

inode->i_state &= ~I_LOCK;

wake_up(&inode->i_wait);

return inode;

}

/*

* Uhhuh, somebody else created the same inode under

* us. Use the old inode instead of the one we just

* allocated.

*/

__iget(old);//如果找到了inode结构

spin_unlock(&inode_lock);

destroy_inode(inode);

inode = old;//使用找到的inode结构

wait_on_inode(inode);

}

return inode;

}    sb->s_op->read_inode(inode);//根据不同的文件系统指向不同的代码。

总结:

我们把文件系统比喻作"接口卡",而把虚拟文件系统VFS比喻成一条插槽。因此,file结构中的指针f_op就可以看作插槽中的一个触点,并且在dentry、inode、super_operations数据结构中都有类似的触点。

我们在上文也看到了。主要是以下不同:

文件操作跳转表,即file_operations数据结构:file结构中的指针f_op指向具体的file_operations结构,这是open()、read()、write()等文件操作的跳转表。一种文件系统并不只限于一个file_operations结构,如ext2就有两个这样的数据结构,分别用于普通文件和目录文件。

目录项操作跳转表:即dentry_operations数据结构:dentry结构中的指针d_op指向具体的dentry_operations数据结构,这是内核中hash()、compare()等内部操作的跳转表。

索引节点操作跳转表,即inode_operations数据结构;inode结构中的指针i_op指向具体的inode_operations数据结构,lookup()、permissions()等内部函数的跳转表。

超级块操作跳转表,即super_operations数据结构:super_block结构中的指针s_op指向具体的super_operations数据结构,这是read_inode()、write_inode()、delete_inode()等内部操作的跳转表。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值