【文件管理】文件的读read()

来源:互联网 发布:港股交易软件 编辑:程序博客网 时间:2024/05/18 03:42

文件的sys_read()和sys_write()是类似的;在sys_write()中要验证用户空间的缓冲区可读,并且使用file_opserations结构中函数指针write;而在sys_read()中,要验证用户空间的缓冲区可写,并且使用file_opserations结构中函数指针read;在ext2文件系统黄总,这个函数指针就是generic_file_read();


(1)在generic_file_read()中,首先检查对用户空间缓冲区的写访问权,并为读文件操作准备一个读操作描述符结构,即read_descriptor_t,以减少在调用do_generic_file_read();

(2)在do_generic_file_read()中,参数actor是个函数指针,实际参数是file_read_actor(),这个函数的作用是将文件的内容从缓冲区拷贝到用户空间的缓冲区中;

(2.1)在get_max_readahead()中,利用这个函数根据inode结构中设备号就可确定文件的最大预读量;由于预读的引入,在file结构中要维持两个上下文,一个是当前位置f_ops,代表正真的读写上下文,另一个则是预读的上下文,也就是f_reada,f_rmax,末端f_raend,f_ralen,大小f_rawin;

(3)index是当前读写位置所在页面的序号,offest则为页面内部的位移;如果index大于f_raend,那么就要新建一个新的预读窗口;否则就要推进现有的预读窗口;如果读的量是在前半个页面,就可以完成了,那就不需要预读了,否则就要设置needed和f_ramax参数了;假定第一个缓冲页面找到了,且一致,那就要通过actor,把缓冲页面把内容复制到用户空间的缓冲区中,并使用page_cache_release(递减使用计数)将这个page释放掉;假定第二个页面找到了,但是内容不一致,不能马上从这个页面读出;页面内容不一致只是一个暂时的现象,这是由于某个进程写并未提交造成的,只要等一会就可以了,不如预读一些页面,通过generic_file_readhead()启动预读;如果等了,页面还是不一致,那就只好从设备上读出页面,使用address_space_operations中的ext2_readpage()来读,调用的是block_read_full_page();虽然通过预读消耗了一段时间,目标页面的读入仍然不能肯定已经完成了,要通过wait_on_page()完成;当涉及的第三个逻辑页面没有被缓冲在内存中;因此还要分配一个页面,使用page_cache_alloc()分配一个页面备用;但是分配成功以后,还要查看一次目标页面是否被缓冲;这是因为page_cache_alloc()有可能会睡眠,有可能让别的的进程抢先为目标页面建立缓冲,如果真的这样,就和前面操作第一个和第二个页面的逻辑相同了;至于分配得的页面cached_page则成了已经分配但是尚未使用的缓冲页面,我们不必将其释放掉;否则的没有发生这种情况,那就将分配得的页面链入到所有有关的队列中,包括所属的inode结构中的指针address_space,全局性的缓冲页面队列,全局性的缓冲杂凑队列,全局性的缓冲页面LRU队列,然后就转向readpage,此后就和上述的第二个页面后面的操作差不多了;

(4)在generic_file_readhead()中,参数reada_ok表示目标页面page是否还在原来的预读窗口之中;如果某页面page已被锁住,也就是这个页面记录块的设备层读入请求已经发出了;如果已发出,而当前页面又在先前的预读窗口之内,并且原来的预读窗口已经包含了对当前页面以后若干页面的预读,那就保持max_ahead,最后将无功而返,这种情况下generic_file_readhead()只是做了简单的检测而不是真正的预读;但是被锁住了,但是并没有预读(file结构中f_ralen为0,或者当前页面已是预读窗口的最后一个页面或者超出了预读窗口的上沿index>=raend,或者当前页面已是预读窗口中的瞎眼以下),那就要另起一个预读窗口了;如果当前页面没有被锁住,设备驱动层的读入请求为发出,这时候将原来的预读窗口,并且当前页面落在原有窗口之内时才预读;

(5)在generic_file_readhead()中,在确定了合适的预读量以后,就开始通过一个while循环依次启动对各个页面的读入;

0 0
原创粉丝点击