集群与分布式文件系统及Linux内核文件系统开发详解
1. 集群文件系统概述
随着集群文件系统的日益普及,越来越多的应用环境从中受益。新的应用开始利用集群中的多个节点,以实现比一些基于对称多处理 (SMP) 环境更高的可扩展性。除了 VERITAS SanPoint Foundation Suite 之外,近年来还出现了许多不同的集群文件系统。
2. 其他常见集群文件系统
-
SGI 集群文件系统 (CXFS)
- 基本信息 :由 Silicon Graphics Incorporated (SGI) 提供,基于对 SAN 存储的共享访问,允许多个服务器呈现一个集群文件系统。它构建在 SGI XFS 文件系统和 XVM 卷管理器之上。
- 工作机制 :提供元数据服务器,所有元数据操作都必须通过该服务器处理。对于数据 I/O,有权访问存储的客户端可以直接访问数据。采用基于令牌的方案来控制对文件各部分的访问,令牌还允许客户端缓存文件的各个部分。如果客户端需要更改文件的任何部分,必须通知元数据服务器,然后由服务器执行操作。
-
Linux/Sistina 全局文件系统 (GFS)
- 发展历程 :该项目于 1995 年由明尼苏达大学发起,最初旨在对通过光纤通道连接的存储上的大型科学数据集进行后处理。由于无法更好地将 GFS 集成到最初开发它的 SGI IRIX 内核中,于是开始将其移植到 Linux。
- 核心特点 :基于日志的文件系统,是一个完全对称的集群文件系统,集群中的任何节点都可以执行事务。每个节点都有自己的意图日志,如果某个节点崩溃,集群中的其他节点会重新播放该日志。
-
Sun Cluster
- 整体方案 :Sun 提供的集群解决方案,包括一个分层的集群文件系统,最多可支持 8 个节点。核心是资源组管理器,用于管理一组资源(相互依赖的应用程序)。
- 文件系统特点 :Sun 全局文件系统是一个分层文件系统,可以运行在大多数本地文件系统之上。引入了两个新的 vnode 操作以提高全局文件系统的性能。该全局文件系统提供一个类似 NFS 的服务器,通过一个镜像主服务器的辅助服务器进行通信。当主服务器发生更新时,操作会在辅助服务器上进行检查点记录。如果主服务器发生故障,任何未完成的操作都会回滚。与其他一些集群文件系统解决方案不同,所有 I/O 都通过单个服务器进行。
-
Compaq/HP True64 Cluster
- 集群支持 :Digital(现在是 Compaq 的一部分)多年来一直在生产集群。Compaq 提供了一个名为 TruCluster Server 的集群栈,最多可支持 8 个节点。
- 文件系统结构 :与 VERITAS 集群文件系统不同,在 VERITAS 中文件系统的本地和集群组件位于同一代码库中,而 Compaq 的解决方案提供了一个分层的集群文件系统,可以位于任何底层本地文件系统之上。虽然可以从集群中的任何节点读取文件,但只有当本地文件系统是 AdvFS(高级文件系统)时,才能从任何节点写入文件。
3. 集群与分布式文件系统发展总结
在 UNIX 的历史中,人们一直在尝试在计算机之间共享文件。早期使用简单的 UNIX 命令,如 uucp。随着局域网的出现和计算机的广泛普及,分布式文件系统开始涌现。由于其简单性和可移植性的目标,NFS 成为 UNIX 系统中共享文件系统的事实上的标准。随着多台机器之间共享数据存储的出现,需要提供统一的存储视图,从而催生了集群文件系统和卷管理。近年来,出现了许多商业和开源的集群文件系统。分布式文件系统和集群文件系统解决的是不同的问题,因此它们之间没有太大的冲突。相反,集群文件系统可以很容易地导出供 NFS 客户端使用。
4. Linux 内核文件系统开发 - uxfs 简介
为了让读者更好地理解文件系统在 Linux 内核中的工作原理,这里介绍一个非常简单但功能完整的文件系统 uxfs。它提供了足够的接口和功能,允许创建层次化树结构、创建常规文件以及对常规文件进行读写操作。同时,它还有 mkfs 命令和简单的 fsdb 命令。不过,该文件系统存在一些缺陷,读者可以通过后续的练习来修复这些缺陷并添加新功能。
5. uxfs 文件系统设计要点
| 设计要点 | 详细信息 |
|---|---|
| 块大小 | 仅使用 512 字节的块,由 ux_fs.h 头文件中的 UX_BSIZE 常量定义。 |
| 块数量 | 文件系统中有固定数量的块,除了超级块和索引节点的空间外,有 470 个数据块,由 UX_MAXBLOCKS 常量定义。 |
| 索引节点数量 | 只有 32 个索引节点 (UX_MAXFILES)。索引节点 0 和 1 保留,索引节点 2 用于根目录,索引节点 3 用于 lost+found 目录,因此有 28 个索引节点可供用户文件和目录使用。 |
| 超级块存储 | 超级块存储在块 0 中,占用一个块。超级块内部有两个数组,分别记录索引节点和数据块是否正在使用,这使得文件系统源代码非常易于阅读,因为无需操作位图。超级块还包含记录空闲索引节点和数据块数量的字段。 |
| 索引节点存储 | 每个数据块对应一个索引节点。第一个索引节点存储在块 8 中。由于索引节点 0 和 1 未使用,根目录索引节点存储在块 10 中,lost+found 目录存储在块 11 中。其余索引节点存储在块 12 到 39 中。 |
| 数据块存储 | 第一个数据块存储在块 33 中。创建文件系统时,块 50 用于存储根目录的目录项,块 51 用于存储 lost+found 目录的条目。 |
| 文件大小限制 | 每个索引节点只有 9 个直接数据块,这将文件大小限制为 (9 * 512) = 4608 字节。 |
| 目录项大小 | 目录项大小固定,存储一个索引节点号和一个 28 字节的文件名,每个目录项大小为 32 字节。 |
6. 内核接口支持
设计文件系统时,需要确定要支持的内核接口。除了读写常规文件以及创建和删除目录外,还需要决定是否支持硬链接、符号链接、重命名等操作。文件系统必须导出四个向量,即 super_operations、file_operations、address_space_operations 和 inode_operations 向量。除了直接支持某些功能外,还可以调用一些通用函数来替代提供 uxfs 特定的函数,这大大简化了创建文件系统的工作。
7. 获得 Linux 内核源代码
可以从以下网站获取 Linux 内核源代码:www.kernel.org。该网站主页显示了最新版本的内核信息,例如在撰写本文时,最新稳定版本为 2.4.18(2002 - 07 - 10 00:40 UTC F V VI Changelog)。点击内核版本即可下载最新内核,点击 Changelog 可以查看最新内核的所有更新。所有自 Linux 诞生以来的内核都可以在该网站找到。要使用相关源代码,需要 2.4.18 内核,或者可以从 www.wiley.com/compbooks/pate 获取适用于最新 Linux 内核的 uxfs 源代码,该网站还包含如何为标准 Linux 发行版构建 uxfs 文件系统的说明。
下载内核源代码后,它是一个 gzipped tar 存档文件,需要进行解压缩和提取操作。内核源代码通常位于 /usr/src 下,但这不是必需的。例如,如果将 gzipped 存档文件放在 /usr/src 中,可以执行以下步骤:
# bunzip2 linux-2.4.18.tar.bz2
# mv linux linux.orig
# tar xvf linux-2.4.18.tar
# mv linux linux-2.4.18
# ln -s linux-2.4.18 linux
8. Linux 内核源代码树结构
graph LR;
arch(arch) --> Intel(Intel)
arch --> Sparc(Sparc)
arch --> MIPS(MIPS)
arch --> IBMs390(IBM s390)
CREDITS(CREDITS) --> 记录贡献者信息
Documentation(Documentation) --> filesystems(文件系统相关文档)
drivers(drivers) --> 所有Linux设备驱动
fs(fs) --> dcache(dcache)
fs --> buffer_cache(buffer cache)
fs --> inode_cache(inode cache)
fs --> file_system_call(file-related系统调用处理)
fs --> 各Linux文件系统目录
include(include) --> 架构特定头文件
include --> 通用头文件
include --> fs.h
include --> dcache.h
init(init) --> 内核启动函数
ipc(ipc) --> 系统V IPC相关代码
kdb(kdb) --> 内核调试器代码
kernel(kernel) --> 核心内核例程
lib(lib) --> 内核中的标准C库函数对应代码
MAINTAINERS(MAINTAINERS) --> 记录内核各部分负责人
mm(mm) --> 内存管理代码
net(net) --> 网络协议代码
- arch :包含 Linux 支持的不同机器架构的目录,如 Intel、Sparc、MIPS 和 IBM s390。
- CREDITS :列出了内核的主要贡献者及其专业领域或贡献信息。
- Documentation :包含大量与内核源代码一起分发的文档,其中 filesystems 目录包含一些不同 Linux 文件系统的信息以及通用的文件系统相关信息。
- drivers :包含所有 Linux 设备驱动程序。
- fs :对于对文件系统感兴趣的人来说是最相关的目录,与 mm 目录一起包含了许多页面缓存/数据 I/O 管理代码。fs 目录中的文件实现了 dcache、缓冲区缓存、索引节点缓存和文件相关的系统调用处理。此外,fs 目录中还有每个 Linux 文件系统的子目录,其中包含文件系统的源代码。
- include :可以访问所有内核头文件,包含架构特定的头文件以及所有架构通用的头文件。通用头文件可以在 linux 子目录中找到,fs.h 头文件对文件系统开发者尤为重要,dcache.h 头文件定义了 Linux dcache 使用的结构。
- init :包含在内核启动期间执行的函数。
- ipc :包含适用于 System V IPC(进程间通信)的源代码,包括信号量、共享内存和消息队列。
- kdb :如果安装了 kdb 补丁,该目录包含内核调试器的源代码。需要注意的是,kdb 补丁还会更改内核中的其他文件。
- kernel :包含核心内核例程,如进程管理、系统调用处理、模块管理等。
- lib :内核中一些标准 C 库函数的对应源代码可以在该目录中找到。
- MAINTAINERS :列出了负责内核各个部分的人员。
- mm :包含所有不特定于某个架构的内存管理代码,Linux 页面缓存管理例程可以在该目录中找到。
- net :存储了所有网络协议(如 TCP、UDP、IP 等)的代码。
对于想要学习文件系统的读者来说,include、fs 和 mm 目录是可以找到大多数与文件系统相关结构和例程的地方。此外,drivers/block 目录中也有一些有趣的文件,适合那些想要更详细了解文件系统/驱动程序接口的人。
9. 内核配置
在构建内核之前,必须确定内核的配置。因为内核源代码树中有许多组件并非是构建内核所必需的,例如有众多不同的 SCSI 适配器设备驱动程序,如果不需要 SCSI 访问,将其构建到内核中就是不必要的。所以需要明确自己的硬件配置,进而确定所需的内核组件。
定义内核配置有几种不同的方法,除了参考下面的说明,还可以查阅 Linux 内核 HOWTO,该文档在互联网上有多个副本,可在以下网站找到:www.tldp.org/HOWTO/Kernel - HOWTO.html 。
以下是一些具体的配置方法:
-
参考已安装内核的配置文件
:在安装 Linux 操作系统时安装内核源代码,这样会有一个已安装内核的配置文件可供参考。可以将已安装内核源代码树中的配置文件复制到新内核源代码树中,例如:
# cp /usr/src/linux - 2.4.18 - 3/.config /usr/src/linux - 2.4.18/.config
不过要注意,如果新安装的内核与已安装内核的配置有很大差异,某些选项可能可用也可能不可用,但这种方法在大多数情况下是可行的。
-
使用
make menuconfig
命令
:可以分别对已安装内核和新内核源代码运行该命令。例如,对于 Red Hat 7.3,对已安装内核执行:
# cd /usr/src/linux - 2.4.18 - 3
# make menuconfig
对新内核执行:
# cd /usr/src/linux - 2.4.18
# make menuconfig
将两个窗口并排显示,通过浏览当前内核的配置,就能轻松确定新内核需要选择哪些组件。另一种方法是充分了解自己的硬件类型。在并排比较配置时,为新内核选择当前内核中已选择的所有组件是比较稳妥的做法。
在
make menuconfig
界面中,项目如果有星号表示已选中,可加载的内核模块用字母 “M” 表示。屏幕顶部会有操作说明,按 Enter 键可展开菜单到下一级,按 Escape 键可返回上一级。完成配置更改后,一系列的 Escape 键操作会提示是否保存并退出。注意不需要保存当前内核的配置,特别是在不小心做了更改的情况下。保存配置并退出程序后,会出现以下消息:
Saving your kernel configuration...
*** End of Linux kernel configuration.
*** Check the top - level Makefile for additional configuration.
*** Next, you must run ’make dep’
按照提示执行以下命令:
# make dep
# make clean
make dep
会根据内核配置过程中选择的选项集构建所有必要的内核依赖项,
make clean
则是确保构建环境干净,避免后续内核编译时拾取与所选配置不匹配的预编译文件。
10. 内核编译
完成内核配置后,接下来就是编译内核,这是最耗时的一步。可以通过以下命令实现:
# make
编译完成后,还需要安装新构建的内核。
11. 内核安装
内核安装涉及到引导加载程序的配置,常见的引导加载程序有 LILO 和 GRUB,下面分别介绍它们的配置方法。
11.1 LILO 配置
如果使用 LILO 作为引导加载程序,需要编辑
/etc/lilo.conf
文件,添加新内核的相关信息。以下是一个简单的示例:
image = /boot/vmlinuz - 2.4.18
label = linux - 2.4.18
root = /dev/hda1
read - only
编辑完成后,运行以下命令更新 LILO:
# lilo
11.2 GRUB 配置
如果使用 GRUB 作为引导加载程序,需要编辑
/boot/grub/grub.conf
文件。以下是一个示例:
title Linux 2.4.18
root (hd0,0)
kernel /boot/vmlinuz - 2.4.18 ro root = /dev/hda1
initrd /boot/initrd - 2.4.18.img
编辑完成后,保存文件即可。
12. uxfs 文件系统的使用与调试
在完成内核的编译和安装后,就可以使用 uxfs 文件系统了。以下是使用和调试 uxfs 文件系统的一些步骤:
12.1 编译和加载 uxfs 模块
可以按照以下步骤编译和加载 uxfs 模块:
1. 确保已经下载并配置好所需的内核源代码。
2. 进入 uxfs 源代码所在目录。
3. 编译 uxfs 模块:
# make
- 加载 uxfs 模块:
# insmod uxfs.ko
12.2 创建 uxfs 文件系统
使用
mkfs
命令创建 uxfs 文件系统:
# mkfs.uxfs /dev/sdb1
12.3 挂载 uxfs 文件系统
将创建好的 uxfs 文件系统挂载到指定目录:
# mount -t uxfs /dev/sdb1 /mnt/uxfs
12.4 调试 uxfs 文件系统
可以使用
printk()
语句以及 kdb 和 gdb 调试器来调试和分析内核和文件系统的流程。例如,在代码中添加
printk()
语句输出调试信息:
#include <linux/kernel.h>
void some_function() {
printk(KERN_INFO "This is a debug message from uxfs.\n");
}
13. uxfs 文件系统总结
uxfs 文件系统虽然简单,但为我们提供了一个很好的学习 Linux 内核文件系统工作原理的示例。它的设计注重简单性,只包含了实现基本功能所必需的代码。通过学习 uxfs 文件系统,我们可以了解到文件系统在 Linux 内核中的基本工作流程,包括超级块、索引节点、数据块的管理,以及文件的创建、读写等操作。同时,通过对 uxfs 文件系统的实验和改进,我们可以进一步加深对文件系统的理解,掌握文件系统开发的基本技能。
以下是 uxfs 文件系统的主要特点总结:
| 特点 | 描述 |
| ---- | ---- |
| 简单性 | 只包含必要的代码,易于理解和学习。 |
| 功能完整性 | 支持层次化树结构、常规文件的创建、读写操作。 |
| 可扩展性 | 存在一些缺陷,可通过练习进行修复和添加新功能。 |
通过对集群文件系统和 uxfs 文件系统的学习,我们可以看到文件系统技术的发展和演变,以及如何在 Linux 内核中实现和管理文件系统。无论是集群文件系统还是简单的 uxfs 文件系统,都在不同的场景中发挥着重要的作用。
超级会员免费看
2776

被折叠的 条评论
为什么被折叠?



