块设备驱动
  HvTJUzsxOBtS 2023年11月22日 27 0


块设备I/O与字符设备操做的主要区别如下所示。

  • 块设备只能以块为单位接收输入返回输出,而字符设备则以字节为单位。大多数设备是字符设备,它们不需要缓冲并且不以固定块大小进行操作。
  • 块设备对于I/O请求有对应的缓冲区,所以它们可以选择以什么顺序进行响应。字符设备无
    须缓冲且被直接读/写。
  • 字符设备只能被顺序读写,块设备可以随机访问。

·
1) 结构体 block_device_operations

在文件 include/linux/fs.h 中定义了结构体 block_device_operations, 此结构体描述了对块设备的

操作的集合,具体代码如下所示:

block_device_operations结构体

struct block_device_operations {
    int (*open) (struct block_device *, fmode_t);      // 打开
    int (*release) (struct gendisk *, fmode_t);            //释放
    int (*locked_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
    int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
    int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
    int (*direct_access) (struct block_device *, sector_t,
                        void **, unsigned long *);
    int (*media_changed) (struct gendisk *);        // 介质被改变
    int (*revalidate_disk) (struct gendisk *);          // 使介质改变
    int (*getgeo)(struct block_device *, struct hd_geometry *);      // 填充驱动器信息
    struct module *owner;    //  模块拥有者
};
 

2) 结构体 gendisk

结构体 gendisk 来描述一个独立的磁盘设备或者分区,具体代码如下:

struct gendisk {
    int major;            /* 主设备号 */
    int first_minor;      //  第一个次设备号
    int minors;                     /*最大此设备数,如果不能分区 为1 */
    char disk_name[32];        /* name of major driver */
    struct hd_struct **part;    /*磁盘分区信息 */
    int part_uevent_suppress;
    struct block_device_operations *fops;   // 块设备操作
    struct request_queue *queue;               // 请求队列,用于 管理设备 I/O 请求队列的指针
    void *private_data;                    //   私有数据 
    sector_t capacity;                 //  扇区数 ,512 字节 为一个扇区,描述设备容量

    int flags;
    struct device *driverfs_dev;
    struct kobject kobj;
    struct kobject *holder_dir;
    struct kobject *slave_dir;

    struct timer_rand_state *random;
    int policy;

    atomic_t sync_io;        /* RAID */
    unsigned long stamp;
    int in_flight;
#ifdef    CONFIG_SMP
    struct disk_stats *dkstats;
#else
    struct disk_stats dkstats;
#endif
    struct work_struct async_notify;
};
 

3) 结构体 request 和 bio

(1) 请求 reauest 

结构体request和requestqueue在Lmux块设备驱动中,使用request结构体来表征等待进行的
I/O请求,用来表征一个块I/O请求队列。这两个结构体的定义代码如下所示:

struct request{undefined

        struct list_head queuelist;

        unsigned long flags;

        sector_t sector;/*要传输的下一个扇区*/

        unsigned long nr_sectors;/*要传送的扇区数目*/

        unsigned int current_nr_sector;/*当前要传送的扇区*/

        sector_t hard_sector;/*要完成的下一个扇区*/

        unsigned long hard_nr_sectors;/*要被完成的扇区数目*/

        unsigned int hard_cur_sectors;/*当前要被完成的扇区数目*/

        struct bio* bio;/*请求的bio结构体的链表*/

        struct bio* biotail;/*请求的bio结构体的链表尾*/

        

        /*请求在屋里内存中占据的不连续的段的数目*/

        unsigned short nr_phys_segments;

        unsigned short nr_hw_segments;

        int tag;

        char* buffer;/*传送的缓冲区,内核的虚拟地址*/

        int ref_count;/*引用计数*/

        ...

    };


(2) 请求队列 request_queue 

请求队列跟踪等候的块I/O请求,它存储用于描述这个设备能够支持的请求的类型信息。请求队列
还要实现一个插入接口,这个接囗允许使用多个I/O调度器,I/O调度器以最优性能的方式向驱动提交
I/O请求。大部分I/O调度器积累批量的I/O请求,并将其排列为递增/递减的块索引顺序后提交给驱动。
另外,I/O调度器还负责合并邻近的请求,当一个新的I/O请求被提交给调度器后,它会在队列中搜寻
包含邻近的扇区的请求。如果找到一个并且此请求合理,则调度器会将这两个请求合并。
结构体request_queue的定义代码如下所示:

struct request_queue{

...

/*自旋锁,保护队列结构体*/

;

* queue_lock;

struct kobject kobj;/*队列kobject*/

/*队列设置*/

unsigned long nr_requests;/*最大的请求数量*/

unsigned int  nr_congestion_on;

unsigned int  nr_congestion_off;

unsigned int  nr_batching;

unsigned short max_sectors;/*最大扇区数*/

unsigned short max_hw_sectors;

unsigned short max_phys_sectors;/*最大的段数*/

unsigned short max_hw_segments;

unsigned short hardsect_size;/*硬件扇区尺寸*/

unsigned int max_segment_size;/*最大的段尺寸*/

unsigned long seg_boundary_mask;/*段边界掩码*/

unsigned int dma_alignment;/*DMA传送内存对齐限制*/

struct blk_queue_tag* queue_tags;

;/*引用计数*/

unsigned int in_flight;

unsigned int sg_timeout;

unsigned int sg_reserved_size;

int node;

struct list_head drain_list;

struct request* flush_rq;

unsigned char ordered;

};

当然: 在块设备上 ,同样可以使用函数 实现 块设备 驱动的 模块卸载 、 加载 、打开与释放操作,相关知识请参阅先关资料。

Android 的 块设备 驱动在目录 /dev/block 中,其中主要内容如下所示:

块设备驱动_块设备

 在上述内容中,主设备号为1的是各个内存块设备,主设备号为7的是各个回环块设备,主设
备号为31的是mtd设备中的块设备,mmcblk0 表示SD卡的块设备。
在Android 统中,可以使用mount命令来查看系统中被挂起的文件系统。使用mount命令的
格式如下所示:

mount [-t vfstype]  [-o options]    device dir

上述命令中主要参数的具体说明如下所示。
(1) -t vfstype:用于指定文件系统的类型,通常不必指定。mount会自动选择正确的类型。常用
类型有如下6类。

  • 光盘或光盘镜像:is09660.
  • DOSFAT16文件系统:msdos
  • Windows9xFAT32文件系统:vfat
  • WindowsNTNTFS文件系统:ntfs
  • Mount Windows 文件网络共享:smbfs
  • UNIX(Linux)文件网络共享:nfs

(2) -o options:主要用来描述设备或档案的挂接方式。常用的参数有如下4类。

  • loop:用来把一个文件当成硬盘分区挂接上系统。
  • ro:采用只读方式挂接设备。
  • rw:采用读/写方式挂接设备。
  • iocharset:指定访问文件系统所用字符集。

(3) device:要挂接(Mount)的设备。

(4) dir : 设备在系统上的挂载点 (Mount Point)

另外,在Android系统中可以使用df命令来查看系统中各个盘的使用情况。使用df命令的格式
如下所示:

df [optionsl
参数 options 常用取值的具体说明如下所示。

  • 一s:对每个Names参数只给出占用的数据块总数。
  • —a:递归地显示指定目录中各文件及子目录中各文件占用的数据块数。若既不指定一,也
    不指定一a,则只显示Names中的每一个目录及其中的各子目录所占的磁盘块数。
  • —k:以1024字节为单位列出磁盘空间的使用情况。
  • 一x:不统计不同文件系统上的目录。
  • -l : 计算所有的文件大小,对硬链接文件则计算多次。
  • -i : 显示 inode 而非块使用量
  • —h:以容易理解的格式打印输出文件系统大小,例如136KB、254MB、21GB.
  • -P : 使用 POSIX 输出格式
  • -T : 显示文件系统类型

文章摘自:

《Android 底层接口与驱动开发技术详解》

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月22日 0

暂无评论

推荐阅读
HvTJUzsxOBtS