linux mtd 块设备,MTD块设备的数据读取

本文详细介绍了Linux MTD(Memory Technology Device)块设备的数据读取过程,包括同步读do_sync_read和异步读generic_file_aio_read。讲解了从页缓存到磁盘读取的流程,涉及页缓存、预读、异步读取等机制,并深入到块设备的读取函数,如block_read_full_page和submit_bh,展示了数据请求如何通过请求队列和I/O调度器进行处理。
摘要由CSDN通过智能技术生成

二,数据读取

数据读取分为同步读do_sync_read和异步读generic_file_aio_read。

它们的区别是同步读,要等数据读取结束函数才返回,异步读是在函数返回时数据读取可能还没结束。同步读是通过调用异步读取函数加等待函数实现的。

ssize_t

generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,

unsigned long nr_segs, loff_t pos)

{

struct file *filp = iocb->ki_filp;

ssize_t retval;

unsigned long seg;

size_t count;

loff_t *ppos = &iocb->ki_pos;

count = 0;

//检测用于存放将要读取数据的存储空间是否有效,

//此处是VERIFY_WRITE是因为读取的数据将要写入这些内存中。

retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);

if (retval)

return retval;

/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */

/*

将磁盘上的数据缓存在内存中,加速文件的读写。实际上,在一般情况下,read/write是只跟缓存打交道的。(当然,存在特殊情况。下面会说到。)read就直接从缓存读数据。如果要读的数据还不在缓存中,则触发一次读盘操作,然后等待磁盘上的数据被更新到磁盘高速缓存中;write也是直接写到缓存里去,然后就不用管了。后续内核会负责将数据写回磁盘。

如果定义了O_DIRECT:直接传送数据`绕过了页高速缓存

*/

if (filp->f_flags & O_DIRECT) {

}

for (seg = 0; seg

read_descriptor_t desc;

//read_descriptor_t:读操作描述符`用来记录读的状态

desc.written = 0;

desc.arg.buf = iov[seg].iov_base;

desc.count = iov[seg].iov_len;

if (desc.count == 0)

continue;

desc.error = 0;

//将读取请求向下层函数发送

do_generic_file_read(filp, ppos, &desc, file_read_actor);

retval += desc.written;

if (desc.error) {

retval = retval ?: desc.error;

break;

}

if (desc.count > 0)

break;

}

out:

return retval;

}

/*****************************************************************************/

在看函数do_generic_file_read前有必要先看看函数file_read_actor。

int file_read_actor(read_descriptor_t *desc, struct page *page,

unsigned long offset, unsigned long size)

{

//大部分时间读写操作即是对缓存的读写,如果在缓存中找到了要读写的数据块则直接拷贝

//到用户空间。

left = __copy_to_user(desc->arg.buf, kaddr + offset, size);

}

/*****************************************************************************/

static void do_generic_file_read(struct file *filp, loff_t *ppos,

read_descriptor_t *desc, read_actor_t actor)

{

struct address_space *mapping = filp->f_mapping;

struct inode *inode = mapping->host;

struct file_ra_state *ra = &filp->f_ra;

pgoff_t index;

pgoff_t last_index;

pgoff_t prev_index;

unsigned long offset;      /* offset into pagecache page */

unsigned int prev_offset;

int error;

//找到页面的偏移量。即确定是存储在那个存面中

index = *ppos >> PAGE_CACHE_SHIFT;

prev_index = ra->prev_pos >> PAGE_CACHE_SHIFT;

prev_offset = ra->prev_pos & (PAGE_CACHE_SIZE-1);//获取页内偏移

//计算要读取数据在存储空间中的最后页面索引号

last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;

offset = *ppos & ~PAGE_CACHE_MASK;

for (;;) {

struct page *page;

pgoff_t end_index;

loff_t isize;

unsigned long nr, ret;

//检查当前进程是否设置了重新调度标志`如果有`调用schdule()重新调度一次

cond_resched();

find_page:

//寻找当前位置对应的缓存页

page = find_get_page(mapping, index);

if (!page) {

//没有找到对应的缓存页,说明在页缓存区中不存在此页面对应的缓存页page_cache_sync_readahead(mapping,

ra, filp,

index, last_index - index);

page = find_get_page(mapping, index);

if (unlikely(page == NULL))

goto no_cached_page;

}

if (PageReadahead(page)) {

//文件预读

page_cache_async_readahead(mapping,

ra, filp,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值