• 块设备驱动


     

    for (i = 0; i < nr; i++) {

    struct buffer_head *bh = bhs[i];

    submit_bh(rw, bh);

    struct bio *bio; // 使用bh来构造bio (block input/output)

    submit_bio(rw, bio);

    // 通用的构造请求: 使用bio来构造请求(request)

    generic_make_request(bio);

    __generic_make_request(bio);

    request_queue_t *q = bdev_get_queue(bio->bi_bdev); // 找到队列

     

    // 调用队列的"构造请求函数"

    ret = q->make_request_fn(q, bio);

    // 默认的函数是__make_request

    __make_request

    // 先尝试合并

    elv_merge(q, &req, bio);

     

    // 如果合并不成,使用bio构造请求

    init_request_from_bio(req, bio);

     

    // 把请求放入队列

    add_request(q, req);

     

    // 执行队列

    __generic_unplug_device(q);

    // 调用队列的"处理函数"

    q->request_fn(q);

       

    驱动程序

    1 /*
    2 * 块设备驱动程序:内存用作磁盘
    3 * 参考:
    4 * .linux-2.6.22.6driverslockxd.c
    5 * .linux-2.6.22.6driverslockz2ram.c
    6 */
    7
    8 #include <linux/module.h>
    9 #include <linux/errno.h>
    10 #include <linux/interrupt.h>
    11 #include <linux/mm.h>
    12 #include <linux/fs.h>
    13 #include <linux/kernel.h>
    14 #include <linux/timer.h>
    15 #include <linux/genhd.h>
    16 #include <linux/hdreg.h>
    17 #include <linux/ioport.h>
    18 #include <linux/init.h>
    19 #include <linux/wait.h>
    20 #include <linux/blkdev.h>
    21 #include <linux/blkpg.h>
    22 #include <linux/delay.h>
    23 #include <linux/io.h>
    24
    25 #include <asm/system.h>
    26 #include <asm/uaccess.h>
    27 #include <asm/dma.h>
    28
    29 /* 1M */
    30 #define RAMBlock_SIZE (1024*1024)
    31
    32 static unsigned char *ramBlock_buf;
    33
    34 static struct gendisk *ramBlock_disk;
    35 static request_queue_t *ramBlock_queue;
    36
    37 static int major;
    38
    39 /* 自旋锁 */
    40 static DEFINE_SPINLOCK(ramBlock_lock);
    41
    42 //为了使用fdisk分区工具,假装自己是磁盘,
    43 //有2个面,32个环,RAMBlock_SIZE/heads/cylinders/512个扇区
    44 //容量:RAMBlock_SIZE = heads*cylinders*sectors*512
    45 //1 disk                 = 2 heads
    46 //1 heads                  = 32 cylinders
    47 //1 cylinders        = RAMBlock_SIZE/heads/cylinders/512 sectors = 32 sectors
    48 static int ramBlock_getgeo(struct block_device *bdev, struct hd_geometry *geo)
    49 {
    50         geo->heads                 = 2;
    51         geo->cylinders         = 32;
    52         geo->sectors         = 32;
    53         return 0;
    54 }
    55
    56
    57 static struct block_device_operations ramBlock_fops = {
    58         .owner = THIS_MODULE,
    59         .getgeo = ramBlock_getgeo,
    60 };
    61
    62 static void do_ramBlock_request(request_queue_t *q)
    63 {
    64         static int r_cnt = 0;
    65         static int w_cnt = 0;
    66         struct request *req;
    67
    68         //以电梯调度算法,取出下一个请求
    69         while ((req = elv_next_request(q)) != NULL) {
    70                 /* 6 读写 */
    71                 //数据传输三要素:源、目的、长度
    72                 //源/目的        (要操作第几个扇区)
    73                 unsigned long offset = req->sector << 9;        //<< 9 相当于 * 512
    74
    75                 //目的/源        (读、写缓冲区)
    76                 //req->buffer
    77
    78                 //长度        (缓冲区长度(sector的倍数))
    79                 unsigned long len = req->current_nr_sectors << 9;
    80
    81                 //读数据
    82                 if (rq_data_dir(req) == READ)
    83                 {
    84                         printk("do_ramblock_request read %d ", ++r_cnt);
    85                         memcpy(req->buffer, ramBlock_buf+offset, len);
    86                 }
    87                 else {        //写数据
    88                         printk("do_ramblock_request read %d ", ++r_cnt);
    89                         memcpy(ramBlock_buf+offset, req->buffer, len);
    90                 }
    91
    92                 /******** 6 end ********/
    93                 end_request(req, 1);
    94         }
    95         return;
    96 }
    97
    98
    99 /* 1 出入口函数 */
    100 static int ramBlock_init(void)
    101 {
    102         /* 2 分配一个gendisk结构体 */
    103         ramBlock_disk = alloc_disk(16); //次设备号个数:分区个数+1
    104         /******** 2 end ********/
    105
    106         /* 3 设置 */
    107         //3.1 分配/设置队列(提供读写功能)
    108         ramBlock_queue = blk_init_queue(do_ramBlock_request, &ramBlock_lock);        
    109         
    110         //3.2 设置其他属性:如容量
    111         ramBlock_disk->queue                = ramBlock_queue;
    112
    113         major = register_blkdev(0, "ramBlock_disk");                //cat /proc/devices
    114         ramBlock_disk->major                = major;
    115
    116         ramBlock_disk->first_minor        = 0;
    117         sprintf(ramBlock_disk->disk_name, "ramBlock_disk");
    118         ramBlock_disk->fops                        = &ramBlock_fops;
    119         set_capacity(ramBlock_disk, RAMBlock_SIZE/512);                //第二个参数表示扇区个数,相对于内核而言,一个扇区为512字节
    120         /******** 3 end ********/
    121
    122         /*
    123          * 除了第4、第6、及以后的操作外,实际已经完成了块设备驱动框架的编写;        
    124          */
    125
    126         /* 4 硬件相关的操作 */
    127         ramBlock_buf = kzalloc(RAMBlock_SIZE, GFP_KERNEL);
    128         /******** 4 end ********/
    129
    130         /* 5 注册 */
    131         add_disk(ramBlock_disk);
    132         /******** 5 end ********/
    133         return 0;
    134 }
    135
    136
    137 static void ramBlock_exit(void)
    138 {
    139         unregister_blkdev(major, "ramBlock_disk");
    140         del_gendisk(ramBlock_disk);
    141         put_disk(ramBlock_disk);
    142         blk_cleanup_queue(ramBlock_queue);
    143         kfree(ramBlock_buf);
    144         return;
    145 }
    146
    147 module_init(ramBlock_init);
    148 module_exit(ramBlock_exit);
    149 MODULE_LICENSE("GPL");
    150 /******** 1 end ********/

       

       

    调试

    1. insmod ramBlock.ko

       

    2. 格式化:

    mkdosfs /dev/ramBlock_disk

       

    3. 挂接:

    mount /dev/ramBlock_disk /tmp

       

    4. 读写文件:

    cd /tmp

    vi 1.txt

       

    (分区:fdisk /dev/ramBlock_disk)

       

    5. 卸载

    cd /

    umount /tmp/

       

    6. 把/dev/ramBlock_disk目录下的文件,以镜像的形式保存到/mnt下

    cat /dev/ramBlock_disk > /mnt/ramBlock_disk.bin

       

    7. 在PC上查看ramBlock_disk.bin(把ramBlock_disk.bin作为回环设备挂接到/mnt)

    sudo mount -o loop ramBlock_disk.bin /mn

      

  • 相关阅读:
    Ext.Net 1.2.0_利用 Ext.Net 自定义 GridPanel Ajax 控件
    ASP.NET_0404_ASP.NET 重定向:页面传值
    程序设计_洗牌程序
    表单/验证表单——千万不要做一个只会拖控件、“照猫画虎”、copy/paste 程序员
    ASP.NET_0204_ASP.NET 重定向:如何将用户重定向到另一页
    Oracle 11g R1(11.1) Joins表连接
    隐藏 iframe 技术——Ajax 时代一个重要的环节
    Ext.Net 1.2.0_改变 Ext.Net.GridPanel 某行或某列的式样
    数据结构冒泡排序和直接插入排序
    XMLHttpRequest——Ajax 时代的到来
  • 原文地址:https://www.cnblogs.com/lilto/p/11878255.html
Copyright © 2020-2023  润新知