2012年(44)
分类: LINUX
2012-08-08 17:22:03
2010-07-21 21:36:59| 分类: arm linux设备驱 | 标签: |字号大中小
在文件block_dev.c中定义并实现了一个块设备文件操作函数集:
const struct file_operations def_blk_fops = {
.open = blkdev_open,
.release = blkdev_close,
.llseek = block_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write_nolock,
.mmap = generic_file_mmap,
.fsync = block_fsync,
.unlocked_ioctl = block_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_blkdev_ioctl,
#endif
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
};
操作函数集def_blk_fops中的函数又都是通过调用另一个函数集def_blk_aops来实现数据的传递的。这个函数集也是在文件block_dev.c中定义并实现的。
static const struct address_space_operations def_blk_aops = {
.readpage = blkdev_readpage,
.writepage = blkdev_writepage,
.sync_page = block_sync_page,
.write_begin = blkdev_write_begin,
.write_end = blkdev_write_end,
.writepages = generic_writepages,
.releasepage = blkdev_releasepage,
.direct_IO = blkdev_direct_IO,
};
/******************************************************************/
/******************************************************************/
/******************************************************************/
/******************************************************************/
一,块设备文件的打开
文件的打开是通过函数 blkdev_open来实现的,在该函数中调用了一些函数,这些函数有调用另一些函数,这样一层一层的进行了很多层调用。在此我们从最里层向外看。
//该函数即是对一个刚分配的inode结构进行初始化
struct inode *inode_init_always(struct super_block *sb, struct inode *inode)
{
static const struct address_space_operations empty_aops;
static struct inode_operations empty_iops;
static const struct file_operations empty_fops;
//指针mapping指向inode->i_data
struct address_space *const mapping = &inode->i_data;
inode->i_sb = sb;
inode->i_blkbits = sb->s_blocksize_bits;
inode->i_flags = 0;
atomic_set(&inode->i_count, 1);
。
。
。
mapping_set_gfp_mask(mapping, GFP_HIGHUSER_MOVABLE);
mapping->assoc_mapping = NULL;
mapping->backing_dev_info = &default_backing_dev_info;
mapping->writeback_index = 0;
。
。
。
inode->i_private = NULL;
//由于指针 mapping指向的是inode->i_data,
//所以inode->i_mapping也指向了inode->i_data,这一点很重要。
//在上层函数中对inode->i_data的改变也就是对inode->i_mapping的改变,
//在上层函数中会通过inode->i_mapping来调用它们所指向的对象,通过
//改变inode->i_dat来改变inode->i_mapping指向的对象。
inode->i_mapping = mapping;
return inode;
out_free_security:
security_inode_free(inode);
out_free_inode:
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
kmem_cache_free(inode_cachep, (inode));
return NULL;
}
/*****************************************************************************/
static struct inode *alloc_inode(struct super_block *sb)
{
struct inode *inode;
if (sb->s_op->alloc_inode)
inode = sb->s_op->alloc_inode(sb);
Else//分配一个inode 结构体
inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL);
/********************************************/
if (inode)//初始化该结构体
return inode_init_always(sb, inode);
/********************************************/
return NULL;
}
/*****************************************************************************/
//获取一个新的inode结构体并初始化一些字段
static struct inode *get_new_inode(struct super_block *sb,
struct hlist_head *head,
int (*test)(struct inode *, void *),
int (*set)(struct inode *, void *),
void *data)
{
struct inode *inode;
/********************************************/
inode = alloc_inode(sb);
/********************************************/
if (inode) {
。
。
。
}
return inode;
set_failed:
spin_unlock(&inode_lock);
destroy_inode(inode);
return NULL;
}
/*****************************************************************************/
struct inode *iget5_locked(struct super_block *sb, unsigned long hashval,
int (*test)(struct inode *, void *),
int (*set)(struct inode *, void *), void *data)
{
struct hlist_head *head = inode_hashtable + hash(sb, hashval);
struct inode *inode;
inode = ifind(sb, head, test, data, 1);
if (inode)
return inode;
/********************************************/
// 如果在inode cache中没找到就从新分配一个。
return get_new_inode(sb, head, test, set, data);
/********************************************/
}
/*****************************************************************************/
struct block_device *bdget(dev_t dev)
{
struct block_device *bdev;
struct inode *inode;
/********************************************/
inode = iget5_locked(blockdev_superblock, hash(dev),
bdev_test, bdev_set, &dev);
/********************************************/
if (!inode)
return NULL;
bdev = &BDEV_I(inode)->bdev;
if (inode->i_state & I_NEW) {
bdev->bd_inode = inode;//记住此处的指向关系
。
。
。
inode->i_rdev = dev;
inode->i_bdev = bdev;
/*
结构体def_blk_aops即是在文件block_dev.c中实现的操作函数集。
在inode结构刚分配进行初始化时,在初始化函数inode_init_always中
将inode->i_mapping 指向了inode->i_data,对指向了inode->i_data
的改变即是对inode->i_mapping的改变。
此时inode->i_mapping.a_ops也指向了操作函数集def_blk_aops。
*/
inode->i_data.a_ops = &def_blk_aops;
。
。
。
inode->i_data.backing_dev_info = &default_backing_dev_info;
}
return bdev;
}
/*****************************************************************************/
static struct block_device *bd_acquire(struct inode *inode)
{
struct block_device *bdev;
spin_lock(&bdev_lock);
bdev = inode->i_bdev;
spin_unlock(&bdev_lock);
/********************************************/
bdev = bdget(inode->i_rdev);
/********************************************/
if (bdev) {
spin_lock(&bdev_lock);
if (!inode->i_bdev) {
atomic_inc(&bdev->bd_inode->i_count);
inode->i_bdev = bdev;
//在函数 bdget(inode->i_rdev)中将bdev->bd_inode->i_mapping指向了def_blk_aops。
//此处即是让inode->i_mapping指向操作函数集def_blk_aops。
inode->i_mapping = bdev->bd_inode->i_mapping;
list_add(&inode->i_devices, &bdev->bd_inodes);
}
spin_unlock(&bdev_lock);
}
return bdev;
}
/*****************************************************************************/
//总算轮到函数blkdev_open了!!!
static int blkdev_open(struct inode * inode, struct file * filp)
{
struct block_device *bdev;
int res;
。
。
。
/********************************************/
bdev = bd_acquire(inode);
/********************************************/
/*
bdev->bd_inode->i_mapping指向了def_blk_aops的表述有误,但是结构体def_blk_aops使我们最关心的,展示了这么多层函数调用就是为了寻找它的踪迹。准确的说应该是
filp->f_mapping.a_ops指向了def_blk_aops但是mapping的踪迹也就是def_blk_aops的踪迹。
*/
//在函数 bdget(inode->i_rdev)中将bdev->bd_inode->i_mapping指向了def_blk_aops。
//到现在总算让inode->i_mapping指向了操作函数集def_blk_aops。以后我们就可以
//通过filp->f_mapping.a_ops 来调用操作函数def_blk_aops了。
filp->f_mapping = bdev->bd_inode->i_mapping;
res = blkdev_get(bdev, filp->f_mode);
if (res)
return res;
if (filp->f_mode & FMODE_EXCL) {
res = bd_claim(bdev, filp);
if (res)
goto out_blkdev_put;
}
return 0;
out_blkdev_put:
blkdev_put(bdev, filp->f_mode);
return res;
}
最后在函数blkdev_get(bdev, filp->f_mode)的多层调用下实现了块设备的打开。
bdev->bd_disk->fops->open(bdev, mode);