本文主要参考《深入理解Linux内核》,结合2.6.11.1版的内核代码,分析内核文件子系统中的打开设备文件函数,梳理了关于内核块设备文件打开的处理流程。
注意:
1、不描述内核同步、错误处理相关的内容
2、参考信息除具体说明外,包含在《深入理解Linux内核》第三版中
3、源码摘自Linux内核2.6.11.1版
1、open_bdev_excl
函数功能:
打开设备名为path的块设备,返回块设备描述符的地址
函数参数:
Path:块设备文件的路径名(如:/dev/sda1);
Flags:mount系统调用的的flag参数
Holder: 指向类型为file_system_type的文件系统类型对象的指针
函数源码及处理流程:
struct block_device*open_bdev_excl(const char *path, int flags, void *holder)
{
structblock_device *bdev;
mode_tmode = FMODE_READ;
interror = 0;
bdev= lookup_bdev(path);
if(IS_ERR(bdev))
returnbdev;
if(!(flags & MS_RDONLY))
mode|= FMODE_WRITE;
error= blkdev_get(bdev, mode, 0);
if(error)
returnERR_PTR(error);
error= -EACCES;
if(!(flags & MS_RDONLY) && bdev_read_only(bdev))
gotoblkdev_put;
error= bd_claim(bdev, holder);
if(error)
gotoblkdev_put;
returnbdev;
blkdev_put:
blkdev_put(bdev);
returnERR_PTR(error);
}
函数处理流程:
1、调用lookup_bdev函数,根据设备文件名path,查找或分配一个block_device对象,地址存入局部变量bdev中
2、根据flags参数设置文件系统权限为只读(FMODE_READ)或读写(FMODE_READ| FMODE_WRITE)
3、调用blkdev_get函数,初始化bdev中和分区、磁盘相关的数据,参见后面分析
4、调用bd_claim函数,更新bdev对象和其包含对象的持有者信息
2、lookup_bdev
函数功能:
打开或查找设备名为path的块设备。
函数参数:
略
函数源码:
/**
* lookup_bdev - lookup a struct block_device by name
*
* @path: specialfile representing the block device
*
* Get a reference to the blockdevice at @pathin the current
* namespace if possible and return it. Return ERR_PTR(error)
* otherwise.
*/
struct block_device *lookup_bdev(constchar *path)
{
structblock_device *bdev;
structinode *inode;
structnameidata nd;
interror;
if(!path || !*path)
returnERR_PTR(-EINVAL);
error= path_lookup(path, LOOKUP_FOLLOW, &nd);
if(error)
returnERR_PTR(error);
inode= nd.dentry->d_inode;
error= -ENOTBLK;
if(!S_ISBLK(inode->i_mode))
gotofail;
error= -EACCES;
if(nd.mnt->mnt_flags & MNT_NODEV)
gotofail;
error= -ENOMEM;
bdev= bd_acquire(inode);
if(!bdev)
gotofail;
out:
path_release(&nd);
returnbdev;
fail:
bdev= ERR_PTR(error);
gotoout;
}
函数处理流程:
1、调用path_lookup函数(参见p495“路径名查找”),查找块设备文件名对应的nameidata对象并存入nd局部变量中,设备文件对应的节点对象地址存入inode类型的inode局部变量中
2、调用bd_acquire函数,打开或查找设备文件名为path的块设备,返回块设备描述符
3、blkdev_get
函数功能:
初始化块设备描述符中和分区、磁盘相关的字段
函数参数:
略
函数源码:
int blkdev_get(struct block_device*bdev, mode_t mode, unsigned flags)
{
/*
* This crockload is due to bad choice of->open() type.
* It will go away.
* For now, block device ->open() routinemust _not_
* examine anything in 'inode' argument except->i_rdev.
*/
structfile fake_file = {};
structdentry fake_dentry = {};
fake_file.f_mode= mode;
fake_file.f_flags= flags;
fake_file.f_dentry= &fake_dentry;
fake_dentry.d_inode= bdev->bd_inode;
returndo_open(bdev, &fake_file);
}
static int do