Linux 文件系统配置

硬件

磁盘挂载

/etc/fstab

/etc/fstab:包含存储设备、文件系统信息,配置自动挂载 各种文件系统格式硬盘、分区、可移动设备、远程设备 (即mount参数存盘)

1
<fs> <mountpoint> <type> <opts> <dump> <pass>
  • <fs>:挂载设备/分区名

    • /dev/sda:设备/分区名
    • UUID=xxxxx:使用设备UUID值表示设备
    • tmpfs:tmpfs分区,默认被设置为内存的一半(可在 <opts>中添加size=2G指定最大空间)
    • 所有设备/分区都有唯一UUID,由文件系统生成工具mkfs. 创建文件系统时生成
  • <mountpoint>:挂载点,路径名(文件夹)

    • /
    • /boot
    • 路径名中包含可以空格使用\040(8进制)表示
  • <type>:文件系统类型

    • ext2
    • ext3
    • reiserfs
    • xfs
    • jfs
    • iso9660
    • vfat
    • ntfs
    • swap
    • tmpfs:临时文件系统,驻留在交换分区、内存中
      • 提高文件访问速度,保证重启时自动清除这些文件
      • 常用tmpfs的目录:/tmp/var/lock/var/run
    • auto:由mount自动判断
  • <opts>:文件系统参数

    • noatime:关闭atime特性

      • 不更新文件系统上inode访问记录,提高性能,否则 即使从缓冲读取也会产生磁盘写操作
      • 老特性可以放心关闭,能减少loadcycle
      • 包含nodiratime
    • nodiratime:不更新文件系统上目录inode访问记录

    • relatime:实时更新inode访问记录,只有记录中访问 时间早于当前访问才会被更新

      • 类似noatime,但不会打断其他程序探测,文件在 上次访问后是否需被修改(的进程)
    • auto:在启动、终端中输入$ mount -a时自动挂载

    • noauto:手动挂载

    • ro:挂载为自读权限

    • rw:挂载为读写权限

    • exec:设备/分区中文件可执行

    • noexec:文件不可以执行

    • sync:所有I/O将以同步方式进行

    • async:所有I/O将以异步方式进行

    • user:允许任何用户挂载设备,默认包含 noexec,nosuid,nodev(可被覆盖)

    • nouser:只允许root用户挂载

    • suid:允许set-user/group-id(固化权限)执行

      • set-user/group-id参见linux/shell/config_files
    • nosuid:不允许set-user/group-id权限位

    • dev:解释文件系统上的块特殊设备

    • nodev:不解析文件系统上块特殊设备

    • umask:设备/分区中文件/目录默认权限掩码

      • 权限掩码参见linux/kernel/file_system.md
    • dmask:设备/分区中目录默认权限掩码
    • fmask:设备/分区中普通文件默认权限掩码

    • nofail:设备不存在则直接忽略不报错

      • 常用于配置外部设备
    • defaults:默认配置,等价于 rw,suid,exec,auto,nouser,async

  • <dump>:决定是否dump备份

    • 1:dump对此文件系统做备份
    • 0:dump忽略此文件系统
    • 大部分用户没有安装dump,应该置0
  • <pass>:是否以fsck检查扇区,按数字递增依次检查(相同 则同时检查)

    • 0:不检验(如:swap分区、/proc文件系统)
    • 1:最先检验(一般根目录分区配置为1
    • 2:在1之后检验(其他分区配置为2
  • /etc/fstab是启动时配置文件,实际文件系统挂载是记录到 /etc/mtab/proc/mounts两个文件中

  • 根目录/必须挂载,必须先于其他的挂载点挂载

文件系统配置

Ext 配置文件

  • /etc/mke2fs.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[defaults]
base_features = sparse_super,large_file,filetype,resize_inode,dir_index,ext_attr
default_mntopts = acl,user_xattr
enable_periodic_fsck = 0
blocksize = 4096 # 块大小
inode_size = 256 # Inode 大小
inode_ratio = 16384 # 分配 Inode 号间隔

[fs_types]
ext3 = {
features = has_journal
}
ext4 = {
features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize
inode_size = 256
}

[options]
fname_encoding = utf8

Linux 文件系统命令

文件系统状态

dudf

目录、文件操作

pwd

pwd:显示当前工作目录绝对路径

cd

cd:更改工作目录路径

  • 缺省回到用户目录
  • -:回到上个目录

ls

1
$ ls [params] expr

列出当前工作目录目录、文件信息

参数

  • -a:列出所有文件,包括隐藏文件
  • -l:文件详细信息
    • 详细信息格式、含义参见config_file
  • -t:按最后修改时间排序
  • -S:按文件大小排序
  • -r:反向排序
  • -h:显示文件大小时增加可读性
  • -F:添加描述符到条目后
    • @:符号链接
    • *:文件
    • /:目录
  • -i:显示索引节点

输出结果

ls_results.png

  • 文件权限:包括10个字符

    • 第1字符:文件类型
      • -;普通文件
      • d:目录
      • l:link,符号链接
      • s:socket
      • b:block,块设备
      • c:charactor,字符设备(流)
      • p:FIFO Pipe
    • 第2-4字符:owner,文件属主权限
    • 第5-7字符:group,同组用户权限
    • 第8-10字符:other,其他用户权限
      • 权限分别为r读、w写、x执行
      • 相应位置为-表示没有此权限
    • 执行位还可能是其他特殊字符
      • users:文件set-user-id、执行权限同时被置位
      • groups:文件set-group-id、执行权限同时被置位
      • userS:文件set-user-id被置位,执行权限未置位
      • groupS:文件set-group-id被置位,执行权限未置位
      • othert:文件sticky bit、执行权限均被置位
      • otherT:文件sticky bit被置位、执行权限未置位
    • 关于权限具体含义,参见linux/kernel/file_system
    • 权限设置,参见linux/shell/cmd_fds
  • 文件数量

    • 一般文件:硬链接数目
    • 目录:目录中第一级子目录个数
  • 文件属主名

  • 文件属主默认用户组名

  • 文件大小(Byte)

  • 最后修改时间

  • 文件名

dirs

显示目录列表

touch

创建空文件或更改文件时间

mkdir

创建目录

rmdir

删除空目录

cp

复制文件和目录

mv

移动、重命名文件、目录

rm

删除文件、目录

  • 删除目录link时,注意末尾不要带/,否则被认为是目录, 此时rm -r <target>会删除源目录中文件

file

查询文件的文件类型

du

显示目录、文件磁盘占用量(文件系统数据库情况)

参数

  • -a/--all:显示所有后代各文件、文件夹大小
    • 否则默认为显示所有后代文件夹大小
  • -c/--total:额外显示总和
  • -s/--summarize:仅显示总和
  • --max-depth=[num]:显示文件夹的深度
  • -S/--separate-dirs:文件夹大小不包括子文件夹大小

  • -b/--bytes:以byte为单位

  • -k/--kilobytes:以KB为单位
  • -m/--megabytes:以MB为单位
  • -h:human-readable,提升可读性
  • -H/--si:同-h,但是单位换算以1000为进制

  • -x/--one-file-system:以最初处理的文件系统为准,忽略 其他遇到的文件系统

  • -L=/--dereference=:显示选项中指定的符号链接的源文件 大小
  • -D/--dereference-args:显示指定符号链接的源文件大小
  • -X=/--exclude-from=[file]:从文件中读取指定的目录、 文件
  • --exclude=[dir/file]:掠过指定目录、文件
  • -l/--count-links:重复计算hard-link

wc

统计文件行数、单词数、字节数、字符数

-    `-l, -w, -c`

tree

树状图逐级列出目录内容

cksum

显示文件CRC校验值、字节统计

mk5sum

显示、检查MD5(128bit)校验和

sum

为文件输出校验和及块计数

dirname

输出给出参数字符串中的目录名(不包括尾部/) ,如果参数中不带/输出.表示当前目录

basename

输出给出参数字符串中的文件、目录

ln

创建链接文件

stat

显示文件、文件系统状态

文件、目录权限、属性

chown

更改文件、目录的用户所有者、组群所有者

chgrp

更改文件、目录所属组

umask

显示、设置文件、目录创建默认权限掩码

getfacl

显示文件、目录ACL

setfacl

设置文件、目录ACL

chacl

更改文件、目录ACL

lsattr

查看文件、目录属性

chattr

更改文件、目录属性

umask

查看/设置权限掩码,默认0000

1
2
3
4
5
6
$ umask
# 数字形式返回当前权限掩码
$ umask -S
# 符号形式返回当前权限掩码
$ umask 0003
# 设置权限掩码为`0003`
  • 权限掩码参见linux/kernel/permissions

chmod

关于文件、目录权限参见config_files###文件描述

  • 普通用户只能修改user权限位
  • root用户可以修改任意用户、任意文件权限

参数

  • -R:对整个目录、子文件(目录)同时修改权限

操作

1
2
$ chmod [ugoa][+-=][rwxst] file
$ chmod xxxx file
  • ugoa:分别表示user、group、other、all权限位
  • +-=:表示增加、减少、设置权限
  • rwxst:表示5不同的权限

    • ST不是一种权限,只是一种特殊的状态
    • 设置状态时s时,是根据相应的x是否有确定s/S
    • 设置状态t同理
  • xxxx:每个8进制数表示一组权限,对应二进制表示相应权限 是否置位

    • 第1个数字:set-user-id、set-group-id、sticky bit
    • 后面3个数字分别表示user、group、other权限
    • 第1个数字位0时可以省略(常见)

示例

1
2
$ chmod u+s file1
$ chmod 7777 file1

磁盘

df

文件系统信息

fdisk

查看系统分区

mkfs

格式化分区

fsck

检查修复文件系统

mount

查看已挂载的文件系统、挂载分区

umount

卸载指定设备

free

查看系统内存、虚拟内存占用

Ext 文件系统

Ext 文件系统

Ext 文件系统结构

linux_file_system_ext_structure

Index Node

Index Node/Inode 索引节点:记录文件的元信息

  • 文件元信息

    • 文件大小
    • 访问权限
    • 创建时间
    • 修改时间
    • 数据块位置
  • Inode 是文件的唯一标识,和文件一一对应

    • 存储在磁盘中,占用磁盘空间,大小为 126B 整数倍
    • 通常会把索引节点加载到内存中,加速文件的访问
  • Inode 并未存储 Inode 号、文件名,而是存储在文件所在目录的数据块中

Inode

  • Inode 号在同一文件系统内部唯一,可以、且被用于确定、定位 Inode

    • 创建文件系统时,每个块组中起始 Inode 号、Inode Table 起始地址确定
      • Inode 号按分配比率(间隔字节数)预分配
      • 若系统中大文件较多,Inode 分配比率应较大,避免 Inode Table 占用过大空间
    • 根据 Inode 号、Inode 结构大小计算偏移即可查确定
  • Ext 预留部分 Inode 作特殊用途

    • 0:不存在,用于标识已删除文件
    • 1:虚拟文件系统,如:/proc/sys
    • 2:根目录
    • 3ACL 索引
    • 4ACL 数据
    • 5boot loader
    • 6:未删除的目录
    • 7Reserved GDT
    • 8:日志
    • 11:首个非预留 Inode 号,通常是 lost+found 目录
  • Inode 大小默认值在 /etc/mke2fs.conf 文件中指定
  • ls -i 可查看文件 Inode
  • find 可以使用 -inum 参数寻找指定 Inode 号文件

Inode 寻址

  • Ext2/3Inode 寻址混合直接查找、多级索引
  • Inode 中包含 15 个指针 i_block[0..14],分为 4 级

    • i_block[0..11]:直接寻址指针,直接指向数据块
    • i_block[12]:一级间接寻址指针,指向存储指针的块
    • i_block[13]:二级间接寻址指针
    • i_block[14]:三级间接寻址指针
  • 根据文件大小选择不同的寻址方法

    • 文件小于 12block 时,直接用直接寻址指针
    • 文件较大时则利用更高级别的间接寻址指针,多级索引
    • Ext2/3 对超大文件存取效率低下,需要核对指针过多

    linux_file_system_storage_ext

Inode 内容

  • 硬链接:指向 Inode(文件) 的 目录项

    • 此处文件、硬链接说明
      • 文件:Inode、相应数据块
      • 硬链接:目录文件中目录项
    • 硬链接是目录项
      • 同一个文件的多个硬链接应是仅文件名不同的目录项
      • Ext 文件系统中 Inode 号、文件名均在存储在目录项中即完美支持硬链接
  • 硬链接创建、删除

    • 创建硬链接会增加文件的硬链接数
      • 不能跨分区创建硬链接:不同分区 Inode 号会重复
      • 不能手动对目录文件创建硬链接:防止路径混乱,文件系统已经为目录创建硬链接
        • .:当前目录硬链接
        • ..:上级目录硬链接
      • 目录的硬链接数 = 2 + 一级子目录数
        • 父目录中目录项
        • 自身 . 目录项
        • 子目录中 .. 目录项
    • 删除文件实质上就是删除硬链接,文件的硬链接数量归 0 时才被真正删除
    • ls -l 中第二行即为文件的硬链接数(包含文件自身)
  • / 根目录是自引用的(唯一),即 .. 也指向自身
  • 符号链接 / 软链接:通过文件名的链接文件的 文件
    • 符号链接是文件
      • 文件内容可认为是指向的目标路径,这也决定温文件大小
      • 符号链接文件本身也可以有多个硬链接、符号链接
    • 一般不占用数据块,Inode 记录即可描述完成
      • 只有符号链接指向的目标路径过长(大于 60B)时才会分配数据块
    • 符号链接权限不重要,取决于最终目标文件
  • readlink 可以查看符号链接之

设备文件、FIFOSocket

  • 设备文件、FIFOSocket
    • 没有大小,不占用数据块,在 Inode 记录中即可描述完成
      • 主设备号:标识设备类型
      • 次设备号:标识同种设备类型的不同编号

Block Group

Block Group 块组:逻辑上对块分组,提高查询效率

  • 块组划分是文件系统创建的一部分

    • 一个磁盘分区包含多个块组
    • 块组是逻辑层面的划分,不会类似分区在磁盘上标记、划分
  • 每个块组包含多个元数据区、数据区

    • 元数据区:存储 BmapInode TableImap 等数据
    • 数据区:存储文件数据
  • 块组特点

    • 块组大小(包含块数)= 块 bit 数,即单个 block (作为)Bmap 能标记的块数量
      • 此大小包含元数据区(也需要 Bmap 标记是否被占用)
    • 块组设置的 Inode 数量、Inode Table 由系统决定

分区级 Block

  • 以下这些块不会出现在所有块组中,存储文件系统级别信息

Boot Block

  • Boot Block / Boot Sector:存放有 boot loader 的块

    • 特点
      • 位于分区的首个块
      • 占用 1024B
      • 只有装有系统的主分区、逻辑分区才有 Boot Block
    • Boot Block 在不同分区时称为
      • 主分区装有操作系统时:Volume Boot Records
      • 逻辑分区装有操作系统时:Extended Boot Records
  • MBR 会引导 VBR/EBR,开机启动时,首先加载 MBRboot loader

    • 单操作系统时,直接定位到所在分区的 Boot Block,加载此处的 boot loader
    • 多操作系统时,加载 MBRboot loader 后列出操作系统菜单,指向各分区的 boot block

    linux_file_system_ext_super_block_mbr

    • 通过 MBR 管理启动菜单方式已经被 Grub 取代

Super Block

  • Super Block:存储文件系统信息、属性元数据

    • 存储的信息包括
      • 块组的 block 数量、Inode 号数量
      • 文件系统本身的空闲 block 数量、Inode 数量
      • 文件系统本身的属性信息:时间戳、是否正常、自检时间
    • (首个)超级块的位置取决于块大小
      • 块大小为 1KB 时,引导块正好占用 1 个 block,则超级块号为 1
      • 块大小大于 1KB 时,超级块和引导块均位于 0 号块
  • 超级块对文件系统至关重要

    • 超级块丢失和损坏必然导致文件系统损坏
    • Ext2 只在 0、1 和 3、5、7 的幂次块组中保存超级块信息

      • 但文件系统只使用首个块组的超级块信息获取文件系统属性,除非损坏或丢失
      • 有些旧式文件系统将超级块备份至每个块组
  • df 命令读取文件系统的超级块,统计速度快

Group Descriptor Table

  • GDT 块组描述符表:存储块组的信息、属性元数据

    • Ext 每个块组使用 32B 描述,被称为块组描述符,所有块组描述符组成 GBT
      • GDT 和超级块同时出现在某些块组中
      • 默认也只会读取 0 号块组的中 GDT
  • Reserved GDT:保留作为 GDT 使用的块(扩容之后块组增加)

    • GDT、超级块同时出现,同时修改
  • GDTReserved GDT、超级块在某些块组同时出现,能提升维护效率

块组级 Block

Block Bitmap

Block Bitmap/Bmap 块位图:标记各块空闲状态

  • Bmap 只优化写效率
    • 向磁盘写数据时才需要寻找空闲块,读数据时按照索引读取即可
    • Bamp 查询速度足够快,则向磁盘写数据效率极大取决于磁盘的随机读写效率

Inode Table

  • Inode Table:物理上将多个 Inode 合并存储在块中
    • Inode 大小一般小于块大小,合并存储能节约存储空间

Inode Bitmap

Inode Bitmap/Imap 位图:标记各 Inode 号占用状态

Data Blocks

  • Data Blocks:直接存储数据的块
    • 数据占用的块由文件对应 Inode 记录中块指针找到
    • 不同类型文件在数据块中存储的内容不同
      • 常规文件:存储文件数据
      • 目录:存储目录下文件、一级子目录
      • 符号链接:目标路径名较短则直接存储在 Inode 中,否则分配数据块保存

目录文件数据块

linux_file_system_ext_data_block_directory

  • 目录文件数据块存储多条目录项,每条目录项包含目录下
    • 文件 Inode
    • 目录项长度 rec_len
    • 文件名长度 name_len
    • 文件类型
      • 0:未知
      • 1:普通文件
      • 2:目录
      • 3:*character devicev
      • 4block device
      • 5:命名管道
      • 6socket
      • 7:符号链接
    • 文件名:文件名、一级子目录名、...

Directory Entry

Directory Entry/Dentry 目录项(缓存):存放内存中的缩略版磁盘文件系统目录树结构

  • Dentry 中需要记录

    • 文件名称
    • Inode 指针:与文件名建立映射关系
    • 与其他目录项的层级关联关系
      • 包括:父目录、子目录链表
      • 多个目录项通过指针关联起来就形成目录结构
  • Dentry 是由内核维护,缓存在内存中

    • 内核会把读过的文件用 Dentry 缓存在内存中,提高文件系统效率
  • InodeDentry 是一对多的关系

    • 即一个文件可以有多个别字
    • 硬链接实现就是多个 Dentry 中的 Inode 指向同一个文件

文件系统挂载

  • Mount 挂载:将文件系统关联到路径

  • 文件系统必须要挂载在一定路径下才能被使用

    • 文件系统体现在系统中即目录,即其文件系统的入口目录(根目录)
    • 而入口目录无名、无显式 Inode
      • Ext 中文件名、Inode 号存储在父目录中,入口目录是文件系统最底层目录,不存在父目录
      • 入口目录无名,所以挂载在任何目录下都是合理的
      • 入口目录被预留 Inode 号为 2,可直接寻址
  • 挂载方式

    • / 根目录下挂载根文件系统,在系统启动之初即挂载
    • 其余文件系统则挂载在根文件系统的目录之下

挂载逻辑

  • 挂载实现逻辑

    • 新建 Inode,将其寻址指针指向待挂载文件系统
    • 将挂载点目录 Inode 标记为不可用
    • 修改挂载点目录在其父目录目录项至新建 Inode
      • 挂载期间原目录会被遮蔽
      • 挂载点仍然是所在文件系统的文件,但是其数据不在
  • 同步挂载信息

    • 挂载完成后,将挂载记录、相关信息写入 /proc/self/{mounts, mountstats, mountinfo}
    • 同步 /proc/self/mounts 同步至 /etc/mtab(若有必要)

文件操作

文件读取

  • / 文件系统在系统启动时即挂载,此时已经读取超级块、GDT 等文件系统块
  • 同文件系统内 / 开头绝对地址

    • 根据 GDT 确定各块组 Inode Table 块号
    • Inode Table 中查找 / 目录文件 Inode
      • / Inode 号已知为预留 Inode 号 2,可直接在 Inode Table 中定位
    • 获取 / 数据块,并读取其中目录项
    • 在目录项中查找目标记录,获取文件 Inode
    • 如上重复,直到找到目标文件 Inode,根据 i_block 寻址指针读取数据块
  • 相对地址

    • 按照所处目录的目录项获取 Inode 号,同绝对地址即可
  • 跨文件系统地址

    • 类似同文件系统
    • 但挂载点目录会指向目标文件系统入口目录,再同绝对地址即可

文件删除

  • 删除普通文件

    • 同读取找到文件 Inode、数据块
      • 将文件 Inode 硬链接数量减一
      • 若硬链接数量归 0,执行删除,否则不变
    • Inode 中寻址指针删除
      • 此时即无法找到文件数据
    • Imap 中标记文件 Inode 号为未使用
    • 删除文件所属目录的目录项
      • 实务中会将目录项 Inode 号标记为 0,避免产生空洞
      • 此时文件即不可见
    • Bmap 中文件数据块块号标记为未使用
      • 此时即释放文件占用空间,若此时有其他进程持有数据块的指针,则文件系统不会立即释放该空间
      • Ext 系统中此步骤会导致删除大文件效率低
  • 删除目录文件

    • 若目录非空,则尝试递归删除其中文件、子目录
    • 若目录为空,类似普通文件删除目录

文件移动、重命名

  • 同目录文件重命名:修改文件所属目录的目录项中文件名

  • 同文件系统下移动:增、删目录项

    • 文件移动不修改 InodeInode 号等
  • 不同文件系统下移动:先复制、再删除

  • 命名冲突时,覆盖会删除冲突文件,并修改相应目录项至新文件
  • 因此,Ext 无法用同名子目录覆盖父目录,在尝试删除父目录时即失败

文件存储、复制

  • 文件存储

    • 读取 GDT,寻找空闲块组
    • 根据块组 Imap 为文件分配未使用 Inode
    • Inode Table 中完善 Inode 中文件元数据
    • 在所属目录中添加目录项
    • 将数据写入数据块
      • Ext2/3 中每次调用 block 分配器为数据分配 1 个数据块,直至写入完毕
      • Ext4 中允许一次分配多个数据块
    • Inode Table 中更新 Inode 寻址指针
  • 文件复制同文件存储

Ext2/3/4 迭代

  • Ext 文件系统特点
    • 在创建时即划分好,方便使用时分配
      • 不支持动态划分、分配
      • 格式化超大磁盘时较慢

Ext3 日志功能

  • Ext2 中只有两个区:元数据区、数据区

    • 从数据块中写入数据的中断中恢复检查一致性需要大量时间,甚至失败
  • Ext3 增加日志区

    • 在向数据块中写入数据前会在日志区标记
    • 则根据日志区的标记即可判断操作完成情况,提高一致性确认效率

Ext4 段分配

  • Ext2/3

    • Bmap 标记、分配块能提高效率,但扫描 Bmap 效率仍很低
    • 多级索引寻址效率低
  • Ext4 中使用 extent 管理数据块

    • extent 尽可能包含物理上连续的块
    • Inode 中使用 4 个 extent 片段流替代多级索引指针
      • 每个 extent 片段流设定起始块号、块数量
      • extent 指向的块保存数据或索引指针
    • 支持调用一次 block 分配器分配多个块,并标记对应 Bmap

    linux_file_system_ext4_extent_structure

  • Ext 删除数据

    • 会依次释放 Bmap 位、更新目录结构、释放 Inode 空间

Linux文件系统设计

文件系统

磁盘存储

  • Sector 扇区:扇区概念来源于机械硬盘,指磁盘上各磁道上的扇环

    • 物理扇区:磁盘读写的最小单位
      • 早期硬盘多为 512B 大小,新式硬盘多为 4096B 或更高以提高数据记录密度
    • 逻辑扇区:硬盘可以接受读写指令的最小操作单元
      • 为兼容性而设计,硬盘内部将物理扇区逻辑上划分多个 512B 扇区片段提供给文件系统
      • 实际读写时由硬盘固件负责逻辑扇区、物理扇区间转换,对文件系统透明
  • Logical Block Address (逻辑)块/簇:多个扇区组成的操作系统最小读写单位

    • 常见的块大小为 4KB,一般为扇区 $2^N$ 倍
    • 特点
      • 提高了读写效率
      • 减少文件碎片
      • 造成一定空间浪费
  • 分区:从磁盘上划分出了的连续的扇区

    • 分区格式化:对分区范围内扇区使用进行规划
      • 引导分区设置
      • 扇区分组为块、编号
    • 分区对齐:将逻辑块对齐到磁盘物理扇区

      • 分区格式化是按照逻辑扇区划分,若分区中存储起始位置没有对齐至物理扇区边缘,则分区中块也无法对齐到物理扇区边缘
        • 分区未对齐更多是因为引导区占用扇区数不是物理扇区整数倍,导致之后存储区域无法对齐
        • 则分区一般是将分区起始位置对齐到物理扇区整数倍处即可
      • 分区未对齐时,操作系统每次读、写会多读、写一个物理扇区,降低磁盘性能
      • 4K 对齐:多数磁盘物理扇区大小为 4K,实际对齐需检查物理扇区大小

      disk_partition_alignment_unaligned disk_partition_alignment_aligned

  • 固态存储同样有扇区概念,但还有页等概念,更加复杂
  • 磁盘存储区域
    • 超级块:存储文件系统的详细信息,文件系统挂载时载入内存
      • 块数量
      • 块大小
      • 空闲块
    • 索引节点区:存储索引节点,文件被访问时载入内存
    • 数据块区:存储文件、目录数据

文件

  • Linux 系统中:一切皆文件
    • 普通的文件
    • 目录(不是目录项)
      • 同样用 Inode 唯一标识
      • 其中存储的内容是子目录、文件
    • 块设备
    • 管道
    • Socket

linux_file_system_structure

文件读写

linux_file_usage

  • 操作系统会跟踪进程打开的所有文件,即为每个进程维护一个打开文件表

    • 文件表中每项代表文件描述符(open 函数返回)
      • 即文件描述符是打开文件的标识
    • 文件表中维护打开文件状态、信息
      • 文件指针:系统跟踪上次读写位置作为当前文件位置指针,对某进程唯一
      • 文件打开计数器:跟踪文件打开、关闭数量,仅计数为 0 时关闭文件,删除条目
      • 文件磁盘位置:避免磁盘交互
      • 访问权限(访问模式):方便操作系统允许、拒绝 I/O 请求
  • 文件系统屏蔽了用户字节操作和磁盘数据块操作之间差异

    • 用户读取 1byte 数据时,文件系统获取所在块,返回所需部分
    • 用户写入 1byte 数据时,文件系统获取应写入的块,修改后写回

文件在磁盘中的存储

  • 连续空间存储方式:文件存储在磁盘连续的物理空间中

    • 需预先知道待存储的文件大小:Inode 中需包含文件起始块位置、长度
    • 特点
      • 读写效率高
      • 磁盘空间碎片化
      • 文件长度不易扩展
  • 非连续空间存放方式:链表方式

    • 隐式链表:文件头中包含首块、尾块位置,各数据块中包含指向下个数据块的指针
      • 无法直接访问数据块:只能通过指针顺序访问
      • 稳定性差:任何指针丢失、损坏都会导致文件数据损坏
    • 显式链表:将链接各数据块的指针显式存储在链接表(File Allocation Table)中(改进隐式链表问题)

      linux_file_system_storage_explicit_link

      • 链接表为每个磁盘设置一张,其中每项表示一个数据块,内容为下个数据块指针
      • 链接表可存放在内存中以提高检索速度,但会占用内存空间,也因此不适合大磁盘
      • 长期使用会使文件资料逐渐分散
    • 特点
      • 可消除磁盘碎片
      • 文件长度可动态扩展
      • 存储指针的有额外空间开销
  • 索引存储方式:为每个文件创建索引数据块,存储指向文件数据块的指针列表

    linux_file_system_storage_index

    • 文件头中需包含指向索引数据块的指针
    • 特点

      • 文件创建、增大、缩小方便
      • 无磁盘碎片问题
      • 支持顺序读写、随机读写
      • 存储索引有额外空间开销
      • 文件系统效率与查找策略高度相关
    • 大文件支持扩展

      • 链式索引块:链表链接索引

        linux_file_system_storage_link_index

      • 多级索引块:索引索引索引

        linux_file_system_storage_index_index

文件系统

文件系统:操作系统用于明确存储设备或分区上文件的方法和数据结构

  • 文件系统即在存储设备上组织文件(持久数据)的子系统

    • 基本数据单位是文件,对文件的组织方式的不同即形成不同的文件系统
    • 存储设备:磁盘、光盘、网络存储、虚拟数据
      • 存储设备可以包含多个文件系统
  • Virtual File System 虚拟文件系统:包含一组所有文件系统都支持的数据结构和标准接口

    • 作为提供给用户的统一接口

    linux_virtual_file_system_structure

  • 操作系统中负责管理、存储文件信息的软件称为文件管理系统,简称文件系统

文件系统分类

  • 磁盘文件系统:数据存储在磁盘中

    • EXT2
      • Linux 的正宗文件系统,早期常用
      • 支持 undelete,误删文件可恢复,但是操作比较麻烦
    • EXT3
      • EXT2 发展而来
      • 支持大文件
      • 不支持反删除,RedhatFedora 推荐
    • ReiserFS
      • 支持大文件
      • 支持反删除,操作简单
  • 内存文件系统:数据存储在内存中

    • 如:/proc/sys 等文件系统
    • 读写此类文件实际上是读写内核中相关数据
  • 网络文件系统:访问其他计算机主机数据的文件系统

    • NFS
    • SMB
FileSystem File Size Limit Filesystem Size Limit
ext2/ext3 with 1KB blocksize 16448MB 2048GB
ext2/ext3 with 2KB blocksize 256GB 8192GB
ext2/ext3 with 4KB blocksize 2048GB 8192GB
ext2/ext3 with 8KB blocksize 65568GB 32TB
ReiserFS3.5 2GB 16TB
ReiserFS3.6 1EB 16TB
XFS 8EB 8EB
JFS with 512B blocksize 8EB 512TB
JFS with 4KB blocksize 8EB 4PB
NFSv2(client side) 2GB 8EB
NFSv3(client side) 8EB 8EB
  • 文件系统要先挂在在某个目录上才能正常使用,Linux 会把文件系统挂载到根目录

File Allocation Table

  • FAT 文件分配表:采用 FAT 显式链表组织文件的文件系统

    • 简单,几乎所有的个人操作系统均支持,适合移动介质的文件系统
    • FAT12:12bits 寻址长度
    • FAT16:16bits 寻址长度
    • FAT32:目前只使用了其中 28bits 寻址长度
      • 按 4KB 块计算,FAT32 最大容量为 1TB
      • FAT32 起始扇区中记录有扇区总数,此限制 FAT32 最大容量 2TB
      • FAT32 最大支持 4GB 大小文件
  • Extended File Allocation Table

    • 优点
      • 允许更大分区容量、更大文件、更大逻辑块大小
      • 采用空余空间寻址,空间分配、删除性能得以改进
    • 缺点
      • 兼容性不如 FAT32:旧设备、UEFI 不支持

权限设计

  • r:读文件
  • w:修改、删除文件
  • x:可以执行文件
  • s:强制位权限(固化用户/组权限)
    • set-user-id:user执行权限位出现
    • set-group-id:group执行权限位出现
  • t:粘滞位权限(在swap中停留)

权限判断规则

  • linux中权限是根据user-idgroup-id判断用户和资源 关系,然后选择相应的类型用户(user、group、other)权限组 判断是否有相应权限

  • 需要注意的是,访问资源实际上不是用户,而是用户开启的 进程,所以这里涉及了4中不同的用户标识

    • real-user-id:UID,用户id

    • real-group-id:GID,用户默认组id

    • effective-user-id:是针对进程(可执行文件)而言, 指内核真正用于判断进程权限的user-id

    • effective-group-id:同effective-user-id,内核 判断真正判断进程权限的group-id

  • 一般情况下effective-user-id就是read-user-id,即启动 进程用户的UID,所以一般来说用户创建的进程的对资源访问 权限就是就是自身权限

可执行文件权限

  • r:读文件
  • w:写文件
  • x:执行文件

s权限

当可执行文件具有set-user-id权限时

  • 其他用户执行该文件启动的进程的effective-user-id不再是 real-user-id,即和执行用户的UID不再一致,而是用户属主 的UID

  • 内核根据进程effective-user-id判断进程权限,进程的权限 实际上同属主的权限,而不是执行用户权限

  • 这样用户就在执行这种可执行文件,暂时拥有该可执行文件属主 执行该可执行文件权限,否则可能由于进程访问其他资源原因 无法正常执行

  • 可看作是将属主的部分权限(在该文件上涉及到的权限) 固化在文件上

set-group-id类似的可以看作是将属主默认组权限固化在文件上

t权限

  • 文件被执行时,文本段会被加载到swap中,程序结束后仍然 保留在swap中

  • 下次执行文件时,文本段直接从swap中加载,因为swap为连续 block,加载速度会提高

目录权限说明

linux中目录是一种特殊的文件,其包含目录下所有文件(包括 子目录)的文件名、i-node号

  • r:列出目录下所有文件

  • w:增加、删除、重命名目录下的文件

  • x:可以是(搜索)路径的一部分

    • 即必须对要访问的文件中路径中所有目录都有执行权限
    • 可以将目录执行权限看作是过境证明
  • s:好像没啥用

  • t:用户只能增加、删除、重命名目录下属于自己文件

    • w权限补充,否则用户拥有目录w权限则可以操作目录 下所有文件
    • /home目录权限就是1777,设置有粘滞位权限

权限掩码

文件/目录默认权限 = 现有权限(0777减去权限掩码

  • 权限掩码设置参见linux/shell/cmd_fslinux/shell/config_file

文件、目录访问

pathlib

os.path

判断存在

1
2
3
4
5
os.path.isdir(r"C:\Users")
os.path.isfile(r"C:\Users")
# 判断路径名是简单文件、目录
os.path.exists(r"C:\Users")
# 判断路径名是否存在
  • os.stat配合stat模块有更丰富的功能

路径操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pfile = os.path.join(r"C:\temp", "output.txt")
# 连接文件名、目录

os.path.split(pfile)
# 分离文件名、目录

os.path.dirname(pfile)
# 返回路径中目录
os.path.basename(pfile)
# 返回路径中
os.path.splitext(pfile)
# 返回文件扩展名

os.path.normpath(r"C:\temp/index.html")
# 调整路径为当前平台标准,尤其是分隔符混用时
os.path.abspath("index.html")
# 返回文件的**完整绝对路径名**
# 扩展`.`、`..`等语法
  • os.sep配合字符串.join.split方法可以实现基本相同 效果

fileinput

stat

stat:包含os.stat信息相关常量、函数以便跨平台使用

1
2
3
4
5
6
7
8
import stat

info = os.stat(filename)
info[stat.ST_MODE]
# `stat.ST_MODE`就是字符串
# 只是这样封装易于跨平台
stat.S_ISDIR(info.st_mode)
# 通过整数`info.st_mode`判断是否是目录
  • os.path中包含常用部分相同功能函数

glob

glob.glob

1
2
3
import glob

def glob.glob(pathname,*,recursive=False)
  • 参数

    • pathname:文件名模式
      • 接受shell常用文件名模式语法
        • ?:单个字符
        • *:任意字符
        • []:字符选集
      • .开头路径不被以上?*匹配
    • recursive
      • False:默认
      • True**将递归匹配所有子目录、文件
  • 返回值:匹配文件名列表

    • 目录前缀层次同参数
  • glob.glob是利用glob.fnmatch模块匹配名称模式

shutil

shutil模块:包含文件操作相关

fnmatch

linecache

macpath

filecmp

tempfile

Windows Linux Subsystem

说明

WSL是一个兼容层,类似反过来的Wine,但更底层

  • Linux、Windows程序不兼容,是因为二者内核提供的接口不同

    • ls/dir命令
      • 在Linux下调用getdents内核调用
      • 在Windows下调用NtQueryDirectoryFile内核调用
  • WSL提供Linux内核接口,并转换为NT内核接口

    • 在WSL中执行ls仍然调用getdents
    • WSL收到请求,将系统调用转换为NT内核接口 NTQueryDirectoryFile
    • NT内核收到WSL请求,返回执行结果
    • WSL将结果包装后返回
  • 毕相较于真正Linux系统仍然有不足

    • Docker等涉及未实现的内核特性软件如法使用
    • Raw socket相关相关操作容易出错
    • I/O性能相对孱弱

Cygwin对比

wsl_architecture

  • Cygwin提供了完整的POSIX系统调用API(以运行库 Cygwin*.dll形式提供,但是仍然工作在User Mode

    • Cygwin将POSIX系统调用转换为Win32 API(因为其架设在 Win32子系统上),很多内核操作(如:fork)受限于 Win32实现

    • Linux应用程序必须链接到Cynwin*.dll,需要修改源码 重新编译后才能执行,这样应用程序才不会直接请求内核, 而是调用Cygwin运行库,且编译出的可执行文件为 Win32 PE格式封装,只能在Windows下执行

  • WSL中Linux应用程序进程被包裹在Pico Process中,其发出的 所有系统调用会被直接送往Kernel Mode中的 lxcore.syslxss.sys

    • WSL将POSIX系统调用转换为更底层的NP API调用(WSL和 Win32平行,直接架设在NT内核上)

    • 可以直接执行ELF格式封装的Linux可执行程序

启用

  • 控制面板 ->
  • 程序和功能 ->
  • 启用或关闭windows功能 ->
  • 适用于Linux的Windows子系统

其他

使用

进入WSL

除在图形界面中点击图标,以默认参数启动,还可以在terminal (cmd/powershell等)自定义进入WSL参数

  • wsl.exe:打开默认发行版中默认shell
  • distroname.exe:打开指定发行版中默认shell
  • bash.exe:打开默认发行版中bash shell
  • 这些应用程序默认在path中,可以直接执行

版本管理

  • wslconfig.exe可以用于管理多个子系统的发行版

WSL、Windows互操作

文件

  • Windows所有盘符挂载在WSL中/mnt目录下

  • WSL中所有数据存放在%HOME%/AppData/Local/Packages/{linux发行包名}/LocalState/rootfs

    • 不要在Windows下直接修改,造成权限错误

命令

  • 在cmd中直接调用WSL命令
    1
    2
    PS> wsl [-e] ls -al
    // wsl带参数执行
  • 在WSL中调用Windows命令行程序(在$PATH中)

    1
    2
    $ which ipconfig.exe
    $ ipconfig.exe
  • 在WSL中启动Windows应用(在$PATH中)

    1
    $ notepad.exe
  • 通过pipes通信

    1
    2
    $ cat foo.txt | clip.exe
    PS> ipconfig | wsl grep IPv4

端口、环境变量

  • WSL与Windows共享端口(NT内核?)
  • WSL继承Windows的部分环境变量,如:PATH

Terminal推荐

  • wsl-terminal: 专为WSL开发的终端模拟器,基于minttywslbridge,稳定 易用

  • ConEmu:老牌终端模拟器, 功能强大

  • Hyper:基于Electron的跨平台 终端模拟器

WSL-Terminal

  • WSL-Terminal中包含一些快捷工具

    • tools目录中包含一些脚本,可以通过wscripts.exe 执行修改注册列表,添加一些功能
      • 添加WSL中vim、emacs等打开到右键菜单
      • 添加在WSL中打开文件夹到右键菜单
    • run-wsl-file.exe可以用于在快捷执行wsl脚本,只需要 将其选择为文件打开方式
    • vim.exe可以用WSL中vim打开任何文件,当然一般是配合 tools/中脚本在右键注册后使用
  • 配置

    • 配置文件etc/wsl-terminal.conf
    • 主题文件etc/themes/
    • mintty配置文件etc/mintty

其他问题

文件权限问题

  • 在WSL中,windows实现了两种文件系统用于支持不同使用场景

VolFs

VolFs:着力于在windows文件系统上提供完整的linux文件系统特性 ,通过各种手段实现了对InodesDirectory EntriesFile ObjectsFile DescriptorsSpecial File Types 的支持

  • 为支持Inodes,VolFS会把文件权限等信息保存在 NTFS Extended Attributes

    • 在Windows中新建的文件缺少此扩展参数,有些编辑器也会 在保存文件是去掉这些附加参数
    • 所以不要在Windows中修改WSL文件,否则VolFs无法正确 获得文件metadata
  • WSL中/就是VolFs文件系统

DrvFs

DrvFs:着力提供于Windows系统的互操作性,从Windows的文件权限 (即文件->属性->安全选项卡中的权限)推断出文件对应Linux权限

  • 所有windows盘符挂在在WSL中/mnt是都使用DrvFs文件系统

  • 由于DrvFs文件权限继承机制很微妙,结果就是所有文件权限 都是0777

    • 所以ls结果都是绿色的
    • 早期DrvFs不支持metadata,在Build 17063之后支持 文件写入metadata,但是需要重新挂载磁盘
  • 可以通过设置DrvFs metadata设置默认文件权限

    1
    2
    3
    4
    5
    $ sudo umount /mnt/e
    $ sudo mount -t drvfs E: /mnt/e -o metadata
    // 此时虽然支持文件权限修改,但默认权限仍然是*0777*
    $ sudo mount -t drvfs E: /mnt/e -o metadata,uid=1000,gid=1000,umask=22,fmask=111
    // 此时磁盘中默认文件权限为*0644*
  • 更合适的方式是通过/etc/wsl.conf配置DrvFs自动挂载属性

AutoMatically Configuring WSL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 # `/etc/wsl.conf`
[automount]
# 是否自动挂载
enabled = true
# 是否处理`/etc/fstab`文件
mountFsTab = true
# 挂载路径
root = /mnt/
# DrvFs挂载选项,若需要针对不同drive配置,建议使用`/etc/fstab`
options = "metadata,umask=023,dmask=022,fmask=001"
[network]
generateHosts = true
generateResolvConf = true
[interop]
# 是否允许WSL载入windows进程
enabled = true
appendWindowsPath = true
  • 如果需要给不同盘符设置不同挂载参数,需要修改 /etc/fstab

    1
    E: /mnt/e drvfs rw,relatime,uid=1000,gid=1000,metadata,umask=22,fmask=111 0 0