使用 Amd Automounter

作者:Erez Zadok

如今,管理员管理着拥有众多网络文件系统 (NFS) 文件服务器和客户端的大型站点。用户希望能够登录到任何主机,并从任何远程服务器访问相同的文件。为所有用户提供此访问权限的简单方法是在每个客户端上手动挂载所有文件服务器。这不仅难以管理,而且任何无法访问的服务器都可能导致所有客户端挂起。此外,用户必须知道使用什么名称来访问来自特定服务器的文件。

这些问题的解决方案是自动挂载器。自动挂载器配置有所有文件服务器的知识,因此管理员只需在一个地方维护自动挂载器的配置即可。此外,当用户首次尝试访问通向该服务器的路径名时,自动挂载器会按需提供对远程文件服务器的访问;这确保只有正在使用和可访问的服务器才会被挂载到客户端上,从而最大限度地减少挂起的可能性。最后,自动挂载器为资源提供统一的命名空间。例如,路径名 /src/kernel 可以隐藏这些文件的实际位置是 server1:/n/raid/l/ksrc/v2.4/21preX 这一事实。

大多数商业供应商和 Linux 发行版都包含自动挂载器。然而,此类自动挂载器通常仅在单个平台上工作,使用不兼容的配置或提供有限的功能集。Amd Automounter,也称为 Berkeley Automounter,在开发时考虑了可移植性和丰富的功能集。它在众多 UNIX 系统上以相同的方式运行,提供其他自动挂载器中功能的超集,并支持大量功能,即使对于要求最苛刻的管理员也是如此。如果您是异构 UNIX 站点的管理员,并且希望让您的生活更轻松,那么 Amd 是您的不二之选。

本文解释了 Amd 的工作原理,并提供了一组示例来演示 Amd 的功能。本文面向站点管理员和任何对文件系统有特殊癖好的人。我们假设您对 Linux、NFS 和文件系统有基本的了解。仅用几页篇幅来详细介绍 Amd Automounter 是不可能的;这需要整整一本书才能完成。尽管如此,我们的示例旨在从 Amd 更简单、更常见的用途开始,并逐渐增加复杂性。

Amd 的工作原理

Amd 是一个用户级守护程序,它附加到名为自动挂载点的目录。每当用户尝试访问该自动挂载目录时,Amd 都会收到来自内核的请求。然后,Amd 确保用户请求的实际资源可用,并响应内核的请求。最后,内核将适当的状态代码返回给用户,用户神奇地在请求的路径名中看到所需的文件。

让我们来看一个例子。假设 Amd 已启动并附加到目录 /src。用户运行ls -l /src/kernel。内核知道 Amd 守护程序是 /src 目录的有效文件服务器,因此内核挂起用户的 ls 进程,并向 Amd 发送消息,要求它解析自动挂载点 /src 中的名称 kernel。当 Amd 启动时,它会为每个自动挂载点加载自动挂载器映射。这些自动挂载器映射可以从纯文件、NIS/NIS+、LDAP、N/DBM 等读取。Amd 为 /src 加载的映射是键值对列表。键表示 Amd 应在自动挂载目录中提供的名称,值包含 Amd 解析对命名键的访问所需的信息。对于我们的示例,映射可能包含

kernel  type:=nfs;rhost:=server1;\
          rfs:=/n/raid/l/ksrc/v2.4/21preX

在本例中,键是kernel,它与其值之间用空格分隔。该值由三个变量赋值组成,用分号分隔。我们使用反斜杠作为多行继续字符。变量使用 := Pascal 风格的语法赋值。这里,type 变量表示映射条目描述了 NFS 挂载。rhost 变量给出远程 NFS 服务器的名称。最后,rfs 变量描述了该远程主机上导出的目录的路径名。

回到挂起的 ls 进程,当 Amd 收到来自内核的对名称 kernel 的查找请求时,Amd 会查询其映射并找到具有该名称的条目。Amd 从远程主机 server1 挂载 /n/raid/l/ksrc/v2.4/21preX 目录。然后,它将有关 NFS 挂载目录的类型和实际位置的足够信息返回给内核,以便内核恢复 ls 进程。ls 进程恢复列出目录 /src/kernel 的内容,而没有意识到 Amd 和内核之间发生的活动,更不用说 /src/kernel 的文件的实际位置了。

Amd 还会检查自动挂载条目上次使用的时间,并自动卸载未使用的条目。这确保系统仅挂载正在使用的条目。如果您想知道是否可以控制超时时间,是的,您可以。事实上,您可以控制数十个参数。现在您可能想知道是否需要花费数天时间来配置 Amd。不,您不需要;大多数参数都经过仔细调整,并具有适当的默认值。

Amd 启动配置文件

Amd 使用一个配置文件,通常存储在 /etc/amd.conf 中。此文件的语法类似于 smb.conf 配置文件。考虑

[global]
log_file = /var/log/amd
debug_options = all,noreaddir

[/net]
map_type = file
map_name = /etc/amd.net
mount_type = nfs

[/home]
map_type = nis
map_name = amd.users
mount_type = autofs

此 amd.conf 文件首先指定适用于所有自动挂载目录的全局选项。所有选项都是简单的键值对。第一个全局选项 (log_file) 指定 Amd 记录信息(例如错误和跟踪活动)的文件路径名。第二个全局选项 (debug_options) 请求打开除与目录读取操作关联的调试之外的所有详细调试。接下来,我们定义两个自动挂载目录。在这里,Amd 附加并管理目录 /net,其条目来自文件 /etc/amd.net。Amd 还管理一个 /home 自动挂载目录,其条目从站点的 NIS (YP) 服务器读取。

mount_type 参数需要一些背景解释。默认情况下,Amd 对内核表现为用户级 NFSv2/UDP 服务器。也就是说,当内核必须通知 Amd 用户已请求查找条目(例如,/src/kernel)时,内核会向 Amd 发送 RPC 消息,以与内核联系任何其他远程 NFS 服务器相同的方式编码 NFS_LOOKUP 请求。这里唯一的区别是 Amd 是用户级进程,而不是基于内核的 NFS 服务器,并且 Amd 在本地主机上运行,因此内核将其 NFS RPC 发送到 127.0.0.1。作为用户级 NFS 服务器,Amd 是可移植的,并且在每个 UNIX 主机上都以相同的方式工作。但是,用户级 NFS 服务器会产生额外的上下文切换和内核数据副本,从而降低性能。更糟糕的是,如果 Amd 进程意外死亡(这种情况永远不会发生,因为我们的代码 100% 没有错误),它可能会挂起主机上访问自动挂载目录的每个进程,有时需要重新启动系统才能清除。

十年前,Sun Microsystems 意识到了这些自动挂载器的缺陷,并设计了一个特殊的内核内自动挂载器帮助文件系统,称为 Autofs。Autofs 在内核中提供了自动挂载器所需的大部分关键功能,在内核中可以更可靠、更快速地完成工作。Autofs 通常与用户级自动挂载器协同工作,用户级自动挂载器的任务简化为映射查找和解析。从上面的 amd.conf 示例中可以看出,Amd 非常灵活,可以同时作为用户级 NFS 服务器和 Autofs 兼容的自动挂载器工作。您只需将 mount_type 参数设置为正确的值即可。那么为什么不一直使用 Autofs 呢?不幸的是,Autofs 并非在所有操作系统上都可用,并且在那些可用的系统(Linux、Solaris 和少数其他系统)上,它使用了行为不同的不兼容实现。出于这些原因,并非所有管理员都喜欢使用 Autofs。尽管如此,使用 Amd,您可以选择使用哪个。

用户主目录

在几乎每个大型站点中,用户主目录都分布在多个文件服务器上。当用户的主目录首先存在于 /u/staff/serv1/ezk 中,然后当安装新的文件服务器或迁移数据时,目录被移动到 /u/newraid3/ezk 时,用户会感到特别恼火。一种更好的方法是为所有主目录提供统一的命名约定,这样 /home/ezk 始终指向用户主目录的最新位置。管理员可以将用户的主目录迁移到新的、更大的文件服务器,只需更改 amd.users 映射中 ezk 条目的定义即可。以下是一个小型 amd.users 映射的示例,该映射从两台不同的服务器挂载三个用户的主目录

#comment: amd.home map
/defaults  type:=nfs
ezk  rhost:=serv1;rfs:=/staffdisk/ezk
joe  rhost:=raid3;rfs:=/newdisk/joe
dan  rhost:=raid3;rfs:=/newdisk/dan

此示例以一个名为 /defaults 的特殊条目开头,该条目定义映射中所有条目通用的值;在这里,此映射中的所有挂载都是 NFS 挂载。随后的三行指定用户名,以及要挂载的远程主机和分区,以解析用户的主目录。尽管每个用户的主目录的路径名(例如 /home/joe)可以长期保持不变,但 Joe 的主目录的实际远程主机和远程文件系统可能会经常更改,而不会给 Joe 带来不便。

与 Perl 一样,在 Amd 中有几种方法可以实现相同的目标,有些方法比其他方法更好。由于几个原因,上面的映射不是最优映射。因此,这里有一些优化 Amd 映射的技巧。首先,考虑当您访问 /home/dan 并且在主机 raid3 上运行时会发生什么:Amd 尝试从 raid3 作为 NFS 服务器执行 raid3(作为 NFS 客户端)的 NFS 挂载。这相当愚蠢,仅仅为了访问主机本地的路径名,就经历了整个网络堆栈和 NFS 协议的开销。因此,Amd 定义了一种不同的挂载类型,即链接类型(使用符号链接)。因此,Dan 的映射条目可以重写为

dan  -rhost:=raid3;rfs:=/newdisk/dan \
      host!=${rhost};type:=nfs \
      host==${rhost};type:=link

此修订后的映射条目引入了 Amd 映射的几个新功能。首先,反斜杠前面有空格。Amd 忽略反斜杠后的空格,但不忽略反斜杠前的空格;Dan 的映射条目实际上被分解为三个不同的空格分隔组件,称为位置。第一个位置以连字符开头,并定义映射条目本身的默认值,覆盖 /defaults 中的任何内容。第二个和第三个位置以选择器开头。Amd 映射选择器是动态变量,Amd 可以在运行时比较其值。正如您可能从所有自动挂载器的鼻祖那里期望的那样,Amd 支持数十个选择器。Amd 一次评估 Dan 的映射条目的一个位置,直到找到一个选择器评估为 true 的位置;然后 Amd 挂载给定的位置。按顺序,Amd 首先比较当前正在运行的主机名是否不等于 rhost 的预定义值。在除 raid3 之外的任何主机上,然后 Amd 执行 NFS 类型挂载。在 raid3 本身上,Amd 使用更快更简单的符号链接类型挂载。

amd.home 映射包含第二个效率低下之处:它从同一 NFS 服务器挂载 /newdisk/joe 和 /newdisk/dan,尽管它们很可能是同一物理导出的文件系统的子目录。这很慢并且浪费内核资源。一种更好的方法是使用相同的 rfs,但返回作为实际挂载点的子目录的路径名(sublink 会自动附加到返回的路径名)

/defaults  type:=nfs;sublink:=${key}
joe  rhost:=raid3;rfs:=/newdisk
dan  rhost:=raid3;rfs:=/newdisk
/net 映射

自动挂载器映射的常见用途是允许从任何主机挂载任何文件系统,通常称为网络映射。此映射条目提供了一种全面且统一的访问所有文件服务器的方式

/defaults  fs:=/a/${rhost}/root/${rfs}
*       rhost:=${key};type:=host;rfs:=/

这个简短的示例包含了很多内容。首先,我们将默认 fs 变量的值定义为唯一标识要挂载的远程 NFS 服务器和文件系统的路径名。我们可以这样做,因为 fs 变量定义了本地主机上 Amd 挂载远程主机文件系统的路径名。此路径名必须是唯一的,以避免冲突。

其次,实际映射条目的键(星号)是一个通配符条目,它匹配任何内容,并将键变量的值设置为在 /net 中查找的名称的值。此通配符键值成为远程主机名 (rhost)。接下来,我们指定类型为 host 的特殊 Amd 挂载条目,并将 rfs 变量设置为请求挂载来自该远程主机的所有导出的文件系统(从 / 开始)。Amd 中的主机挂载类型通过查询远程主机的 rpc.mountd 守护程序以获取所有导出的文件系统的列表来工作。然后,它依次挂载每个文件系统。例如,假设主机 foo 导出两个名为 /homes 和 /proj/X11 的文件系统。如果您chdir到 /net/foo,Amd 将 foo:/homes 挂载到 /a/foo/root/home 中,并将 foo:/proj/X11 挂载到 /a/foo/root/proj/X11 中。/net/foo 中的ls方便地显示了这两个挂载的目录。

统一所有映射

在拥有许多子组(有时对主组具有部分管理控制权)的大型站点中,通常存在这样一种情况,即您可以挂载的内容取决于您所在的位置。为了提高效率,您可能需要在将不同架构的二进制文件分发到不同的子网上时受到限制。使用一组集中的 Amd 映射,可以满足本地需求

/defaults  type:=link
lbin  in_network(eng);fs:=/local/${arch}/bin \
      in_network(10.0.1.0/24);fs:=/x/beta/bin

此映射使用 in_network 函数选择器。函数选择器根据当前系统条件和传递给这些函数的参数评估为 true 或 false。此选择器比较当前主机名是否是 eng 网络的一部分,eng 网络通常在 /etc/networks 中定义。如果是,则 Amd 将 arch 变量的值扩展为当前正在运行的架构。它还将 lbin 条目解析为 IA-32 系统上的 /local/i386/bin,SPARC 系统上的 /local/sparc/bin,依此类推。此映射中的下一个位置显示 in_network 选择器可以匹配网络/网络掩码对。事实上,此选择器不仅可以使用多种形式进行匹配,而且还可以匹配您的主机上运行的任何本地接口。此功能提供了优化多宿主主机上的网络路由的优势。

ISO-9660 镜像

许多人手头都备有 ISO-9660 CD-ROM 镜像,但访问其内容需要将其刻录到 CD-ROM 上,或者使用特殊的循环驱动器在 Linux 上挂载镜像。cdfs 挂载类型知道如何挂载 ISO-9660 CD。但是,如果您在 dev 参数中列出文件名并指定 loop 挂载选项,则 Amd 可以直接挂载这些 ISO 镜像文件。然后,您可以浏览它们,而无需从每个 ISO 镜像中复制文件。

/defaults  type:=cdfs;opts:=loop
shrike1  dev:=/iso/rh9/shrike-disc1.iso
shrike2  dev:=/iso/rh9/shrike-disc2.iso
shrike3  dev:=/iso/rh9/shrike-disc3.iso
自定义映射

每个有自尊的工具都应具有内置的可扩展机制,以适应意外情况。为了让 Amd 挂载给定的文件系统,它必须提前知道如何挂载它(阅读:您忠实地破解 C 源代码)。使用程序类型挂载,您可以定义自定义方法来挂载和卸载您的本地主机知道但 Amd 不知道的任何文件系统

r2  type:=program;dev:=/dev/sda1;\
      mount:="/sbin/dohans dohans ${dev} ${fs}";\
      unmount:="/sbin/undohans undohans ${fs}"

上面的示例将预定义的 dev 参数以及自动确定的 fs 参数传递给一个名为 dohans 的 shell 脚本,该脚本可以执行挂载 /dev/sda1 作为 ReiserFS 所需的任何操作。

结论

Amd 自动挂载器是一个功能强大的工具,具有许多功能来支持众多站点的需求。通过适当的维护,站点管理员可以为用户提供许多有用的功能,同时减少系统管理工作量。Amd 是 Am-utils 发行版的一部分,该发行版预装在大多数 Linux 发行版中。有关更多信息、最新源代码、访问邮件列表和在线文档,请访问 www.am-utils.org。祝您自动挂载愉快。

Erez Zadok (ezk@cs.stonybrook.edu) 是石溪大学计算机科学系的教员,从事文件系统和操作系统研究。Erez 是 Linux NFS 和自动挂载器管理(Sybex,2001 年)的作者,并且在过去十年中,一直是 Am-utils 的主要维护者。Ion Badulescu、Nick Williams 和 Rainer Orth 这三位共同维护者为维护 Am-utils 提供了极大的帮助。

加载 Disqus 评论