linux mtd 块设备,MTD块设备的打开过程

在文件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);