内核日记
前些天读“linux内核源代码情景分析”(毛德操),觉得开始写得还不错,后面的讲解过于细节,让人不能从整体上有个把握(看了几本国内写的内核的书,好象都是给几段编码,加点注解)。我感觉,即然内核也是一个软件,就应该以软件工程的方法去理解它。用软件工程设计方法当然是:需求,总体设计,详细设计,编码等等。我想老毛的书基本在编码讲解层次上,让人不能有一种宏观把握的清晰思路。我感觉要读懂源码,应该首先从总体上理解,即弄明白设计理念,其次才是具体的编码理解。所以我这两天转向从总体上把握它。现在在读
<深入理解linux内核>,它写得很好,我已读了中断异常,时钟中断,进程几章,它把中断异常,时钟中断设计的思路讲得非常清楚,我推荐大家读一下此书。
我有个问题还没想太清楚,请大家指点:
一个进程要进入TASK_INTERRUPTIBLE OR TASK_UNINTERRUPTIBLE状态,这应该具备什么条件,及如何唤醒(能不能醒就看进程能不能被放入就绪队列)?
这个问题我想了又想,觉得:
进程要睡觉有自愿和被迫两种
自愿,主要是调sleep_on()等,他们的唤醒靠挂在定时器上的函数,此函数会把相应的睡眠进程放入就绪队列,从而唤醒了进程。
被迫方式主要是因为等待事件。等待事件我理解为等待某信号量可用,当内核函数帮进程检查某信号量是否可用时,若发现不可用,内核函数就会把进程挂到等待队列中(信号量的队列中,好象挂到信号量的队列中便没必要挂到等待队列中,只要不让进程挂到运行队列便可),不让进程被调度。当某进程释放信号量指示的资源或发出某事件时,它会调用类似的PV操作的V操作函数,此V操作函数会把等待进程放入就绪队列,从而唤醒了进程。
这便是我对进程睡觉和被唤醒的理解,不知正确于否?欢迎发表你读内核的感受。
相互交流,共同进步
<深入理解linux内核>,它写得很好,我已读了中断异常,时钟中断,进程几章,它把中断异常,时钟中断设计的思路讲得非常清楚,我推荐大家读一下此书。
我有个问题还没想太清楚,请大家指点:
一个进程要进入TASK_INTERRUPTIBLE OR TASK_UNINTERRUPTIBLE状态,这应该具备什么条件,及如何唤醒(能不能醒就看进程能不能被放入就绪队列)?
这个问题我想了又想,觉得:
进程要睡觉有自愿和被迫两种
自愿,主要是调sleep_on()等,他们的唤醒靠挂在定时器上的函数,此函数会把相应的睡眠进程放入就绪队列,从而唤醒了进程。
被迫方式主要是因为等待事件。等待事件我理解为等待某信号量可用,当内核函数帮进程检查某信号量是否可用时,若发现不可用,内核函数就会把进程挂到等待队列中(信号量的队列中,好象挂到信号量的队列中便没必要挂到等待队列中,只要不让进程挂到运行队列便可),不让进程被调度。当某进程释放信号量指示的资源或发出某事件时,它会调用类似的PV操作的V操作函数,此V操作函数会把等待进程放入就绪队列,从而唤醒了进程。
这便是我对进程睡觉和被唤醒的理解,不知正确于否?欢迎发表你读内核的感受。
相互交流,共同进步
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
跟踪进程如何查被跟踪进程的内存数据?
首先声明一下,本人一不小心把贴子发错位置了,放到了“内核源代码学习”,所以我在这里又放了一份。
所以你若回贴,请回到内核日记里。很是抱歉。
今日日记:
我想再问一个问题:
进入TASK_INT..,TASK_UNINT..的是不是都必须处在某个等待队列中?
我的理解是:有的进程进入睡眠态根本不挂入等待队列,
理由是:比如定时睡眠(内核函数为:sleep_on_timeout(),
interruptible_sleep_on_timeout()),这些函数会为进程申请一个动态定时器,然后把定时器的data域设成进程的PID,这样当定时器到时,便会把进程唤醒,这就没有用到等待队列。
不知理解正确于否,欢迎指正。
今天看了信号量机制和内存管理(buddy算法和slab分配器,还有点问题,不过等看完再提),还有就是跟踪系统调用。
我想就跟踪再提个问题:
硬件对跟踪提供了两种机制:eflags的IF标志,调试寄存器组
linux在进程控制表中提供:PF_TRACESYS标志用来中断系统调用
(不知还有没有别的方式?)
当A进程被B进程跟踪时,B则为A的父进程(这点应该没有问题吧),若此时A遇上断点被中断,它会进入TASK_STOPPED状态,B会收到一个SIGCHLD信号,从而被唤醒当B运行时,它会检查A的状态,无外乎是看 B的硬件上下文,B的某内存数据,或B的进程控制表中能体现的所有信息。(还会不会看别的什么?)
我现在想问:B通过系统调用要求看这些信息时,内核如何服务?
我把我的想法写出,欢迎补充指正:
1。B要看A的寄存器和进程控制表中能体现的所有信息,内核只需从进程控制表中提取便可。
2。B要看内存某内存数据,则应该给系统调用传地址参数,内核就必须想法找到
A的地址空间中找到此数据,如何找呢?(这是问题的关键) 我想内核会利用A的页全局目录,采用计算方法找此数据的物理地址,然后利用内核的内存的固定映射方法得到在A空间的线性地址(此地址>3G),然后就可以访问到此数据。
不知我的理解是否正确?
所以你若回贴,请回到内核日记里。很是抱歉。
今日日记:
我想再问一个问题:
进入TASK_INT..,TASK_UNINT..的是不是都必须处在某个等待队列中?
我的理解是:有的进程进入睡眠态根本不挂入等待队列,
理由是:比如定时睡眠(内核函数为:sleep_on_timeout(),
interruptible_sleep_on_timeout()),这些函数会为进程申请一个动态定时器,然后把定时器的data域设成进程的PID,这样当定时器到时,便会把进程唤醒,这就没有用到等待队列。
不知理解正确于否,欢迎指正。
今天看了信号量机制和内存管理(buddy算法和slab分配器,还有点问题,不过等看完再提),还有就是跟踪系统调用。
我想就跟踪再提个问题:
硬件对跟踪提供了两种机制:eflags的IF标志,调试寄存器组
linux在进程控制表中提供:PF_TRACESYS标志用来中断系统调用
(不知还有没有别的方式?)
当A进程被B进程跟踪时,B则为A的父进程(这点应该没有问题吧),若此时A遇上断点被中断,它会进入TASK_STOPPED状态,B会收到一个SIGCHLD信号,从而被唤醒当B运行时,它会检查A的状态,无外乎是看 B的硬件上下文,B的某内存数据,或B的进程控制表中能体现的所有信息。(还会不会看别的什么?)
我现在想问:B通过系统调用要求看这些信息时,内核如何服务?
我把我的想法写出,欢迎补充指正:
1。B要看A的寄存器和进程控制表中能体现的所有信息,内核只需从进程控制表中提取便可。
2。B要看内存某内存数据,则应该给系统调用传地址参数,内核就必须想法找到
A的地址空间中找到此数据,如何找呢?(这是问题的关键) 我想内核会利用A的页全局目录,采用计算方法找此数据的物理地址,然后利用内核的内存的固定映射方法得到在A空间的线性地址(此地址>3G),然后就可以访问到此数据。
不知我的理解是否正确?
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
2003.04.19读核日记:
2003.04.19读核日记:
今天看内存管理,深感知识面不够! 在内存管理的3个主要数据结构:BUDDY算法,SLAB分配器,vm_area分块,其中slab最难理解。 现在有一点不太明白,提出来请大家指点: kmalloc,vmalloc,malloc有什么区别? 内核通过buddy对大块物理内存进行管理,通过slab分配器对零碎的数据结构提供 分配服务,这样内核所需的内存无论大块小块都有函数可用了。 那用户进程的内存空间如何管理?内核通过vm_area_struct技术实现用户线性空间大块内存分配,比如:代码区,数据区,堆区,栈区。我现在想问,当进程需要小块内存时,由谁来管理?我知道,一般用户通过malloc来分配零碎的内存。 但malloc通过什么方法来对得到零碎内存,是通过系统调用,还是不用系统调用?我查了系统调用,好象没有相应的系统调用,我又没有发现内核为用户空间的零碎内存管理提供任何算法。所以我怀疑malloc没有用系统调用,可不用系统调用它又用什么方法来实现呢?我想了以想,觉得若malloc不用系统调用,则它必须自己来管理,即它必须自己建立一个管理数据结构,那又用什么数据结构呢,最简单的方法就是用链把已分配的零碎块串起来,复杂一点的话也可仿slab来管理。 不知大家谁对malloc的分配机理清楚?若大家谁有C库源码,不妨共享一下。 对了,还有一个问题? 对库如何实现反汇编? __________________ 宝剑锋从磨砺出,梅花香自苦寒来 | |
![]() |
再问malloc
brk只能修改堆栈的大小,或着说是边界,而且它是以页为单位。
malloc肯定要利用brk,但是malloc必须实现页内的小对象的管理,必须在页内一小块一小块的割内存.而这是brk无法胜任的
所以我怀颖malloc要自己实现小对象的管理。
不过我还没证实。我已下载到C库的源码,不过可能一时半会还看不懂。
malloc肯定要利用brk,但是malloc必须实现页内的小对象的管理,必须在页内一小块一小块的割内存.而这是brk无法胜任的
所以我怀颖malloc要自己实现小对象的管理。
不过我还没证实。我已下载到C库的源码,不过可能一时半会还看不懂。
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
2003.04.20读核日记--未来LINUX架构随想
2003.04.20读核日记--未来LINUX架构随想
今日浏览了一下VFS,对它的设计思想很是佩服。它实现的思路我的理解就如
PCI插槽,插上不同的独立设计的具体文件系统,便可扩展功能。
所以与其说VFS是一个通用文件系统的接口,不如说它是一个技术规范。
通过这种规范,可实现不同的软件的无缝对接。
再联想到POSIX,不也是OS设计的规范吗,所以我想,会不会有一天能把linux
的各部分之间也设计能用规范相联,就如同组装PC机一样。不过,令人心慰的是
VFS已经实现了文件系统与具体文件系统的规范。我想下一步应该把内存管理也设计成规范,linux其它部分只通过标准的函数接口就能完成从物理内存分配,回收
,进程空间的管理,还有缓冲的管理。说到缓冲的管理,我想linux内核的缓冲主要有两大类:一是固定对象的分配回收的缓冲(或叫缓冲池),如通过SLAB进行的小对象分配机制。二是高速缓冲,如磁盘块的预读管理,页面的老化等。应该把这两种缓冲管理也标准化。 说不定到那时,我们也可象设计具体文件系统那样把内存管理单独设计成一个模块,然后不用重编内核,就可以把原内存管理模块通过如INS_MM_MODE的函数换成自己设计的内存管理模块。我都想过了,在替换时,要实现旧新工作的交接,即要把旧模块的数据记录转换给新模块,以使新模块重绘内核内存图景。我们的目标:LINUX要傻瓜式组装,将有许多内存管理,进程管理,文件系统的插件可选,以适应自己具体情况的需要。
不过目前的目标:好好读核,不要空谈。(这两天学习有点冒进的苗头,书光想住后翻)
希望大家也在此谈谈你们的读核经验,以让象我这样的棒槌少走点弯路。
今日浏览了一下VFS,对它的设计思想很是佩服。它实现的思路我的理解就如
PCI插槽,插上不同的独立设计的具体文件系统,便可扩展功能。
所以与其说VFS是一个通用文件系统的接口,不如说它是一个技术规范。
通过这种规范,可实现不同的软件的无缝对接。
再联想到POSIX,不也是OS设计的规范吗,所以我想,会不会有一天能把linux
的各部分之间也设计能用规范相联,就如同组装PC机一样。不过,令人心慰的是
VFS已经实现了文件系统与具体文件系统的规范。我想下一步应该把内存管理也设计成规范,linux其它部分只通过标准的函数接口就能完成从物理内存分配,回收
,进程空间的管理,还有缓冲的管理。说到缓冲的管理,我想linux内核的缓冲主要有两大类:一是固定对象的分配回收的缓冲(或叫缓冲池),如通过SLAB进行的小对象分配机制。二是高速缓冲,如磁盘块的预读管理,页面的老化等。应该把这两种缓冲管理也标准化。 说不定到那时,我们也可象设计具体文件系统那样把内存管理单独设计成一个模块,然后不用重编内核,就可以把原内存管理模块通过如INS_MM_MODE的函数换成自己设计的内存管理模块。我都想过了,在替换时,要实现旧新工作的交接,即要把旧模块的数据记录转换给新模块,以使新模块重绘内核内存图景。我们的目标:LINUX要傻瓜式组装,将有许多内存管理,进程管理,文件系统的插件可选,以适应自己具体情况的需要。
不过目前的目标:好好读核,不要空谈。(这两天学习有点冒进的苗头,书光想住后翻)
希望大家也在此谈谈你们的读核经验,以让象我这样的棒槌少走点弯路。
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
2003.04.21读核日记--发现linux在初始化BUDDY算法的数据结构时很低效
今日读BUDDY内存分配算法,算法确实很不错,但LINUX在初始化BUDDY算法的数据结构时很低效。
我先打个比喻:给你一个大碗,里面装满了大米,现在让你大米转移到
另一个碗里,你是把米从一个碗直接倒到另一个碗里,还是把米一粒一粒从一个碗放到另一个碗里?答案是明确的,直接倒。
而linux在初始化BUDDY算法的数据结构时却选择了类似把米从一个碗一粒一粒放到另一个碗里方法。
好了,看看系统是如何初始化BUDDY算法的数据结构的。
BUDDY在回收页面时一般用free_pages(),free_page(),它们都要实现伙伴的合并。而且最多9-order次合并。
在mem_init()中,通过对所有的动态内存进行逐页扫描,并调用free_page()来把空页一页一页的插入BUDDY中。
事实上,动态内存就那么几大块,所以完全可以用一个递归函数用很少的
次数就可完成工作。
我写了一个:
buddy_init( start_addr,end_addr, order)
//start_addr,end_addr为要释放的内存块首尾,order为要插入的BUDDY槽号
{unsigned long mask=(~0ul)<
page * start,end; //中间以order为边界的大块的首尾地址
if(order==0)
{free_page(start_addr); return; } //递归出口,即只有一页要求释放
//求出start,end;
start=(start_addr+(1< end= end_addr&mask;
for(tmp=start,tmp {free_pages(tmp,order); //中间以order为边界的大块的释放
}
if(start_addr!=start) //若相等,则说明没有左零头,不用再递归
buddy_init(start_addr,start,order-1);
if(end_addr!=end) //若相等,则说明没有右零头,不用再递归
buddy_init(end,end_addr,order-1);
}
函数写的不严密,但其思想是尽量用free_pages()来大块大块的插入,
因为这样一次最多可释放512页,比一页一页效率高多了。
我先打个比喻:给你一个大碗,里面装满了大米,现在让你大米转移到
另一个碗里,你是把米从一个碗直接倒到另一个碗里,还是把米一粒一粒从一个碗放到另一个碗里?答案是明确的,直接倒。
而linux在初始化BUDDY算法的数据结构时却选择了类似把米从一个碗一粒一粒放到另一个碗里方法。
好了,看看系统是如何初始化BUDDY算法的数据结构的。
BUDDY在回收页面时一般用free_pages(),free_page(),它们都要实现伙伴的合并。而且最多9-order次合并。
在mem_init()中,通过对所有的动态内存进行逐页扫描,并调用free_page()来把空页一页一页的插入BUDDY中。
事实上,动态内存就那么几大块,所以完全可以用一个递归函数用很少的
次数就可完成工作。
我写了一个:
buddy_init( start_addr,end_addr, order)
//start_addr,end_addr为要释放的内存块首尾,order为要插入的BUDDY槽号
{unsigned long mask=(~0ul)<
page * start,end; //中间以order为边界的大块的首尾地址
if(order==0)
{free_page(start_addr); return; } //递归出口,即只有一页要求释放
//求出start,end;
start=(start_addr+(1< end= end_addr&mask;
for(tmp=start,tmp {free_pages(tmp,order); //中间以order为边界的大块的释放
}
if(start_addr!=start) //若相等,则说明没有左零头,不用再递归
buddy_init(start_addr,start,order-1);
if(end_addr!=end) //若相等,则说明没有右零头,不用再递归
buddy_init(end,end_addr,order-1);
}
函数写的不严密,但其思想是尽量用free_pages()来大块大块的插入,
因为这样一次最多可释放512页,比一页一页效率高多了。
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
2003.4.21读核日记更正
因为是先写到记事本里,再粘上来,但不知为什么数据没粘全,所以再粘一遍
很抱歉
今日读BUDDY内存分配算法,算法确实很不错,但LINUX在初始化BUDDY算法的数据结构时很低效。
我先打个比喻:给你一个大碗,里面装满了大米,现在让你大米转移到
另一个碗里,你是把米从一个碗直接倒到另一个碗里,还是把米一粒一粒从一个碗放到另一个碗里?答案是明确的,直接倒。
而linux在初始化BUDDY算法的数据结构时却选择了类似把米从一个碗一粒一粒放到另一个碗里方法。
好了,看看系统是如何初始化BUDDY算法的数据结构的。
BUDDY在回收页面时一般用free_pages(),free_page(),它们都要实现伙伴的合并。而且最多9-order次合并。
在mem_init()中,通过对所有的动态内存进行逐页扫描,并调用free_page()来把空页一页一页的插入BUDDY中。
事实上,动态内存就那么几大块,所以完全可以用一个递归函数用很少的
次数就可完成工作。
我写了一个:
buddy_init( start_addr,end_addr, order)
//start_addr,end_addr为要释放的内存块首尾,order为要插入的BUDDY槽号
{unsigned long mask=(~0ul)<
page * start,end; //中间以order为边界的大块的首尾地址
if(order==0)
{free_page(start_addr); return; } //递归出口,即只有一页要求释放
//求出start,end;
start=(start_addr+(1< end= end_addr&mask;
for(tmp=start;tmp {free_pages(tmp,order); //中间以order为边界的大块的释放
}
if(start_addr!=start) //若相等,则说明没有左零头,不用再递归
buddy_init(start_addr,start,order-1);
if(end_addr!=end) //若相等,则说明没有右零头,不用再递归
buddy_init(end,end_addr,order-1);
}
函数写的不严密,但其思想是尽量用free_pages()来大块大块的释放,
因为这样一次最多可释放512页,比一页一页效率高多了。
很抱歉
今日读BUDDY内存分配算法,算法确实很不错,但LINUX在初始化BUDDY算法的数据结构时很低效。
我先打个比喻:给你一个大碗,里面装满了大米,现在让你大米转移到
另一个碗里,你是把米从一个碗直接倒到另一个碗里,还是把米一粒一粒从一个碗放到另一个碗里?答案是明确的,直接倒。
而linux在初始化BUDDY算法的数据结构时却选择了类似把米从一个碗一粒一粒放到另一个碗里方法。
好了,看看系统是如何初始化BUDDY算法的数据结构的。
BUDDY在回收页面时一般用free_pages(),free_page(),它们都要实现伙伴的合并。而且最多9-order次合并。
在mem_init()中,通过对所有的动态内存进行逐页扫描,并调用free_page()来把空页一页一页的插入BUDDY中。
事实上,动态内存就那么几大块,所以完全可以用一个递归函数用很少的
次数就可完成工作。
我写了一个:
buddy_init( start_addr,end_addr, order)
//start_addr,end_addr为要释放的内存块首尾,order为要插入的BUDDY槽号
{unsigned long mask=(~0ul)<
page * start,end; //中间以order为边界的大块的首尾地址
if(order==0)
{free_page(start_addr); return; } //递归出口,即只有一页要求释放
//求出start,end;
start=(start_addr+(1< end= end_addr&mask;
for(tmp=start;tmp {free_pages(tmp,order); //中间以order为边界的大块的释放
}
if(start_addr!=start) //若相等,则说明没有左零头,不用再递归
buddy_init(start_addr,start,order-1);
if(end_addr!=end) //若相等,则说明没有右零头,不用再递归
buddy_init(end,end_addr,order-1);
}
函数写的不严密,但其思想是尽量用free_pages()来大块大块的释放,
因为这样一次最多可释放512页,比一页一页效率高多了。
__________________
宝剑锋从磨砺出,梅花香自苦寒来
此帖于 2003-04-22 09:18 被 blueflame 编辑.
宝剑锋从磨砺出,梅花香自苦寒来
我很久以前也看过buddy算法,也用它写过程序,只是没看过它的初始化的情况,只是好像有一点你没有注意(不知道是不是我记错了),例如你的start=(start_addr+(1"<<"order)-1)&mask;是不是应该在1"<<"order)后面来个PAGE_SHIFT,当然这是小事.至于你说的低效的问题.也许是.对了,你看过他的初始化程序,那么最初系统是不是全部按照order从9,8..开始往下排列.也就是先排9order的,零星的排8,再零星的排7...
ps:会不会是系统初始化的时候,怕某块物理内存坏了,造成内存空间的不连续性,所以要一页一页的插入合并阿?
ps2:你说的打不出某些程序,那是因为这个社区大概是为了安全或者别的编码之类的原因,把一些特殊字符解释错了吧,比如你在两个>之外加一对引号就能正常输入你的程序了.
ps:会不会是系统初始化的时候,怕某块物理内存坏了,造成内存空间的不连续性,所以要一页一页的插入合并阿?
ps2:你说的打不出某些程序,那是因为这个社区大概是为了安全或者别的编码之类的原因,把一些特殊字符解释错了吧,比如你在两个>之外加一对引号就能正常输入你的程序了.
__________________
依然记得从你口中说出再见坚决如铁,昏暗中有种烈日灼身的错觉;
依然记得从你眼中滑落的泪伤心欲绝,混乱中有种热泪烧伤的错觉....
依然记得从你口中说出再见坚决如铁,昏暗中有种烈日灼身的错觉;
依然记得从你眼中滑落的泪伤心欲绝,混乱中有种热泪烧伤的错觉....
此帖于 2003-04-22 09:18 被 blueflame 编辑.
blueflame:
还是你经验丰富呀,把没显示出来的东西看到了。
我现在也明白过来了:用查看源代码直接读此页的html文本,你是不是这样做的?
free_page()释放一页时,它会从order0开始,改相应的map标记,然后看能不能向上合并(就是通过map的相应位来判断其伙伴在不在),若不可以,它就插入order0,然后返回;若可以,它会和伙伴合并,再向order1里试插入,若还可以合并,则以此推,直到order9,才算结束。
所以若用free_page()初始化化BUDDY时,会发生大量的合并,(因为此时的动态内存是大块连续的,所以最后,除左右零头外,都是属于order9的块)
但若用free_pages(),则因为直接把order9的块分离出来插入order9,所以根本不存在合并现象.至于左右零头,它们会再分解,插入相应的槽中,也不会发生合并现象,因为试图合并,必然失败。
至于说是检查物理内存是否损坏,我想可以分离出来,不要因为要扫描每页物理内存,就“顺便”初始化BUDDY,总之,用free_page()代价太大,(不过确实很
省心,不用另写代码了)
还是你经验丰富呀,把没显示出来的东西看到了。
我现在也明白过来了:用查看源代码直接读此页的html文本,你是不是这样做的?
free_page()释放一页时,它会从order0开始,改相应的map标记,然后看能不能向上合并(就是通过map的相应位来判断其伙伴在不在),若不可以,它就插入order0,然后返回;若可以,它会和伙伴合并,再向order1里试插入,若还可以合并,则以此推,直到order9,才算结束。
所以若用free_page()初始化化BUDDY时,会发生大量的合并,(因为此时的动态内存是大块连续的,所以最后,除左右零头外,都是属于order9的块)
但若用free_pages(),则因为直接把order9的块分离出来插入order9,所以根本不存在合并现象.至于左右零头,它们会再分解,插入相应的槽中,也不会发生合并现象,因为试图合并,必然失败。
至于说是检查物理内存是否损坏,我想可以分离出来,不要因为要扫描每页物理内存,就“顺便”初始化BUDDY,总之,用free_page()代价太大,(不过确实很
省心,不用另写代码了)
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
2003.04.22读核日记--slad算法的2.4内核版本更简洁了
今天读了<<深入理解linux内核>>(第一版,2.2内核)的slab分配器原理。
书中讲的kmem_cache_t,kmem_slab_t原理都非常清楚,但一到
kmem_bufctl_t时,让人弄不清它到底如何同前两个结构配合。(当然,这不是作者的过,而是2.2版本对算法实现的不完美)。
最后,我不得不看源代码(2.4.18版本),发现对”对象描述符“的实现有了很大的改进:
1。若SLAB描述符在SLAB内部,它由2.2版本在SLAB的尾部改到首部,且后面紧跟对象描述符。
2。对象描述符原则上可在内部或外部,但linux只把它放在内部,不再放在外部,所以不用记录对象描述符的地址,通过kmem_cache_t,kmem_slab_t,及对象的地址便可算出对象描述符的地址,而且对象描述符的作用更加简单,只是把空对象链起来;已分配的对象的对象描述符没有什么作用了。
我为弄清它,还看了understanding linux kernel第2版,还有情景分析。发现情景分析基本上就是代码,所以讲的不好,书中只有两个图,图2.8画的是2.2版本的情况,图2.9则不知它要表达什么。所以我建议大家看buddy和slab算法时,看understanding linux kernel 第一版和第2版,比较着看,真是讲得很好,它中的图做的很精细,对理解算法很有帮助。
看看不同版本,想想linux的成长过程,不也是很有启发意义的吗?
书中讲的kmem_cache_t,kmem_slab_t原理都非常清楚,但一到
kmem_bufctl_t时,让人弄不清它到底如何同前两个结构配合。(当然,这不是作者的过,而是2.2版本对算法实现的不完美)。
最后,我不得不看源代码(2.4.18版本),发现对”对象描述符“的实现有了很大的改进:
1。若SLAB描述符在SLAB内部,它由2.2版本在SLAB的尾部改到首部,且后面紧跟对象描述符。
2。对象描述符原则上可在内部或外部,但linux只把它放在内部,不再放在外部,所以不用记录对象描述符的地址,通过kmem_cache_t,kmem_slab_t,及对象的地址便可算出对象描述符的地址,而且对象描述符的作用更加简单,只是把空对象链起来;已分配的对象的对象描述符没有什么作用了。
我为弄清它,还看了understanding linux kernel第2版,还有情景分析。发现情景分析基本上就是代码,所以讲的不好,书中只有两个图,图2.8画的是2.2版本的情况,图2.9则不知它要表达什么。所以我建议大家看buddy和slab算法时,看understanding linux kernel 第一版和第2版,比较着看,真是讲得很好,它中的图做的很精细,对理解算法很有帮助。
看看不同版本,想想linux的成长过程,不也是很有启发意义的吗?
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
对2003.04.22读核日记--更正
昨天发了关于slab算法的帖子,晚上睡觉又想了想,发现有点问题,所以一大早就爬起来,又分析了源代码。
所以做以下更正:
对象描述符在linux2.4中还是可内可外的,只是它和slab描述符如影随形。即它总是紧跟在slab描述符后面,因此,只要知道slab描述符的地址,便可算出对象描述符的地址。
总之,slab描述符在外,它就在外,slab描述符在内,它就在内;
当slab描述符在内时,放在slab区的开始处,即跟在着色区的后面。
当slab描述符在外时,因为不同的cache的slab区放的对象个数不同,所以一个slab所需要的对象描述符的个数是不同的,通过计算可得到“slab描述符加对象描述符数组”所需的内存大小,这便是分配slab描述符时的真正大小。所以在外的slab描述符可能分布在cache_sizes的不同cache中。
所以做以下更正:
对象描述符在linux2.4中还是可内可外的,只是它和slab描述符如影随形。即它总是紧跟在slab描述符后面,因此,只要知道slab描述符的地址,便可算出对象描述符的地址。
总之,slab描述符在外,它就在外,slab描述符在内,它就在内;
当slab描述符在内时,放在slab区的开始处,即跟在着色区的后面。
当slab描述符在外时,因为不同的cache的slab区放的对象个数不同,所以一个slab所需要的对象描述符的个数是不同的,通过计算可得到“slab描述符加对象描述符数组”所需的内存大小,这便是分配slab描述符时的真正大小。所以在外的slab描述符可能分布在cache_sizes的不同cache中。
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
blueflame:
谢谢你的关心。其实过去的一个月我都在看linux,整天的看,有时也看得很烦,当烦的时候,我就下载一部电影看看,或睡上一觉,也就没什么了。
我把学习Linux分成三个阶段:第一阶段是从整体上把linux的各种重要数据结构
和各部分之间的关系及工作机理从思想上想通,再辅之以学习系统编程(我把它称为完成linux的总体设计)就目前来看,到下学期开学就可完成;第二阶段是把linux再从头到尾过一遍,主要完成源代码的分析(我把它称为物理设计);我估计需2个月。第三阶段基本上就是不断跟踪Linux内核的发展,并有能力做一点修改。
请问你网络方面参考了什么书?
你打算怎么攻克它?
(笑也不争春,只把春来报,待到山花烂漫时,她在从中笑)
谢谢你的关心。其实过去的一个月我都在看linux,整天的看,有时也看得很烦,当烦的时候,我就下载一部电影看看,或睡上一觉,也就没什么了。
我把学习Linux分成三个阶段:第一阶段是从整体上把linux的各种重要数据结构
和各部分之间的关系及工作机理从思想上想通,再辅之以学习系统编程(我把它称为完成linux的总体设计)就目前来看,到下学期开学就可完成;第二阶段是把linux再从头到尾过一遍,主要完成源代码的分析(我把它称为物理设计);我估计需2个月。第三阶段基本上就是不断跟踪Linux内核的发展,并有能力做一点修改。
请问你网络方面参考了什么书?
你打算怎么攻克它?
(笑也不争春,只把春来报,待到山花烂漫时,她在从中笑)
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
2003.04.25读核日记--感谢大家的关心
谢谢大家的关心.我会继续读下去,把感慨发下去的。其实我只是想休息一两天,修整修整,看看电影,不亦乐乎.
通过这些天读内核管理,我感觉无论是内存的分配还是缓冲的管理,用的数据结构不是链表就是数组。而且为了更加有效的管理一群对象,采用的方式无外乎是
:1。通过增加索引级数。如slab分配器:就通过3级来管理,最高一级是kmem_cache_s,接下来是kmem_slab_t,再下来是kmem_bufctl_s,最后是对象本身.(试想它为什么会用3级,其实本来可以用一级的,即用hash或一条链串起来便可它最终就是要取个对象,中间级对外是隐藏的)只要能想通了这个,以后一看到要讲数据结构,我就首先看看它是用几级索引。然后我就能推断出它的基本组织结构,即不同级别之间如何关联。
2。在同一级别的组织,采用的形式也无外乎:要么是用链表串起来,要么是数组,要么用hash,要么用树(如AVL)。前两种是基本形式,后两种只不过为了增加速度。
注意到数组和链表的不同效果没有?比如串数组是用偏移作指针,而链表却只能用地址作指针啦。
3。对分配来的空间进行二次分割时,也有两种基本策略,一种是管理空闲块法,即把空间离散块串起来,典型的就是buddy,slab,别一种是把分配出去的串起来,典型的就是vma_area_struct,vma_struct;
再说vfs吧,说白了,系统根本目的就是为了实现按名存取(为了提高效率那叫改进,linux为了提高效率都改进了好几年啦,所以不要指望马上就学会人家的效率,所以我感觉一个软件能实现它是第一步,其次才是改进它,cpu本身不也改进了好多年吗?还在改进中。看看linux以前的版本,你就知道linus也不是什么神仙,他的以前的版本的算法有许多也是很烂的,只不过后来才改进的),一句话,本来是一级管理的本质问题.但若用一级索引,那文件不多如牛毛吗,所以才有了,按目录,按逻辑盘,按进程等等的多级层次。所以想通了它。那整个数据结构也就历历在目了。
请大家补充指正!
再次感谢大家对我的关心。
通过这些天读内核管理,我感觉无论是内存的分配还是缓冲的管理,用的数据结构不是链表就是数组。而且为了更加有效的管理一群对象,采用的方式无外乎是
:1。通过增加索引级数。如slab分配器:就通过3级来管理,最高一级是kmem_cache_s,接下来是kmem_slab_t,再下来是kmem_bufctl_s,最后是对象本身.(试想它为什么会用3级,其实本来可以用一级的,即用hash或一条链串起来便可它最终就是要取个对象,中间级对外是隐藏的)只要能想通了这个,以后一看到要讲数据结构,我就首先看看它是用几级索引。然后我就能推断出它的基本组织结构,即不同级别之间如何关联。
2。在同一级别的组织,采用的形式也无外乎:要么是用链表串起来,要么是数组,要么用hash,要么用树(如AVL)。前两种是基本形式,后两种只不过为了增加速度。
注意到数组和链表的不同效果没有?比如串数组是用偏移作指针,而链表却只能用地址作指针啦。
3。对分配来的空间进行二次分割时,也有两种基本策略,一种是管理空闲块法,即把空间离散块串起来,典型的就是buddy,slab,别一种是把分配出去的串起来,典型的就是vma_area_struct,vma_struct;
再说vfs吧,说白了,系统根本目的就是为了实现按名存取(为了提高效率那叫改进,linux为了提高效率都改进了好几年啦,所以不要指望马上就学会人家的效率,所以我感觉一个软件能实现它是第一步,其次才是改进它,cpu本身不也改进了好多年吗?还在改进中。看看linux以前的版本,你就知道linus也不是什么神仙,他的以前的版本的算法有许多也是很烂的,只不过后来才改进的),一句话,本来是一级管理的本质问题.但若用一级索引,那文件不多如牛毛吗,所以才有了,按目录,按逻辑盘,按进程等等的多级层次。所以想通了它。那整个数据结构也就历历在目了。
请大家补充指正!
再次感谢大家对我的关心。
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
2003.04.28读核日记--高速缓存的数据结构的理解
今天读了<<深入理解linux内核>>第14章磁盘高速缓存,对它的数据结构基本理解了。这使我对VFS这一块的阅读有了很大的信心。
现将理解表述如下(本来想画一张图,但觉得太费事)
1。高速缓存主要有3种:目录高速缓存,缓冲区高速缓存和页高速缓存。
其实我觉得书中称“缓冲区“及缓冲首部(buffer_head)这个词不好。我觉得应该换个名字更好:比如叫:块对象(block object)和块描述符(block descripter)。
2.缓冲区高速缓存的整个数据结构
1)创建一块”缓冲区”和“缓冲区首部”,两个来源不同
缓冲区来源于BUDDY,即BUDDY给分一个页框,它再把这个页框分成几个等大的缓冲区。而缓冲区首部来源于SLAB分配器。
每一个缓冲区都要有一个缓冲区首部来描述它。一个页框中的这几个缓冲区你可称它为兄弟,它们用一个链串起来的。
2)创建完后,它们是空闲的,就必须把它管理起来,用作”周转资金“,如何管理呢?
因为不同的设备可能定义不同的块大小,所以缓冲区的块大小是不统一的。方法是把相同大小的缓冲区的缓冲区描述符(即缓冲区首部,但我还是喜欢叫它缓冲区描述符)串成一条链,这样因为块大小的可能情况是:512,1024,2048,4096,8192,16384,32768,所以共生成7条链。但一个块大小不能超过一页,所以PC机只用前4条链。7条链的链头用一个数组free_list统一存放。好啦,空闲块已经管理起来了,以后用,就可先从这里取,若不够,再新创建。
3)把分配出去的管理起来:因为这些缓冲区可能是干净的,脏的,或正要写入磁盘。就把它们分成3条链串起来。3个链头放在一个数组lru_list中。好啦,分配出去的也管理起来了。但为了快速查找,再给它加个hash表,表为:hash_table
用hash就必须提供键,缓冲区的检索就是用设备号和块号来作键的。
至于那些函数,只要脑里有这个数据结构框架,则一看就懂。
3。页高速缓存的数据结构很相对简单。不说了,但要注意的是他是
用索引节点和文件偏移作hash键的.还有要注意的是缓冲页最终要分割成几个缓冲区,并给这些块缓冲区分配缓冲区描述符,利用缓冲区的写回和读取函数来完成磁盘的操作。(因为磁盘只认块,不认页),书中有几幅很好的图。能促进人理解这些结构。
欢迎指正。
现将理解表述如下(本来想画一张图,但觉得太费事)
1。高速缓存主要有3种:目录高速缓存,缓冲区高速缓存和页高速缓存。
其实我觉得书中称“缓冲区“及缓冲首部(buffer_head)这个词不好。我觉得应该换个名字更好:比如叫:块对象(block object)和块描述符(block descripter)。
2.缓冲区高速缓存的整个数据结构
1)创建一块”缓冲区”和“缓冲区首部”,两个来源不同
缓冲区来源于BUDDY,即BUDDY给分一个页框,它再把这个页框分成几个等大的缓冲区。而缓冲区首部来源于SLAB分配器。
每一个缓冲区都要有一个缓冲区首部来描述它。一个页框中的这几个缓冲区你可称它为兄弟,它们用一个链串起来的。
2)创建完后,它们是空闲的,就必须把它管理起来,用作”周转资金“,如何管理呢?
因为不同的设备可能定义不同的块大小,所以缓冲区的块大小是不统一的。方法是把相同大小的缓冲区的缓冲区描述符(即缓冲区首部,但我还是喜欢叫它缓冲区描述符)串成一条链,这样因为块大小的可能情况是:512,1024,2048,4096,8192,16384,32768,所以共生成7条链。但一个块大小不能超过一页,所以PC机只用前4条链。7条链的链头用一个数组free_list统一存放。好啦,空闲块已经管理起来了,以后用,就可先从这里取,若不够,再新创建。
3)把分配出去的管理起来:因为这些缓冲区可能是干净的,脏的,或正要写入磁盘。就把它们分成3条链串起来。3个链头放在一个数组lru_list中。好啦,分配出去的也管理起来了。但为了快速查找,再给它加个hash表,表为:hash_table
用hash就必须提供键,缓冲区的检索就是用设备号和块号来作键的。
至于那些函数,只要脑里有这个数据结构框架,则一看就懂。
3。页高速缓存的数据结构很相对简单。不说了,但要注意的是他是
用索引节点和文件偏移作hash键的.还有要注意的是缓冲页最终要分割成几个缓冲区,并给这些块缓冲区分配缓冲区描述符,利用缓冲区的写回和读取函数来完成磁盘的操作。(因为磁盘只认块,不认页),书中有几幅很好的图。能促进人理解这些结构。
欢迎指正。
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
我也有同感,有时,我什么也没做,硬盘就狂转不停,我想肯定是在交换,可又好象没必要,我没做什么呀。
光看内核讲解的书,我感到有点累了,没有实践,那么多数据结构总记不住。所以我有点想换换方式,想学一段系统和模块编程,从外部观察linux内核的行为。同时,也想把以前学过的内核原理好好消化一下,再前进,我感到与设备有关的这块不好弄,前面的BH又忘的差不多了,所以看起来有点吃力。
哎,学内核真是苦呀。简直就是对人的毅立的考验。
光看内核讲解的书,我感到有点累了,没有实践,那么多数据结构总记不住。所以我有点想换换方式,想学一段系统和模块编程,从外部观察linux内核的行为。同时,也想把以前学过的内核原理好好消化一下,再前进,我感到与设备有关的这块不好弄,前面的BH又忘的差不多了,所以看起来有点吃力。
哎,学内核真是苦呀。简直就是对人的毅立的考验。
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
2003.04.30读核日记--关于FAT文件系统的结构
应blueflame的提问,我把FAT更详细的一些数据结构写出,供大家参考:
总体结构依次是:
IPL(引导区),fat表1,fat表2,根目录,数据区。
fat表2与fat表1一样,主要是起备份作用。数据区以簇为基本单位进行分配。
IPL即起引导系统作用,又含有类似超级块的数据,所以应该从这里取超级块的信息。
fat表有两个作用,一个是起记录空闲块的作用,一个起文件数据链指针的作用。fat其实是个数组,它的每一项(fat12是12位算一项,即1.5个字节,fat16是2字节一项),每一项记录它对应的簇的使用情况。当它为0,表示此簇空闲,当不为0,表示文件的下一簇的簇号(别外有几个特殊的数有特殊意义,如
fat16时,0xffff表示文件结束,即没有下一簇了。)
在fat中的簇与ext2中的块是一个意思,都为基本分配单位。
从fat的结构可见,它比ext2简单多了。文件的不同块通过fat表联起来,而不象
ext2,把它放在i节点,或文件内部(指二级,三级索引所需的块)
下面为各部具体的结构:
1。IPL(initial program loader)结构:
占一个扇区
偏移(16进制) 长度(字节) 内容
======================================
00 3 短跳指令
03 8 OEM厂家名和版本
0b 2 每扇字节数
0d 1 每簇扇数
0e 2 预约的扇区数
10 1 FAT的个数
11 2 根目录项数
13 2 逻辑扇区数
15 1 介质描述符
16 2 每FAT的扇区数
18 2 每磁道扇区数
1a 2 磁头数
1c 2 隐含的扇区数
--------------
1e IPL引导程序
---------------
4个分区表
2。FAT表的数值含义(指12位和16位的)
簇值(0x) 内容
========================
000(fat12) 空闲簇
0000(fat16)
---------------------------------------
001 不用的代码
0001
---------------------------------------
ff7 不良簇(即簇可能有坏区)
fff7
--------------------------------------
ff8--fff 文件结束标志
fff8-ffff
---------------------------------------
002--ff6 下一个簇号
0002--fff6
=======================
3。 目录项的结构:每项32字节
偏移 字节数 内容
========================
00-07 8 文件名
08-0a 3 扩展名
0b 1 文件属性
0x-15 10 保留区
16-17 2 最终编辑时间
18-19 2 最终编辑日期
1a-1b 2 起始簇号
1c-1f 4 文件大小
文件名第一字节含义
00表示此目录未使用
e5表示此目录项被删
2e,若第2字节也是2E,则表示为父目录(..)
若第2字节不是2E,则表示为本身目录(.)
文件属性:
0 只读
1 隐含
2 系统
3 卷标
4 子目录
5 存档
4。一些数据的计算:
注意:簇号从2开始排
逻辑扇区号=(簇号-2)*簇长+数据区起始扇号
逻辑扇区数=预约扇区数+(扇数每FAT)*FAT表数+根目录扇区数+簇数*(扇数每簇)
根目录扇区数=(根目录项数*32)/(字节每扇区)
最大簇号=簇数+1
FAT簇数<=4085 :用FAT12
>=4086 :用FAT16
如有错误,欢迎指正
也请有知道fat32,ntfs结构的人补充。
总体结构依次是:
IPL(引导区),fat表1,fat表2,根目录,数据区。
fat表2与fat表1一样,主要是起备份作用。数据区以簇为基本单位进行分配。
IPL即起引导系统作用,又含有类似超级块的数据,所以应该从这里取超级块的信息。
fat表有两个作用,一个是起记录空闲块的作用,一个起文件数据链指针的作用。fat其实是个数组,它的每一项(fat12是12位算一项,即1.5个字节,fat16是2字节一项),每一项记录它对应的簇的使用情况。当它为0,表示此簇空闲,当不为0,表示文件的下一簇的簇号(别外有几个特殊的数有特殊意义,如
fat16时,0xffff表示文件结束,即没有下一簇了。)
在fat中的簇与ext2中的块是一个意思,都为基本分配单位。
从fat的结构可见,它比ext2简单多了。文件的不同块通过fat表联起来,而不象
ext2,把它放在i节点,或文件内部(指二级,三级索引所需的块)
下面为各部具体的结构:
1。IPL(initial program loader)结构:
占一个扇区
偏移(16进制) 长度(字节) 内容
======================================
00 3 短跳指令
03 8 OEM厂家名和版本
0b 2 每扇字节数
0d 1 每簇扇数
0e 2 预约的扇区数
10 1 FAT的个数
11 2 根目录项数
13 2 逻辑扇区数
15 1 介质描述符
16 2 每FAT的扇区数
18 2 每磁道扇区数
1a 2 磁头数
1c 2 隐含的扇区数
--------------
1e IPL引导程序
---------------
4个分区表
2。FAT表的数值含义(指12位和16位的)
簇值(0x) 内容
========================
000(fat12) 空闲簇
0000(fat16)
---------------------------------------
001 不用的代码
0001
---------------------------------------
ff7 不良簇(即簇可能有坏区)
fff7
--------------------------------------
ff8--fff 文件结束标志
fff8-ffff
---------------------------------------
002--ff6 下一个簇号
0002--fff6
=======================
3。 目录项的结构:每项32字节
偏移 字节数 内容
========================
00-07 8 文件名
08-0a 3 扩展名
0b 1 文件属性
0x-15 10 保留区
16-17 2 最终编辑时间
18-19 2 最终编辑日期
1a-1b 2 起始簇号
1c-1f 4 文件大小
文件名第一字节含义
00表示此目录未使用
e5表示此目录项被删
2e,若第2字节也是2E,则表示为父目录(..)
若第2字节不是2E,则表示为本身目录(.)
文件属性:
0 只读
1 隐含
2 系统
3 卷标
4 子目录
5 存档
4。一些数据的计算:
注意:簇号从2开始排
逻辑扇区号=(簇号-2)*簇长+数据区起始扇号
逻辑扇区数=预约扇区数+(扇数每FAT)*FAT表数+根目录扇区数+簇数*(扇数每簇)
根目录扇区数=(根目录项数*32)/(字节每扇区)
最大簇号=簇数+1
FAT簇数<=4085 :用FAT12
>=4086 :用FAT16
如有错误,欢迎指正
也请有知道fat32,ntfs结构的人补充。
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
2003.04.28读核日记--高速缓存的数据结构的理解
你说的缓冲区高速缓存,一个页框中可能会有几个缓冲区.还有那7条练,在我的印象中好像那是关于文件缓冲用的.而你说第三种页高速缓存才是用于文件缓存.我对于这几种缓存的叫法一直比较模糊.缓冲区高速缓存是不是buffer cache.那应该好像不会用于文件缓冲的.这种页的mapping结构应该是null.
你说的缓冲区高速缓存,一个页框中可能会有几个缓冲区.还有那7条练,在我的印象中好像那是关于文件缓冲用的.而你说第三种页高速缓存才是用于文件缓存.我对于这几种缓存的叫法一直比较模糊.缓冲区高速缓存是不是buffer cache.那应该好像不会用于文件缓冲的.这种页的mapping结构应该是null.
__________________
依然记得从你口中说出再见坚决如铁,昏暗中有种烈日灼身的错觉;
依然记得从你眼中滑落的泪伤心欲绝,混乱中有种热泪烧伤的错觉....
依然记得从你口中说出再见坚决如铁,昏暗中有种烈日灼身的错觉;
依然记得从你眼中滑落的泪伤心欲绝,混乱中有种热泪烧伤的错觉....
buffer cache就指得是缓冲区高缓,page cache指得是页高缓,也就是你所说的文件高缓,因为文件就是以页为单位进行读写,所以文件用的高缓就是指页高缓。
这两个名英文名词,我感觉给人一个错觉,比如buffer一般让人理解为一个缓冲区,无论其大小,但此处的buffer cache中的buffer 强调的是磁盘块大小了缓冲区,它直接与磁盘读写联系,即磁盘上一个盘块通过DMA读入后,就首先放在buffer cache的一个buffer中,所以我感觉把这个buffer cache理解block cache
更让人好理解。
因为一个文件的一页,在磁盘上可能对应几个磁盘块(因为1页>1块),且这几个块可能不是连续的,所以当把这个文件的一个页读入内存,就必须把这个页框分成几个块(由页划分的块显然连续),当磁盘上此页的几个磁盘块读入内存后,就连续的放入到此页中,即几个连续块中。所以完成了由不连续的磁盘块到连续的内存块的映射。同时完成了外存的一页到内存的一页的映射。
所以说页高缓最终要利用buffer高缓,来完成外存的读写,或者说它层次是:
外存文件的一页(分解为几块,可能不连续)------外存的磁盘块-----内存的buffer块-------内存文件的一页(由一个页框划分的几个连续buffer构成).----页高缓系统
2.4中用的address_space其实并没什么新鲜的,它不过是把页高缓的管理数据更加集中存放罢了。所以只要懂2.2版,再看2.4就没什么难的。
表达能力有限,总感觉说不清楚,understanding linux kernel的第一版(2.2内核)和第二版(2.4内核)吧,它讲得比较透彻。
这两个名英文名词,我感觉给人一个错觉,比如buffer一般让人理解为一个缓冲区,无论其大小,但此处的buffer cache中的buffer 强调的是磁盘块大小了缓冲区,它直接与磁盘读写联系,即磁盘上一个盘块通过DMA读入后,就首先放在buffer cache的一个buffer中,所以我感觉把这个buffer cache理解block cache
更让人好理解。
因为一个文件的一页,在磁盘上可能对应几个磁盘块(因为1页>1块),且这几个块可能不是连续的,所以当把这个文件的一个页读入内存,就必须把这个页框分成几个块(由页划分的块显然连续),当磁盘上此页的几个磁盘块读入内存后,就连续的放入到此页中,即几个连续块中。所以完成了由不连续的磁盘块到连续的内存块的映射。同时完成了外存的一页到内存的一页的映射。
所以说页高缓最终要利用buffer高缓,来完成外存的读写,或者说它层次是:
外存文件的一页(分解为几块,可能不连续)------外存的磁盘块-----内存的buffer块-------内存文件的一页(由一个页框划分的几个连续buffer构成).----页高缓系统
2.4中用的address_space其实并没什么新鲜的,它不过是把页高缓的管理数据更加集中存放罢了。所以只要懂2.2版,再看2.4就没什么难的。
表达能力有限,总感觉说不清楚,understanding linux kernel的第一版(2.2内核)和第二版(2.4内核)吧,它讲得比较透彻。
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来
我看了blueflame推荐的那篇文章,但好象有几个地方是不是有问题:
"我们知道越是靠磁盘外部的柱面,旋转越快,而且每次旋转时,磁盘读写头可以覆盖较多的区域,也就意味着靠外部的柱面可以得到较好的性能。所以在分区时,我们应该考虑将访问频率高的,对系统性能影响相对较大的分区置于磁盘的靠外部分" 1。硬盘的磁道是从里到外编号,还是从外到里?我没查过资料,但光盘是从里到外编号应该没什么问题吧,这从刻光盘时就可看出来,所以我想谁能查一下资料证实一下。 (他讲的好象是从外到里,而我怀疑) 2。他那么分区我认为没有用。因为磁盘转速并不是匀速的,而是当磁头从里到外移动时,为了保持基本不变的读数据的线速,必须不断的调整转速,使读数据的线速基本不变,所以我怀疑他说的在磁头在外面时,读速快,是一种想当然的认识,也请大家证实一下。 3。他讲到用软raid技术,我认为这不能提高性能,最多是增加了磁盘的冗余度,从而提高了可靠性而已。 因为把同一个盘划成不同的区,这些区必然有内外之别(这与用不同的硬盘作raid是两码事,因为不同的硬盘可并行操作,而同一个盘划成不同区,也只能串行寻道,而且为了找不同的区,还必须不停的寻道)。所以我怀疑性能有提高这种说法,也请大家证实一下。 __________________ 宝剑锋从磨砺出,梅花香自苦寒来 | |
![]() |
不要指望交换算法能让你满意了,若让你满意了,别人就不满意了。你若想让自己满意,就必须使算法的天平向你倾斜。
我看了understanding the linux kernel,总算明白了这个道理:
”As a matter of fact,the hardest job of a developer working on the virtual memory subsystem consists of finding an algorithm that ensures acceptable performances both to desktop machines and to high-level machines like large database servers.
Unfortunately,finding a good page frame reclaiming algorithm is a rather empirical job,with very little support for theory.The situation is somewhat similar to evaluation the parameters that achieve good system performance,without asking too many questions about why it works well.Often,it's just a matter of "let's try this approach and see what happens..."An unpleasant side effect of this empirical approach is the code changes quickly,even in the evennumbered versions of Linux,which are supposed to be stable.
“
所以,应该用”let's try this approach and see what happens..."心态去
读这一部分的算法,理解作者的用意便可。你要是不服气,改改它,让它适合你的胃口。
比如:你上面不断的写文件,显然不要缓冲,只要写回文件到硬盘才是最佳的算法。
我看了understanding the linux kernel,总算明白了这个道理:
”As a matter of fact,the hardest job of a developer working on the virtual memory subsystem consists of finding an algorithm that ensures acceptable performances both to desktop machines and to high-level machines like large database servers.
Unfortunately,finding a good page frame reclaiming algorithm is a rather empirical job,with very little support for theory.The situation is somewhat similar to evaluation the parameters that achieve good system performance,without asking too many questions about why it works well.Often,it's just a matter of "let's try this approach and see what happens..."An unpleasant side effect of this empirical approach is the code changes quickly,even in the evennumbered versions of Linux,which are supposed to be stable.
“
所以,应该用”let's try this approach and see what happens..."心态去
读这一部分的算法,理解作者的用意便可。你要是不服气,改改它,让它适合你的胃口。
比如:你上面不断的写文件,显然不要缓冲,只要写回文件到硬盘才是最佳的算法。
__________________
宝剑锋从磨砺出,梅花香自苦寒来
宝剑锋从磨砺出,梅花香自苦寒来