在开始阐述exfat的fread过程时,先推荐一盘linux的read的博客( http://blog.csdn.net/guopeixin/article/details/5962489),我从这篇文章中学习到很多东西,以便我快速的掌握exfat read流程。
exfat的read过程,跟VFS的generanel的read过程完全一致,在开源代码中只是对VFS的标准函数进行了封装而已。具体如下:
exfat read函数的层次模型
目前exfat文件系统只分析到Block Layer。
exfat文件系统的read发起点是系统标准函数fread,fread调用系统API函数sys_read,sys_read函数再调用vfs_read,vfs_read函数再调用file->f_op->read()。
而file->f_op->read()实际上就是具体的文件系统向通用Block层注册的一个函数指针。
exfat文件系统在填充inode的时候初始化对应节点的相关操作,具体如下代码
static int exfat_fill_inode(struct inode *inode, FILE_ID_T *fid)
{
struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
FS_INFO_T *p_fs = &(sbi->fs_info);
DIR_ENTRY_T info;
memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(FILE_ID_T));
FsReadStat(inode, &info);
EXFAT_I(inode)->i_pos = 0;
EXFAT_I(inode)->target = NULL;
inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid;
inode->i_version++;
inode->i_generation = get_seconds();
if (info.Attr & ATTR_SUBDIR) { /* directory */
inode->i_generation &= ~1;
inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO);
inode->i_op = &exfat_dir_inode_operations;
inode->i_fop = &exfat_dir_operations;
i_size_write(inode, info.Size);
EXFAT_I(inode)->mmu_private = i_size_read(inode);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00)
set_nlink(inode, info.NumSubdirs);
#else
inode->i_nlink = info.NumSubdirs;
#endif
} else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */
inode->i_generation |= 1;
inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO);
inode->i_op = &exfat_symlink_inode_operations;
i_size_write(inode, info.Size);
EXFAT_I(inode)->mmu_private = i_size_read(inode);
} else { /* regular file */
inode->i_generation |= 1;
inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO);
inode->i_op = &exfat_file_inode_operations;
inode->i_fop = &exfat_file_operations;
inode->i_mapping->a_ops = &exfat_aops; //注册页面缓冲的一些接口
inode->i_mapping->nrpages = 0;
i_size_write(inode, info.Size);
EXFAT_I(inode)->mmu_private = i_size_read(inode);
}
exfat_save_attr(inode, info.Attr);
inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1))
& ~((loff_t)p_fs->cluster_size - 1)) >> 9;
exfat_time_fat2unix(sbi, &inode->i_mtime, &info.ModifyTimestamp);
exfat_time_fat2unix(sbi, &inode->i_ctime, &info.CreateTimestamp);
exfat_time_fat2unix(sbi, &inode->i_atime, &info.AccessTimestamp);
return 0;
}
从上面的函数看可以发现,exfat创建inode的时候就针对不同的inode(directory, symbolic link,file)初始化了不同的控制。对于file read(fread),我们重点关注相关控制函数的注册和具体实现,代码如下
inode->i_fop = &exfat_file_operations;
inode->i_mapping->a_ops = &exfat_aops; //注册页面缓冲的一些接口
const struct file_operations exfat_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.release = exfat_file_release,
.unlocked_ioctl = exfat_generic_ioctl,
.fsync = generic_file_fsync,
.splice_read = generic_file_splice_read,
};
const struct address_space_operations exfat_aops = {
.readpage = exfat_readpage,
.readpages = exfat_readpages,
.writepage = exfat_writepage,
.writepages = exfat_writepages,
.write_begin = exfat_write_begin,
.write_end = exfat_write_end,
.direct_IO = exfat_direct_IO,
.bmap = _exfat_bmap
};
控制流程图如下:
流程图中mapping->a_ops->readpage(filp, page)实际上是执行exfat_aops.readpage,即exfat_readpage。
exfat_readpag的函数就是调用mpage_readpage函数,函数如下:
static int exfat_readpage(struct file *file, struct page *page)
{
int ret;
ret = mpage_readpage(page, exfat_get_block);
return ret;
}
static int exfat_readpages(struct file *file, struct address_space *mapping,
struct list_head *pages, unsigned nr_pages)
{
int ret;
ret = mpage_readpages(mapping, pages, nr_pages, exfat_get_block);
return ret;
}
static int exfat_writepage(struct page *page, struct writeback_control *wbc)
{
int ret;
ret = block_write_full_page(page, exfat_get_block, wbc);
return ret;
}
static int exfat_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
int ret;
ret = mpage_writepages(mapping, wbc, exfat_get_block);
return ret;
}
exfat_readpage的控制流程图如下:
到此,exfat文件系统read完成向block设备请求disk mapping,并提交get_block操作。
分析至此,exfat完成了read driver控制,并把控制权交给block driver
linux文件读写参考博客http://blog.chinaunix.net/uid-22111121-id-2678792.html说明