分析RTEMS的RAMDISK的使用和原理等

本文的例子是指 \rtems-4.10.2\testsuites\samples\fileio 的文件系统访问的例子RAMDISK部分


/*
 * RAM disk driver so you can create a RAM disk from the shell prompt.
 */
/**
 * The RAM Disk configuration.
 */
rtems_ramdisk_config rtems_ramdisk_configuration[] =
{
  {
    block_size: 512,
    block_num:  1024,
    location:   NULL
  }
};


/**
 * The number of RAM Disk configurations.
 */
size_t rtems_ramdisk_configuration_size = 1;


RAMDISK 有2个全局变量需要用户去指定的,也就是有多少个RAMdisk,还有每个RAMdisk多大,一个块多大
    block_size: 512,
    block_num:  1024,
    location:   NULL
一般一个块大小不会少于512字节,否则就无法格式化为FAT格式了,多大需要用户自己去指定。


假设使用 shell ,
  rtems_shell_add_cmd ("mkrd", "files",
                       "Create a RAM disk driver", create_ramdisk);
配置了一个命令 mkrd,具体是执行 create_ramdisk 是用来创建一个 ramdisk的。


可以不带参数,块大小和数量就是指前面设定了。
sc = rtems_io_register_driver (RTEMS_DRIVER_AUTO_MAJOR,
                                 &rtems_ramdisk_io_ops,
                                 &major);


/**
 * Create the RAM Disk Driver entry.
 */
rtems_driver_address_table rtems_ramdisk_io_ops = {
  initialization_entry: ramdisk_initialize,
  open_entry:           rtems_blkdev_generic_open,
  close_entry:          rtems_blkdev_generic_close,
  read_entry:           rtems_blkdev_generic_read,
  write_entry:          rtems_blkdev_generic_write,
  control_entry:        rtems_blkdev_generic_ioctl
};


注册一个驱动,注意,注册一个驱动,不会在 /dev上建立一个节点,而是由初始化函数自己去
创建的。
在 rtems_io_register_driver函数中
当分配到一个 major 后,跟着执行 rtems_io_initialize,实际上是调用 rtems_ramdisk_io_ops
传入的初始化函数,也就是  ramdisk_initialize


在 ramdisk_initialize 函数中首先初始化disk IO,如果已经初始化则会立刻返回的
rc = rtems_disk_io_initialize();
    if (rc != RTEMS_SUCCESSFUL)
        return rc;
注意这时的入口参数,major 是之前已经分配好的,minor为0,参数 arg 为 NULL


接着根据 rtems_ramdisk_configuration_size 知道系统到底有多少个ramdisk需要初始化。
这里设置为1,所以
从 dev_t dev = rtems_filesystem_make_dev_t(major, i); 可以看出,如果有多个ramdisk,则每个
ramdisk的minor 从 0~N ,用来区分到底是哪个盘。


#define RAMDISK_DEVICE_BASE_NAME "/dev/rd"
char name [] = RAMDISK_DEVICE_BASE_NAME "a";
name [sizeof(RAMDISK_DEVICE_BASE_NAME)] += i;


从这里看出,这个盘的名字为 /dev/rda ,如果有多个,则为 /dev/rdb ,/dev/rdc .... 等等。


接着需要生成一个或者多个物理盘,
rc = rtems_disk_create_phys(dev, c->block_size, c->block_num,
                                    ramdisk_ioctl, r, name);
参数为 major。minor的组合 dev,块大小数量,注册一个回调函数 ramdisk_ioctl ,让盘自己提供一些
处理的方法,r 为这个驱动的信息,用来绑定到盘上面的,最后name就是刚才说的 /dev/rda 等


在 rtems_disk_create_phys 里面会调用这个真正的生产函数
sc = create_disk(dev, name, &dd);
分配内存等,最后会发现一个系统调用 mknod,将这个节点真正的注册到 /dev 上面。
if (mknod(alloc_name, 0777 | S_IFBLK, dev) < 0)


到这里为止,系统里面注册了一个驱动,根据major来区分是否ram盘,然后通过minor区分具体哪个
在文件系统的 /dev目录就存在了 rda 等的具体一个盘的节点了。


但是,这个盘还是不能用的。就好像新的硬盘买回来什么都没有,必须进行,分区,格式化,最后才能存储数据。




下面说怎么在 fileio 例子中做测试
   p -> part_table_initialize
   f -> mount all disks in fs_table
   l -> list  file
   r -> read  file
   w -> write file
   s -> start shell


先执行 w 写入文件,不用怕,因为默认是使用了 IMFS 来启动的,所以这个文件系统一定能用。
输入文件名,例如 /test,然后输入大小,输入 100 字节,接着输入一个缓冲大小,输入 512 就行了。


   Enter your selection ==>w
 =========================
 WRITE FILE ...           
 =========================
--- unused dynamic memory: 65709332 bytes ---
Enter path/filename ==>/test
use suffix K for Kbytes, M for Mbytes or no suffix for bytes:
Enter filesize to write ==>100
use suffix K for Kbytes, M for Mbytes or no suffix for bytes:
Enter block size to use for write calls ==>512
... allocating 512 bytes of buffer for write data
... filling buffer with write data
... creating file "/test"
... writing to file
time elapsed for write:  0 seconds
write data rate: inf KBytes/second
... closing file
... deallocating buffer


 ******** End of file write
--- unused dynamic memory: 65709332 bytes ---


接着按 s 进入shell,ls一下根目录,应该出现了 test文件,然后cat一下文件内容
RTEMS SHELL (Ver.1.0-FRC):/dev/console. Dec 13 2013. 'help' to list commands.
[/] # ls
dev     etc     scripts test
[/] # cat test
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog


表面文件已经存在了。可以 exit命令退出刚才的菜单,选择读取和list来测试。


接着看看怎么测试 ramdisk
上面的分析看到,这个demo上面添加了 mkrd,用来生成一个
RTEMS SHELL (Ver.1.0-FRC):/dev/console. Dec 13 2013. 'help' to list commands.
[/] # mkrd
Register RAM Disk Driver [blocks=1024 block-size=512]:successful
[/] # ls /dev/
console rda
[/] # 


执行返回成功,一个块是 512字节,一共有 1024个,在 /dev上生成了 rda 的节点,这个和上面的分析
是完全吻合的。


接着执行格式化,生成一个加载点,ramdisk,然后加载到上面。


[/] # mkdir ramdisk
[/] # mkdos -t 16 /dev/rda
msdos format: /dev/rda
msdos format successful
[/] # mount -t dosfs /dev/rda /ramdisk
mounted /dev/rda -> /ramdisk
[/] # 


可以看到,操作都成功了。怎么验证呢?
现在已经加载成功了,表示对 /ramdisk 的操作实际上是写进去 ramdisk里面的。
先回去刚才的菜单执行 w ,在 /ramdisk 目录生成一个 test文件,操作和刚才一样
又回到shell,查看 /ramdisk 目录下确实有个这么一个文件
[/] # ls /ramdisk/
test
[/] # cat /ramdisk/test
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
[/] # 


接着 unmount 盘
[/] # unmount /ramdisk
unmounted /ramdisk
[/] # ls /ramdisk
[/] # 


可以看到,unmount之后,这个目录本来有的文件就没有了。因为文件是保存在 ramdisk里面的
[/] # mount -t dosfs /dev/rda /ramdisk
mounted /dev/rda -> /ramdisk
[/] # ls /ramdisk
test
[/] # ls /ramdisk
test
[/] # cat /ramdisk/test
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
[/] 


重新加载之后发现文件还在,内容也是一样的,这样就验证了,ramdisk确实是已经正常运行了。在ramdisk直接可以用cp
等命令复制文件到根目录,等待操作都是可以的。




更多的细节,读写是怎么实现的呢?
rc = rtems_disk_create_phys(dev, c->block_size, c->block_num,
                                    ramdisk_ioctl, r, name);
看看这个处理句柄
int
ramdisk_ioctl(rtems_disk_device *dd, uint32_t req, void *argp)
        case RTEMS_BLKIO_REQUEST:
        {
            rtems_blkdev_request *r = argp;
            struct ramdisk *rd = rtems_disk_get_driver_data(dd);


            switch (r->req)
            {
                case RTEMS_BLKDEV_REQ_READ:
                    return ramdisk_read(rd, r);


                case RTEMS_BLKDEV_REQ_WRITE:
                    return ramdisk_write(rd, r);


                default:
                    errno = EINVAL;
                    return -1;
            }
            break;
        }
可以看到,具体的读写是通过调用 ioctl来实现的,反向跟踪能找到根源
rtems_driver_address_table rtems_ramdisk_io_ops = {
  .....
  read_entry:           rtems_blkdev_generic_read,
  .....
};


ramdisk的设备驱动注册的时候指定了 rtems_blkdev_generic_read 作为个驱动的读方法,也就是说,ramdisk作为一个
block device 块设备,用其通用的操作
rtems_device_driver
rtems_blkdev_generic_read(
    rtems_device_major_number major __attribute__((unused)),
    rtems_device_minor_number minor __attribute__((unused)),
    void                    * arg)
{
----》
rc = rtems_bdbuf_read(dev, block, &diskbuf);


生成一个读请求
rtems_bdbuf_create_read_request (dd, media_block, bds_per_group, req, &bd);
    --》req->req = RTEMS_BLKDEV_REQ_READ;


sc = rtems_bdbuf_execute_transfer_request (dd, req, true);
    --》result = dd->ioctl (dd->phys_dev, RTEMS_BLKIO_REQUEST, req);


这里的 ioctl 就是之前创建disk的时候传入的ioctl回调函数,也就是 ramdisk_ioctl 了。
而两个参数 RTEMS_BLKIO_REQUEST 和 RTEMS_BLKDEV_REQ_READ就是这么传进来的。而具体的读写
是有 ramdisk_ioctl 自己去实现的。


这是基本的设计思想了,块设备是一个非相关的设计,具体怎么读写磁盘是由各个驱动自己去实现的。
另外RTEMS的函数名字很长很完整,感觉看起来实在太舒服了。


分析到这里为止了。基本能解释架构了。
接着需要分析的是文件系统的实现,和 bdpart 相关的,目前还没有看懂,慢慢来。


Etual
2013-12-19
网友gavotte开发的Ramdisk,是从微软的Ramdisk改写的,完全免费,支持windows2k以上的操作系统,内存盘容量基本没限制,并且经朋友们长期使用,非常稳定。我在原英文版的基础上汉化成简体中文,做了一些细节调整,方便大家使用。特备详细的使用说明! 内存盘的特性是把数据完全存储在内存中,所以一旦关闭计算机,就会导致内存盘中的数据完全丢失,这个特性使得内存盘特别适合于存储一些临时文件,如IE的缓存,Windows应用程序运行时产生的临时文件,这些文件都适合放到内存盘上,从而减少硬盘上文件碎片的产生,并且不需要主动删除这些临时文件,一旦重新启动,这些垃圾文件就自动消失了。也正是这个特性,使得内存盘不适合存储重要的数据文档,因为一旦死机,这些东西就再也找不回来了。 安装使用内存盘大操作系统要求是windows2K以上,内存256兆以上。内存太小就不要使用内存盘了,否则会降低windows的运行效率。 一、Ramdisk的安装 运行Ramdisk.exe,如果没有安装过内存盘,那么仅是点击“安装内存盘"按钮就可以了,安装时windows可能会警告驱动程序没有数字签名,不去理睬它,按“确定”就可以了。安装完毕,除了“安装内存盘”按钮以外的其他按钮都可用了。设置非常简单,仅包括盘符、内存盘大小、磁盘类型3个选项。还有一些高级设置可通过修改注册表,一般情况下不需要设置。 二、选择内存盘大小 这个数值完全取决于你的电脑的内存多少。如果你的电脑只有256兆内存,那么内存盘选择32兆就可以了,512MB内存可选择64-128MB之间,如果你有1G内存以上,最多可以把内存盘的大小设置为784兆。 三、选择盘符 缺省是R,只要是没有使用的盘符都行。 四、选择磁盘类型 缺省是硬盘类型,还可以设置为内存盘可移动磁盘类型。 五、完成 选择好需要的设置后,按“应用”按钮或者“确定”按钮就可以了,打开资源管理器,你就会发现多了一个盘符R(假定你设置的盘符是R,以后都直接用盘符R来代表内存盘)。 六、通过系统设置充分发挥内存盘的作用 1、首先设置系统的临时文件夹目录 告诉系统应用程序把临时文件都写到内存盘上,这样可以提高系统的运行效率,又不需要担心死机导致的临时文件夹目录逐渐增大的问题。 右键点击桌面上面的“我的电脑”,高级=》环境变量,设置包括“用户环境变量”“系统环境变量”都改成R:\TEMP,记住,最好不要用R:的根目录作为临时目录。 2、更改IE的缓存目录 告诉IE把浏览网页时产生的临时文件都写到内存盘上,可以加快ie的浏览速度。 选择 控制面板=》intetnet选项=》常规=》设置,修改IE的缓存目录,如果是宽带,这个目录大小设置3-5M即可。 3、其他应用程序的设置 如winzip、winrar,需要单独设置,一般都比较容易找到修改设置的位置(注意:过大的压缩文件即体积超过内存盘容量的,解压时会出错)。但是如果在设置系统的临时文件夹目录以后,安装这些软件,一般会根据系统设置自动调整,不需要修改了。 4、编译程序产生的临时文件 用过visual C 或者Gcc开发的朋友都知道,编译的过程会产生大量的临时文件,少的也有十几兆,可以调整编译器的设置,使得编译产生的中间文件都存到内存盘上,可以极大提高编译速度。 5、使用P2P软件下载,如edonkey,emule,BT等 这些软件的一个缺陷是由于是多线程访问硬盘,使得硬盘的磁头大量的无规律的移动,可能导致硬盘磁头的磨损,但是这个缺点对于内存盘来说,却根本不是缺点,因为内存盘根本没有磁头的机械运动,不过要记住下载完成后,要及时把文件拷贝到硬盘上,以免重启后文件丢失。 6、开临时ftp服务器分流热门文件 如果内存足够大,可以把热门的文件完全放到内存盘上,这样就不怕多线程访问ftp造成硬盘损坏的问题了。 一般,修改设置不需要重新启动,但是,如果有其他应用程序正在访问Ramdisk,会要求重启动。这时最好关闭访问Ramdisk的程序,值得注意的是ie的缓存,如果被设置到Ramdisk,这时修改内存盘的设置,就会要求重启动,因为IE缓存在登陆后就被资源管理器打开了,即使没用IE也会被占住。方法是登陆另一个管理员账号,或者修改IE缓冲目录(修改IE缓冲也要求重新登陆)。 补充:前面所讲的内存盘的用处都属于缓冲数据的用途,以便提高系统的运行效率,下面讲一点用内存盘模拟各种容量软驱的用途。 现在很多朋友的机器上都没有安装软驱,然而有一些程序,必须要有软驱才能运行,如制作瑞星杀毒软件的杀毒盘,或者一些软件需要验证钥盘后才能运行。 方法是把内存盘的类型设定为“可移动磁盘”,它也是软驱的类型。内存盘大小设置成需要的容量,如普通的软驱是1.44兆,也就是1440k的大小,盘符设置为A(如果没有特殊要求,其他的盘符也可以),然后双击“应用”按钮。 下面讲一个用Ramdisk模拟大容量软盘的例子,而Cenatek公司的内存盘则只能模拟标准容量的软驱。 Acronis系列软件Acronis PartitionExpert 2003、Acronis RecoveryExpert Deluxe、True Image 6.0等,均是上好的分区工具、文件恢复工具、系统备份工具等,与PQ、Easyrecover、Ghost等功能相同甚至更好,但Acronis系列软件做的紧急启动光盘很特殊,如果是用软盘做紧急启动盘则功能受限,或者需要超过3张以上的磁盘,如Ac ronis PartitionExpert 2003如果是完全版启动软盘是4张软盘,此系列紧急启动光盘在Windows或DOS下均无法看到任何文件,就算用什么软件也看不到任何文件,隐藏方法很特殊,但是紧急启动光盘是确实能启动的,如果用软件做成ISO文件,此ISO文件也是可以启动的,但用ISOButer等也看不到文件,用WinISO可以导出其启动文件,但有4M多,一般的启动软盘影像文件是1.44或2.88或更小,如何突破2.88MB限制,制作任意大小的软盘镜像?答案是Ramdisk。 步骤: 1、磁盘容量选择5M,磁盘类型选择“可移动磁盘”。 2、运行Bootable Rescue Media Builder,制作启动镜像。 3、双击Save Image按钮,这样就得到了5兆大小的PartitionExpert的启动镜像文件。 4、可以用bcdw加载这个启动镜像,制作多重启动光盘。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值