首页 > 编程知识 正文

shell脚本延时,cron表达式每分钟执行一次

时间:2023-05-06 19:52:13 阅读:106630 作者:4488

1 .背景:

嵌入式设备写SD卡时,偶尔会调用write卡顿、内核linux-3.4.y

2. linux内核io进程

1.APP应用程序调用write,咬入内核并执行vfs_write函数,将数据写入页面缓存。 每个缓存页面都包含几个缓冲区。 在写入之前需要

[1]检查页面是否正在回写,如果正在回写,则挂起进程,启动进程直到回写标志被清除

[2]检查页面buffer是否锁定,如果是锁定的,则挂起进程并等待唤醒

2 .内核具有驻留线程,为每个bdi创建线程,定期检查是否需要回写,必要时提交bio向sd卡写入驱动程序

3.bio结束时执行回调,清除页面返回标志

3 .相关函数分析(记录主要函数,便于跟踪源代码) )。

3.1写页面缓存

3.1.1重要结构:

conststructfile _ operations fat _ 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=fat_file_release,

. unlocked _ ioctl=fat _ generic _ ioctl,

#ifdef CONFIG_COMPAT

.com pat _ ioctl=fat _ generic _ compat _ ioctl,

#endif

. fsync=fat_file_fsync,

. splice _ read=generic _ file _ splice _ read,

(;

struct address _ space _ operations {

int(*writepage ) ) struct page *page,struct writeback_control *wbc;

int(*readpage ) ) struct file *,struct page *;

int(sync_page ) (结构页* );

int(*writepages ) (struct address_space *,struct writeback_control * );

int(set_page_dirty ) ) struct page *page );

int(*readpages ) ) struct file *filp,struct address_space *mapping,

struct list_head *pages,unsigned nr_pages;

int(*write_begin ) ) struct file *,struct address_space *mapping,

loff_t pos,unsigned len,unsigned flags,

struct page **pagep,void **fsdata;

int ) write_end(structfile*,struct address_space *mapping,

loff_t pos,unsigned len,unsigned copied,

struct page *page,void *fsdata;

sector_t(*bmap ) ) struct address_space *,sector_t;

int(*invalidatepage ) (struct page *,unsigned long );

int(*releasepage ) (结构页*,int );

void(*freepage ) (结构页* );

size_t(direct_io ) int、struct kiocb *、const struct iovec *iov、

loff_t offset,unsigned long nr_segs;

struct page * * get _ xip _ page (struct address _ space *,sector_t,

int;

/* migratethecontentsofapagetothespecifiedtarget * /

int(*migratepage ) (structpage *,struct page );

int(*launder_page ) (

struct page *);

int (*error_remove_page) (struct mapping *mapping, struct page *page);

int (*swap_activate)(struct file *);

int (*swap_deactivate)(struct file *);

};

3.1.2 函数调用流程:

vfs_write-->

do_sync_write-->

f_op->aio_write(generic_file_aio_write)-->(mm/filemap.c)

__generic_file_aio_write-->

generic_file_buffered_write-->

generic_perform_write-->(重要函数)

a_ops->write_begin(block_write_begin)-->(fs/buffer.c)主要耗时在下面两个函数

grab_cache_page_write_begin-->

wait_on_page_writeback-->(申请到页之后,如果改页正在被回写,需要挂起当前进程,等待回写之后的唤醒)(主要耗时)

__block_write_begin

wait_on_buffer-->(为页分配缓冲区,如果申请的缓冲区加了锁,挂起进程,等待解锁后唤醒)(次要耗时)

static inline void wait_on_buffer(struct buffer_head *bh)

{

might_sleep();

if (buffer_locked(bh))

__wait_on_buffer(bh);

}

3.1.3 参考资料:

https://www.cnblogs.com/children/p/3420430.html

https://www.jianshu.com/p/d33ec2707e7f

http://blog.chinaunix.net/uid-14528823-id-4289180.html

https://my.oschina.net/u/2475751/blog/535859

https://blog.csdn.net/wh8_2011/article/details/51787282

https://www.cnblogs.com/honpey/p/4931962.html

https://blog.csdn.net/ctoday/article/details/37966233

3.2 内核回写线程:

3.2.1 函数分析

linux3.2之后,内核中有一个常驻内存的线程bdi_forker_thread,负责为bdi_object创建bdi_writeback_thread线程,同时检测如果bdi_writeback_thread线程长时间处于空闲状态,便会将其销毁。

bdi_writeback_thread线程在fs/fs-writeback.c中,它在一个while循环中检查是否需要回写,然后执行调度函数等待唤醒。内核每隔固定时间唤醒该线程,这个时间可以查看文件/proc/sys/vm/dirty_writeback_centisecs。

bdi_writeback_thread调用wb_do_writeback函数进行回写

wb_do_writeback处理bdi-work_list需要回写的work,同时也从两个方面检查有没有页高速缓存需要回写,一是有没有脏页存在过长的时间,而是脏页比例是否达到了设置的上限,相应的文件为/proc/sys/vm/dirty_expire_centisecs和/proc/sys/vm/dirty_background_ratio

wb_do_writeback-->

wb_writeback-->

writeback_sb_inodes-->

writeback_single_inode-->

do_writepages-->(mm/page-writeback.c)

mapping->a_ops->writepages-->

fat32注册的mapping->a_ops->writepages即为fat_writepages(fs/fat/inode.c),fat_writepages调用mpage_writepages(fs/mpage.c), mpage_writepages调用__mpage_writepage

【copy】--------------------------------------

_mpage_writepage函数是写文件的核心接口。代码大致流程如下:如果page有buffer_head,则完成磁盘映射,代码只支持所有page都被设为脏页的写,除非没有设为脏页的page放到文件的尾部,即要求page设置脏页的连续性。如果page没有buffer_head,在接口中所有page被设为脏页。如果所有的block都是连续的则直接进入bio请求流程,否则重新回到writepage的映射流程。

用page_has_buffers判断当前page是否有buffer_head(bh),如果有则用page_buffers将当前page转换为buffer_head的bh指针,之后用bh->b_this_page遍历当前page的所有bh,调用buffer_locked(bh)加锁buffer——head,即使出现一个bh没有被映射都会进入confused流程,first_unmapped记录了第一个没有映射的bh,除了要保证所有的bh都被映射,还要保证所有的bh都被置为脏页并且完成了uptodate。如果每个page的block数不为0(通过判断first_unmapped是否非0),则直接进入当前page已经被映射的流程page_is_mapped,否则进入confused流程。

如果当前page没有buffer_head(bh),需要将当前page映射到磁盘上,使用buffer_head变量map_bh封装,做buffer_head和bio之间的转换。

page_is_mapped流程中如果有bio资源并且检测到当前的页面和前面一个页面的磁盘块号不连续(代码对应bio && mpd->last_block_in_bio != blocks[0] – 1,blocks[0]表示第一个磁盘块),则用mpage_bio_submit来提交一个积累bio请求,将之前的连续block写到设备中。否则进入alloc_new流程。

alloc_new流程中,判断bio为空(表示前面刚刚提交了一个bio)则需要用mpage_alloc重新申请一个bio资源,之后用bio_add_page向bio中添加当前page,如果bio中的长度不能容纳下这次添加page的整个长度,则先将添加到bio上的数据提交bio请求mpage_bio_submit,剩下的数据重新进入到alloc_new流程做bio的申请操作。如果一次性将page中的所有数据全部添加到bio上,在page有buffer的情况下要将所有的buffer全部清除脏页位。用set_page_writeback设置该page为写回状态,给page解锁(unlock_page)。当bh的boundary被设置或者当前页面和前面一个页面的磁盘块号不连续,就先提交一个累积连续block的bio。否则说明当前page中的所有block都是连续的,并且与之前的page中block也是连续的,这种情况下不需要提交bio,只更新前面一个页面的磁盘块号mpd->last_block_in_bio为当前page的最后一个block号,之后退出进行下一个page的连续性检查,直到碰到不连续的再做bio提交。

confused流程中会提交bio操作,但是会设置映射错误。

【end】----------------------------------------

总之,__mpage_writepage函数调用mpage_end_io提交bio,驱动将脏页写入sd卡,这个过程中对页进行保护。bio完成后执行回调bio->bi_end_io = mpage_end_io,清除页的writeback标志

3.2.2 参考资料:

https://blog.csdn.net/asmxpl/article/details/21548129

http://blog.sina.com.cn/s/blog_6f5549150102vaoz.html

http://blog.chinaunix.net/uid-7494944-id-3833328.html

https://blog.csdn.net/zhufengtianya/article/details/42145985

4. 补充

[1]

buffer head的lock和unlock目前还没有分析

[2]

我们调用write函数写页高速缓存的时候,检查页的writeback标志,如果正在回写,就挂起进程等待唤醒,就write函数阻塞了;bio执行结束后调用回调清除页的writeback标志,应用程序被唤醒。

之前说过内核每隔固定时间(/proc/sys/vm/dirty_writeback_centisecs)做一次回写检查,一般当脏页比例达到/proc/sys/vm/dirty_background_ratio就进行回写。我们同时减小这个两个参数的值,发现bio消耗时间的峰值减低了

dirty_writeback_centisecs(s) dirty_background_ratio(%) bio_max_time(ms)

5 10 6000

2 5 4800

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。