1 生态
磁盘级文件的保存由磁盘级文件系统决定,我们有必要了解磁盘从而更好地理解文件;
早在7~8年前,甚至10年前,笔记本电脑存储介质(🙅♀️不是内存)磁盘陆陆续续变成SSD(固态硬盘),早在10年前,甚至20年前,笔记本刚出来的时候比较厚,装载的是机械磁盘,外形笨重,轻量化和小型化比较困难,如果停留在机械磁盘厂商的笔记本就会卖不过对手,电子产品一般追求极致,早期笔记本刚出来装载的机械磁盘比如希捷的磁盘,慢慢的变成磁盘和SSD混盘,但是SSD比较贵,一般是磁盘的1.5 ~2倍,SSD轻便客服端主流,台式机有的也装SSD,但机械磁盘在服务器端依然是主流,因为机械磁盘的单盘容量比较大,而企业有海量的数据需要存储,离用户近的场景可能使用SSD,以求高IO,机械磁盘是学习OS重要的方式
机械磁盘出名的厂商比如希捷、西部数据、西数、东芝很多都是日韩或西方的欧美企业,磁盘很多元器件比较精密,日本曾做过指甲盖大小的磁盘,当时机械磁盘的主流技术都在西方,当时中国起步晚,很难追赶;包括现在的OS,随着我国存储能力和工业制造能力的增强,国产的SSD做的特别好,包括内存技术也还可以,存储原理不同
机械磁盘西方主导
现如今,桌面级台式机/笔记本用的都是SSD,企业端后端80%的存储硬件,永久化存储介质都是机械硬盘,10~20%的SSD或者flash卡,厂商提供机械磁盘或者硬盘分为to B和to C,企业级磁盘和桌面级磁盘desktop,to B和to C的区别是,to C的机械磁盘会对同一块磁盘把某些技术做裁剪,缩容,大部分桌面级磁盘一般都是台式机在使用,机械磁盘容量一般是1/2/4T,性价比高,因为磁盘易损,但是对老百姓使用而言足够了
而企业级磁盘面向后端,单盘4/8/16T,运算精度较高,工艺更精细
磁盘全称机械磁盘,是计算机中的唯一机械设备,具有永久存储能力,属于外设=>速度慢,但是容量大,价格低,甚至能做到几毛或几分/GB,大型互联网公司每年买100万个磁盘,每个磁盘2000,这成本就不低,如果换成SSD或flash卡,要翻5/10/20倍
同时,企业内也有专门的岗位,来处理IO问题
现在的笔记本、手机电子产品接近光速,而企业级磁盘还是物理速度

下面是主体,表层是铝合金板,螺丝上紧,周围打一圈密封胶
拆卸表层,下层如下所示

磁盘一旦拆开进入空气中的灰尘,对用户来说磁盘基本报废,磁盘密封内部无菌/尘,做磁盘第一步是打造一个无尘实验室/生产车间,下一步才是磁盘技术

如果单盘4G*(4*6) *8 *机柜数,容量约为800GB *机柜数,一般大型互联网公司机房的服务器都是几十万台,过百万
计算机硬件耦合度比软件做得好,网卡,内存条,显卡,磁盘,不区分厂商都能插到电脑上用,磁盘、服务器、机柜、网线生产厂商各生产个的,还能组装到一起使用
企业级磁盘希捷做得最好,磁盘的价格贵,服务器更贵,一体机式的单盘服务器便宜的四五万,贵的几十万,与配置有关,服务器有单/双CPU,一般都是双,甚至更高;机柜更贵,做机房还要供电,买地,盖楼,买得起的是大型互联网公司,机房的本质是强大的算力和存储能力,阿里巴巴/亚马逊花了大量的人力物力建机房,但是有大量剩余的算力,波峰波谷,白天电脑也不是任何时候都全工号运行,有的时间上网的人少,过剩的算力经过软件设计,打包成云服务,给搞不起机房的小公司用,企业回收成本,也降低创业公司(一般<=100人),个人,研究机构使用算力的成本,提高整个社会的效率,没个100-200亿买不起
服务器是有淘汰寿命的,7 *24运转,标准服务器的使用年限是3-5年
散热,电脑热的不行会卡死,这么多服务器在一个封闭的空间,开空调,冬天灌外部的冷风,夏天几乎是24h开空调
企业要减少运营成本,到地价/电价/人力成本便宜的地方去,比如内蒙古,贵州,包括正在建的雅鲁藏布江空间站,将来周围会有大量机房
西北->西南/沿海地区,电力有损耗,运输成本,所以在西北比如青海没有这些成本,电价低,也有上海北京(一般是老机房)
为了降低运维成本,有很多脑洞大的手段,谷歌把机房建到了海里,机房布满管道,海水流动把热量带走
也可以在俄罗斯西伯利亚建,hanhang🙅♀️不是内存)磁盘陆陆续续变成SSD(固态硬盘),早在10年前,甚至20年前,笔记本刚出来的时候比较厚,装载的是机械磁盘,外形笨重,轻量化和小型化比较困难,如果停留在机械磁盘厂商的笔记本就会卖不过对手,电子产品一般追求极致,早期笔记本刚出来装载的机械磁盘比如希捷的磁盘,慢慢的变成磁盘和SSD混盘,但是SSD比较贵,一般是磁盘的1.5 ~2倍,SSD轻便客服端主流,台式机有的也装SSD,但机械磁盘在服务器端依然是主流,因为机械磁盘的单盘容量比较大,而企业有海量的数据需要存储,离用户近的场景可能使用SSD,以求高IO,机械磁盘是学习OS重要的方式
机械磁盘出名的厂商比如希捷、西部数据、西数、东芝很多都是日韩或西方的欧美企业,磁盘很多元器件比较精密,日本曾做过指甲盖大小的磁盘,当时机械磁盘的主流技术都在西方,当时中国起步晚,很难追赶;包括现在的OS,随着我国存储能力和工业制造能力的增强,国产的SSD做的特别好,包括内存技术也还可以,存储原理不同机械磁盘西方主导现如今,桌面级台式机/笔记本用的都是SSD,企业端后端80%的存储硬件,永久化存储介质都是机械硬盘,10~20%的SSD或者flash卡,厂商提供机械磁盘或者硬盘分为to B和to C,企业级磁盘和桌面级磁盘desktop,to B和to C的区别是,to C的机械磁盘会对同一块磁盘把某些技术做裁剪,缩容,大部分桌面级磁盘一般都是台式机在使用,机械磁盘容量一般是1/2/4T,性价比高,因为磁盘易损,但是对老百姓使用而言足够了而企业级磁盘面向后端,单盘4/8/16T,运算精度较高,工艺更精细硬件物理结构磁盘结构 抽象 OS如何看待磁盘磁盘全称机械磁盘,是计算机中的唯一机械设备,具有永久存储能力,属于外设=>速度慢,但是容量大,价格低,甚至能做到几毛或几分/GB,大型互联网公司每年买100万个磁盘,每个磁盘2000,这成本就不低,如果换成SSD或flash卡,要翻5/10/20倍同时,企业内也有专门的岗位,来处理IO问题现在的笔记本、手机电子产品接近光速,而企业级磁盘还是物理速度
如果单盘4G*(4*6) *8 *机柜数,容量约为800GB *机柜数,一般大型互联网公司机房的服务器都是几十万台,过百万计算机硬件耦合度比软件做得好,网卡,内存条,显卡,磁盘,不区分厂商都能插到电脑上用,磁盘、服务器、机柜、网线生产厂商各生产个的,还能组装到一起使用企业级磁盘希捷做得最好磁盘的价格贵,服务器更贵,一体机式的单盘服务器便宜的四五万,贵的几十万,与配置有关,服务器有单/双CPU,一般都是双,甚至更高;机柜更贵,做机房还要供电,买地,盖楼,买得起的是大型互联网公司,机房的本质是强大的算力和存储能力,阿里巴巴/亚马逊花了大量的人力物力建机房,但是有大量剩余的算力,波峰波谷,白天电脑也不是任何时候都全工号运行,有的时间上网的人少,过剩的算力经过软件设计,打包成云服务,给搞不起机房的小公司用,企业回收成本,也降低创业公司(一般<=100人),个人,研究机构使用算力的成本,提高整个社会的效率,没个100-200亿买不起服务器是有淘汰寿命的,7 *24运转,标准服务器的使用年限是3-5年散热,电脑热的不行会卡死,这么多服务器在一个封闭的空间,开空调,冬天灌外部的冷风,夏天几乎是24h开空调企业要减少运营成本,到地价/电价/人力成本便宜的地方去,比如内蒙古,贵州,包括正在建的雅鲁藏布江空间站,将来周围会有大量机房西北->西南/沿海地区,电力有损耗,运输成本,所以在西北比如青海没有这些成本,电价低,也有上海北京(一般是老机房)为了降低运维成本,有很多脑洞大的手段,谷歌把机房建到了海里,机房布满管道,海水流动把热量带走也可以在俄罗斯西伯利亚建,hanhang
2 磁盘物理结构
我们看到,每一个机械硬盘拆开表明的铝板,是一个光滑的光盘,下图是早年的光盘,可以放进DVD等看电影,听音乐,本质是光盘上存储数据,这个光盘一旦形成只能读,不能写;但是磁盘可读可写,正反两面都是光滑的

那么磁盘是怎么存数据的?

先看磁铁,有两极,可以用作表示0和1,可以想象成磁盘上聚簇了大量的磁铁(非常微小),表面打磨光滑,向磁盘写01二进制是应用程序员的表达方式,本质是改变磁盘上每一个磁铁的南北极,电磁不分家,通过电,改变磁铁上的南北极,磁盘是有弱点的,磁头上有电力,通过电磁感应,改变南北极,写入01,而且磁铁放几十年不会改变,磁盘写入01之后是永久性介质,写完就长期保存不变
国家安全要求互联网公司淘汰下来的报废磁盘数据要彻底消除,可以通过高温消磁(磁铁经过高温丧失磁性),因为上面存的是大量的用户数据;或者通过软件的方式全部置0/1
高温消磁最不可逆,但是对企业来说,成本太高,也有其它说做
磁盘在高速旋转,磁头在摆动,二者没有紧挨,一般相距微米/纳米级高度,如果紧挨,高速旋转,摩擦生热,高温会丧失磁性
磁盘相当于纸,磁头相当于笔,如果用于笔记本,要搬来搬去或者不慎摔了,磁头可能会上下震动,刮花盘面,而且摩擦产生高温,可能导致丢失数据;如果刮到了比较敏感的地区,比如boot区,开机的地方,可能笔记本开不了机
在机械磁盘用于笔记本的时候,不到半年/一年,笔记本蓝屏/黑屏,因为搬来搬去刮花的多了,而且磁盘本身也有马达震动产生高温,用的久了产生莫名其妙的错误,如果系统错了,重装大法
磁头臂上有线圈,通电,线圈在磁场中受力,磁头臂左右摆动,磁头在磁盘上空,在不同磁道间移动,控制电流大小、方向,能精准定位到某一磁道读写;磁头臂上自带一个弹簧(复位弹簧),音圈马达没电,不再产生推力维持位置,弹簧弹力+永磁铁的吸附力一起把磁头臂强行推回到最内侧的停靠区(landing zone,安全区,不是数据磁道,防止刮伤盘片)


所有盘面在主轴马达的带领下高速旋转,磁头在机械臂杆的带领下左右移动,所有磁头(盘面数=磁头数)的运动轨迹一致,所有盘片共旋转,所有盘面相同半径的磁道构成柱面

扇区是磁盘存储数据的基本单位 ,一般是512B,是块设备,也可能是4knB(n=1,2,4,...),是指IO时最小修改单位,比如内存存储数据单位是B,至少CPU从内存读一个字节修改并写回
那么离圆心越近,扇区的面积越小,我们认为扇区的容量相同,所以离圆心越近,数据密度更大(现代磁盘可能离圆心远的位置多做几个扇区,需要厂商提供更复杂的调度算法)
3 磁盘存储数据
向磁盘写入,文件=内容+属性,都是数据,要写入数据到磁盘,首先要找到写入哪一个扇区,以512B为单位
定位一个扇区,从而定位任意一个扇区,从而定位任意多个扇区(一个文件可能存储在多个扇区)
我们先来一个比较形象的理解(但和真实情况有出入),下面是磁带,通过两个齿轮的转动,可以遍历磁带上,访问磁带上的数据

我们可以把每一个盘面想象成一卷磁带,把磁带拉平,就是线性的,最外围的磁道扇区从0开始编号,接着把每一个盘面拉成的磁带拼到一起,整个磁盘就是一个线性数组,每个元素就是扇区,从1开始编号,扇区的编号就是LBA(linear block address)地址

所以我们可以这样确定扇区
1.在哪一个盘面,根据磁头(header)编号
2.在盘面的哪一个磁道(cylinder)
3.在磁道的哪一个扇区(sector)
也叫CHS定位
实际在访问一个扇区的时候先访问的是柱面,接着是盘面(磁头号),最后是磁道中的一个扇区,先让所有磁头摆动到柱面,盘片旋转到对应的扇区,接着找到要使用的磁头,磁头进行读写



按柱面铺开,每一个柱面按磁道铺开,如下所示

磁盘本质由柱面构成,每个柱面不同盘面的磁道按磁道号从小到大平铺,接着不同柱面的扇区铺到一起,因此是柱面号,盘面号,扇区号,可以定位一个扇区,磁盘本质是三维数组,可以理解为一维数组,那么CHS的本质就是三维数组下标,LBA的本质是一维数组下标,只需要知道磁盘总容量和一个扇区的大小,就知道有多少个扇区,根据扇区编号也就是LBA来访问扇区即可;类似内存总容量为4GB,存储单元为B,那么内存也可以看做一维数组,下标从0~2^32-1;CHS和LBA之间的转换由磁盘来做,扇区编号从1开始,柱面,磁头编号从0开始
C柱面号=LBA/(每个磁道的扇区数* 盘面数)
H盘面号=(LBA%(每个磁道的扇区数 * 盘面数))/盘面数
S扇区号=(LBA%每个磁道的扇区数)+1
LBA=C * (每个磁道的扇区数*盘面数)+H *每个磁道的扇区数+S
向磁盘指定位置写入数据,比如LBA=200,数据为xxx,磁盘包括任何外设都有控制器,比如控制器里有r/w的权限位,接收LBA地址,存放数据data,OS在向磁盘写入的时候指明是r还是w,LBA地址,以及要写入的数据即可,包括虚拟地址空间是大于内存容量的,那么页表一部分对应的是内存,一部分对应的是磁盘

Xshell下通过fisk -l查看磁盘情况,有扇区大小

但实际上我们知道磁盘IO是很慢的,那么一次读取一个磁盘不划算,所以块其实是磁盘的最小读写单位,因此OS给磁盘提供的实际上是块号,一般块的大小为4KB,连续的8个扇区组成一个块,主要的原因是提高效率,其他因素比如软硬件解耦,如果更换磁盘OS不需要管扇区大小的变化,永远只需要提供块号,剩下的工作是磁盘的

Xsehll下stat 文件名可以查看磁盘的块大小


OS内部对磁盘进行分区,分组都是先描述再组织
4 磁盘分组介绍

inode bitmap标识inode table中每一个inode是否被使用,block bitmap标识每一个block是否被使用,GDT(group descriptor table),inode table和data blocks是存放文件数据的,而inode bitmap和block bitmap是标识inode和block的使用信息的,相当于是表示局部信息,而GDT就是标识整个组的信息的,还有多少可用的block和inode,哪些被占用了,哪些没被占用等,block bitmap,inode bitmap,inode table和data blocks的起始块号,结束块号,各自在块的具体什么位置等信息,GDT管一个组,那一个分区多少组,有多少block和inode,可用的有多少,super block是记录整个分区的信息,比如分区有多大,分区总共有多少块,分区的起始块号,结束块号,最后一次写入/挂载时间等,那super block是描述整个分区的,为什么在组里呢?其实每个分区的2~3个组有super block,因为super block记录整个分区的信息,一旦丢失,整个分区就废了,但是磁盘易损,磁头摆动,或者发生振动,都可能损坏磁盘,所以存2 ~ 3份的意义在于备份,如果一个super block坏了,进行修复,可以把其它完好的super block拷贝到当前super block
那么删除文件做了什么呢?其实删除文件不需要把文件对应的data block都清空置零或置1,只需要查inode把对应的data block在位图中置0,表示可用即可,把对应的inode在位图中也置0,但拷贝就是实打实的拷贝文件属性+数据,比较慢
inode大小是128B,在内存中填充完以二进制的形式写到inode table,固定不变,存的都是整数,一个块有4KB/27B=2^5个inode,inode属性没有文件名也是考虑到文件名是变长的

inode结构

cpp
/*
* Structure of an inode on the disk
*/
struct ext2_inode {
__le16 i_mode; /* File mode */
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size; /* Size in bytes */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Creation time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
__le16 i_links_count; /* Links count */
__le32 i_blocks; /* Blocks count */
__le32 i_flags; /* File flags */
union {
struct {
__le32 l_i_reserved1;
} linux1;
struct {
__le32 h_i_translator;
} hurd1;
struct {
__le32 m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
__le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
__le32 i_generation; /* File version (for NFS) */
__le32 i_file_acl; /* File ACL */
__le32 i_dir_acl; /* Directory ACL */
__le32 i_faddr; /* Fragment address */
union {
struct {
__u8 l_i_frag; /* Fragment number */
__u8 l_i_fsize; /* Fragment size */
__u16 i_pad1;
__le16 l_i_uid_high; /* these 2 fields */
__le16 l_i_gid_high; /* were reserved2[0] */
__u32 l_i_reserved2;
} linux2;
struct {
__u8 h_i_frag; /* Fragment number */
__u8 h_i_fsize; /* Fragment size */
__le16 h_i_mode_high;
__le16 h_i_uid_high;
__le16 h_i_gid_high;
__le32 h_i_author;
} hurd2;
struct {
__u8 m_i_frag; /* Fragment number */
__u8 m_i_fsize; /* Fragment size */
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
};
超级块

cpp
/*
* Structure of the super block
*/
struct ext2_super_block {
__le32 s_inodes_count; /* Inodes count */
__le32 s_blocks_count; /* Blocks count */
__le32 s_r_blocks_count; /* Reserved blocks count */
__le32 s_free_blocks_count; /* Free blocks count */
__le32 s_free_inodes_count; /* Free inodes count */
__le32 s_first_data_block; /* First Data Block */
__le32 s_log_block_size; /* Block size */
__le32 s_log_frag_size; /* Fragment size */
__le32 s_blocks_per_group; /* # Blocks per group */
__le32 s_frags_per_group; /* # Fragments per group */
__le32 s_inodes_per_group; /* # Inodes per group */
__le32 s_mtime; /* Mount time */
__le32 s_wtime; /* Write time */
__le16 s_mnt_count; /* Mount count */
__le16 s_max_mnt_count; /* Maximal mount count */
__le16 s_magic; /* Magic signature */
__le16 s_state; /* File system state */
__le16 s_errors; /* Behaviour when detecting errors */
__le16 s_minor_rev_level; /* minor revision level */
__le32 s_lastcheck; /* time of last check */
__le32 s_checkinterval; /* max. time between checks */
__le32 s_creator_os; /* OS */
__le32 s_rev_level; /* Revision level */
__le16 s_def_resuid; /* Default uid for reserved blocks */
__le16 s_def_resgid; /* Default gid for reserved blocks */
/*
* These fields are for EXT2_DYNAMIC_REV superblocks only.
*
* Note: the difference between the compatible feature set and
* the incompatible feature set is that if there is a bit set
* in the incompatible feature set that the kernel doesn't
* know about, it should refuse to mount the filesystem.
*
* e2fsck's requirements are more strict; if it doesn't know
* about a feature in either the compatible or incompatible
* feature set, it must abort and not try to meddle with
* things it doesn't understand...
*/
__le32 s_first_ino; /* First non-reserved inode */
__le16 s_inode_size; /* size of inode structure */
__le16 s_block_group_nr; /* block group # of this superblock */
__le32 s_feature_compat; /* compatible feature set */
__le32 s_feature_incompat; /* incompatible feature set */
__le32 s_feature_ro_compat; /* readonly-compatible feature set */
__u8 s_uuid[16]; /* 128-bit uuid for volume */
char s_volume_name[16]; /* volume name */
char s_last_mounted[64]; /* directory where last mounted */
__le32 s_algorithm_usage_bitmap; /* For compression */
/*
* Performance hints. Directory preallocation should only
* happen if the EXT2_COMPAT_PREALLOC flag is on.
*/
__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
__u16 s_padding1;
/*
* Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
*/
__u8 s_journal_uuid[16]; /* uuid of journal superblock */
__u32 s_journal_inum; /* inode number of journal file */
__u32 s_journal_dev; /* device number of journal file */
__u32 s_last_orphan; /* start of list of inodes to delete */
__u32 s_hash_seed[4]; /* HTREE hash seed */
__u8 s_def_hash_version; /* Default hash version to use */
__u8 s_reserved_char_pad;
__u16 s_reserved_word_pad;
__le32 s_default_mount_opts;
__le32 s_first_meta_bg; /* First metablock block group */
__u32 s_reserved[190]; /* Padding to the end of the block */
};