感谢支持
我们一直在努力

Linux RAMDisk 源码分析

在产品中使用了ramdisk, 看了一部分的源码,分析和共享一下。内核源码 2.6.18


安装ramdisk


ramdisk 在linux里面被认为是个内存的块设备,通常以rm0,rm1… 挂在dev下,首先需要格式化块设备成linux的文件系统,然后在将想使用的目录mount 到dev/rm0…下,这样操作目录,在目录里操作文件就在内存里。


ramdisk是一个块设备,需要格式化成linux能认识的文件系统(ext2,ext3),那么对ramdisk的 IO的操作 ,就绕不过page cache,也就是无意中多了一次内存复制。


通常在linux中,由于块设备的随机读写是急剧降低性能的,linux 系统中会有一些合并算法,我们将每次设备的请求认为是一个操作,那么在内核中不会将每一次的请求都提交给块设备,而是在一定的时间内把请求合并成一个队列,然后 调整队列里请求的顺序,尽量让请求(比如块设备中地址相近的)排序在相邻的位置,这样可以提高磁头访问的效率。


最后将队列提交给块设备,相见常用的四种电梯调度算法,就不描述了。



ramdisk是以内存作为访问的块设备,随机访问的速度非常块,调度算法不能提高IO的效率,反而因为合并请求而导致访问性能下降,所以ramdisk没有使用调度算法,在初始化ramdisk的时候,重新设置了queue的调度算法。


drivers/block/rd.c


  1. static int __init rd_init(void)  

  2. {  

  3.      …  

  4.      blk_queue_make_request(rd_queue[i], &rd_make_request);  

  5. ….  

  6. }  


在函数里rd_make_request,核心就是rd_blkdev_pagecache_IO


  1. static int rd_blkdev_pagecache_IO(int rw, struct bio_vec *vec, sector_t sector,  

  2.                 struct address_space *mapping)  

  3. {  

  4.     pgoff_t index = sector >> (PAGE_CACHE_SHIFT – 9);  

  5.     unsigned int vec_offset = vec->bv_offset;  

  6.     int offset = (sector << 9) & ~PAGE_CACHE_MASK;  

  7.     int size = vec->bv_len;  

  8.     int err = 0;  

  9.   

  10.     do {  

  11.         int count;  

  12.         struct page *page;  

  13.         char *src;  

  14.         char *dst;  

  15.   

  16.         count = PAGE_CACHE_SIZE – offset;  

  17.         if (count > size)  

  18.             count = size;  

  19.         size -= count;  

  20.   

  21.         page = grab_cache_page(mapping, index);   

  22.         if (!page) {  

  23.             err = -ENOMEM;  

  24.             goto out;  

  25.         }  

  26.   

  27.         if (!PageUptodate(page))  

  28.             make_page_uptodate(page);  

  29.   

  30.         index++;  

  31.   

  32.         if (rw == READ) {  

  33.             src = kmap_atomic(page, KM_USER0) + offset;  

  34.             dst = kmap_atomic(vec->bv_page, KM_USER1) + vec_offset;  

  35.         } else {  

  36.             src = kmap_atomic(vec->bv_page, KM_USER0) + vec_offset;  

  37.             dst = kmap_atomic(page, KM_USER1) + offset;  

  38.         }  

  39.         offset = 0;  

  40.         vec_offset += count;  

  41.   

  42.         memcpy(dst, src, count);  

  43.   

  44.         kunmap_atomic(src, KM_USER0);  

  45.         kunmap_atomic(dst, KM_USER1);  

  46.   

  47.         if (rw == READ)  

  48.             flush_dcache_page(vec->bv_page);  

  49.         else  

  50.             set_page_dirty(page);  

  51.         unlock_page(page);  

  52.         put_page(page);  

  53.     } while (size);  

  54.   

  55.  out:  

  56.     return err;  

  57. }  

a. Grab_Cache_Page


grab_cache_page -> find_or_create_page


address_space *mapping,这是Ramdisk block 的块结构,通过index,可以很块的找到在ramdisk里面的内容(也可以说在默认的ramdisk里块和linux 的页的大小是一致的),而不是在 ext 文件系统中所表示的inode的address_space。


find_or_create_page, 是查找ramdisk里的页的位置,在ramdisk中内容是以页的形式来保存的,如果页面不存在,会生成新的页面,如果页面存在会锁住该页,同时加到lru cache的列表中去。该函数是允许睡眠的,在锁住页面的时候,会等待直到页面的状态位设置成set_bit(PG_locked, &(page)->flags),具体的函数__lock_page实现

赞(0) 打赏
转载请注明出处:服务器评测 » Linux RAMDisk 源码分析
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏