Linux操作系统(四):磁盘与文件系统管理

  • 关于本文内容的导读
  • 认识Linux文件系统
  • 文件系统的简单操作、磁盘分区、格式化、检验与挂载
  • 内存交换分区、文件系统观察、GNU的parted分区操作

 一、关于本文内容的导读

这部分不涉及具体内容的解析,只是作为浏览和查找相关知识点的引导内容,采用【主题 | 命令 | 对应内容小节编号】三个关键信息的组合模式,依照这些信息可以快速查找到相关详细的示例和解析。

然后就是关于这篇博客的内容与之前的一篇博客磁盘分区相关性非常强,如果对相关的内容不了解建议先了解,另外就是这篇博客涉及磁盘管理基本上都需要管理员身份才有权先操作,所以建议全程使用root用户测试相关示例。

查看ext文件系统的基本信息 | dumpe2fs | 2.2
查看系统格式化的设备(盘符)文件 | blkid | 2.2
查看挂载点对应的文件系统文件 | df -T | 2.7  (注:关于df命令后面第三节会详细介绍)
查看xfs文件系统的基本信息 | xfs_info | 2.7
查看系统上的文件系统 | df | 3.1.1
查看文件或目录容量 | du | 3.1.1
建立文件链接 | ln | 3.1.2
查看系统上的磁盘列表信息 | lsblk | 3.2.1
查看系统上的磁盘分区类型和分区信息 | parted 磁盘设备名称 print | 3.2.1  (parted还可以实现磁盘分区功能,后面再介绍)
磁盘分区之管理MBR格式的磁盘 | fdisk | 3.2.2
磁盘分区之管理GPT格式的磁盘 | gdisk | 3.2.2
更新内核分区表信息 | partprobe | 3.2.2
磁盘格式化(创建xfs文件系统) | mkfs.xfs | 3.3.1
磁盘格式化(创建ext4文件系统) | mke2fs/mksf.ext4 | 3.3.1
文件系统检查与修复(xfs) | xfs_repair | 3.3.2
文件系统检查与修复(ext) | e2fsck | 3.3.2
文件系统挂载 | mount | 3.3.3
文件系统卸载 | umount | 3.3.3
创建块专用或字符专用文件 | mknod | 3.3.4  (块文件包括:磁盘、磁带等;字符文件就是没有缓冲的I/O设备比如鼠标和键盘;还可以创建通道文件FIFO)
修改xfs文件系统参数 | xfs_admin | 3.3.4
修改ext文件系统参数 | tune2fs | 3.3.4
设置启动挂载需要修改/etc/fstab文件会使用到nano命令,这个命令在Linux操作系统(二):初步了解Linux操作系统与基本操作中的2.6有介绍;
创建一个空白文件 | dd | 3.3.5  (这个命令在下一篇关于文件与文件系统压缩中会详细介绍,它的实际应用时转换和拷贝文件)
创建交换区 | mkswap | 4.1
启动(挂载)交换区 | swapon | 4.1
取消(卸载)交换区 | swapoff | 4.1
GNU的磁盘管理命令 | parted | 4.3  (同时兼容MBR和GPT格式的磁盘分区操作)

 二、认识Linux文件系统及简单操作

 2.1文件系统的特性

磁盘分区完毕后还需要格式化(format),之后操作系统才能够使用这个文件系统,为什么需要格式化呢?

这是因为每种操作系统所设置的文件属性/权限并不相同,为了存放这些文件所需的数据,因此需要将分区进行格式化,以成为操作系统能够利用的文件系统格式(filesystem)。

在windows 98以前的微软操作系统主要使用的文件系统时FAF(或FAT16),windows 2000以后的版本有所谓的NTFS文件系统。

在Linux的正统文件系统则是ext2(Linux second Extended file system,ext2fs),在默认情况下windows不支持Linux的ext2文件系统。

传统的磁盘与文件系统应用中,一个分区就只能被格式化成为一个文件系统,所以可以说是一个文件系统就是一个硬盘分区。由于新技术的发展,有了LVM与软件磁盘阵列(software raid),这些技术可以将一个分区格式为多个文件系统,也能够将多个分区合成一个文件系统(LVM,RAID)。所以,现在格式化时已经不再是针对硬盘分区来格式化,通常被称为一个可被挂载的数据为一个文件系统而不是一个分区

文件系统如何运行?这与操作系统的文件有关,较新的操作系统的文件除了文件实际内容外,通常含有非常多的属性,例如Linux操作系统的文件权限(rwx)与文件属性(拥有者、用户组、时间参数等)。文件系统通常会将这两部分的数据存放在不同的区块,权限与属性放在inode中,实际数据则放置到数据区块中。另外超级区块(superblock)会记录整个文件系统的整体信息,包括inode与数据区块的总量、使用量、剩余量等。

关于inode与区块都有编号,这里来介绍一下超级区块、inode、数据区块三者之间的关系:

超级区块:记录文件系统的整体信息,包括inode与数据区块的总量、使用量、剩余量,以及文件系统的格式与相关信息等;

inode:记录文件属性,一个文件占用一个inode,同时记录此文件的数据所在的区块号码;

数据区块:实际记录文件的内容,若文件太大时,会占用多个区块;

这里先通过inode与数据区块的示图来了解他们的关系与基本结构:

假设某个文件的属性与权限数据存储在inode 3号区块内,而这个inode记录了文件数据放置在2、7、13、15这四个数据区块中。

将文件数据实际存储的区块编号全部放在inode中,当需要使用数据时通过inode中存放的数据实际存储区块编号定位到磁盘指定的位置,对磁盘上的数据进行读写操作,这种数据存取方式被称为索引式文件存储

除了这种索引式数据存区以外,当然还有其他类型的文件系统存取数据的方式,比如U盘一般使用的FAT格式的文件及系统就没有inode,所以FAT没办法将这个文件所有区块的数据全部读出来,而是需要一个一个地将区块读出,读完一个区块的数据才会知道下一个区块在何处,比如示图中的“FAT文件系统数据存取示意图”,假设一个文件的数据分别按顺序存储在1、6、4、12四个区块中,它的数据使用方式就是1->6->4->12,如图所示,这是因为FAT格式采用每个数据区块的头尾两个部分来标记当前区块编号和下一个数据区块的编号,所以不获取到前一个数据区块就不会知道文件的下一个数据区块是哪一个,至于FAT格式下文件的第一个数据区块则由文件系统的文件列表来标记,当要使用一个文件的数据时先通过查找文件列表中的文件所对应的第一个数据区块,然后开始逐个数据区块查找。

磁盘碎片整理:

由于文件数据区块之间太过离散,这种情况就会导致磁盘的读取性能就会非常差,通过磁盘碎片整理将同一个文件所属区块集合在一起,这样可以让磁盘的数据读取速度提高。磁盘碎片整理对FTA的文件系统需要不时的进行碎片整理,而ext2是索引文件系统,基本上不太需要进行碎片整理,但是磁盘使用非常久的话,常常删除、编辑、新增文件时还是可能导致数据太过离散的问题。

2.1Linux的ext2文件系统(inode)

Ext是基于inode为基础的Linux文件系统,所以Ext文件系统的基础结构就是由超级区块、inode表、数据块组成的。

文件系统一开始就会将inode与数据区块固定好,除非重新格式化(或使用resize2fs等命令修改其大小),否则inode与数据区块固定后就不再变动。然而这其中会存在一个问题,就是一个文件系统可能会高达数百GB的容量,如果将inode与数据区块都放在一起就会导致数据管理非常难以管理。所以Ext2文件系统格式化的时候会区分为多个区块群组,每个区块群组都有独立的inode、数据区块、超级区块系统。

在整体规划中,文件系统最前面有一个启动扇区,这个扇区可以安装启动引导程序,这样就可以实现将不同的启动引导程序安装到别的文件系统的前面,而不会覆盖磁盘唯一的MBR,这样才能够实现出多重引导的环境。启动引导程序会有一个额外的分区,这个额外的分区在grub启动引导程序中被定义为BIOS boot(MBR启动引导没有这个额外分区),这个额外的分区除了开机过程需要的程序还会存储区块群组(由于没有找到相关资料,推测MBR启动引导模式应该是使用分区的启动扇区作为区块群组),这个额外的分区也被称为启动引导扇区。(这部分内容结合Linux操作系统(附一):磁盘分区进行了解)

启动引导扇区中存储的区块群组信息及结构(Ext2文件系统示意图)

根据上面Ext2的文件系统示意图来了解群组中六个结构的内容:

2.1.1数据区块(Data Block)

区块引导扇区就是实际用来存储数据的地方,ext2文件系统支持的区块大小有1K、2K、4K三种,在格式化时每个区块的大小就固定了,且每个区块都有编号以方便inode记录。因为区块的大小限制,也就决定了文件系统支持的最大磁盘容量和最大单一文件容量,下面是ext2文件系统的限制:

ext2能支持大于2GB以上的单一文件容量,但应用也有可能因为使用旧的限制而不能支持文件的2GB容量。ext2文件系统的区块的一些其他限制:

1.区块的大小与数量在格式化完以后就不能修改(除非重新格式化);
2.每个区块内最多只能放置一个文件的数据;
3.如果文件大于区块的大小,则一个文件会占用多个区块;
4.如果文件小于区块,则区块的剩余容量就不能够在被使用(磁盘空间会浪费)。

2.1.2inode table(inode表)

inode表中记录的就是每个inode对应的文件的属性和文件数据区块的编号,下面来看在inode表中记录的文件具体信息:

1.文件的读写权限,即read、write、excute;
2.文件的拥有者与用户组,即owner、group;
3.文件的大小;
4.文件建立或状态改变的时间(ctime);
5.文件最近一次被读取的时间(atime);
6.文件最近修改的时间(mtime);
7.定义文件特性的标识(flag),如SetUID;
8.该文件真正内容的指向(pointer);

inode的大小都是固定的128B(新版ext4与xfs可以设置256B),每个文件都会占用一个inode,系统读取文件时需要先找到inode,并分析inode所记录的权限与用户是否符合,符合权限才能到文件真正的数据区块中读取文件数据。

由于inode固定大小的限制,所以能记录的数据非常有限,记录一个数据区块的编码就需要4B,假设一个文件有400MB且每个区块为4K时,那至少也要10万个记录才能记录完全部数据区块,这在一个inode上显然没有办法实现,所以文件系统在一个inode记录中提供了12个直接数据区块记录,一个间接、一个双间接与一个三间接记录区,这个记录结构大概是这样:

在上面的inode结构示图中,文件权限/属性记录区域就是inode表中每个inode的前面七个信息,后面的直接间接则表示了inode真正数据区块号码(即第八个信息:pointer),只是因为inode本身容量大小的限制,在inode表内部可能没办法完全记录完文件的所有数据实际的数据区块,所以就会通过直接或间接的方式来实现数据区块的记录,下面来解释一下inode记录区块:

直接记录区块:在inode表中有12个记录区块直接记录对应的数据区块编号。
间接记录区块:在inode表之外拿一个数据区块(假设表示为Indirect record block)来记录当前文件的数据区块编号,这个间接记录区块中只记录了这个Indirect record block的编号。
双间接记录区块:在inode表之外拿一个数据区块来记录Indirect record block的编号,假设这个数据区块表示为two Indirect record block,这个双间接记录区块就只记录two Indirect record block的编号,two Indirect record block记录的数据区块编号全是Indirect record block的编号,再由Indirect record block记录真正的数据区块编号。
三间接记录区块:安装前面的描述以此类推,在inode表之外拿一个数据区块来记录two Indirect record block的编号,假设这个数据区块表示为three Indirect record block,这个三间接记录区块记录的就是three Indirect record block的编号。

通过上面对inode的结构介绍,按照每个数据区块为1K来计算每个文件的最大容量限额:

12个直接指向:12*1K=12K;
间接指向:256*1k = 256K;
双间接指向:256*256*1K = 2562K;
三间接指向:256*256*256*1K = 2563K;
每个文件的最大容量限额:12K+256K+2562K+2563K=16GB;
//为什么每个磁盘是256个记录:一个数据区块是1K即1024B,每个数据区块编码占用4B,所以每个数据区块记录的数据分区编码为256个;

2.1.3超级区块(Superblock)

超级区块是记录整个文件系统相关信息的地方,它负责记录当前文件系统的主要信息,拿windows系统来说超级区块就是当前的设备上C、D、E、F各个磁盘分区各自的属性记录区,它主要包含有以下信息:

数据区块与inode的总量;
未使用与已使用的inode与数据块的数量;
数据区块与inode的大小(block为1、2、4K,inode为128、256K)
文件系统的挂载时间、最近一次写入数据的时间、最近一次检验磁盘(fsck)的时间等文件系统的相关信息;
一个有效位数值,如果该文件系统已经被挂载,则有效位为0,如果未被挂载,则有效位为1。

超级区块记录了当前文件系统的基本信息,一般来说超级区块的大小为1K,这些信息可以用dumpe2fs命令来查看。如果超级区块顺坏,文件系统会需要花很长时间来恢复。

2.1.4文件系统描述(Filesystem Description)

这里描述了每个区块群组的开始与结束的区块,以及说明每个区段(超级区块、对照表、inode对照表、数据区块)分别介于那个区块之间,这部分也能用dumpe2fs来观察。

2.1.5区块对照表(block bitmap)

用来记录哪些数据区块已经被使用了和哪些数据区块没有被使用,当新增文件时就要将文件对应的数据区块标记为已使用,当删除文件时原本文件数据对应的数据区块就要被标记为未使用。

2.1.6inode对照表(inode bitmap)

用来记录哪些inode编号已经被使用了,哪些inode编号未被使用,当新增一个文件时对应的inode编号标识为已使用,当删除文件时原文件对应的inode编号就要被标记为未使用。

2.2通过dumpe2fs查看ext文件系统的基本信息

在使用dumpe2fs命令需要目前系统格式化的设备,也就是之前在Linux操作系统(附一):磁盘分区中所说到的磁盘分区,即MBR和GPT的磁盘分区所产生的磁盘分区,系统的磁盘分区与文件系统的磁盘分区是两个不同层的分区表达,系统分区是基于系统的内核和硬件设备所产生的,它们的分区最小单元区块是基于磁盘硬件上的柱面产生(即系block),比如MBR格式基于一个柱面的原硬件容量单元,或者还有基于GPT的一个逻辑区块容量单元。

而文件系统的分区是在系统分区基础上,一个系统分区可以作为一个文件系统分区也可以被格式化为多个文件系统分区,一个超级区块下又会包含多个区块群组,一个群组才真正对应着一个独立的文件系统。

通过前面的介绍应该大概了解系统的磁盘分区和文件系统的磁盘分区之间的关系,不过这里还有一个小小的差别没有介绍,就是文件系统下的block与系统分区下的block之间的差别,如果已经详细的了解了系统磁盘分区会发现,它们之间的大小是不一致的,在ext2的文件系统下的block比之前讲到的MBR和GPT的block都要大,这是因为文件系统下将多个系统磁盘区块作为一个文件系统的区块,就像在GPT中也会有将多个磁盘硬件柱面作为一个逻辑区块,这两者的性质都是一样,都是在逻辑层面定义的区块。

一个文件系统的区块就是一个文件的最小容量,所以一个文件的实际数据如果小于一个文件系统的区块的大小,那么这时候多余的容量就会被浪费。假设现在有10000个小文件,每个文件大小均为50B,这时候假设文件系统的区块是1K会浪费的容量是(1024B*10000 = 9.76MB)-(50*10000=0.47MB)= 9.29MB。

dumpe2fs命令的语法

 dumpe2fs [-bn] 设备文件名

选项与参数:

-b:列出保留坏道的部分;
-h:仅列出superblock的数据,不会列出其他的区段内容,即超级区块的内容

然后就是设备文件名是指系统磁盘分区的设备名,在Linux操作系统(附一):磁盘分区的3.1中有介绍系统磁盘分区对应的文件名,就是dumpe2fs命令语法中需要的设备文件名,可以通过 blkid 命令来查看当前系统分区的设备文件,而且要注意blkid命令是系统管理员命令,需要在root用户下使用。

然后还需要注意的是dumpe2fs是ext文件系统的命令,只能在CentOS6及以下版本中使用,CentOS7是xfs文件系统,后面在介绍相关命令。

 blkid  #打印结果:/dev/sda1: UUID="ee8ff3a9-c743-41fe-bb1e-aabf6c580a58" TYPE="ext4" /dev/sda2... /dev/sda3...

 dumpe2fs /dev/sda1  #由于打印结果太多,这里就不粘贴了,下面将一些主要的信息做一些介绍

dumpe2fs打印的内容主要包括两个部分,一个是超级区块的信息,另一个是区块群组信息:

dumpe2fs打印的超级区块信息内容

1.Filesystem volume name    #文件系统名称(可能为<none>即没有设置名称)
2.Last mounted on    #上一次挂载的目录位置
3.Filesystem UUID    #当前文件系统程序的全局唯一标识符
4.Filesystem magic number    #上方的UUID为Linux对设备的定义码
5.Filesystem revision #    #下方的features为文件系统的特征数据
6.Filesystem features    #文件系统特征
7.Filesystem flags    #文件系统标识
8.Default mount options    #默认在挂载时会主动加上的挂载参数
9.Filesystem state    #文件系统的状态(clean表示没问题)
10.Errors behavior    
11.Filesystem OS type    #当前文件系统所作用在的操作系统类型
12.Inode count    #inode的总数
13.Block count    #区块的总数
14.Reserved block count    #保留的区块总数
15.Free blocks    #还有多少区块可用数量
16.Free inodes    #还有多少inodes可用数量
17.First block    #第一个区块编码
18.Block size    #单个区块的容量
19.Fragment size    #单个逻辑区块的容量
20.Reserved GDT blocks    #保留的组描述符占用的区块数量
21.Blocks per group    #群组的区块容量
22.Fragments per group  #群组的逻辑区块容量
23.Inodes per group  #群组的索引容量
24.Inode blocks per group  #每个群组的inode块的数量
25.Flex block group size  
26.Filesystem created  #创建文件系统的时间
27.Last mount time    #最后挂载的时间
28.Last write time    #最后写入的时间
29.Mount count    #距离上一次文件系统检查走被挂载的次数
30.Maximum mount count    #最大挂载次数
31.Last checked    #文件系统最后一次检查的时间
32.Check interval    #检查间隔时间
33.Lifetime writes    #总共写入的数据
34.Reserved blocks uid    #保留快的UID(用户)
35.Reserved blocks gid    #保留块的GID(用户群组)
36.First inode    #第一个inode
37.Inode size    #索引的大小,已经记录到了哪个inode值
38.Journal inode    #日志的索引
39.Default directory hash
40.Directory Hash Seed
41.Journal backup
42.Journal features
43.Journal size    #日志的可供存储大小
44.Journal length    #日志的长度
45.Journal sequence    
46.Journal start    #日志状态

dumpe2fs打印的区块群组信息内容(以Group 0作为示例)

Group 0: (Blocks 1-8192) [ITABLE_ZEROED]    #第一块区块群组的位置
  Checksum 0x8f6b, unused inodes 2007
  Primary superblock at 1, Group descriptors at 2-3    #所属超级区块的所在位置
  Reserved GDT blocks at 4-259
  Block bitmap at 260 (+259), Inode bitmap at 276 (+275)
  Inode table at 292-544 (+291)    #群组的inode表所在位置
  3836 free blocks, 2007 free inodes, 2 directories, 2007 unused inodes
  Free blocks: 4357-8192    #当前群组剩余的区块数量
  Free inodes: 18-2024    #当前群组剩余的索引数量

2.3文件系统与目录树的关系

Linux操作系统(三):文件、目录中就提到过目录本身也是一个文件,它的文件数据中存储是文件信息,这个信息其实就是文件名和文件本身的inode。所以文件本身其实不记录自己的文件名,文件名其实是目录用来标识文件的,然后这个标识指向一个可以真正找到文件数据的inode,所以文件名是被存储在目录本身的数据区块中。

在Linux中将文件组织起来的是一个目录树,这应该在前面的博客内容中也有提到,就算没有提到日常使用计算机也可以感受的到,系统就是通过这个目录树一层一层的找到对应的目录和文件。

Linux操作系统(三):文件、目录中介绍过ls这个命令,这个命令有一个i选项还记得吧,可以通过这个选项来查看文件的inode,比如下面使用 ls -li 来查看root根目录下各个文件的inode及其文件其他信息:

 ls -li  #下面是打印结果:

 total 96
 188693 -rw-------. 1 root root  3317 May  6 18:21 anaconda-ks.cfg
 194702 drwxr-xr-x. 2 root root  4096 May  7 06:14 Desktop ...

下面再通过/etc/passwd来解释一下系统是如何通过目录树和inode读取文件的(root用户):

 ll -di / /etc /etc/passwd
     2 dr-xr-xr-x.  22 root root  4096 Jun  9 21:25 /
129798 drwxr-xr-x. 102 root root 12288 Jun  9 23:31 /etc
183602 -rw-r--r--.   1 root root  1428 May  6 18:21 /etc/passwd

系统先通过根目录 / 获取到它的inode为2,并且可以从根目录对应的文件权限上看到当前用户拥有读取权限,然后通过inode为2读取到根目录文件数据;

从根目录文件数据中找到 /etc 并获取到它对应的文件的inode为129798,同样当前用户拥有etc的读取权限,然后通过inode为129798读取到etc的文件数据;

从etc文件数据中找到 passwd 的inode为183602,同样当前用户拥有passwd的读取权限,然后根据passwd的inode找到对应的数据区块,然后将passwd的文件数据读取出来。

由上面的文件读取操作示例了解到了系统读取文件的基本过程,这也同时说明了一个问题,就是文件系统不是越大越好,虽然大容量的文件系统可以存储很多数据,但同时也带来一个查询效率会随着文件系统的容量增加而降低的问题(需要一层一层的查找),并且磁盘在长期的使用过程中会不断的有增删操作,会导致一个文件的多个数据区块并不是一个连续的存储区块,所以在文件系统容量越大,在读取同一个文件时磁盘的机械手臂移动的幅度会非常大,会造成数据读取性能下降。

2.4ext2/ext3/ext4文件的存取与日志式文件系统的功能

在前面的文件系统与目录树关系中介绍了文件读取,接着来了解文件的写入操作,当要写入一个文件时需要经过的基本过程是:

1.先确定用户对于预增文件的目录是否有可写和可执行权限;
2.然后从文件系统的inode对照表中找到到未使用的inode编号,并将新文件的权限/属性写入;
3.根据区块对照表找到未使用的数据区块,并将数据写入到数据区块中,然后更新inode的区块指向;
4.将刚刚写入的inode和数据区块同步更新inode对照表和区块对照表,并更新超级区块的内容。

一般来说,inode表和数据区块被称为数据存储区域,至于其他的超级区块、区块对照表、inode对照表等区段被称为元数据,因为这三者的数据经常变动,每次新增、删除、编辑都可能会影响到这三部分数据,因此才被曾为元数据。

然后关于数据的写入操作需要关注一个文件,就是当数据写入时可能突发停电、内核错误等其他情况导致数据写入终端,这时候写入的整个流程可能只完成了一部分,这就会导致文件系统中的数据不一致。在ext2文件系统中,就会根据超级区块中的有效位(是否挂载)与文件系统状态(正确卸载与否)等相关数据来判断是否存在数据的不一致性问题或错误,如果存在就会强制进行一次数据检查并修复文件系统,如果需要检查就会使用e2fsck这个程序来实现,不过这种检查会非常消耗时间。

对于数据不一致性问题,在ext3、ext4中引入了日志文件系统,它们会规划出一个区块,用来专门记录写入或修改文件时的步骤,这时候就可以通过这些记录的信息来判断文件系统中是否存在不一致性的问题,而不再需要对整个文件系统进行检查了,这就大大的提高了文件系统不一致性检查的效率,这个被用作记录的区块被称为日志区块,记录的数据被称为日志,下面来简单的介绍一下日志记录的步骤:

1.预备:当要写入一个文件时,先在日志记录中记录某个文件准备写入的信息;
2.实际写入:开始写入文件的权限与数据;开始更新元(metadada)数据;
3.结束:完成元数据的更新后,在日志记录区块中完成该文件的记录;

虽然ext2没有日志系统,但ext3和ext4可以实现向下兼容,可以通过更新文件系统来解决这个问题。

2.5Linux文件系统的运行

如果对计算机的组成原理有所了解的话肯定知道,磁盘中的数据并不是直接被CPU使用的,而是中间还有一个硬件结构——内存,如果不了解的话问题也不大,这里并不会影响对我接下来要解释的内容产生影响。简单的来说,CUP使用的数据实际上是在内存上的,这是因为在磁盘上读写数据的速度与CPU的运算速度差别非常大,而内存的速度相比磁盘就要快很多,但是内存只有在通电的情况下才能存储数据,一旦断电内存中的数据就会失效。

所以在系统启动时会先将磁盘上的数据添加到内存中来提供给CUP使用,但是内存的空间也是有限的。为了解决这个问题,Linux采用了异步处理的方式,就是当一个文件数据加载到内存中时,如果没问没有被修改就会被标记为干净(clean),但如果内存中的文件数据被更改过,此时内存中的数据就会被标记为脏(Dirty),此时所有的操作还是在内存中执行,并没有写入到磁盘中。系统会采用不定时的将内存中的标记为脏(Dirty)的数据写回磁盘,保证磁盘与内存数据的一致性,当然也可以通过sync命令来实现手动强制写入磁盘。

除了不定时的将数据从内存中同步到磁盘和手动sync命令实现同步数据,在关机命令被调用的时候也会主动调用sync将数据同步到磁盘,如果不正常关机(断电、宕机或其他情况),就会导致数据没有同步到磁盘内,再次启动系统时就需要花很多时间进行磁盘校验,甚至导致文件系统的损坏(非磁盘损坏)。

2.6挂载点与VFS

每个文件系统都有独立的inode、区块、超级区块等信息,这个文件系统要能够连接到目录树才能够被使用,将文件系统与目录树结合的操作就称为挂载。

所以挂载点是目录,该目录就是文件系统的入口,因此不是任何文件系统都能够被使用,必须挂载到某个目录才可以,另外挂载的文件系统对应的inode是唯一,但同一个文件系统的inode可以被多个目录挂载,比如根目录和/boot就是同时挂载一个文件系统(可能有的系统上/home也是挂载这一个文件系统,但我测试的系统不是):

 ls -lid / /boot  #下面的内存是打印结果:

  2 dr-xr-xr-x. 22 root root 4096 Jun  9 21:25 /
  2 dr-xr-xr-x.  5 root root 1024 May  6 18:20 /boot

然后还有之前在Linux操作系统(三):文件、目录中介绍的/ 、/. 、/..同样指向同一个文件系统,这里就不测试了。

最后就是关于VFS的内容了,在Linux系统中标准文件系统是ext2,还有增加了日志功能的ext3和ext4,事实上Linux还支持很多其他的文件系统格式,下面是常见的支持文件系统:

传统文件系统:ext2、minix、FAT(用vfat模块)、iso9660(光盘)等;
日志文件系统:ext3、ext4、ReiserFS、Window'NTFS、IBM's、SGI'sXFS、ZFS;
网络文件系统:NFS、SMBFS;

查看当前Linux支持的文件系统命令:

ls -l /lib/module/$(uname -r)/kernel/fs

查看当前已经加载到内存中支持的文件系统:

cat /proc/filesystems

在一个系统下可以支持多个文件系统,而当我们对文件进行读写操作时并不需要手动的去调用对应支持的文件系统程序,这就是因为在Linux中有VFS(Virtual Filesystem Switch)内核,当我们去使用某个文件时,VFS会自动的帮助我们匹配对应的文件系统程序来处理我们的操作,大概的流程就是:

用户进程-->系统调用界面(内核提供)-->虚拟文件系统(VFS)-->调用对应的文件系统程序-->高速缓存-->设备驱动程序-->磁盘设备控制器。

2.7XFS文件系统

在CentOS7中已经是默认支持XFS文件系统,这是因为ext文件系统的预先规划格式化太慢,而XFS文件系统在这方面则是采用动态配置的方式解决了这个问题,下面就先来了解这两者的区别:

通过前面对ext文件系统的介绍可以了解到ext文件系统的inode、区块、元数据都是在文件系统格式化的之前就全部规划好了,这虽然方便管理,但是格式化的时候却是非常消耗时间。而xfs文件系统采用的是动态配置,即在文件系统格式化时并不对编号和区块进行规划,而是在创建文件时动态的去配置,从而达到提高格式化的效率的目的。

XFS文件系统配置

xfs本身也是一个日志文件系统,一开始就是用来开发用于高容量磁盘以及高性能文件系统,因此非常适合现在的系统环境,同时几乎具备所有ext4文件系统的功能。xfs文件系统在数据分布上主要划分为三个部分:一个数据区(data section)、一个文件系统活动登入区(log section)、一个时实运行区(realtime section),这三个数据内容如下:

数据区:根ext差不多,包括inode、数据区块、超级区块等数据都放置在这个区块。同样分为多个存储区群组(allocation groups)来分别放置文件系统所需要的数据,每个存储区群组都包含:超级区块、剩余空间的管理机制、inode的分配追踪。而且inode与数据区块都是系统需要用到时才动态配置产生,所以格式化非常块。

文件系统活动登入区:该区域用来记录文件系统的变化,类似于日志区。文件变化会在这里记录下来,直到该变化完整的写入数据区后,该条记录才会结束。

时实运行区:当文件要建立时,xfs会在这个区域里面找到数个extent区块,将文件放置在这个区块内,等到分配完以后,再写入到数据区(data section)中。这个extent区块的大小要在格式化的时候就先指定,最小值是4K最大是1G,一般非磁盘阵列的磁盘默认为64K容量,如果具有磁盘整列的stripe情况下,则建议将extent设置为stripe一样大,这个extent最好不要随便改变,不然可能会影响文件系统性能。

xfs的区块与inode有多种不同的容量可供设置,区块容量可以在512B~64K之间调整,不过Linux的环境下,由于存储控制的关系(页面文件pagesize的容量之故),因此最大只能使用4K而已,即便可以设置容量超过4K也不能被挂载。至于inode容量可以在256B~2MB之间,不过一般还是使用256B的默认值就够用了。

XFS文件系统的描述数据观察

根查看ext文件系统的信息一样,先找到磁盘设备,xfs文件系统可以通过df命令查看挂载点挂载的文件系统设备文件信息:

 df -T /  #这里我测试的是根目录这个挂载点挂载的文件系统,打印结果在下方:

 /dev/mapper/centos-root xfs  17811456 7366084 10445372   42% /

然后通过xfs_info命令来查看/dev/mapper/centos-root这个磁盘设备对应的文件:

 xfs_info 挂载点 | 设备文件名  #语法

 xfs_info /dev/mapper/centos-root

打印的信息解析:

meta-data=/dev/mapper/centos-root isize=512    agcount=4, agsize=1113856 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0 spinodes=0
data     =                       bsize=4096   blocks=4455424, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal               bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

第一行:isize表示inode的容量;agcount表示存储区群组个数;agsize表示表示每个存储区群组有多少个区块;

第二行:sectsz表示逻辑扇区的容量;

第四行:bsize表示区块的容量,这里每个区块是4096个字节即4K;blocks表示文件系统一共有多少个区块;

第五行:sunit与swidth与磁盘阵列的stripe相关性较高,后面格式化相关内容介绍;

第七行:internal表示这个登入区的位置在文件系统内,4K*2560个区块,共10M的容量;

第九行:realtime区域里面的extsz容量为4K,目前还没有使用。

 三、文件系统的简单操作、磁盘分区、格式化、检验与挂载

 3.1.1磁盘与目录的容量

查看系统上的文件系统的df命令

 df [-ahikHTm] [目录 | 文件名]

df命令的选项与参数解析:

-a:列出所有文件系统,包括系统特有的/proc等文件系统;
-k:以KBytes的容量显示各文件系统;
-m:以MBytes的容量显示各文件系统;
-h:以较易阅读的GBytes、MBytes、KBytes等格式自行显示;
-H:以M=1000K替换1024K的进位方式;
-T:连同硬盘分区的文件系统名称(例如xfs)也列出来;
-i:不用磁盘容量,而已inode的数量显示;

默认情况下df不加任何选项和参数会将所有文件系统都列出来,但不包含特殊的内存内的文件系统与swap,然后再来看看df都会打印出来哪些信息:

默认的信息:
Filesystem:文件系统对应的设备名,由此可以判断文件系统是在哪个硬盘分区;
1K-blicks:说明下面的数字单位是1KB,用以用-h或-m来改变容量;
Used:已使用的容量;
Available:剩余的容量;
Use%:磁盘使用率;
Mounted on:磁盘的挂载目录(即挂载点);
其他信息:
Type:文件系统的类型(由-T选项产生)
Inodes:文件系统的总inodes个数,也是用来表达容量的数据(由-i选项产生)

关于df命令需要注意的是-a选项会将所有文件系统都打印出来,这里面会包含非常多的特殊文件系统,这些文件系统几乎都在内存中,例如/proc这个挂载点,这些特殊文件系统都会占用磁盘空间。另外就是要特别关系根目录挂载的文件系统的剩余容量,因为所有数据都是由根目录衍生出来的,当根目录的容量剩余为0时系统就可能问题大了。

最后就是/dev/shm这个目录挂载的文件系统,它是由内存虚拟出来的磁盘空间,通常是物理内存的一半。由于是内存模拟出来的,所以在这个目录下读写文件速度会非常块,但需要注意这个目录下存储的文件数据会在关机时全部消失,因为它不会写到磁盘上。

查看文件或目录容量的du命令

 du [-achskmx] 文件或目录名称

默认情况下列出当前目录下所有文件的容量,包括子目录的所有文件,下面来看具体选项解析:

-a:列出所有文件的容量,而不仅仅是当前目录下的;
-c:在处理完所有参数以后,给出容量的总计;
-h:以较易读懂的方式显示,会给容量数值加上单位; -s:仅列出总量,而不是列出每个目录个别目录的占用容量; -S:不包括子目录下的总计,与-s有点差别
-x:只显示指定参数的实际容量,而不包括其子目录;
-k:以KBytes列出容量显示; -m:以MBytes列出容量显示;

3.1.2硬链接与符号链接

通过对文件系统的了解,要获取文件的真正数据最终都是需要根据文件系统上对应的inode来获取,文件名只是存在于目录上用于检索文件对应的inode,在Linux操作系统(三):文件、目录中的2.2中就提到过链接文件,但仅仅是从文件名的角度简单的介绍,实际上链接文件分为两种情况:

硬链接:直接新增一个文件名链接到指定的inode;
符号连接:创建一个新的文件名指向现有的文件名;

硬链接带来的好处就是提高文件数据的获取效率和链接不会因为其他链接的改变导致无法找到文件的情况,因为不需要经过多个文件名的符号解析,但其也存在局限性:硬链接不能跨文件系统,不支持链接目录。

符号链接可以跨文件系统和链接目录,但也会出现因为链接中的某个环节文件名发生改变或被删除,建立在这个文件名上面的其他文件名就会无法找到该文件了。

建立文件链接的ln命令

 ln [-sf] 源文件 目标文件

ln命令的选项参数解析:

-s:建立符号链接,以替代硬链接,在不支持符号链接的系统上仅仅产生一个错误提示(当不适用这个选项时建立的连接就是硬链接,目标文件名直接指向文件的inode,加上这个选项链接就会指向源文件名成为符号连接);
-f:删除以存在的目标文件;

3.2.1查看磁盘分区信息

对于系统管理者而言,磁盘管理是相当重要的一环,如果想要在系统上新增一块磁盘,至少需要一下四个步骤的操作:

1.对磁盘进行划分,以建立可用的磁盘分区;
2.对硬盘分区进行格式化(format),以建立系统可用的文件系统;
3.对刚刚建立好的文件系统进行检验;
4.在Linux系统上,需要建立挂载点,并将它挂载起来。

查看系统上所有磁盘列表的lsblk命令

 lsblk [-dfimpt] [device]

lsblk命令选项解析:

-d:仅列出磁盘本身,不打印磁盘的分区数据;
-f:同时列出磁盘内的文件系统名称;
-i:使用ASCII的字符输出;
-m:同时输出该设备的/dev下面的权限信息;
-p:列出该设备的完整文件名,而不是仅列出最后的名称;
-t:列出磁盘设备的详细数据,包括磁盘阵列机制、预读写的数据量大小;

下面是在虚拟机上测试的lsblk -p的输出结果:

NAME                        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
/dev/sda                      8:0    0   20G  0 disk 
├─/dev/sda1                   8:1    0    1G  0 part /boot
└─/dev/sda2                   8:2    0   19G  0 part 
  ├─/dev/mapper/centos-root 253:0    0   17G  0 lvm  /
  └─/dev/mapper/centos-swap 253:1    0    2G  0 lvm  [SWAP]
/dev/sr0                     11:0    1  4.4G  0 rom  /run/media/tx/CentOS 7 x86_64

打印的信息分别是:

name:设备文件名;MAJ:MIN:分别表示主要与次要设备代码,用于内核识别设备用的;RM:是否是可卸载设备,如(光盘、USB磁盘等);SIZE:容量;RO:是否为只读设备;TYPE:磁盘分区类型(磁盘disk、分区partition、值读存储器rom、逻辑卷LVM);MOUNTPINT:挂载点;

查看磁盘的分区表类型与分区信息的parted命令

 parted [设备] [命令 [参数] ]

parted命令除了可以查看分区的信息,还可以用来实现磁盘分区的功能,这里仅仅介绍查看分区的信息,使用parted查看分区的信息只需要在命令后面指定分区的设备文件名 + print命令:

[root@localhost ~]# parted /dev/sda print
Model: VMware, VMware Virtual S (scsi)    #磁盘的模块名称
Disk /dev/sda: 21.5GB    #磁盘的总容量
Sector size (logical/physical): 512B/512B    #磁盘的每个逻辑/物理区块的容量
Partition Table: msdos    #分区表的格式(MBR/GPT)
Disk Flags: 

Number  Start   End     Size    Type     File system  标志    #这里是分区信息
 1      1049kB  1075MB  1074MB  primary  xfs          启动
 2      1075MB  21.5GB  20.4GB  primary               lvm

3.2.2实现磁盘分区的操作

管理磁盘分区需要基于不同的磁盘分区格式,MBR格式下使用fdisk,再GPT格式下使用gdisk,它们的基本选项和参数都差不,由于我测试的设备还是MBR格式,所以使用fdisk作为主要的解析内容,这两个命令几乎都是一样的,如果你的设备磁盘分区格式是GPT的话参考gdisk的文档对照下面的步骤基本也都搞得定:

使用fdisk命令管理MBR格式的磁盘

 fdisk [options] <disk>  #更改分区表

 fdisk [options] -l <disk>  #列出分区表

 fdisk -s [partition]  #给出分区大小(区块数)

fdisk命令的选项解析:

-d:<size>    #扇区大小(512102420484096);
-c:    #兼容模式:“dos”或“nondos”(默认);
-h:    #打印此帮助文档;
-u:<size>    #显示单位:"cylinders"(柱面)或“sectors”(扇区,默认);
-V:    #打印fdisk的版本;
-C:<number>    #指定柱面数;
-H: <number>   #指定磁头数;
-S:<number>    #指定每个磁道的扇区数;

以上这些选项仅仅是fdisk命令本身的选项,而实际上fdisk命令是提供了一个交互式接口来管理分区,所以它还有许多的子命令分别用于不同的管理功能;进行分区操作时是在内存中完成,没有直接同步到磁盘,直到执行w子命令才会保存到磁盘上真正实现管理操作。

下面先来了解fdisk的子命令:

   a   toggle a bootable flag    #一个可启动标志的开关
   b   edit bsd disklabel    #编辑BSD磁盘标签
   c   toggle the dos compatibility flag    #切换到DOS兼容表示
   d   delete a partition    #删除一个分区
   g   create a new empty GPT partition table    #创建一个新的空的GPT分区表
   G   create an IRIX (SGI) partition table    #创建一个IRIX(SGI)分区表
   l   list known partition types    #列出已知的分区类型
   m   print this menu    #打印菜单
   n   add a new partition    #添加新的分区
   o   create a new empty DOS partition table    #创建一个新的空的DOS分区表
   p   print the partition table    #打印分区表
   q   quit without saving changes    #退出,不保存更改
   s   create a new empty Sun disklabel    #创建一个新的空的Sun磁盘标签
   t   change a partition's system id    #修改一个分区的系统id
   u   change display/entry units    #更改显示/输入单元
   v   verify the partition table    #验证分区表
   w   write table to disk and exit    #写入表到磁盘并退出
   x   extra functionality (experts only)    #额外功能

创建磁盘分区的具体操作步骤

1.查看系统上所有的磁盘列表,相关命令就是3.2.1中介绍的lsblk(使用该命令的-p选项,查看完整的设备文件路径),通过打印的size数据计算出每个磁盘的剩余空间,根据剩余空间和实际需求,选择空间可用的磁盘进行分区操作;

2.使用 parted 目标分区磁盘文件 print 查看磁盘的分区模式,因为MBR与GPT格式会决定磁盘应该如何分区,以及每个磁盘区块的容量相关信息也是分区必须参考的数据。

3.根据磁盘分区格式选择对应的程序命令实现磁盘分区,MBR使用fdisk,GPT使用gdisk。下面进入具体磁盘分区操作演示,由于我的设备是MBR格式,这里演示就是fdisk的命令:

前面的两个步骤就不展示了,这里直接进入fdisk命令的演示:

 fdisk /dev/sda  #对磁盘sda进行分区操作

执行命令以后输入子命令 p 查看当前的分区列表以及磁盘的容量相关信息:

命令(输入 m 获取帮助):p

磁盘 /dev/sda:128.8 GB, 128849018880 字节,251658240 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x000e48a1

   设备 Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048     2099199     1048576   83  Linux
/dev/sda2         2099200    41943039    19921920   8e  Linux LVM

从打印的信息可以看到当前磁盘有两个分区,其他信息一目了然就不过多的介绍了,接着输入子命令 n 正式进入磁盘分区操作:

命令(输入 m 获取帮助):n
Partition type:
   p   primary (2 primary, 0 extended, 2 free)
   e   extended
Select (default p): 

这里是选择磁盘分区类型,它有一些提示信息,如果对这些信息不了解可以参考Linux操作系统(附一):磁盘分区这篇博客,p primary表示主分区并且主分区中已经有两个主分区,没有扩展分区,总共还可以划分两个分区;e extended表示扩展分区的相关信息,由于我当前的系统上还没有扩展分区,所以就没有更多的信息。

这两个提示信息前面的p、e也就是分区类型的简写表示,这里我先输入:p来创建一个主分区,因为在MBR格式中可以创建三个主分区和一个扩展分区,然后扩展分区又可以创建逻辑分区,这些在之前的博客中都有详细的介绍。

Select (default p): p
分区号 (3,4,默认 3):

分区编号也就是MBR分区表中的编号,总共四个,这里我选择:3。

分区号 (3,4,默认 3):3
起始 扇区 (41943040-251658239,默认为 41943040):

起始扇区(需要注意的是在CentOS6中是柱面而不是扇区,但问题不大,根据前面的分区进行连续划分就好,所以选择默认即可):41943040

起始 扇区 (41943040-251658239,默认为 41943040):41943040
Last 扇区, +扇区 or +size{K,M,G} (41943040-251658239,默认为 251658239):

这里是需要设置结束扇区,提示信息中已经给出了设置范围,如果使用扇区编号就需要计算你要划分的容量要划到哪个扇区,除了设置指定的扇区编号还可以使用容量的方式设置,就像提示信息中提示的那样,使用容量设置前面需要有“+”加号、容量值、容量单位,这里我就直接设置容量为20G:

Last 扇区, +扇区 or +size{K,M,G} (41943040-251658239,默认为 251658239):+20G
分区 3 已设置为 Linux 类型,大小设为 20 GiB

命令(输入 m 获取帮助):

到这里就是一个磁盘分区划分的操作已经在内存中完成了,可以使用子命令 p 就可以查看刚刚划分的分区了,也可以继续使用子命令 n 划分分区或使用子命令 w 将当前的分区写入到磁盘真正完成分区操作。

这里我先来查看一下分区信息:

命令(输入 m 获取帮助):p

磁盘 /dev/sda:128.8 GB, 128849018880 字节,251658240 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x000e48a1

   设备 Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048     2099199     1048576   83  Linux
/dev/sda2         2099200    41943039    19921920   8e  Linux LVM
/dev/sda3        41943040    83886079    20971520   83  Linux

命令(输入 m 获取帮助):

可以从分区列表信息中看到刚刚划分的磁盘分区/dev/sda3的磁盘分区信息,这里我接着将磁盘所有剩余的空间划分给扩展分区:

命令(输入 m 获取帮助):n
Partition type:
   p   primary (3 primary, 0 extended, 1 free)
   e   extended
Select (default e): e
已选择分区 4
起始 扇区 (83886080-251658239,默认为 83886080):83886080
Last 扇区, +扇区 or +size{K,M,G} (83886080-251658239,默认为 251658239):251658239
分区 4 已设置为 Extended 类型,大小设为 80 GiB

命令(输入 m 获取帮助):

需要注意的是扩展分区是不能直接被使用的,在扩展分区下还可以划分逻辑分区,然后逻辑分区才可以被格式化使用,所接着在扩展分区上划分逻辑分区:

命令(输入 m 获取帮助):n
All primary partitions are in use
添加逻辑分区 5
起始 扇区 (83888128-251658239,默认为 83888128):83888128
Last 扇区, +扇区 or +size{K,M,G} (83888128-251658239,默认为 251658239):+20G
分区 5 已设置为 Linux 类型,大小设为 20 GiB

命令(输入 m 获取帮助):

到这一步我执行子命令 w 将刚刚的磁盘分区操作写入到磁盘:

命令(输入 m 获取帮助):w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: 设备或资源忙.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
正在同步磁盘。

但需要注意,写入到磁盘不会被立即执行,因为磁盘系统还在使用这块磁盘当心出问题,所以分区表并不会立即更新,这时候有两种处理方式,其一是重新启动,其二是使用命令 partprobe 强制更新内核分区表信息:

 partprobe [-d] [-s] [devices...]

从命令语法上可以看到partprobe可以指定更新的磁盘,然后-d是用来表示不要更新内核(暂时不理解这个选项的真正作用),-s是表示在更新完磁盘分区列表后打印出分区的相关信息,一般情况下不需要指定磁盘,直接使用命令+s选项即可:

partprobe -s
/dev/sda: msdos partitions 1 2 3 4 <5>
Warning: 无法以读写方式打开 /dev/sr0 (只读文件系统)。/dev/sr0 已按照只读方式打开。
/dev/sr0: msdos partitions 2

可以看到打印出的信息中表示出/dev/sda磁盘已经有5各分区,<5>表示逻辑分区,然后就可以使用 lsblk -p 来查看磁盘分区列表信息了:

NAME                        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
/dev/sda                      8:0    0  120G  0 disk 
├─/dev/sda1                   8:1    0    1G  0 part /boot
├─/dev/sda2                   8:2    0   19G  0 part 
│ ├─/dev/mapper/centos-root 253:0    0   17G  0 lvm  /
│ └─/dev/mapper/centos-swap 253:1    0    2G  0 lvm  [SWAP]
├─/dev/sda3                   8:3    0   20G  0 part 
├─/dev/sda4                   8:4    0  512B  0 part 
└─/dev/sda5                   8:5    0   20G  0 part 
/dev/sdb                      8:16   0   20G  0 disk 
/dev/sr0                     11:0    1  4.4G  0 rom  /run/media/tx/CentOS 7 x86_64

需要注意的是,这时候的还仅仅是实现了磁盘分区,分区内还没有格式化和创建文件系统,还是无法被使用的,要想使用这些分区还需要格式化创建文件系统还有挂载等一系列操作。

3.3.1磁盘格式化

格式化其实就是创建文件系统,Linux中实现格式化的命令程序是mkfs(make filesystem),由于文件系统存在很多种,所以实际格式化命令还需要依据需要创建的文件系统而定,比如我当前是在CentOS7的环境下,其使用的默认文件系统是xfs,所以格式化实际命令是mkfs.xfs,如果是在CentOS6中默认文件系统就是ext4,那格式化命令就是mkfs.ext4,它是mke2fs的别名,mke2fs命令是用来格式化ext2/ext3/ext4文件系统的命令程序。

mkfs.xfs与mke2fs差异也不算很大,理解了一种命令另一种也就自然懂了,这里先来介绍mkfs.fsx:

 mkfs.xfs  [  -b  block_size  ]  [  -m  global_metadata_options  ]  [ -d data_section_options ] [ -f ] [ -i inode_options ] [ -l log_section_options ] [ -n naming_options ] [ -p protofile  ]  [  -q  ]  [  -r  real‐time_section_options ] [ -s sector_size ] [ -L label ] [ -N ] [ -K ] device

mkfs命令与之前介绍的命令有点不一样,它的选项都是并列的而且还非常多,这不用当心,这些选项都是用来设置文件系统相关数据的,相关的内容在第二节中已经有详细的介绍,只要了解选项与对应数据的含义就非常简单。一般情况下使用选项的默认参数也没问题,但如果了解文件系统的运行原理针对系统内核设置参数的话可以提高文件系统的性能,下面就来了解mkfs.xfs的选项:

-b:用来设置区块容量,值的单位是字节,设置范围在512到64K之间,但目前Linux最大限制为4K。另外还可以使用log=区块大小指定为以2为底的对数值,也可以使用size=容量值(即默认的详细方式);

-m:这个选项是用来指定元数据格式用的,适用于整个文件系统,取值有crc=value、finobt=value、uuid=value。

  crc是用来指定是否创建一个文件系统来维护和检查所有的CRC信息,取值为0(禁用)或1(启用);

  finobt用来指定是否在每个分配中使用单独的空闲索引节点btree索引组,取值为0(禁用)或1(启用)。默认情况下xfs不会为为文件系统创建空闲的inode b树,这是为了向后兼容RHEL7内核提供的选项,如果启用了空闲索引节点btree,旧的RHEL7内核将无法安装所创建的文件系统,当选择使用-m crc=0,free inode btree特性不受支持并禁用。

  uuid用来指定生成的文件系统的uuid的值,默认随机生成。

-d:这个选项用来设置文件数据部分的相关内容,即data section的位置、大小、其他参数。具体包括:

  agcount=value用来设置存储群组的个数,即allocation groups(AG)的个数,文件系统被分成群组以提高XFS的性能,多群主意味着分配块时可以实现更多的并行性和索引节点,这与CUP的核心有关。最小群组大小为16MiB,最大小于1TiB。这个参数与agsize是互斥的,两者只需要设置一个即可。

  agsize=value用来设置AG的容量,这个参数与agcount是互斥的,两者只需要设置一个即可。

  name=value用来设置文件系统的特殊文件的名称,这种情况下日志部分必须指定为内部,并且不能有时实部分(结合-l选项)。

  file[=value]用来设置格式化的设备是个文件而不是设备,例如虚拟磁盘,取值为0或1,1表示文件正常(默认)。

  size=value用来设置data section的容量,也就说可以不将全部的设备容量用完。

  sunit=value用来设置RAID设备或逻辑卷的分条单元(stripe)大小,与su相当,不过单位使用的是【几个sector(512Bytes大小)】的意思。

  su=value用来设置RAID设备或逻辑卷的分条单元(stripe)大小,与sunit一样,不过su使用字节单位的值设置。

  swidth=value用来设置RAID设备或逻辑卷的磁盘数量(通常也被称为分条宽度),与sw相当,不过单位使用的是【几个sector(512Bytes大小)】的意思。

  sw=value用来设置RAID设备或逻辑卷的磁盘数量(通常也被称为分条宽度),与swidth相当,不过sw使用字节单位的值设置。

  noalign用来自动几何检测,即使底层存储设备提供了该信息,也会创建没有条带几何对齐的文件系统。

-f:如果设备内已有文件系统,则需要使用这个选项来强制格式化。

-i:于inode的大小和inode的一些其他参数。

  size=value | log=value | perblock=value用于设置inode的大小,size=的以字节为单位的值,使用log=的以二为底的对数值,或者使用perblock=指定适合文件系统块的数字。最小值(缺省值)是256字节。最大值为2048 (2kib),但是inode大小不能超过文件系统块大小的一半。一般情况下使用256Bytes就足够了。

  maxpct=value指定文件系统中可以分配给索引节点的最大空间百分比,对于1TB以下的文件系统,默认值为25%;对于50TB以下的文件系统,默认值为5%;对于大于50TB的文件系统,默认值为1%,该值可以通过xfs_growfs修改。

  align[=value]用于指定inode分配是否对齐,当取值为0时表示不对其,取值为1时表示对齐。对齐的inode访问通常比非对齐的inode效率要高,而且必须在创建文件系统时对齐,因为此时分配节点索引。当文件系统需要支持不具有索引对齐特性的IRIX版本挂载时,可以使用该选项关闭索引节点对齐。

  attr=value用于指定要使用的扩展属性,默认情况下,该值为2,它使用一种有效的算法来管理属性和区段数据之间的可用内联索引节点空间。以前的版本1保留了用于属性和区段数据的固定区域,以便兼容比版本2.6.16更老的内核。

  projid32bit[=value]用于启动32位配额项目标识符,取值为0或1,1表示启用32bit的projid,如果省略该值会默认为1。

  sparse[=value]启用稀疏索引节点分配。

-l:设置文件日志部分的位置、大小和其他参数。

  internal[=value]用于指定日志是否为內置,而不是另外一个设备或逻辑卷。取值为0或1(默认,內置)。

  logdev=device用于指定日志应该位于与数据部分分开的设备上,这与internal=1参数是互斥的。

  size=value用于设置日志部分的大小,如果日志包含在数据段中,并且没有指定大小,则mkfs.xfs尝试根据文件系统大小选择合适的日志大小,实际日志大小取决于文件系统和目录快大小。

  version=value用于指定日志的版本,当前默认值是2,它允许更大的日志缓冲区大小,以及支持条纹对齐的日志写入(参考sunit和su选项)。以前的版本1限制32k日志缓冲区,并且不支持条带对齐写入,保留它是为了向后兼容。

  sunit=value指定日志对其的方式,单位是使用【几个sector(512Bytes大小)】的意思,与su参数相当,只是su使用字节为单位。日志将按此边界对齐,并四舍五入到此边界。

  su=value指定日志分条大小,与sunit相当,不过sw使用字节单位的值设置。

  lazy-count=value改变超级区块中记录各种持久计数器的方法,简单的说就是会不会时实更新元数据,当取值为0表示时实更新元数据,当取值为1时则不会更新元数据,而是将数据更新的每个节点信息保存,等到合适的时机再将数据写入到磁盘的元数据中。

-n:用于文件系统的命名(目录)区域指定版本和大小参数。

  size=value | log=value块大小可以用size=指定为以字节为单位的值,也可以用log=指定为以2为底的对数值。

  version=value命名(目录)版本值可以是2或'ci',如果未指定默认为2,不支持版本为1的目录。目录块大小可以是文件系统块大小的任意2次方,最大可以是65536。当取值为'ci'之启用ASCII不区分大小写的文件名查找和版本2目录。

  ftype=value该特性允许将inode类型存储在目录结构中,这样readdir(3)和getdent(2)就不需要通过查找inode来确定inode类型。取值为0或1,1表示文件类型信息将存储在目录结构中。缺省值为1。当crc被启用时(默认),ftype功能总是被启用,不能被关闭。

-p:(文档中的内容非常多,暂时不太懂其中所表达的含义,后期来补充)

-q:默认情况下创建完文件系统后打印其参数信息,-q则表示不打印文件系统的参数。

-r:用于指定文件系统时实部分的位置、大小和其他参数。

  rtdev=device将文件系统的时实部分放到指定的设备(分区)中,取值为设备块的名称。

  extsize=value指定文件系统时实区的区块大小,允许最小容量是系统块的大小,最大为4KiB,默认大小是条带卷的宽度,而非条带卷的64Kib。

  size=value指定文件系统时实区的大小,只有当文件系统的时实部分占用空间小于包含该部分的分区或逻辑卷的大小时,才需要设置该参数。

  noalign禁用条带大小检查,强制一个没有条带几何形状的时实设备。

-s:指定文件系统基本扇区的大小,可以直接使用字节为单位的值,也可以时log以2为底的对数值。

-L:设置文件系统的标头名称Labal name的意思。

-N:在没有真正创建文件系统的情况下打印出文件系统的参数信息。

-K:不要试图在mkfs时丢弃块。

使用默认参数格式化分区创建xfs文件系统

 mkfs.xfs /dev/sda3  #说的简单点就是在mkfs.xfs命令后面不添加任何选项,直接使用一个需要格式化的分区设备文件进行默认格式化创建文件系统

格式化后的文件系统基本信息:

meta-data=/dev/sda3              isize=512    agcount=4, agsize=1310720 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0, sparse=0
data     =                       bsize=4096   blocks=5242880, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

然后使用 blkid 查看这个磁盘分区信息:

blkid /dev/sda3
/dev/sda3: UUID="e1d17f7d-7a48-4892-99b1-c05a954ee05b" TYPE="xfs" 

关于自定义格式化磁盘创建文件系统需要了解的内容比较多,比如硬件设备、系统内核、文件系统类型都会有不同的特性,这里就拿我当前虚拟化的Linux主机来说,我虚拟了两个物理内核,并且模拟了超线程技术可以模拟出4各CPU,那么agcount就可以设置为4。首先通过grep命令来查看当前主机的CPU数:

grep 'processor' /proc/cpuinfo
processor    : 0
processor    : 1
processor    : 2
processor    : 3

通过grep查看cpu信息确认当前主机确时有4各cpu,然后基于内核个数优化磁盘分区文件系统配置参数,将刚刚格式化的磁盘分区sda3重新格式化:

mkfs.xfs -f -d agcount=4 /dev/sda3  #将刚刚格式化的磁盘分区sda3重新强制格式化
meta-data=/dev/sda3              isize=512    agcount=4, agsize=1310720 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0, sparse=0
data     =                       bsize=4096   blocks=5242880, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

关于文件系统的性能优化所涉及的内容比较多,特别是当前还没有涉及磁盘阵列等相关内容,待后期将所涉及的知识点了解的差不多了再专门针对文件系统优化写一篇博客吧,这里主要还是介绍一下文件系统的基本操作。

然后关于mkfs命令与各个文件系统的结合它实际上也是命令重命名,实际上它的基础命令是 mkfs -t 文件系统名 磁盘分区设备文件

3.3.2文件系统检验

在系统运行时谁都无法保证硬件和电源(甚至软件)不会有问题,所以宕机是不可能避免的概率事件,这些不正常的情况可能会导致磁盘与内存数据没有完全同步,导致文件系统错乱。所以当这些情况发生时就需要对文件系统进行检查,不同的文件系统检查恢复的命令也不太一样,不过还是用xfs和ext4两个主流的文件系统作为示例,xfs文件系统的检查恢复命令是xfs_repair,ext4的是fsck.ext4,fsck跟mkfs一样也是一个综合命令,针对ext4建议直接使用fsck.ext4。

下面先来了解 xfs_repair 命令:

 xfs_repair [-fLlrnpmcotvd] 设备名称

xfs_repair的选项解析:

-f:后面的设备是一个文件而不是实体设备;
-L:强制将日志归零,哪怕日志中包含元数据更改。使用该选项时可能会导致文件系统损坏,造成数据丢失。
-l:指定文件系统的外部日志所在的设备特殊文件,仅适应于使用外部日志的文件系统,相关内容了解xfs(5)的文档。
-r:指定文件系统的时实部分所在的设备特殊文件。仅适应于使用时实部分的文件系统,相关内容参考xfs(5)的文档。
-n:单纯的检查,不修改文件系统任何数据。
-p:禁用inode和目录块的读取,如果发现xfs_repair卡住并停止运行就可以使用这个选项,中断卡住的xfs_repair是安全的。
-m:指定xfs_repair的大约最大内存量,以兆字节为单位。
-c:更改文件系统参数。有关文件系统参数信息参考xfs_admin(8)的文档。
-o subopt[=value]:对文件系统检查和修复做一些优化参数配置,包括subopt的选项包括bhash、ag_stride、force_geometry,详细的参数设置参考man文档。
-t:设置xfs_repair运行时输出进度的时间间隔,单位为秒。
-v:详细的输出,可以多次指定以增加详细程度。
-d:通常再单人维护模式下,针对根目录(/)进行检查与修复的操作,然后立即重启。很危险,不要随便操作。

这里我是用更改格式化的文件系统/dev/sda3来测试xfs_repair的检查和修复:

xfs_repair /dev/sda3    #下面是测试的打印结果,检查总共分为七个流程
Phase 1 - find and verify superblock...
Phase 2 - using internal log
        - zero log...
        - scan filesystem freespace and inode maps...
        - found root inode chunk
Phase 3 - for each AG...
        - scan and clear agi unlinked lists...
        - process known inodes and perform inode discovery...
        - agno = 0
        - agno = 1
        - agno = 2
        - agno = 3
        - process newly discovered inodes...
Phase 4 - check for duplicate blocks...
        - setting up duplicate extent list...
        - check for inodes claiming duplicate blocks...
        - agno = 1
        - agno = 2
        - agno = 3
        - agno = 0
Phase 5 - rebuild AG headers and trees...
        - reset superblock...
Phase 6 - check inode connectivity...
        - resetting contents of realtime bitmap and summary inodes
        - traversing filesystem ...
        - traversal finished ...
        - moving disconnected inodes to lost+found ...
Phase 7 - verify and correct link counts...
done

简单的了解xfs_repair文件系统检查与修复的7各流程,在man的文档中xfs_repair有八个流程,对照着打印结果看吧,详细内容参考man文档:

1.Inode和Inode blockmap(寻址)检查;
2.索引节点分配图检查;
3.大小检查,包括inode声明的块数和inode大小;
4.目录检查;
5.路径名检查;
6.链路计数检查;
7.free-ap检查;
8.超级快检查;

接着简单的了解一下 fsck.ext4 的文件系统检查与修复的命令语法,:

 e2fsck  [  -pacnyrdfkvtDFV  ]  [ -b superblock ] [ -B blocksize ] [ -l|-L bad_blocks_file ] [ -C fd ] [ -j external-journal ] [ -E extended_options ] device

e2fsck的选项解析:

-a:与p的作用一摸一样,它负责提供向后兼容性,建议尽量使用-p;
-b:后面接超级区块的位置,一般来说这个选项用不到,但如果超级区块损坏时,通过这个参数即可利用文件系统内备份的超级区块来尝试恢复,一般来说,超级区块备份在:1K区块放在8193、2K区块放在16384,4K区块放在32768;
-B:通常情况下e2fsck会在不同的块范围上搜索超级块,该选项可以尝试定位特定块范围搜索超级块,如果没有找到超级快将报致命错误结束;
-c:该选项指定e2fsck使用badblocks(8)程序对设备进行只读扫描,以便找到损坏的块,如果选项被指定两次,坏块的扫描将使用非破坏性读写测试来完成。
-C fd:将完成信息写入指定的文件,这样可以简史文件系统检查进度。
-d:打印调试输出;
-D:针对文件系统下的目录进行最佳化配置;
-E extended_options:设置扩展选项,可以针对检查和修复做一些优化等,extended_options具体子选项包括:ea_ver、journal_only、fragcheck、discard、nodiscard;
-f:即使文件系统看起来很干净也要强制检查;
-F:在开始之前刷新文件系统设备的缓冲区缓存;
-j external-journal:设置可以找到该文件系统的外部日志的路径名。
-k:当与-c选项结合使用时,坏块列表中所有坏块都会保留。
-L filename:将坏块列表设置为有filename指定的坏块列表,与-l的作用一样,不同的是-l会在坏块添加到坏块列表之前被清除。
-n:以只读方式打开文件系统,并假定所有问题的答案都是"",该选项不能与-p或-y同时指定;
-p:当文件系统在修复时,若需要回复y的操作时,自动回复y来继续进行修复操作;
-r:这个选项什么都不做,提供它只是为了向后兼容;
-t:计时打印统计信息;
-v:详细的模式;
-y:假设所有问题的答案都是"",这个选项不能与-n或-y同时使用。

测试方式可以参考xfs_repair的测试示例,由于我当的虚拟机没有安装ext4的文件系统程序,这里就不提供测试示例了,不过永远不希望用到这两个命令。

关于文件系统的检查/修复还需要注意一些问题,文件系统检查必须是在管理员root用户权限下操作,被检查的磁盘分区不可挂载在系统上,所以在进行文件系统检查之前需要卸载文件系统,但由于根目录无法卸载,这时候就需要进入单人维护模式强制对根目录下的文件系统进行检查。

xfs_repair所测试的/dev/sda3只是刚刚创建的文件系统,对于新创建的文件系统的检查也是有必要的,避免有问题的文件系统投入正式的工作和生产中,对于已经使用的文件系统就的检查/修复就需要卸载才能操作,接下来就来介绍文件系统的挂载和卸载。

3.3.3文件系统的挂载与卸载

文件系统挂载简单的来说就是将分好区,并格式化创建了文件系统的磁盘绑定到某个目录上,这样磁盘就可以真正的被使用了,因为只有绑定到目录上才可以创建文件夹,才可以被目录系统找得到。文件系统挂载的原则:

1.单一文件系统不应该被挂载在不同的挂载点(目录)上;
2.单一目录不应该重复挂载多个文件系统;
3.要作为挂载点的目录,理论上应该都是空目录才行。

如果挂载文件系统的目录不为空,挂载文件系统之后,原目录下的文件和目录就会被隐藏,只有将被挂载的文件系统卸载原目录下的文件和目录才可以重新被查找到,下面就来了解实现文件系统挂载的 mount 命令:

 mount [-lhV]

 mount -a [-fFnrsvw] [-t 文件系统] [-O optlist]

 mount [-fnrsvw] [-o option[,option]...]  设备文件名 | 目录

 mount [-fnrsvw] [-t 文件系统] [-o options] 设备文件名 目录

mount的选项解析:

-l:单纯的执行mount命令会显示目前的挂载信息,加上-l选项可以增加Label名称。
-a:按照配置文件/etc/fstab的数据将所有未挂载的磁盘都挂载上来。
-t:可以加上文件系统类型指定欲挂载的类型,常见的Linux支持的类型有xfs、ext2、ext3、ext4、reiserfs、vfat、iso9660、nfs、cifs、smbfs。
-o:后面可以添加挂载时设置的参数,比如账号、密码、读写权限等:
    async,sync:此文件系统是否使用同步写入(sync)或非同步(async)的内存机制,默认未async;
    atime,noatime:是否修改文件的读取时间atime,为了性能,某些时候可能会使用不修改文件读取时间noatime;
    ro,rw:挂载文件系统为只读(ro)或可读写(rw);
    auto,noauto:允许此文件系统以mount -a自动挂载(auto);
    dev,nodev:是否允许此文件系统可建立设备文件?dev为允许;
    suid,nosuid:是否允许此文件系统含有suid/sgid的文件格式;
    exec,noexec:是否允许此文件系统上拥有可执行二进制文件?
    user,nouser:是否允许此文件系统让任何使用者执行mount?一般来说,mount仅有root权限可以进行,如果执行user参数则表示一般用户也能够对此分区进行mount;
    defaults:默认值是rw、suid、dev、exec、auto、nouser、and async;
    remount:重新挂载,这个用于系统出错或更新参数时;
-n:在默认情况下,系统会将实际挂载的情况写入/etc/mtab中,以利于其他程序运行;
-f:检查/etc/mtab中的现有记录,当记录中存在时将失败;
-r:将文件系统挂载为只读;
-w:将文件系统挂载为可读可写,这是默认选项;
-s:忽略文件系统类型不支持的挂载选项,而不是失败;
-v:详细的模式;
-B:在其他地方挂载子目录;
-R:在其他地方重新挂载子目录和所有可能的子挂载;
-M:将一个字母移到别的地方;
-target [dir]:只给一个挂载点,mount会被认为是获取挂载点或源设备;
-L:挂载具有指定标签的分区;
-T,-fstab [path]:指定替代的fstab文件;
-U,-uuid uuid:挂载具有指定的uuid分区。

一般情况下实际挂载文件系统也都采用默认的选项及参数的方式,下面是xfs、ext4、vfat等文件系统挂载都可以使用的方式:

 blkid /dev/sda3  #查看文件系统的相关信息,获取文件系统的UUID

           #打印结果:/dev/sda3: UUID="6735e1d5-bead-40f7-8702-e9cebd8607ec" TYPE="xfs"

 mkdir -p /data/xfs  #创建挂载点,即一个空白的目录

 mount UUID="6735e1d5-bead-40f7-8702-e9cebd8607ec" /data/xfs  #挂载文件系统

 df /data/xfs  #检查目录上挂载的文件系统(检查)

 文件系统          1K-块  已用     可用 已用% 挂载点
/dev/sda3      20961280 32992 20928288    1% /data/xfs

除了挂载磁盘分区,还可以挂载CD或DVD光盘,以及挂载移动磁盘vfat:

挂载CD/DVD,需要注意的是光驱挂载之后就无法退出光盘,除非将它卸载才能退出。另外如果当前使用的是图形界面,光盘会被自动挂载到/media目录,如果是命令行就需要手动挂载:

 mkdir /data/cdrom

 mount /dev/sr0 /data/cdrom

 df /data/cdrom  #已用100%是因为是DVD无法再写入

挂载vfat中文移动磁盘(USB磁盘):

 mkdir /data/usb

 mount -o codepage=950,iocharset=utf8 UUID="35BC-6D6B" /data/usb  #codepage=950中文语系代码,iocharset=utf8字符编码集

 df /data/usb

重新挂载根目录与挂载不特定目录

整个目录树最重要的地方是根目录,它不能被卸载,而当进入单人维护模式时又只有只读状态时,可以通过重新挂载来解除只读状态:

 mount -o remount,rw,auto /  #将根目录(/)重新挂载,并加入参数rw与auto

虽然在前面的挂载原则中提到,单一文件不应该被挂载到不同的目录上,但有些时候可能有需要多个目录指向同一个资源,但由于又无法使用符号连接时,也可以使用挂载的方式将一个目录挂载到另一个目录上,挂载会让他们指向同一个inode:

 mount --bind /var /data/var  #--bind可以实现在其他地方重新挂载子目录,该选项可以简写为-B

卸载文件系统的 umount 命令:

 umount -a [-nrv] [-t vfstype]  #vfstype:文件系统类型的意思

 umount [-nrv] device | dir [...]  #device:设备文件名;dir:目录(挂载点)

umount的选项解析:

-a:卸载所有再/etc/mtab文件中描述的文件系统;
-t:卸载指定类型的文件系统;
-f:强制卸载;
-n:在卸载后不讲相应的信息写入/etc/mtab文件中;
-r:如果卸载失败,试图以只读的方式进行重新挂载;
-l:立即卸载文件系统,听说比f还强,但在man文档中没有找到该选项。

实现文件系统卸载的步骤:

 mount  #执行一个空的mount命令,可以将所有文件系统的挂载信息打印出来(打印的内容会有点多)

 umount /data/cdrom  #除了使用挂载点(目录)来卸载,也可以使用设备文件名实现卸载。

需要注意的是如果设备有多个挂载,又只想卸载部分挂载点的挂载,就不要使用设备文件名来实现卸载,那样会将所有挂载点都卸载掉;

3.3.4磁盘/文件系统参数自定义

从开始学习Linux开始就一直被一个概念所围绕,就是一切皆文件。比如磁盘文件/dev/sda3这个文件就是一个存储设备文件,也是块文件;像鼠标、键盘就是输入设备文件,也是字符文件,还有用来表示传输管道的FIFO文件。

那么如何创建一个磁盘文件,如何将磁盘文件与真正的硬件连接起来呢?下面通过ll命令来查看一下/dev/sda*这个磁盘文件:

ll /dev/sda*
brw-rw----. 1 root disk 8, 0 6月  15 01:55 /dev/sda
brw-rw----. 1 root disk 8, 1 6月  15 01:55 /dev/sda1
brw-rw----. 1 root disk 8, 2 6月  15 01:55 /dev/sda2
brw-rw----. 1 root disk 8, 3 6月  15 04:16 /dev/sda3
brw-rw----. 1 root disk 8, 4 6月  15 01:55 /dev/sda4
brw-rw----. 1 root disk 8, 5 6月  15 01:55 /dev/sda5

首先我们直到可以肯定的是创建一个设备文件,其设备类型是存储设备文件,然后是建立这个文件与设备的连接,设备有一个设备代码(major)和次要代码(minor)来让系统实现文件与硬件真正的联系,在上面ll打印的信息中第五列和第六列分别就是设备代码(major)和次要代码(minor),关于设备的代码可以参考内核官网的连接,在Linux2.6版本以后都能够自动产生设备文件,但某些特殊情况下还是可能需要手动创建,创建特殊文件的命令就是mknod:

创建特殊文件的 mknod 命令:

 mknod [-mZ] name  {bc} major minor  #用于创建存储设备文件或输入设备文件,major、minor前面介绍过了,就是设备代码和次要代码

 mknod [-mZ] name {p}  #用于创建FIFO文件

mknod命令的选项与参数:

-m:用于设置文件的权限模式,类似于chmod命令;
-Z:将目标文件 SELinux 安全上下文设置为默认类型(GNU标准选项);
name:要创建的文件名称
b、c、p分别表示不同的设备类型,即存储设备(块文件)、自读设备(字符文件)、FIFO

根据mknod的语法,如果手动的创建/dev/sda3的设备文件的命令就是:

mknod /dev/sda3 b 8 3

虽然在当下的Linux版本中创建特殊文件的可能性不大,但在特殊情况下将设备文件改变到特定目录下就需要手动创建了。除了创建特殊的设备文件以外,可能还想手动设置文件系统的UUID与Label name,修改xfs文件系统使用xfs_admin、ext文件系统使用tune2fs:

修改xfs文件系统的UUID与Label name的 xfs_admin 命令:

 xfs_admin [-lu] [-L label] [-U uuid] 设备名称

xfs_admin的选项与参数解析:

-l:列出这个设备的label name;
-u:了出这个设备的UUID;
-L:设置这个设备的Label name;
-U:设置这个设备的UUID;

修改ext文件系统的UUID与Label name的 tune2fs 命令:

 tune2fs [-l] [-L label] [-U uuid] 设备名称

tune2fs与xfs_admin的语法差不多,只是tune2fs的-l选项打印的内容有一些差别,它跟dumpe2fs -h的功能类似,具体的差别测试一下就知道了,这两个命令都非常简单,就不写示例了。

3.3.5设置启动挂载

为什么要设置启动挂载呢?还记得在3.3.3中挂载磁盘设备/dev/sda3文件系统到/data/xfs上吗?如果这个挂载没有被卸载的话你可以将当前的测试及其重启,然后再来查看挂载点/data/xfs上的挂载,不出意外的话重启之后这个挂载就没了,这就是没有设置启动挂载的原因。

启动挂载就是在系统启动时,自动的去根据配置文件将文件系统自动挂载到挂载点上。这个配置文件就是/etc/fstab,可以通过cat来查看这个配置文件的内容:

/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=a1d9fc31-73a0-491d-bba7-c114bc54dbd6 /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0

/etc/fstab配置文件内容结构是:

[设备名/UUID/LABL NAME] [挂载点] [文件系统] [文件系统参数] [dump] [fsck]

前面三栏都很容易通过字面意思理解,唯一需要多解释一下的就是第一栏三个数据选填一个即可;

第四栏:文件系统参数就是mount命令-o选项的参数;

第五栏:dump是用作备份的命令,现在一般都不用这个自带的备份方案,所以这里输入0表示不启用备份;

第六栏:fsck表示是否检验扇区,早期启动流程中会有一段时间去检查本机的文件系统,这个阶段主要是fsck去完成,现在xfs文件系统没有办法适用,因为xfs会自己进行检查不需要额外的操作,所以输入0不启用检查;

然后就是向配置文件中写入相应的配置信息,在配置文件中手动写入配置信息,这可能会因为配置数据错误导致无法启动成功,那就只能进入单人维护模式,然后使用mount重新挂载根目录 mount -o remount,rw,auto / ,再修改配置文件。

手动配置启动加载配置文件:

 nano /etc/fstab  #在文件的最末尾写上这一段配置内容并保存:/dev/sda3 /data/xfs xfs    defaults 0 0

 mount -a  #使用配置文件的配置数据挂载文件系统(如果不了解-a选项的话回到3.3.3中查看相关信息)

 df  #查看文件系统的挂载信息

然后再重启当前主机,来测试启动后/dev/sda3会不会被自动挂载。

 reboot  #重启,在使用df命令查看当前系统上的文件系统依然挂载在/data/xfs上。

3.3.6特殊设备loop挂载

在前面的3.3.3中讲过将CD和DVD光盘挂载到目录上,在我的虚拟机上并没有实际连接机器的光盘,而是一个虚拟设备,实际上也就是一个模拟的大文件,既然是这样那真实的大文件可不可以挂载呢?

下面我用的是一个centos的镜像文件测试挂载:

 mkdir /data/centos_dvd  #创建挂载点(目录)

 mount -o loop /tmp/CentOS-6.5-x86_64-bin-DVD1.iso /data/centos_dvd  #将镜像文件作为特殊设备挂载到目录上

 df /data/centos_dvd  #查看挂载的信息

 文件系统         1K-块    已用  可用 已用% 挂载点
/dev/loop0     4363088 4363088     0  100% /data/centos_dvd

既然可以挂载DVD的镜像文件,那可不可以制作一个大文件,然后将这个文件格式化后挂载呢?在Linux中有一个dd命令,本身是用于压缩的转换拷贝,这里可以用这个命令来建立一个空文件,关于dd这个命令在下一篇博客中详细介绍:

 dd if=/dev/zero of=/srv/loopdev bs=1M count=512

创建这个空文件会打印这些信息:

记录了512+0 的读入
记录了512+0 的写出
536870912字节(537 MB)已复制,7.48761 秒,71.7 MB/秒

大概解释一下dd这个命令的参数含义:

if表示input file,输入文件,那个/dev/zero是会一直输出0的设备
of表示output file,将一堆零写入到后面的接收文件中/srv/loopdev
bs表示每个block大小,同等与文件系统中的block的意义;
count表示总共又多少个bs的意思,所以这个文件的容量是bs*count

然后将这个大型文件格式化创建xfs文件系统:

mkfs.xfs -f /srv/loopdev  #格式化loopdev并创建xfs文件系统
meta-data=/srv/loopdev           isize=512    agcount=4, agsize=32768 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0, sparse=0
data     =                       bsize=4096   blocks=131072, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=855, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

最后创建挂载点挂载这个特殊文件虚拟的设备:

 blkid /srv/loopdev  #查看文件系统信息:/srv/loopdev: UUID="85acf289-29a1-4757-9a8d-0d78f0d6a502" TYPE="xfs"

 mkdir /data/mnt  #创建挂载点(目录)

 mount -o loop UUID="85acf289-29a1-4757-9a8d-0d78f0d6a502" /data/mnt  #实现挂载

 df /data/mnt  #查看挂载的信息
文件系统        1K-块  已用   可用 已用% 挂载点
/dev/loop0     520868 26436 494432    6% /data/mnt

可能讲这么多loop特殊文件设备的挂载还不了解这个东西有什么用,试想一下,如果你当前将系统的硬盘资源全部挂载到根目录下了,这时候你有各种各样的文件和数据需要分类管理存储,你是不是会很烦恼?

那么现在有了loop这样的特殊文件用来当作磁盘分区使用,是不是就解决了这样的问题,然后关于大文件格式化的文件系统,还可以用来作为Linux上独立分割出的主机系统空间,就像VMware一样Linux上也有类似的应用Xen可以配合loop device的文件类型来进行根目录挂载,写着内容都后面有机会再详细说吧。

 四、内存交换分区、文件系统观察、GNU的parted分区操作

4.1内存交换区创建

内存交换区简单的理解就是在磁盘上划分一块区域出来,被当作内存使用,分区后内存交换区的格式化使用的是 mkswap 命令实现及启动(挂载)使用 swapon 命令,其他的与文件系统就没什么区别了,然后就是取消(卸载)使用 swapoff 命令,有了前面loop特殊文件的挂载实践肯定能想的到内存交换区也可以使用文件创建,不过这里还是先介绍使用物理分区创建:

 lsblk -p  #查看当前系统上所有磁盘列表,根据磁盘容量信息找到有满足安装交换区容量空间的剩余磁盘,我测试的设备上/dev/sda的扩展分区还有足够的容量

 parted /dev/sda print   #查看磁盘的分区表格式,我这里是MBR格式,所以后面的分区操作要使用fdisk

 fdisk /dev/sda  #执行分区操作(详细参考3.2.2),这里我测试了分配了16G的容量

 partprobe -s  #将磁盘分区操作写入磁盘

 lsblk -p  #查看磁盘列表信息(确定磁盘分区操作已经成功写入磁盘)

 mkswap /dev/sda6  #格式化磁盘分区为swap类型

 blkid /dev/sda6  #查看文件系统信息

 free  #查看当前内存使用情况,此时/dev/sda6还没有被添加进去(注意free那一列用下划线标注出来的数据)
              total        used        free      shared  buff/cache   available
Mem:         995704      631232       81904       15160      282568      203220
Swap:       2097148      149504     1947644

 swapon /dev/sda6  #启用这个内存设备

 free  #再查看内存使用情况,发现启用/dev/sda6这个内存设备后free那一列数据增长了很多
              total        used        free      shared  buff/cache   available
Mem:         995704      643876       71308       15164      280520      190624
Swap:      18874360      149504    18724856

 nano /etc/fstab  #跟之前的磁盘文件系统挂载一样,内存设备也需要设置启动挂载,不然系统重启后不会自动挂载

 添加到启动挂载配置文件中的内存设备挂载配置数据: /dev/sda6 swap swap defaults 0 0

 swapon -a  #使启动挂载配置文件/etc/fstab中的内存设备挂载数据生效。

内存设备的挂载挂载点和文件系统两个参数都是swap,其他的与挂载文件系统挂载没有什么区别。接下来看基于文件创建内存交换区的实现示例:

 dd if=/dev/zero of=/data/swap bs=1M count=128  #创建文件

 mkswap /data/swap  #格式化创建swap内存设备

 swapon /data/swap  #启动内存设备

 nano /etc/fstab  #给启动挂载配置文件添加挂载数据(需要注意的是挂载文件内存交换区必须使用文件名,不能使用UUID,否则启动挂载找不到设备):/data/swap swap swap defaults 0 0

 swapon -a  #使启动挂载配置文件/etc/fstab中的内存设备挂载数据生效。

4.2文件系统观察

在前面的文件系统解析中就提到过关于磁盘空间浪费的问题,在此之前是通过假设的方式了解了小文件为什么会造成磁盘空间浪费,这里就磁盘空间浪费这个问题需要获得准确的实证数据,那就是ll命令查看文件属性信息就可以获得判断磁盘浪费空间得准确数据:

ll -sh
总用量 8.0K
4.0K -rw-------. 1 root root 2.1K 6月  13 00:56 anaconda-ks.cfg
4.0K -rw-r--r--. 1 root root 2.2K 6月  13 00:58 initial-setup-ks.cfg

从上面打印的数据来看,第一行有当前查询的文件占用容量的总量,然后具体的文件信息第一列是文件实际占用的磁盘容量,第六列是文件数据的实际容量,可以看到实际数据比实际占用磁盘的容量少很多,这就是磁盘的空间浪费问题,这些问题以后再在相关的博客中详细讨论。

4.3GNU的parted分区操作

还记得在之前的磁盘分区操作中使用parted查看磁盘的分区格式吗?没错就是这个命令,实际上这是一个跨MBR和GPT格式的磁盘分区程序命令,所以采用parted来管理磁盘分区会要方便很多,特别是当你要面对多台不同配置的设备时。下面先来看看parted的语法、选项及子命令的解析:

 parted [options] [device [command [options...]...]]

关于parted命令的选项解析:

-l:列出所有块设备上的分区布局;
-m:显示机器可解析输出;
-s:从不提示用户干预;
-a:为新创建的分区设置对齐类型:
  none:使用磁盘允许的最小对齐类型;
  cylinder:将分区对齐到柱面;
  minimal:使用磁盘拓扑信息给出的最小对齐;
  optimal:使用磁盘拓扑信息给出的最佳对齐

关于parted的子命令解析:

 align-check type partition:检查分区是否满足对齐类型,type表示对齐类型必须为"minimal"或"optimal",partition表示分区;

mklabel label-type:创建一个新的标签类型的分区表,比如:aix,amiga、bsd、dvh、loop等;

mkpart [part-type|part-label] [fs-type] start end:创建分区并可以指定一些设备类型和文件系统,start表示起始的位置,end表示结束的位置;

name partition name:设置分区名称;

print:显示分区表;

quit:退出;

rescue start end:将位于某处丢失的分区将它作为一个条目添加到分区表;

resizepart partition end:改变分区的结束位置,这个操作不会修改分区中存在的任何文件系统;

rm partition:删除分区;

select device:选择设备作为当前要编辑的设备,通常是Linux硬盘设备,但也可以分区、软件raid设备、LVM逻辑卷;

set partition flag state:将分区标志更改为指定的状态,支持的标签"boot",  "root", "swap",  "hidden"等,详细可以参考man文档。还可以通过state设置状态是“on”启动还是“off”关闭;

unit unit:设置位置或大小的指定单位,比如"s"秒、“B”字节、“%”比例的设备大小等,详细参考man文档;

toggle partition flag:切换分区标志;

在这些子命令中有三个常用的子命令和一个特别的命令:

新增分区:mkpart [primary|logical|Extended] [ext4|vfat|xfs] 开始 结束
显示分区:print
删除分区:rm [partition]  #示例(6是磁盘对应的分区列表中的编号):parted /dev/sda rm 6  #注意删除以后需要更新文件系统配置文件,不然不会真正的写入到磁盘,更新命令:partprobe -s
修改磁盘分区的格式:mklabel [gpt|mbr]  #千万别在/dev/vda使用这个子命令测试,无法恢复,我是用一个新的虚拟磁盘测试的,测试命令:parted /dev/sdb mklabel gpt  
                      #但是需要注意的是如果要重新改回mbr格式它的label-type不是mbr,而是msdos,所以上命令应该是这样:parted /dev/sdb mklabel msdos

下面演示一个mkpart新增分区操作:

parted /dev/sda print    #查看当前磁盘的容量情况
Model: VMware, VMware Virtual S (scsi)
Disk /dev/sda: 129GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags: 
Number  Start   End     Size    Type      File system  标志
 1      1049kB  1075MB  1074MB  primary   xfs          启动
 2      1075MB  21.5GB  20.4GB  primary                lvm
 3      21.5GB  42.9GB  21.5GB  primary   xfs
 4      42.9GB  129GB   85.9GB  extended
 5      43.0GB  64.4GB  21.5GB  logical

parted /dev/sda mkpart logical xfs 64.4G 70G    #创建分区并格式化为xfs文件系统(注意这里我是MBR格式主分区表和扩展分区都被占用了,所以只能用逻辑分区logical)
partprobe -s    #创建完将其强制写入磁盘(到这里就完成了分区和格式化)
lsblk -p    #查看磁盘列表

使用parted相比fdisk和gdisk就要方便得多,而且MBR和GPT格式都兼容。

 

posted @ 2022-06-17 10:57  他乡踏雪  阅读(701)  评论(0编辑  收藏  举报