分析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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值