Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1043609
  • 博文数量: 244
  • 博客积分: 6820
  • 博客等级: 准将
  • 技术积分: 3020
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-09 21:33
文章分类

全部博文(244)

文章存档

2013年(1)

2012年(16)

2011年(132)

2010年(3)

2009年(12)

2008年(80)

我的朋友

分类: LINUX

2011-04-15 18:05:47

一、与回写有关参数

在/proc/sys/vm/中所有的文件如下所示,其中有一部分是和页面回收相关的,我先分析页面回写机制,然后分析这些变量对回写的影响。

-rw-r--r-- 1 root root 0 Mar 31 23:54 block_dump
-rw-r--r-- 1 root root 0 Mar 31 23:54 dirty_background_ratio
-rw-r--r-- 1 root root 0 Mar 31 23:54 dirty_expire_centisecs
-rw-r--r-- 1 root root 0 Mar 31 23:54 dirty_ratio
-rw-r--r-- 1 root root 0 Mar 31 23:54 dirty_writeback_centisecs
-rw-r--r-- 1 root root 0 Mar 31 23:54 drop_caches
-rw-r--r-- 1 root root 0 Mar 31 23:54 hugetlb_shm_group
-rw-r--r-- 1 root root 0 Mar 31 23:54 laptop_mode
-rw-r--r-- 1 root root 0 Mar 31 23:54 legacy_va_layout
-rw-r--r-- 1 root root 0 Mar 31 23:54 lowmem_reserve_ratio
-rw-r--r-- 1 root root 0 Mar 31 23:54 max_map_count
-rw-r--r-- 1 root root 0 Mar 31 23:54 min_free_kbytes
-rw-r--r-- 1 root root 0 Mar 31 23:54 min_unmapped_ratio
-rw-r--r-- 1 root root 0 Mar 31 23:54 nr_hugepages
-r--r--r-- 1 root root 0 Mar 31 23:54 nr_pdflush_threads
-rw-r--r-- 1 root root 0 Mar 31 23:54 overcommit_memory
-rw-r--r-- 1 root root 0 Mar 31 23:54 overcommit_ratio
-rw-r--r-- 1 root root 0 Mar 31 23:54 page-cluster
-rw-r--r-- 1 root root 0 Mar 31 23:54 panic_on_oom
-rw-r--r-- 1 root root 0 Mar 31 23:54 percpu_pagelist_fraction
-rw-r--r-- 1 root root 0 Mar 31 23:54 swappiness
-rw-r--r-- 1 root root 0 Mar 31 23:54 swap_token_timeout
-rw-r--r-- 1 root root 0 Mar 31 23:54 vfs_cache_pressure
-rw-r--r-- 1 root root 0 Mar 31 23:54 zone_reclaim_mode

    在mm/pag_writeback.c文件中,找到了如下内容,注释表明这就是那些导出到/proc中的参数。

/* The following parameters are exported via /proc/sys/vm */
//下列参数将导出到/proc/sys/vm目录中
/*
 * Start background writeback (via pdflush) at this percentage
 */
//脏背景阈值。在这个百分比的情况下启动background 回写
//指的是回调函数为background_writeout()的pdflush进程
int dirty_background_ratio = 10;

/*
 * The generator of dirty data starts writeback at this percentage
 */
//这句不知道怎么翻译
int vm_dirty_ratio = 40;

/*
 * The interval between `kupdate'-style writebacks, in jiffies
 */
//以jiffies为单位的,kupdate类型的回写的间隔时间
int dirty_writeback_interval = 5 * HZ;

/*
 * The longest number of jiffies for which data is allowed to remain dirty
 */
//数据允许为脏状态的最长时间(以jiffies为单位)
int dirty_expire_interval = 30 * HZ;

/*
 * Flag that makes the machine dump writes/reads and block dirtyings.
 */
//不知道
int block_dump;

/*
 * Flag that puts the machine in "laptop mode". Doubles as a timeout in jiffies:
 * a full sync is triggered after this time elapses without any disk activity.
 */
//膝上电脑模式
int laptop_mode;

EXPORT_SYMBOL(laptop_mode);

/* End of sysctl-exported parameters */

对这些源代码总结如下表所示:

dirty_background_ratio
 背景阈值,脏页比例达到这个比例时,wakeup_pdflush()被调用
 
vm_dirty_ratio
 阈值
 
dirty_writeback_interval
 kupdate类型的回写的间隔时间
 
dirty_expire_interval
 数据允许为脏状态的最长时间
 
block_dump
 
 
laptop_mode
 膝上电脑模式(为节电,而减少回写)
 

   
这些变量依次与/proc/sys/vm/目录中的dirty_background_ratio、dirty_ratio、dirty_writeback_centisecs、dirty_expire_centisecs、block_dump、laptop_mode。此外文件nr_pdflush_threads和nr_pdflush_threads(pdflush线程数)相关。
有些变量和文件的名字不一致,不过不要紧,先看看文件kernel/sysctl.c中的内容:

{
.ctl_name = VM_DIRTY_BACKGROUND,
.procname = "dirty_background_ratio",
.data = &dirty_background_ratio,
.maxlen = sizeof(dirty_background_ratio),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = &zero,
.extra2 = &one_hundred,
},
{
.ctl_name = VM_DIRTY_RATIO,
.procname = "dirty_ratio",
.data = &vm_dirty_ratio,
.maxlen = sizeof(vm_dirty_ratio),
.mode = 0644,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = &zero,
.extra2 = &one_hundred,
},
{
.ctl_name = VM_DIRTY_WB_CS,
.procname = "dirty_writeback_centisecs",
.data = &dirty_writeback_interval,
.maxlen = sizeof(dirty_writeback_interval),
.mode = 0644,
.proc_handler = &dirty_writeback_centisecs_handler,
},
{
.ctl_name = VM_DIRTY_EXPIRE_CS,
.procname = "dirty_expire_centisecs",
.data = &dirty_expire_interval,
.maxlen = sizeof(dirty_expire_interval),
.mode = 0644,
.proc_handler = &proc_dointvec_userhz_jiffies,
},
{
.ctl_name = VM_NR_PDFLUSH_THREADS,
.procname = "nr_pdflush_threads",
.data = &nr_pdflush_threads,
.maxlen = sizeof nr_pdflush_threads,
.mode = 0444 /* read-only*/,
.proc_handler = &proc_dointvec,
},
……
{
.ctl_name = VM_LAPTOP_MODE,
.procname = "laptop_mode",
.data = &laptop_mode,
.maxlen = sizeof(laptop_mode),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
{
.ctl_name = VM_BLOCK_DUMP,
.procname = "block_dump",
.data = &block_dump,
.maxlen = sizeof(block_dump),
.mode = 0644,
.proc_handler = &proc_dointvec,
.strategy = &sysctl_intvec,
.extra1 = &zero,
},

结构定义在文件include/linux/sysctl.h中

struct ctl_table
{
int ctl_name; /* Binary ID */
const char *procname; /* Text ID for /proc/sys, or zero */
void *data;
int maxlen;
mode_t mode;
ctl_table *child;
proc_handler *proc_handler; /* Callback for text formatting */
ctl_handler *strategy; /* Callback function for all r/w */
struct proc_dir_entry *de; /* /proc control block */
void *extra1;
void *extra2;
};


将其总结如下:
procname
 data
 mode
 proc_handler
 
dirty_background_ratio
 dirty_background_ratio
 0644
 proc_dointvec_minmax
 
dirty_ratio
 vm_dirty_ratio
 0644
 sproc_dointvec_minmax
 
dirty_writeback_centisecs
 dirty_writeback_interval
 0644
 dirty_writeback_centisecs_handler
 
dirty_expire_centisecs
 dirty_expire_interval
 0644
 proc_dointvec_userhz_jiffies
 
nr_pdflush_threads
 nr_pdflush_threads
 0444
 proc_dointvec
 
laptop_mode
 laptop_mode
 0644
 proc_dointvec_jiffies
 
block_dump
 block_dump
 0644
 proc_dointvec
 

 


二、定时回写 wb_kupdate()

在系统启动的过程中,start_kernel()函数会调用page_writeback_init()函数,在这个函数中首先要计算出下次启动计时器的时间。page_writeback_init()的代码如下:

/*
 * If the machine has a large highmem:lowmem ratio then scale back the default
 * dirty memory thresholds: allowing too much dirty highmem pins an excessive
 * number of buffer_heads.
 */
//如果机器中的 highmem:lowmem的比例较高,则缩减默认的脏页阈值

void __init page_writeback_init(void)
{
//nr_free_buffer_pages()得到ZONE_DMA和ZONE_NORMAL中的空闲内存数
//源代码中的注释为:Amount of free RAM allocatable within ZONE_DMA and ZONE_NORMAL
long buffer_pages = nr_free_buffer_pages();
long correction;

//nr_free_pagecache_pages()得到所有的空闲页面数
//源码中的注释为:Amount of free RAM allocatable within all zones
total_pages = nr_free_pagecache_pages();

//计算“调节因子”
correction = (100 * 4 * buffer_pages) / total_pages;

//如果correction < 100,则buffer_pages小于total_pages的1/4
if (correction < 100) {
//重置脏页的背景阈值和阈值,使其变小
dirty_background_ratio *= correction;
dirty_background_ratio /= 100;
vm_dirty_ratio *= correction;
vm_dirty_ratio /= 100;

if (dirty_background_ratio <= 0)
dirty_background_ratio = 1;
if (vm_dirty_ratio <= 0)
vm_dirty_ratio = 1;
}
//设置定时器的启动时间是dirty_writeback_interval之后
mod_timer(&wb_timer, jiffies + dirty_writeback_interval);
set_ratelimit();
register_cpu_notifier(&ratelimit_nb);
}
   
通过代码,我们可以发现page_writeback_init()根据ZONE_DMA和ZONE_LOW中空闲页和系统中所有空闲页的比例可能会重置dirty_background_ratio和vm_dirty_ratio,对于时间间隔dirty_writeback_interval没做修改。

对于wb_timer,有static DEFINE_TIMER(wb_timer, wb_timer_fn, 0, 0),即超时回调函数为wb_timer_fn。wb_timer_fn()函数定义在mm/page-writeback,c中,整个函数就只有一个if语句:

if (pdflush_operation(wb_kupdate, 0) < 0)
mod_timer(&wb_timer, jiffies + HZ); /* delay 1 second */

    调用pdflush_operation()来激活空闲的pdflush线程,如果返回值为小于0,即如果失败,则1s后再次调用wb_timer_fn()

于是,我们终于看到pdflush_operation()函数了,它完成的工作就是"wake up a pdflush thread, and get it to do some work for you","find a worker thread, and passed your payload to it",即唤醒一个pdflush线程,并设置其回调函数fn,让它执行预想的工作。
整个函数大体的流程是:先从pdflush_list链表中获得一个pdflush_work描述符,然后给描述符中的fn赋值,将其赋为wb_kupdate(),最后调用wake_up_process()函数唤醒一个pdflush线程。
   
pdflush线程对应于函数pdflush(),而pdflush()将调用__pdflush(),__pdflush()函数首先将自己的线程置入睡眠状态,等待唤醒。唤醒后,它调用回调函数fn完成具体的工作,之后根据系统策略创建新的pdflush线程、结束线程或继续睡眠。
在这个函数中,会用到nr_pdflush_threads变量,不过它只不过是用来和MAX_PDFLUSH_THREADS(8)、MAX_PDFLUSH_THREADS(2)来比较,以辅助确定是否创建新的pdflush线程等,从而实现机制:"If there have been no idle pdflush instances for 1 second, create a new one.","If the least-recently-went-to-sleep pdflush thread has been asleep for more than one second, terminate a thread."

接下来,转入正题wb_kupdate(),它的函数调用关系如下:

wb_kupdate()
|-- sync_supers()
|-- writeback_inodes()
|  |-- sync_sb_inodes()
|  |  |-- __writeback_single_inode()
|  |  |  |-- __sync_single_inode()
|  |  |  |  |-- do_writepages()
|-- mod_timer()


wb_kupdate()函数先调用sync_supers()将脏的超级块回刷到磁盘,再计算出要回刷的页面数,之后循环调用writeback_inodes()进行回刷工作,每次回刷时最大页面数为MAX_WRITEBACK_PAGES(即1024),当要回刷的页都完成时结束循环。
在这个函数有如下三条赋值语句:

oldest_jif = jiffies - dirty_expire_interval;
start_jif = jiffies;
next_jif = start_jif + dirty_writeback_interval;

oldest_jif、start_jif、next_jif分别是需要回刷的脏页的最晚时间(默认为30s之前)、当前时间、下次回刷的时间(默认为5s之后)。oldest_jif会赋给writeback_control结构wbc的older_than_this字段,即回刷上次回刷之前变脏的脏页。
对于next_jif,在mod_timer之前会有如下if语句:

if (time_before(next_jif, jiffies + HZ))
next_jif = jiffies + HZ;
if (dirty_writeback_interval)
mod_timer(&wb_timer, next_jif);
   
由此可见,如果原定的next_jif比1s之后早,则下次启动定时器的时间为1s后,之后如果dirty_writeback_interval不为0,则重启定时器。补充一点的是:在代码中没有找到对dirty_writeback_interval赋值的语句。


writeback_inodes()用来进行回刷工作,它遍历超级块链表,对于sb->s_dirty或sb->s_io链表不为空的超级块,调用函数sync_sb_inodes()处理该超级块的所有节点。

sync_sb_inodes()将该超级块sb->s_dirty队列中的索引节点都放入sb->s_io链表中,然后遍历sb->s_io链表,循环处理链表中各个索引节点。
如果wbc->older_than_this不为0,则不处理在此之后变脏的索引节点;如果当前线程是pdflush,则在处理索引节点前测试并设置BDI_pdflush,因为可能会有另一个线程在处理这个索引节点;调用__writeback_single_inode()回写与索引节点有关的脏页,之后入股当前线程是pdflush,则清除BDI_pdflush位。每处理完一个索引节点后,都会调用cond_resched()函数。


__writebace_single_inode()前面几行语句用来处理inode已经被上锁的情况,最后一句是最关键的: return __sync_single_inode()。


__sync_single_inode()函数调用do_writepages()将一个inode对应的mapping中的页回写到磁盘,之后根据情况,将inode节点移入sb->s_dirty、inode_in_use或inode_unused链表。

通过这些分析,我们了解了定时回写页高速缓存的机制。wb_kupdate()涉及到的/pooc/sys/vm中的变量dirty_background_ratio、vm_dirty_ratio、dirty_expire_interval、dirty_writeback_interval。pdflush线程自己会用到nr_pdflush_threads。


三、回写 background_writeout()

 3.1wakeup_pdflush

  3.1.1 回写流程
     wakeup_pdflush()函数在nr_page参数为0的情况下,大致计算出系统中的脏页总数(nr_pages = global_page_state(NR_FILE_DIRTY) +global_page_state(NR_UNSTABLE_NFS),再调用pdflush_operation()唤醒一个pdflush线程,设置其回调函数为background_writeout(),而nr_pages则赋给pdflush_work结构的arg0字段。
background_writeout()的结构比较简单,就是多次调用writeback_inodes()函数,试图每次写1024个脏页,直到min_pages个page已经被写完,且系统中脏页小于阈值。

/*
 * writeback at least _min_pages, and keep writing until the amount of dirty
 * memory is less than the background threshold, or until we're all clean.
 */
static void background_writeout(unsigned long _min_pages)
{
long min_pages = _min_pages;
struct writeback_control wbc = {
.bdi = NULL,
.sync_mode = WB_SYNC_NONE,
.older_than_this = NULL,
.nr_to_write = 0,
.nonblocking = 1,
.range_cyclic = 1,
};

for ( ; ; ) {
//背景阈值?
long background_thresh;
//脏页阈值?
long dirty_thresh;

//获取背景阈值和脏页阈值
get_dirty_limits(&background_thresh, &dirty_thresh, NULL);
//要求要写的页写完了,且系统中脏页小于背景阈值,则停止循环
if (global_page_state(NR_FILE_DIRTY) +
global_page_state(NR_UNSTABLE_NFS) < background_thresh
&& min_pages <= 0)
break;
wbc.encountered_congestion = 0;
wbc.nr_to_write = MAX_WRITEBACK_PAGES; //1024
wbc.pages_skipped = 0;
//尝试写1024个脏页
writeback_inodes(&wbc);
min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
//如果页没有写完或跳过了某页,则请求队列可能拥塞
if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
/* Wrote less than expected */
//睡眠
blk_congestion_wait(WRITE, HZ/10);
//这个if的用意是什么?
if (!wbc.encountered_congestion)
break;
}
}
}

在上面的代码中,通过get_dirty_limits()函数对现有的脏页背景阈值和脏阈值进行调整,其代码如下:

//计算出未映射的页面的比例
//NR_FILE_MAPPED是映射的,NR_ANON_PAGES是匿名映射
unmapped_ratio = 100 - ((global_page_state(NR_FILE_MAPPED) +
global_page_state(NR_ANON_PAGES)) * 100) /
total_pages;

//脏阈值
dirty_ratio = vm_dirty_ratio;
//脏阈值不大于未映射页比例的1/2
if (dirty_ratio > unmapped_ratio / 2)
dirty_ratio = unmapped_ratio / 2;

//脏阈值不能小于5%
if (dirty_ratio < 5)
dirty_ratio = 5;

//脏背景阈值
background_ratio = dirty_background_ratio;
//脏背景阈值不大于脏阈值
if (background_ratio >= dirty_ratio)
background_ratio = dirty_ratio / 2;

//脏背景阈值页数 脏阈值页数
background = (background_ratio * available_memory) / 100;
dirty = (dirty_ratio * available_memory) / 100;
tsk = current;
//如果当前进程是释放内存的进程 或 是实时进程 则增加脏背景阈值 和 脏阈值
if (tsk->flags & PF_LESS_THROTTLE || rt_task(tsk)) {
background += background / 4;
dirty += dirty / 4;
}

由此可得,background_writeout()函数借助dirty_background_ratio和vm_dirty_ratio变量来确定回写后脏页应该小于的比例background_ratio。

  3.1.2 回写时机
定时回写的回写时机不需多说。
wakeup_pdflush()会被do_sync()、try_to_free_pages()、free_more_memory()调用,do_sync()与现实的系统调用有关,就不多说了。
try_to_free_pages()会被free_more_memory()、__alloc_pages()调用。
free_more_memory()会被alloc_page_buffers()、__getblk_slow()调用。

现在要做的就是通过这些函数,了解wakeup_pdflush()被调用的“高层语义”。受限于内存管理和回收页框方面的知识,现在还不能进行详细的分析:
1、alloc_page_buffers()
这个函数用来为一个页分配缓冲区首部,以形成缓冲区页,其中会调用alloc_buffer_head来为每个缓冲区首部分配内存,如果buffer_head分配失败,则会调用free_more_memory()释放出一些内存,然后再重新尝试。

2、__getblk_slow()
    __getblk_slow()在调用grow_buffers()失败时调用free_more_memory()函数。

3、__alloc_pages()
函数用来分配内存页,当空闲内存实在太少,调用try_to_free_pages进行内存回收.。
   
free_more_memory()和try_to_free_pages()都会在内存不够时被调用,他们都会唤醒一个pdflush线程,将页高速缓存中的页写回磁盘,使得包含页高速缓存、缓冲区首部等数据结构的页框变成可释放的。

 3.2balance_dirty_pages_ratelimited
通过调用pdflush_operation()函数激活background_writeout()函数进行回写的地方,除了在wakeup_pdflush()中有一处之外,在balance_dirty_pages()中又有一处。通过这个函数追溯到了balance_dirty_pages_ratelimited()。

  3.2.1回写流程
balance_dirty_pages_ratelimited()函数只是balance_dirty_pages_ratelimited_nr()的简单封装。

balance_dirty_pages_ratelimited_nr(mapping, 1);

balance_dirty_pages_ratelimited_nr()在当前的cpu产生速率脏页的速率超过ratelimit的情况下调用balance_dirty_pages()。相关代码如下:

//ratelimit_pages 默认值是32
//After a CPU has dirtied this many pages, balance_dirty_pages_ratelimited
//will look to see if it needs to force writeback or throttling.
ratelimit = ratelimit_pages;
//当系统中的脏页超过阈值时,dirty_exceeded被置位
//如果dirty_exceeded被置位,那么ratelimit将大大减小
//防止进程以32为限定,而使得脏页产生速率过度的超出
if (dirty_exceeded)
ratelimit = 8;

/*
 * Check the rate limiting. Also, we do not want to throttle real-time
 * tasks in balance_dirty_pages(). Period.
 */
preempt_disable();
p =  &__get_cpu_var(ratelimits);
*p += nr_pages_dirtied;
//如果超出速率限制则调用balance_dirty_pages()
if (unlikely(*p >= ratelimit)) {
*p = 0;
preempt_enable();
balance_dirty_pages(mapping);
return;
}
preempt_enable();

balance_dirty_pages()函数会先从正在写的页面所对应的inode所属的文件系统的脏页中回写ratelimit_page + ratelimit_page / 2页(默认48页),之后如果检查系统中的脏页大于阈值,则唤醒一个回调函数为background_writeout()的pdflush线程。相关代码如下:

//每次尝试写nr_to_write页
//如果写后脏页量小于阈值 或 这次写了nr_to_write(48)页 则退出循环
if (nr_reclaimable) {
writeback_inodes(&wbc);
get_dirty_limits(&background_thresh,
  &dirty_thresh, mapping);
nr_reclaimable = global_page_state(NR_FILE_DIRTY) +
global_page_state(NR_UNSTABLE_NFS);
if (nr_reclaimable +
global_page_state(NR_WRITEBACK)
<= dirty_thresh)
break;
pages_written += write_chunk - wbc.nr_to_write;
if (pages_written >= write_chunk)
break; /* We've done our duty */
}
……
//如果是laptop_mode,则趁此回写系统的脏页
//如果不是laptop_mode模式,则在脏页超过脏背景阈值时,启动pdflush线程进行回刷
if ((laptop_mode && pages_written) ||
     (!laptop_mode && (nr_reclaimable > background_thresh)))
pdflush_operation(background_writeout, 0);

这里出现了laptop_mode变量,它对回刷的影响很明显,laptop_mode && pages_written条件中的pages_written在调用writeback_inodes()函数后脏页还较多的情况就会被赋值,于是系统抓住这个机会开始回写。

  3.2.2回写时机
对于函数balance_dirty_pages_ratelimited_nr(),源代码的注释为''Processes which are dirtying memory should call in here once for each page which was newly dirtied. "使页变脏的所有写缓存的操作都要调用balance_dirty_pages_ratelimited_nr()。然后,如上所说就会检查要不要刷与索引节点相关的文件系统的脏页和要不要回刷系统的脏页。

balance_dirty_pages_ratelimited_nr()函数会被三个函数调用,这些函数是:reiserfs_file_write()、balance_dirty_page_ratelimited()、sys_msync(),其中sys_msync()与系统调用有关,reiserfs_file_write()与reiserfs文件系统相关,对此没有做分析。
balance_dirty_page_ratelimited()函数的调用有5处,3处和ntfs有关,1处事在pipe_to_file()中调用,还有一处就是generic_file_buffered_write()。
generic_file_buffered_write()是通用的文件系统对磁盘进行些操作时要调用的函数,它写完缓存后,就会调用balance_dirty_page_ratelimited()。

四、参数对回刷的影响
从上面的分析来讲,dirty_background_ratio和vm_dirty_ratio可以影响回刷时脏页的比例,但系统对它也会做一些调整;dirty_writeback_centisecs会影响定时回刷的时间间隔,但是系统对回刷的时间间隔也会有所调整,此外如果dirty_writeback_centisecs为0,则会停止定时回刷;dirty_expire_centisecs函数是页允许保存脏状态的最长时间,系统在使用时没有对其做修改。

除了直观的影响之外,还可以看下相应的回调函数。ctl_table结构中,proc_handler是读写数据处理的回调函数,该函数处理数据的输入和输出,它在通过/proc文件系统读写数据时被使用。对应于每个参数有:

procname
 proc_handler
 
dirty_background_ratio
 proc_dointvec_minmax
 
dirty_ratio
 sproc_dointvec_minmax
 
dirty_writeback_centisecs
 dirty_writeback_centisecs_handler
 
dirty_expire_centisecs
 proc_dointvec_userhz_jiffies
 
nr_pdflush_threads
 proc_dointvec
 
laptop_mode
 proc_dointvec_jiffies
 
block_dump
 proc_dointvec
 

   
对于nr_pdflush_threads,它是只读的,就不多说了。
函数proc_dointvec_minmax()、proc_dointvec_userhz_jiffies()、proc_dointvec()、proc_dointvec_jiffies()都是通用的函数,在写入后没有特别的处理。
需要注意的是dirty_writeback_centisecs和dirty_expire_centisecs中时间间隔的单位是1/USER_HZ秒(USER_HZ为100,而HZ=CONFIG_HZ,在配置文件.config中CONFIG_HZ=250),函数proc_dointvec_userhz_jiffies()会对其进行转化。
proc_dointvec_minmax()会对写入的数据进行调整,使之在ctl_table结构的.extra1和.extra2之间,对于dirty_background_ratio和dirty_ratio这两个值分别是zero和one_hundred。

dirty_writeback_centisecs_handler()函数在写入数据后,会根据新的dirty_writeback_interval重新启动定时器,如果dirty_writeback_interval是0的话,则关闭定时器,即禁止定时回刷机制。


对于block_dump和laptop_mode对回写的影响,暂时还没有看见,于是用"cs f s XXX"进行查找。

对于block_dump,用到这个变量的地方有两个:submit_bio和__mark_inode_dirty()。个人理解是:如果设置了block_dump,则会输出一些信息。
在submit_bio()中相关代码如下:
if (unlikely(block_dump)) {
char b[BDEVNAME_SIZE];
printk(KERN_DEBUG "%s(%d): %s block %Lu on %s\n",
current->comm, current->pid,
(rw & WRITE) ? "WRITE" : "READ",
(unsigned long long)bio->bi_sector,
bdevname(bio->bi_bdev,b));
}
在__mark_inode_dirty()中相关代码如下:
if (unlikely(block_dump)) {
struct dentry *dentry = NULL;
const char *name = "?";

if (!list_empty(&inode->i_dentry)) {
dentry = list_entry(inode->i_dentry.next,
    struct dentry, d_alias);
if (dentry && dentry->d_name.name)
name = (const char *) dentry->d_name.name;
}

if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev"))
printk(KERN_DEBUG
       "%s(%d): dirtied inode %lu (%s) on %s\n",
       current->comm, current->pid, inode->i_ino,
       name, inode->i_sb->s_id);
}

对于laptop_mode,用到这个变量的地方有七处:end_that_request_last()、do_sync()、xfs_fs_sync_super()、balance_dirty_pages()、laptop_io_completion()、try_to_free_pages()、balance_pgdat()。


发表于 @ 2010年04月06日 15:25:00 | 评论( 0 ) | 编辑| 举报| 收藏

旧一篇:【转】Ramdisk | 新一篇:2010-4-13 pdflush 之 balance_dirty_pages_ratelimited 之ratelimit_pages
-
查看最新精华文章 请访问博客首页相关文章
apache服务器配置全攻略Linux用户(User)和用户组管理概述(二)Kernel Module with /proc/sys support关于APACHE的配置文件httpd.conf[转贴]文档权限:setgid, setuid, sticky查看文件和目录:ls软连接与硬连接2010-4-13 pdflush 之 balance_dirty_pages_ratelimited 之ratelimit_pages发表评论表 情:          评论内容: 用 户 名:登录 注册 匿名评论 匿名用户验 证 码:  重新获得验证码
  专区推荐内容VS2010 SharePoint 入门
Flex4 新特性
【免费下载】WebMatrix建站工具
AIX 专区有奖话题讨论
4.21日Adobe企业RIA开发者研讨会
MeeGo中文社区全新呈现
<<>> 热门招聘职位【Amazon】亚马逊诚聘技术专家!
【趣游北京】高薪诚聘C++高级工程师/工程师 AS3工程师
【华夏纬讯】高薪诚聘C#程序员
【航天信息股份有限公司】诚聘系统架构,需求分析、JAVA开发、C/C++开发研发岗位热招中
【可得眼镜网】诚聘网站技术开发工程师、UED、DBA以及美工设计
这可能是你从未见过的技术人员招聘广告!
【上海东方久信集团】招聘.NET软件工程师
【杭州引力】高薪诚聘ios开发人员
【群硕软件】诚聘优秀IT人才(.Net,Java, Android etc)
【推博网】诚聘PHP/VC/MYSQLDBA/UI/WEB设计等职位
【北京盛安怡和公司】招聘Windows C/C++,php等人员
【PDE】游戏公司诚聘程序员
荷兰互联网公司诚聘Web(Rails)开发工程师
【重庆大龙网】高薪诚聘中高级软件工程师
美资高薪诚聘软件开发及数据库人才
【新迪数字】高薪诚聘JAVA项目软件架构师、JAVA项目主管!!
【尚品网】诚招软件开发工程师
【UniQlick】【8K-12K】急招Java工程师、技术工程师、数据分析师
【 CSDN】高薪诚聘:java、运营、就业、商务策划经理、网站编辑!
【武汉亨通科技】高薪诚聘项目经理、高级软件工程师,邀您加盟!
【careerfocus】科锐福克斯猎头公司强悍猎聘IT人才!
【沃尔玛中国】信息系统部急聘IT英才(上海,深圳)!!!
【融资城】投融资平台高薪诚聘技术总监、产品经理等
【搜狐公司】海量技术职位火热招聘中!
【Amazon】亚马逊诚聘技术专家!
【趣游北京】高薪诚聘C++高级工程师/工程师 AS3工程师
【华夏纬讯】高薪诚聘C#程序员
【航天信息股份有限公司】诚聘系统架构,需求分析、JAVA开发、C/C++开发研发岗位热招中
【可得眼镜网】诚聘网站技术开发工程师、UED、DBA以及美工设计
这可能是你从未见过的技术人员招聘广告!
【上海东方久信集团】招聘.NET软件工程师
【杭州引力】高薪诚聘ios开发人员
【群硕软件】诚聘优秀IT人才(.Net,Java, Android etc)
【推博网】诚聘PHP/VC/MYSQLDBA/UI/WEB设计等职位
【北京盛安怡和公司】招聘Windows C/C++,php等人员
【PDE】游戏公司诚聘程序员
荷兰互联网公司诚聘Web(Rails)开发工程师
【重庆大龙网】高薪诚聘中高级软件工程师
美资高薪诚聘软件开发及数据库人才
【新迪数字】高薪诚聘JAVA项目软件架构师、JAVA项目主管!!
【尚品网】诚招软件开发工程师
【UniQlick】【8K-12K】急招Java工程师、技术工程师、数据分析师
【 CSDN】高薪诚聘:java、运营、就业、商务策划经理、网站编辑!
【武汉亨通科技】高薪诚聘项目经理、高级软件工程师,邀您加盟!
【careerfocus】科锐福克斯猎头公司强悍猎聘IT人才!
【沃尔玛中国】信息系统部急聘IT英才(上海,深圳)!!!
【融资城】投融资平台高薪诚聘技术总监、产品经理等
【搜狐公司】海量技术职位火热招聘中!
. 公司简介|招贤纳士|广告服务|银行汇款帐号|联系方式|版权声明|法律顾问|问题报告
北京创新乐知信息技术有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
江苏乐知网络技术有限公司 提供商务支持
 Email:webmaster@csdn.net
Copyright © 1999-2010, CSDN.NET, All Rights Reserved
 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yangp01/archive/2010/04/06/5454822.aspx

阅读(1258) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~