第021讲 内核设备详解

文章详细介绍了磁盘存储的基础概念,包括磁盘类型如软盘和硬盘,以及磁盘数据结构如扇区、块和段。讨论了块设备在Linux系统中的处理,如块I/O调度层的作用和块设备结构`structblock_device`的关键属性。此外,还提到了gendisk结构和hd_struct结构在描述磁盘和分区时的角色,以及块设备操作集合的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、基本概念

磁盘(disk)是指利用磁记录技术存储数据的存储器。磁盘是计算机主要的存储介质, 可以存储大量的二进制数据,并且断电后也能保持数据不丢失。早期计算机使用的磁盘是软磁 盘(Floppy Disk,简称软盘),如今常用的磁盘是硬磁盘(Hard disk,简称硬盘)。

1、磁盘数据结构

在这里插入图片描述
一个弧道被划分成多个段,每个段就是一个扇区。
2、磁盘访问
sata硬盘实现的串行ATA协议,ATA下盘命令中记录有LBA(logic block address)起始地址和扇区数;
3、扇区
硬盘的基本访问单位,扇区的大小一般是512B。
4、块
扇区时硬件传输数据的基本单位,硬件一次传输一个扇区的数据到内存中。但是和扇区不同的是,块是虚拟文件系统传输数据的基本单位。Linux中块的大小必须是2的幂次方,但不能超过一个页大小(4K)。
5、段
主要为做scatter/gather DMA操作使用,同一个物理页面中在硬盘存储介质上连续的多个块组成一个段。段大小与块有关,必须是块的整数倍。块通常包含多个扇区。段包含多个块,物理段通常包括多个段;段在内核中由结构struct bio_vec来描述。
6、文件块
大小定义和文件系统一样是相对于文件的一个偏移逻辑块,需要通过具体文件系统中的文件对应inode所记录的间接块信息,换算成对应的文件系统块。

扇区由磁盘的物理特性所决定;块缓冲区由内核代码决定;块由缓冲区决定,是块缓冲区大小的整数倍(但是不能超过一页)
在这里插入图片描述
三者之间关系:扇区(512)<=块<=页(4096)块=n*扇区(n为整数)
段由多个块组成,一个段就是一个内存页。Linux系统一次读取磁盘的大小是一个块,页不是一个扇区,块设备驱动由此得名。

6、块设备与文件系统之间的关系

在这里插入图片描述
块设备处理过程涉及Linux内核中很多模块

在这里插入图片描述
块I/O调度层目的:将请求按照它们对应在块设备上的扇区号进行排列,以减少磁头移动,提升效率。

二、块设备详解

  1. 块设备I/O操作
    块设备只能以块为单位接收输入和返回输出,而字符设备则以字节为单位;
    块设备对于I/O请求有对应的缓冲区;
    字符设备只能被顺序读写,而块设备可以随机访问。
  2. 块设备–源码分析(block_device 是伪文件系统bdevfs中对块设备或设备分区抽象,它唯一对应于一个设备号(对分区来讲,主设备号相同,次设备号不同))
struct block_device {
	dev_t			bd_dev;  /* 对应底层设备的设备号 */
	int			bd_openers;	//该设备同时被多少个进程打开
	struct inode *		bd_inode;	/* 块设备的inode,可利用bd_dev通过bdget获得 */
	struct super_block *	bd_super;	// 文件系统的超级块信息
	struct mutex		bd_mutex;	/* open/close mutex */
	void *			bd_claiming;
	void *			bd_holder;
	int			bd_holders;
	bool			bd_write_holder;
#ifdef CONFIG_SYSFS
	struct list_head	bd_holder_disks;
#endif
	struct block_device *	bd_contains;
	unsigned		bd_block_size;	//块大小
	struct hd_struct *	bd_part;	// 指向分区指针,对于gendisk,指向内置的分区
	/* number of times partitions within this device have been opened. */
	unsigned		bd_part_count;	// 该设备的所以分区同时被打开的次数
	int			bd_invalidated;
	struct gendisk *	bd_disk;
	struct request_queue *  bd_queue;
	struct backing_dev_info *bd_bdi;
	struct list_head	bd_list;
	/*
	 * Private data.  You must have bd_claim'ed the block_device
	 * to use this.  NOTE:  bd_claim allows an owner to claim
	 * the same device multiple times, the owner must take special
	 * care to not mess up bd_private for that case.
	 */
	unsigned long		bd_private;

	/* The counter of freeze processes */
	int			bd_fsfreeze_count;
	/* Mutex for freeze */
	struct mutex		bd_fsfreeze_mutex;
};

  1. 通用磁盘–源码分析(gendisk,对于通用磁盘的描述,与真正的底层物理设备相关联)
struct gendisk {
	/* major, first_minor and minors are input parameters only,
	 * don't use directly.  Use disk_devt() and disk_max_parts().
	 */
	int major;			/* 主设备号*/
	int first_minor;	// 第一个次设备号
	int minors;         /* 表示分区的个数,分区号从1开始,0表示gendisk本身 */

	/* 磁盘名称,用于在sysfs和/proc/partitions中表示该磁盘*/
	char disk_name[DISK_NAME_LEN];	/* name of major driver */
	char *(*devnode)(struct gendisk *gd, umode_t *mode);

	unsigned int events;		/* supported events */
	unsigned int async_events;	/* async events, subset of all */

	/* Array of pointers to partitions indexed by partno.
	 * Protected with matching bdev lock but stat and other
	 * non-critical accesses use RCU.  Always access through
	 * helpers.
	 */
	struct disk_part_tbl __rcu *part_tbl;	//分区表
	struct hd_struct part0;	// 表示gendisk本身
	// 指向底层具体设备的操作函数
	const struct block_device_operations *fops;
	// 该磁盘关联的请求队列
	struct request_queue *queue;
	// 私有数据,用于提供用户驱动程序使用
	void *private_data;

	int flags;
	struct kobject *slave_dir;

	struct timer_rand_state *random;
	atomic_t sync_io;		/* RAID */
	struct disk_events *ev;
#ifdef  CONFIG_BLK_DEV_INTEGRITY
	struct kobject integrity_kobj;
#endif	/* CONFIG_BLK_DEV_INTEGRITY */
	int node_id;
	struct badblocks *bb;
};

  1. 磁盘分区–源码分析
struct hd_struct {
	sector_t start_sect;	// 该分区的起始扇区号

	sector_t nr_sects;		// 该分区的扇区个数,也就是分区容量
	seqcount_t nr_sects_seq;
	sector_t alignment_offset;
	unsigned int discard_alignment;
	struct device __dev;
	struct kobject *holder_dir;
	int policy, partno;
	struct partition_meta_info *info;
#ifdef CONFIG_FAIL_MAKE_REQUEST
	int make_it_fail;
#endif
	unsigned long stamp;
	atomic_t in_flight[2];
#ifdef	CONFIG_SMP
	struct disk_stats __percpu *dkstats;
#else
	struct disk_stats dkstats;
#endif
	struct percpu_ref ref;
	struct rcu_head rcu_head;
};
  1. 块设备操作集合–源码分析
struct block_device_operations {
	// 打开与释放
	int (*open) (struct block_device *, fmode_t);
	void (*release) (struct gendisk *, fmode_t);
	int (*rw_page)(struct block_device *, sector_t, struct page *, bool);
	// I/O 控制
	int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
	int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long);
	unsigned int (*check_events) (struct gendisk *disk,
				      unsigned int clearing);
	/* ->media_changed() is DEPRECATED, use ->check_events() instead */
	int (*media_changed) (struct gendisk *);
	void (*unlock_native_capacity) (struct gendisk *);
	int (*revalidate_disk) (struct gendisk *);

	// 获取驱动器信息
	int (*getgeo)(struct block_device *, struct hd_geometry *);
	/* this callback is with swap_lock and sometimes page table lock held */
	void (*swap_slot_free_notify) (struct block_device *, unsigned long);

	// 模块指针
	struct module *owner;
	const struct pr_ops *pr_ops;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值