文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>034_block_dev.c

034_block_dev.c

时间:2009-03-27  来源:hylpro

2007-3-6 
参考资料推荐: 当然是《Linux Device Dri vers 2nd》for 2.4.0 版本的。
Linux Driver 2nd chaper 12 : load block driver

先读一读chaper12, load block driver, 对于理解这个文件相当的有好处。这里仅罗列些block driver 如何与kernel配合的接口和数据结构。
block driver需要先注册自己到blkdevs, 就是这个文件实现的东西,这样kernel可以将此设备以设备文件的方式暴露给app。为了支持数据读写
driver必须实现自己的request_queue, 并注册到blk_dev, 这个queue和其操作函数是内核读写块设备的接口。
如果块设备支持分区,driver驱动还要分配并初始化一个gen_disk, 并用register_disk 进行注册(分区探测)。下图是对LDD Chapter12的一
点简单的总结。

 
了解了块设备驱动,再回过头来看block_dev.c就容易些。此模块提供了几个功能
1)为块设备建立设备文件,文件系统接口
struct file_operations def_blk_fops = {
open: blkdev_open,
release: blkdev_close,
llseek: block_llseek,
read: block_read,
write: block_write,
fsync: block_fsync,
ioctl: blkdev_ioctl,
};
2)管理blkdevs
int unregister_blkdev(unsigned int major, const char * name)
int register_blkdev(unsigned int major, const char * name, struct block_device_operations *bdops)

3)管理block_device
struct block_device *bdget(dev_t dev); 分配 struct block_device
void bdput(struct block_device *bdev) 释放 struct block_device

int blkdev_get(struct block_device *bdev, mode_t mode, unsigned flags, int kind) 调用blkdevs的bd_ops->open
int blkdev_put(struct block_device *bdev, int kind) 调用blkdevs的bd_ops->release

int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg) :block_device->bd_op->ioctl
void __init bdev_init(void)
struct block_device {
struct list_head bd_hash;
atomic_t bd_count;
/* struct address_space bd_data; */
dev_t bd_dev; /* not a kdev_t - it's a search key */
atomic_t bd_openers;
const struct block_device_operations *bd_op;
struct semaphore bd_sem; /* open/close mutex */
};

4)block dev 的其他杂项操作
int check_disk_change(kdev_t dev)
const struct block_device_operations * get_blkfops(unsigned int major)
5) internal function & misc
init_once: for mem cache obj init
hash: for bdget
static struct block_device *bdfind(dev_t dev, struct list_head *head) : for bdget
int get_blkdev_list(char * p) :一个块设备的列表
const char * bdevname(kdev_t dev)

这个文件出现了几个有关block device的结构,并且名字也类似,真是够乱的:
第一类是把块设备虚拟成文件的接口函数:struct file_operations def_blk_fops。第二类是块设备的操作和名字:数组 blkdevs struct block_device_operations *bdops;还有一类是block_device 的操作函数:也包含了block_device_operations *bd_op,呵呵有点意思。这个block_device的作用是嘛?搜索一下bdget可以看出些端倪: devfs_read_inode 和 init_special_inode 把结构block_device 注册到inode 中。这样看来这个结构是block dev到普通文件系统的一个桥梁。devfs和普通文件系统中的dev文件就记录这个东西。而def_blk_fops通过block_device成为打开的设备文件的操作函数,够绕!看看init_special_inodevoid就明白了。
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))
inode->i_fop = &bad_sock_fops;
else
printk(KERN_DEBUG "init_special_inode: bogus imode (%o)\n", mode);
}

而blkdev_get 和 blkdev_put 则绕过了文件系统本身,通过虚拟一个文件来带开和释放一个块设备。比较典型的应用是get_sb_bdev和mount_root:在这些情景下通过open打开一个块设备是很不对头的:这些情景下不对这个块设备进行read 和open操作,而是通过具体的文件系统如 ext2 再通过ll_rw_block来读写块设备。(还是绕)

当直接打开一个块设备(比如 dd)时是通过这个文件提供的def_blk_fops的几个接口把块设备虚拟成一个无结构的扇区序列来进行操作。(参考 init_special_inode)。

至于这个文件的具体函数,则不是那么难以理解。值得一读以前分析的file_map.c 这个文件,回顾一下buffer cache 和page cache 的区别与联系。
ssize_t block_write(struct file * filp, const char * buf,
size_t count, loff_t *ppos)
ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
这两个函数实现对设备文件的读写,从其调用的分配缓冲区的函数 getblk看过去,就知道,直接dd一个设备的话其缓存于buffer cache。 而以前分析filemap。c 的时候知道,普通文件的内容缓存于page cache,普通文件的元数据缓存于buffer cache。
值得注意的是,先前注册到inode中的i_bdev (block_device),并没有在文件的读写过程中发挥什么作用,去搜索i_bdev就可以理解这个inode中的block_device仅仅是为了open, close这个相关的块设备文件而已。真正有用的是inode->i_rdev,init_special_inode中当然也没有忘记初始
化这个变量。
读写块设备文件,主要的工作是把文件的以byte为单位的(start_pos,len)转换为blk size为单位的读写单元,然后一个工作就是缓存,设备文件的读写靠的是buffer cache。 到分析buffer.c的时候再说罢。

static loff_t block_llseek(struct file *file, loff_t offset, int origin) 没啥说的。

static int block_fsync(struct file *filp, struct dentry *dentry, int datasync)
{
return fsync_dev(dentry->d_inode->i_rdev);
}
注意到 fsync_dev
int fsync_dev(kdev_t dev)
{
sync_buffers(dev, 0);

lock_kernel();
sync_supers(dev);
sync_inodes(dev);
DQUOT_SYNC(dev);
unlock_kernel();

return sync_buffers(dev, 1);
}
注意这是对我们分析的一个印证,和一个设备相关的所有数据缓冲:
1)dev相关的buffer cache(以(dev,block)为索引),含有像dd这种应用的缓存:sync_buffers,和普通文件的元数据
2)sync_supers(dev); 设备的super block
3)sync_inodes(dev); sync设备上所有inode(可能是在不同的sb中)的所有文件数据(包括filemap的数据)。(还包括inode本身,inode也算是文件的元数据,但是inode本身没有在buffer cache中,因为inode不仅仅是一个磁盘上的数据影像,他需要进行转换。见mark_inode_dirty,和inode 的分配释放函数,参考inode.c. sync_supers 道理相同。

剩下的函数真的不用多说了。。。。

end。

相关阅读 更多 +
排行榜 更多 +
房间毁灭模拟器最新版

房间毁灭模拟器最新版

休闲益智 下载
街头追逐者最新版

街头追逐者最新版

休闲益智 下载
弓箭手2内置作弊菜单

弓箭手2内置作弊菜单

休闲益智 下载