块设备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 底层接口与驱动开发技术详解》