FreeBSD支持ZFS和UFS以外的各种文件系统。您需要能够通过使用光学介质、闪存驱动器等与其他主机进行互操作。此外,FreeBSD使用专用文件系统 devfs(5)
来管理设备节点。Jail用户可能需要进程文件系统 procfs(5)
。对于不需要重新启动的极快存储,您可以将系统RAM用作文件系统。您可以使用Unix风格的网络文件系统或Microsoft的通用Internet文件系统(Common Internet File System——CIFS)通过网络挂载文件系统。无论你多么努力地避免它,有时你都会被困在挂载ISO映像上。
使用其中任何一个都需要对挂载文件系统有更深入的了解。
我们在前面讨论UFS文件系统时看到了 mount(8)
,但您也将使用它将其他文件系统附加到目录树。mount(8)
命令假定任何本地分区都使用UFS。如果你尝试挂载非UFS文件系统,你会得到一个错误。
xxxxxxxxxx
# mount /dev/cd0 /media
mount: /dev/cd0: Invalid argument
设备节点 /dev/cd0 表示光盘驱动器。我在驱动器中放了一张CD只是为了这次测试,所以它应该可以工作。不过,尝试挂载它会出错。要挂载UFS文件系统,您需要设备节点和挂载点。挂载外部文件系统意味着使用 -t
添加文件系统类型。CD使用ISO 9660文件系统,FreeBSD称之为cd9660。在这里,我指定了在 /cdrom 上挂载该CD的文件系统:
xxxxxxxxxx
# mount -t cd9660 /dev/cd0 /media
我现在可以转到 /media 目录并查看内容。很简单,对吧?
许多文件系统都有自己的 mount(8)
命令的自定义变体。运行 apropos mount_
获取完整列表。是的,您需要后面的下划线;所有的 mount(8)
变体都将其用作分离器。您将找到mount_cd9660(8)
、 mount_msdosfs(8)
和 mount_nfs(8)
等。在没有此类命令的情况下,始终在文件系统上使用 mount -t
。
使用 -o
标志应用挂载选项。您需要查看每个 mount
命令的手册页,以了解文件系统支持哪些mount选项。用逗号分隔多个装载选项。在这里,我在设备节点 /dev/da1 上以只读方式挂载FAT32驱动器,将所有者和组分配给用户 bert :
xxxxxxxxxx
# mount -t msdosfs -o ro,-gbert,-ubert /dev/da1 /media
您可以使用 umount(8)
卸载任何已挂载的文件系统:
xxxxxxxxxx
# umount /media
umount(8)
命令不关心文件系统类型。它只是试图将磁盘分区与文件系统断开连接。然而,它确实关心是否有人在使用文件系统,并且即使有一个进程使用它,它也会拒绝卸载它。如果文件系统中有一个带shell提示符的空闲终端,umount(8)
将拒绝卸载文件系统。
如果您经常连接和断开文件系统,请研究 autofs(5)
以自动处理这些挂载。
以下是一些最常用的外部文件系统,以及对每个文件系统和相应mount命令的简要描述。
FreeBSD包括对FAT的广泛支持,DOS/Windows 9x文件分配表文件系统,通常用于可移动介质和一些双引导系统。此支持涵盖FAT12、FAT16和FAT32变体。但是,您可以使用非FAT文件系统格式化U盘驱动器,因此不要盲目假设所有拇指驱动器都使用FAT。由于目前拇指驱动器最常见的用途是在机器之间传输文件,因此大多数都是FAT32。挂载类型为 msdosfs
(mount -t msdosfs
)。
如果您处理大量FAT32磁盘,请研究 mtools
包,这是一组用于处理FAT文件系统的程序,比默认的FreeBSD工具提供了更大的灵活性。
ISO 9660是CD的标准文件系统,偶尔用于DVD。如果你有CD刻录机,FreeBSD支持读写CD。几乎你遇到的每张CD都是用ISO 9660格式化的。mount命令是 mount -t cd9660
。
位于 /usr/ports/sysutils/cdrtools 中的 cdrtoools
包包含许多用于处理CD映像的有用工具,包括从磁盘上的文件构建ISO映像的工具。
UDF(Universal Disk Format)——通用磁盘格式,是ISO 9660的替代品。您会在一些DVD和蓝光光盘上以及一些大于FAT32支持的32GB的拇指驱动器上找到UDF。随着可移动媒体容量的增加,您将看到越来越多的UDF文件系统。mount命令是 mount -t udf
。
标准的Linux文件系统——EXT2、EXT3和EXT4——支持许多与UFS相同的功能。FreeBSD可以安全地读写EXT2和EXT3文件系统,没有任何问题,但只能以只读方式挂载EXT4文件系统。
挂载Linux文件系统对于灾难恢复、双引导系统或系统迁移最有用。尽管名称如此,mount -t ext2fs
支持挂载所有版本的EXT。
Linux文件系统用户可能会发现 /usr/ports/sysutils/e2fsprogs 中的工具很有用。它们允许您进行 fsck(8)
和评估Linux文件系统等。
文件系统的权限取决于文件系统的功能和挂载它的人。FreeBSD试图支持与UFS或ZFS中没有太大区别的功能。
考虑Linux文件系统,EXT。EXT将权限存储在文件系统中,并让内核将它们映射到UID。由于EXT权限的行为与UFS权限非常相似,并且所有必要的权限信息都在文件系统中可用,FreeBSD尊重这些文件系统上的权限。然而,EXT不支持BSD文件标志,因此您无法将这些标志分配给EXT上的文件。
FAT没有权限系统。即使您在FreeBSD主机中挂载FAT32拇指驱动器,也无法对文件应用权限。
默认情况下,只有root可以挂载文件系统,root拥有所有非Unix文件系统。如果这不是您的偏好,您可以在挂载FAT32、ISO 9660或UDF文件系统时使用 -u
和 -g
标志来设置所有者的用户ID和组ID。例如,如果您正在为用户 xistence 安装FAT32 USB设备,并希望他能够编辑内容,请使用以下命令:
xxxxxxxxxx
# mount -t msdosfs -u xistence -g xistence /dev/da5 /mnt
用户 xistence 现在拥有设备上的文件。
您可能会厌倦为用户安装媒体,尤其是在拥有数十台机器的设施中。要让用户挂载文件系统,请将sysctl vfs.usermount
设置为 1
。然后,用户可以在他们拥有的任何装载点上装载他们有权访问的任何设备。虽然 xistence 无法将可移动设备安装在 /media 上,但他可以将其安装在 /home/xistence/media 上。
您必须能够管理可能通过数据中心门进入的任何可移动媒体。在这里,我们将讨论光盘和闪存驱动器。
我建议不要随意将可移动媒体插入生产服务器——至少是出于安全原因。谁知道那个供应商的USB设备上到底有什么?更糟糕的是,你可以订购故意损坏硬件的“USB杀手”设备。在一次性工作站上安装可疑设备,检查内容,然后将所需数据复制到FreeBSD机器上。这并不能保证是安全的,因为许多USB接口可以将数据注入到操作系统层下的硬件中,但它是最安全的。然而,对于某些应用程序来说,可移动媒体太容易了,当然,当它是我的个人USB设备时,规则也会改变。
使用该设备需要文件系统类型、设备节点和挂载点。
弄清楚可移动驱动器的文件系统可能需要一点试错。CD使用ISO 9660文件系统,而DVD和蓝光使用UDF或ISO 9660和UDF的组合。如有疑问,请先尝试CD9660。USB设备和软盘通常是FAT32。虽然曾经预计大型USB设备会使用UDF,但它们中的大多数仍然使用FAT32。在设备节点上运行 fstyp(8)
以帮助识别其上的文件系统,或在磁盘的设备节点上尝试 gpart show
。
每次插入可移动设备时,它们都可以有不同的设备节点。光盘驱动器更容易识别,因为大多数主机只有很少的光盘驱动器。如果你有一个光驱,它是 /dev/cd0 。USB设备显示为 /dev/da 的下一个可用单元。当您插入USB设备时,控制台和 /var/log/messages 中会显示一条消息,说明设备节点和类型,或者您可以检查新设备的 camcontrol devlist
。
FreeBSD为一般的可移动媒体挂载提供了 /media 挂载点。您可以根据需要创建其他挂载点——它们只是目录。对于各种短期挂载,FreeBSD提供了 /mnt 。
因此,要在 /media 上安装FAT32 USB设备 /dev/da0 ,请运行:
xxxxxxxxxx
# mount -t msdosfs /dev/da0 /media
偶尔,您会发现一个带有分区表的拇指驱动器。这些设备将要求您挂载 /dev/da0s1 或 /dev/da0p1 ,而不是 /dev/da0 。设备的格式决定了这一点,而不是FreeBSD中的任何内容。gpart show
命令可以帮助您找出设备上的哪些分区以及每个分区上的文件系统。
要断开可移动媒体与FreeBSD系统的连接,请先卸载文件系统。在卸载磁盘之前,光盘驱动器不会打开。您可以从USB闪存驱动器的端口中拔出它,但在挂载文件系统时这样做可能会损坏设备上的数据。像使用其他文件系统一样使用 umount(8)
:
xxxxxxxxxx
# umount /media
在许多光盘驱动器上,camcontrol eject
会打开驱动器托盘。
您可以使用可移动介质的条目更新 /etc/fstab ,使系统维护更容易一些。如果可移动文件系统在 /etc/fstab 中有一个条目,则可以在挂载时删除文件系统和设备名称。这意味着您不必记住确切的设备名称或文件系统来挂载设备。
在 /etc/fstab 中列出可移动媒体时,请确保包含 noauto
标志。否则,每当您没有可移动介质时,您的启动将在单用户模式下停止,因为缺少文件系统。
这是 /etc/fstab 中关于光盘驱动器的条目:
xxxxxxxxxx
/dev/cd0 /cdrom cd9660 ro,noauto 0 0
虽然我相信你已经记住了 /etc/fstab 中每一列的含义,但我们会提醒你,这个条目的意思是,“使用ISO 9660文件系统在 /cdrom 上挂载 /dev/cd0 。以只读方式挂载,并且在启动时不会自动挂载。”
这是一个类似的拇指驱动器条目。我使用 large
选项来支持大于128GB的文件系统,如mount_msdosfs(8)
中所述。
xxxxxxxxxx
➊/dev/da0 /media msdosfs rw,noauto,large 0 0
FreeBSD默认不提供这些,但我发现在我经常使用可移动媒体的系统上使用它们要容易得多。确认您的下一个可用da设备是 /dev/da0 ➊,因为尝试挂载已挂载的硬盘是行不通的。
拇指驱动器使用FAT32文件系统,但总是预格式化的。由于拇指驱动器的读写次数有限,与其便宜程度成正比,因此不要随意重新格式化。只有在拇指驱动器的文件系统损坏时才重新格式化。使用 newfs_msdos(8)
创建FAT32文件系统:
xxxxxxxxxx
# newfs_msdos /dev/da0
您将得到几行输出,并且获得一个新的文件系统。
FreeBSD将允许您使用CD 9660或UDF格式将一堆文件捆绑成适合刻录到CD、DVD或蓝光上的映像。您可以将任一映像刻录到磁盘上。FreeBSD本机支持创建ISO,但您需要 cdrtools
包中的程序来创建UDF。
在任何一种情况下,首先将所有要刻录的文件和目录放入一个目录中。映像将完全按照您的排列方式包含这些文件和目录。记住,光盘映像是只读的。您无法更新映像;您只能创建一个新映像,因此请确保您拥有所需的一切。本章稍后,您将学习使用 mdconfig(8)
挂载这些映像。
在这两个示例中,我们都是从 /home/xistence/cdfiles 中包含的文件创建映像。
使用 makefs(8)
创建一个ISO:
xxxxxxxxxx
# makefs ➊-t cd9660 ➋-o allow-deep-trees,rockridge ➌image.iso ➍source-files
首先使用 -t
➊指定要创建的文件系统类型——在本例中为CD 9660。-o
标志➋允许您指定特定于文件系统的选项。您可以从 makefs(8)
手册页中获得完整的选项列表,但此处显示的选项对于大多数图像来说已经足够了。然后,我们需要创建的图像的文件名➌和这些文件的源目录➍。
要将 /home/xistence/cdfiles 中的文件作为 bert.iso 创建映像,请运行:
xxxxxxxxxx
# makefs -t cd9660 -o allow-deep-trees,rockridge bert.iso /home/xistence/cdfiles
伯特现在可以浪费时间将ISO刻录到物理介质上。
创建UDF需要使用 cdrtools
包中的 mkisofs(1)
。使用 -o
指定目标映像文件。分别使用 -J
和 -R
启用Joliet和Rock Ridge扩展名。(我不打算逐一介绍它们的作用,但如果你想让你的ISO表现得像这个千年的磁盘,你就需要它们。)添加 -udf
和 -iso-level 3
标志。
xxxxxxxxxx
# mkisofs -R -J -udf -iso-level 3 -o bert.udf /home/xistence/cdfiles
现在,您有一个基于 /home/xistence/cdfiles
中内容的UDF映像。
无论您创建哪种格式,我都建议您在刻录物理磁盘之前挂载它并仔细检查您的工作。如果你幸运的话,你会记得你忘了在图片上包括的东西。
使用 cdrtools
包中的 cdrecord(1)
将ISO映像刻录到磁盘。将映像文件作为参数。
xxxxxxxxxx
# cdrecord bert.iso
根据驱动器速度和映像大小,这可能需要一段时间。
cdrecord(1)
程序默认使用 /dev/cd0 。如果您有其他光盘驱动器,请使用 -dev
标志提供备用设备名称。
xxxxxxxxxx
# cdrecord -dev=cd9 bert.iso
你现在有一个脆弱的塑料盘,在扔进垃圾填埋场之前,你会用两次。祝贺 你!
虽然您可以使用 cdrecord(1)
将UDF映像刻录到介质,但通常建议使用 dvd+rw
工具包中的 growisofs(1)
命令。你需要 -dvd compat
和 -Z
标志。然后,指定设备和图像文件。
xxxxxxxxxx
# growisofs -dvd-compat -Z /dev/burner=image.udf
假设我想将 bert.udf 刻录到 /dev/cd0 中的蓝光。
xxxxxxxxxx
# growisofs -dvd-compat -Z /dev/cd0=bert.udf
UDF文件可能很大。去泡点茶。最终,你会有一个刻录的磁盘。
USB拇指驱动器越来越多地取代了光盘,部分原因是它们的可重用性。FreeBSD支持使用 dd(1)
将磁盘映像写入拇指驱动器。
请务必确定哪个设备节点是您的拇指驱动器,哪个是您的系统硬盘驱动器。拇指驱动器显示为 /dev/da 设备,与许多硬盘驱动器完全一样。覆盖错误的硬盘驱动器很尴尬。
乍一看,dd(1)
命令看起来很混乱。
xxxxxxxxxx
# dd ➊if=inputfile ➋of=outputdevice ➌bs=1M ➍conv=sync
if=
参数➊给出了要复制的文件。of=
参数➋是要复制到的设备节点。bs=
标志➌给出了一次要复制的数量。如果没有这个,dd(1)
将以512字节为增量进行复制。conv=
参数➍给出了如何转换传入文件的 dd(1)
指令。在这种情况下,sync
命令告诉 dd(1)
同步传入和传出缓冲区的大小。要将 bertimage.udf 刻录到拇指驱动器 /dev/da9 ,我会运行:
xxxxxxxxxx
# dd if=bert.udf of=/dev/da9 bs=1m conv=sync
等一下,你会有一个成像的(imaged)拇指驱动器。dd(1)
的其他用法可能不需要 conv=
标志,但总是使用 bs
。
现在,让我们看看您可能会发现有用的其他一些文件系统。
除了将文件系统放在磁盘或分区上,FreeBSD还允许您从文件、纯RAM和两者的组合中创建分区。此功能最受欢迎的用途之一是用于 memory filesystems 或 memory disks 。在内存中读写文件比访问磁盘上的文件快得多,这使得内存支持的文件系统对某些应用程序来说是一个巨大的优化。然而,与内存中的其他内容一样,在系统关闭时,您会丢失内存磁盘的内容。
FreeBSD支持两种不同的内存支持磁盘:tmpfs(发音为“temp f s”)和 memory disks。虽然它们背后有相似的概念,但底层代码完全不同,它们扮演着不同的角色。对于长时间运行的系统上的内存支持的文件系统,使用 tmpfs(5)
。内存磁盘更灵活,但更适合短期使用或安装磁盘映像。
tmpfs(5)
中的 tmp 并不意味着“临时”。它的字面意思是 tmp ,就像 /tmp 一样。将tmpfs用于快速内存支持的 /tmp 和类似的文件系统。不过,不要在看到包含tmp的路径的任何地方部署tmpfs。虽然/tmp应该在每次启动时都被清除,但 /var/tmp 应该在重新启动后仍然存在。您可能会将tmpfs用于应用程序锁文件和其他临时数据,在这些数据中,大幅提高速度将提高应用程序性能。虽然tmpfs有着一段麻烦的历史,但从FreeBSD 10开始,它已被广泛部署并被认为已准备好投入生产。
通过挂载来创建tmpfs:
xxxxxxxxxx
# mount -t tmpfs tmpfs /tmp
如果您的系统将sysctl vfs.usermount
设置为 1
,则用户可以创建和挂载tmpfs文件系统。
tmpfs默认为系统可用RAM的大小加上可用交换空间。反复将文件复制到 /tmp 可能会耗尽系统内存。这太糟糕了。使用 size
选项为tmpfs设置最大大小。
xxxxxxxxxx
# mount -o size=1g -t tmpfs tmpfs /tmp
使用 uid
、gid
和 mode
选项控制tmpfs的所有权和权限。实际的 /tmp 目录需要具有全局可写性,并设置粘滞位,因此请务必使用选项 mode=1777
。
如果tmpfs是针对特定用户的,即使是只运行单个应用程序的无特权用户,也要为该用户分配tmpfs的所有权。
现在您可以设置最大大小和适当的权限,可以在启动时使用 /etc/fstab 自动创建tmpfs。
xxxxxxxxxx
tmpfs /tmp tmpfs rw,mode=1777,size=1G 0 0
对于更复杂的内存备份磁盘,请考虑传统的内存磁盘。
内存磁盘是一种临时存储设备。尽管有这个名字,但内存磁盘并不总是被视为磁盘的内存块。它可以是这样的设备,但也可能使用文件或交换空间或其他后备存储。无论如何,存储磁盘在系统关闭时都会消失。
内存磁盘有四种类型:malloc支持、swap支持、vnode支持和null。
tmpfs(5)
非常相似,使用大型malloc支持的磁盘是耗尽系统内存的好方法。Malloc支持的磁盘对于无交换嵌入式设备最有用。一旦你知道你想做什么,就使用 mdmfs(8)
来执行该操作。
mdmfs(8)
实用程序是几个程序的方便前端,例如 mdconfig(8)
和 newfs(8)
。它处理了配置设备和在这些设备上创建文件系统的繁琐工作,并使创建内存磁盘尽可能简单。您只需要知道要使用的磁盘的大小、内存磁盘的类型和装载点。
默认设置为 Swap-backed 内存磁盘。只需告诉 mdmfs(8)
磁盘的大小和装载点。在这里,我们在 /home/mwlucas/test 上创建了一个48MB的swap-backed内存磁盘:
xxxxxxxxxx
# mdmfs -t -s 48m md /home/mwlucas/test
-s
标志表示磁盘的大小。如果不带任何参数运行 mount(8)
,您将看到内存磁盘设备 /dev/md0 已装载到该目录上。
-t
标志启用TRIM,我们将在下一节“内存磁盘头痛(Memory Disk Headaches)”中讨论。
要创建和挂载 Malloc-backed的磁盘,请添加 -M
标志。
要挂载Vnode-backed内存磁盘,请使用 -F
标志和映像文件的路径。
xxxxxxxxxx
# mdmfs -F diskimage.file md /mnt
我们一直在这里使用的 md
条目意味着,“我不在乎我得到什么设备名称;只要给我下一个免费的名称。”如果你愿意,你也可以指定一个特定的设备名称。在这里,我声明我想要磁盘设备 /dev/md9 :
xxxxxxxxxx
# mdmfs -F diskimage.file md9 /mnt
传统的交换备份存储磁盘从未将用过的内存返回给系统。一旦你写入内存磁盘,内存就用完了。如果你需要一个更大的内存磁盘,你必须为它永久分配内存。这就是FreeBSD包含 tmpfs(5)
的原因之一。
但是,如果内存磁盘上的文件系统支持TRIM,FreeBSD现在会将未使用的内存返回给系统。TRIM不是一个缩写,而是一种告诉磁盘哪些扇区不再使用的协议。UFS是默认的内存磁盘格式,支持TRIM。使用 -t
标志在mdmfs中启用TRIM。不过,如果您在内存磁盘上使用不同的文件系统,请确保它是严格临时的。
要从存储磁盘中释放内存,请关闭存储磁盘。
要删除内存磁盘,您必须卸载分区并销毁磁盘设备。销毁磁盘设备可以释放设备使用的内存,这在系统负载繁重时非常有用。要查找磁盘设备,请运行 mount(8)
并查找内存磁盘分区。在输出的某个地方,你会发现这样一行:
xxxxxxxxxx
/dev/md41 on /mnt (ufs, local, soft-updates)
在这里,我们看到内存磁盘 /dev/md41 挂载在 /mnt 上。让我们卸载并销毁它。
xxxxxxxxxx
# ➊umount /mnt
# mdconfig ➋-d ➌-u 41
使用 umount
➊卸载与其他文件系统完全相同。然而,mdconfig(8)
调用是一个新的调用。使用 mdconfig(8)
直接管理内存设备。-d
标志➋表示销毁,-u
标志➌表示设备编号。
上述操作会破坏设备 /dev/md41 或 md
设备编号41。此设备使用的内存现在被释放用于其他用途。
如果你在 /etc/fstab 中列出内存磁盘,FreeBSD会在启动时自动创建它们。这些条目看起来比其他条目更复杂,但如果你理解我们迄今为止使用的 mdmfs(8)
命令,就不会太糟糕。
我们可以使用 md 作为设备名称来表示内存磁盘。像选择任何其他设备一样选择挂载点,并使用文件系统类型 mfs
。在 options
下,列出 rw(用于读写)和用于创建此设备的命令行选项。如果这是一个长期挂载,请添加 -t
以启用TRIM。要创建挂载在 /home/mwlucas/test 的48MB文件系统,请使用以下 /etc/fstab 条目:
xxxxxxxxxx
md /home/mwlucas/test mfs rw,-s48m,-t 0 0
看起来很容易,不是吗?唯一的问题是,长线会弄乱你漂亮而均匀的 /etc/fstab 条目的外观。好吧,正如我们很快就会看到的,它们并不是唯一会让这个文件变得丑陋的东西。
您可以使用 mdmfs(8)
查看UFS磁盘映像,但大多数情况下,您希望在不将其刻录到磁盘的情况下检查ISO或UDF文件的内容。(FreeBSD的 tar(1)
可以访问ISO的内容,但不能访问UDF。)只需使用 mdconfig(8)
命令的-a标志将内存磁盘附加到文件中即可。在这里,我将Bert的ISO附加到存储设备上:
xxxxxxxxxx
# mdconfig ➊-a -t ➋vnode -f ➌/home/mwlucas/bert.iso
➍md0
我们告诉 mdconfig(8)
将➊一个vnode-backed的➋内存设备附加到指定的文件中➌。mdconfig(8)
命令通过告诉我们它所连接的设备➍来响应。现在我们只需使用文件系统的正确mount命令挂载设备:
xxxxxxxxxx
# mount -t cd9660 /dev/md0 /mnt
我现在可以验证ISO是否包含Bert的文件,这样他就不会抱怨ISO坏了。
人们在这一点上犯的一个常见错误是在没有指定文件系统类型的情况下挂载映像。您可能会遇到错误,或者您可能会得到一个不包含数据的成功挂载——默认情况下,mount(8)
假设文件系统是UFS!
访问完数据后,一定要卸载映像并销毁内存磁盘设备,就像对任何其他内存设备一样。虽然vnode-backed 的内存磁盘不消耗系统内存,但几个月后,当你想知道为什么它们会出现在 /dev 中时,把未使用的内存设备留在身边会让你感到困惑。如果你不确定系统有什么内存设备,可以使用 mdconfig -l
查看所有配置的 md(5)
设备。
xxxxxxxxxx
# mdconfig -l
md0 md1
我有两个存储设备?添加 -u
标志和设备号,看看它是什么类型的内存设备。让我们看看内存设备1(/dev/md1)是什么:
xxxxxxxxxx
# mdconfig -l -u 1
md1 vnode 456M /slice1/usr/home/mwlucas/iso/omsa-51-live.iso
我在这个系统上安装了ISO映像?哇!我可能需要重新启动一个月。不,那工作太多了;我将卸载文件系统并销毁内存设备。
嵌入式系统中使用的一个技巧是在本地文件上构建完整的文件系统映像。在上一节中,我们看到了如何使用内存磁盘来挂载和访问CD磁盘映像。您可以使用相同的技术来创建、更新和访问UFS磁盘映像。
要在文件中使用文件系统,您必须创建一个大小合适的文件,将文件附加到内存设备,在设备上放置文件系统,然后挂载设备。
使用 truncate(1)
为文件系统创建一个空文件。这些文件是稀疏文件:它们被标记为具有一定的大小,但在你放东西之前实际上不会占用任何空间。一个空的稀疏文件会占用一个文件系统块,并在您向其中放入内容时增长。这意味着您可以为任何大小的磁盘创建映像,但只会占用与您在映像中放入的内容相等的空间。
使用 -s
选项和文件大小创建图像文件。在这里,我创建了一个1GB的文件:
xxxxxxxxxx
# truncate -s 1G filesystem.file
由此产生的文件声称相当大。
xxxxxxxxxx
# ls -l filesystem.file
-rw-r--r-- 1 mwlucas mwlucas 1073741824 Aug 11 11:31 filesystem.file
但如果你检查一下磁盘的使用情况,你会看到一些不同的东西。
xxxxxxxxxx
# du filesystem.file
1 filesystem.file
此1GB文件使用磁盘上的一个块。
稀疏的文件永远不会缩水。他们只能成长。如果你从磁盘映像中删除了一堆文件,映像文件仍然需要这个空间。
此外,并非所有文件系统都支持稀疏文件。UFS和ZFS可以。如果你试图在FAT32文件系统上创建稀疏文件,你可能解决了错误的问题。
要在文件上获取文件系统,首先将文件与具有vnode支持的内存磁盘的设备相关联。我们在上一节中正是这样做的:
xxxxxxxxxx
# mdconfig -a -t vnode -f filesystem.file
md0
现在,让我们在这个设备上创建一个文件系统。这很像使用 newfs(8)
命令在拇指磁盘上创建UFS文件系统。软更新日志在文件支持的文件系统上和在磁盘支持的系统上一样有用,因此请使用 -j
启用它们。
xxxxxxxxxx
# newfs -j /dev/md0
/dev/md0: 1024.0MB (2097152 sectors) block size 32768, fragment size 4096
using 4 cylinder groups of 256.03MB, 8193 blks, 32896 inodes.
with soft updates
super-block backups (for fsck_ffs -b #) at:
192, 524544, 1048896, 1573248
Using inode 4 in cg 0 for 8388608 byte journal
newfs: soft updates journaling set
newfs(8)
程序打印出有关磁盘的基本信息,如磁盘大小、块和片段大小以及索引节点计数。
现在你有了一个文件系统,挂载它:
xxxxxxxxxx
# mount /dev/md0 /mnt
祝贺 你!您现在有一个1GB的文件备份文件系统。将文件复制到它,将其转储到磁带,或以任何使用其他文件系统的方式使用它。但除此之外,您还可以像移动其他文件一样移动它。
您可以在启动时使用 /etc/fstab 中的正确条目自动挂载文件支持的文件系统,就像您可以自动挂载任何其他内存磁盘一样。您只需使用 -F
指定文件名,并使用 -P
告诉系统不要在此文件上创建新的文件系统,而只需使用已有的文件系统。在这里,我们在启动时自动挂载在 /mnt 上创建的文件支持文件系统。
xxxxxxxxxx
md /mnt mfs rw,-P,-F/home/mwlucas/filesystem.file 0 0
我告诉过你,我们会看到 /etc/fstab 条目比通用内存磁盘的条目更丑陋,不是吗?
devfs(5)
是一个用于管理设备节点的动态文件系统。记住,在类Unix操作系统中,一切都是文件。这包括物理硬件。系统上几乎所有的设备都在 /dev 下有一个设备节点。您已经看到了一堆磁盘设备节点,但您也会看到键盘(/dev/ukbd0 或 /dev/kbd0 )、控制台(/dev/console)、混音器(/dev/mixer0)等。您还可以找到逻辑设备的设备节点,如随机数生成器(/dev/random)、终端会话(/dev/ttyv0)等。
从前,系统管理员负责制作这些设备节点文件。Lucky系统管理员管理着一个操作系统,该系统附带了一个shell脚本来处理设备节点的创建和权限。如果操作系统作者没有提供这样的shell脚本,或者如果服务器的shell脚本中没有包含不寻常的硬件,系统管理员必须使用动物牺牲(animal sacrifices)和 mknod(8)
创建节点。如果出现任何小问题,设备将无法工作。另一种选择是在操作系统上为每一块可以想象的硬件提供设备节点。系统管理员可以确信——好吧,大多数情况下是确信——所需的设备节点在 /dev 下的数千个文件中的某个地方是可用的。
当然,内核确切地知道每个设备节点应该具有什么特征。使用devfs(5)
,FreeBSD只需询问内核认为系统应该具有哪些设备节点,并提供这些节点,仅此而已。这对大多数人来说都很有效。然而,你和我并不是“大多数人”。我们对电脑抱有奇怪的期望。也许我们需要让设备节点以不同的名称可用,更改设备节点所有权,或者唯一地配置我们的硬件。FreeBSD将设备节点管理问题分为三部分:配置启动时存在的设备、全局可用性和权限,以及配置使用 devd(8)
启动后动态显示的设备。
当设备节点是磁盘上的永久文件时,系统管理员可以符号链接到这些节点或更改其权限,而不必担心他的更改会消失。有了自动化的动态设备文件系统,这种保证就消失了。(当然,你也不必再担心神秘的 mknod(8)
命令,所以从长远来看,你会过得更好。)设备节点更改可能包括,例如:
设备管理和服务器
在大多数情况下,服务器上的设备节点管理无需任何调整或干预即可工作。我最经常需要摆弄设备节点的地方是笔记本电脑和偶尔的工作站。FreeBSD的设备节点管理工具非常强大和灵活,包括对我在一个世纪内不会使用的东西的支持。我们只谈基础知识。不要以为你必须掌握 devfs(5)
才能让你的服务器正常运行!
在启动时, devfs(8)
根据 /etc/devfs.conf 中的规则创建设备节点。
/etc/devfs.conf 文件允许您为启动时可用的设备创建链接、更改所有权和设置权限。每条规则的格式如下:
xxxxxxxxxx
action realdevice desiredvalue
有效的操作是 link
(创建链接)、perm
(设置权限)和 own
(设置所有者)。realdevice
条目是一个预先存在的设备节点,而最后一个设置是您想要的值。例如,在这里,我们为设备节点创建一个新名称:
xxxxxxxxxx
➊link ➋cd0 ➌cdrom
我们想要一个符号链接➊到设备节点 /dev/cd0➋(光盘驱动器),我们希望这个链接命名为 /dev/cdrom ➌. 如果我们在 /etc/devfs.conf 中使用此条目重新启动,我们的光盘驱动器/dev/cd0 也会显示为 /dev/cdrom ,正如许多桌面多媒体程序所期望的那样。
要更改设备节点的权限,请以八进制形式给出所需的权限作为所需的值:
xxxxxxxxxx
perm cd0 666
在这里,我们设置了 /dev/cd0(我们的CD设备)的权限,以便任何系统用户都可以读取或写入该设备。记住,更改 /dev/cdrom 链接上的权限不会更改设备节点上的权限,只会更改符号链接。
最后,我们还可以更改设备的所有权。更改设备节点的所有者通常表明您正在以错误的方式解决问题,您可能需要停下来思考。然而,如果你坚持的话,FreeBSD很乐意让你把系统搞砸。在这里,我们让特定用户对磁盘设备 /dev/da20 拥有绝对控制权:
xxxxxxxxxx
own da20 xistence:xistence
然而,这可能不会达到预期的效果,因为一些程序仍然认为您必须是root才能在设备上执行操作。我见过不止一个软件如果不是由root运行,甚至没有尝试访问其设备节点,就会自动关闭。当这些程序由普通用户运行时,更改设备节点权限不会阻止它们的投诉。
使用 devfs.conf(5)
进行配置可以解决许多问题,但不是全部。如果你想让设备节点不可见且不可访问,你必须使用devfs规则。
每个 devfs(5)
实例的行为都符合 devfs.rules 中定义的规则。devfs规则适用于启动时存在的设备和动态出现和消失的设备。规则允许您设置设备节点的所有权和权限,并使设备节点可见或不可见。您无法使用devfs规则创建指向设备节点的符号链接。
与 /etc/rc.conf 和 /etc/defaults/rc.conf 类似,FreeBSD使用 /etc/devfs.rules 和 /etc/defaults/devfs.rule 。为您的自定义规则创建 /etc/defvs.rules,并保留默认文件中的条目。
每组devfs规则都以方括号中的名称和规则集编号开头。例如,这是默认配置中的devfs规则:
xxxxxxxxxx
[➊devfsrules_hide_all=➋1]
➌add hide
devfs.rules中的第一条规则名为 devfs_hide_all
➊,规则集编号为1➋。此规则集仅包含一条规则➌。
一旦你有了一组你喜欢的devfs规则,在/etc/rc.conf中启动时启用它们。在这里,我们激活了名为 laptoprules
的devfs规则集:
xxxxxxxxxx
devfs_system_rulesets="laptoprules"
记住,devfs规则适用于系统启动时的设备以及启动后动态配置的设备。
所有devfs规则(在文件中)都以单词 add
开头,用于向规则集中添加规则。然后,您可以使用 path
关键字和设备名称的正则表达式,也可以使用 type
关键字和设备类型。在规则的末尾,您有一个 action
或命令要执行。这是一个devfs规则的示例:
xxxxxxxxxx
add path da* user mwlucas
此规则将节点名称以 da
开头的所有设备节点的所有权分配给用户 mwlucas 。这可能是一个坏主意。
由路径指定的设备使用标准shell正则表达式。如果要匹配各种设备,请使用星号作为通配符。例如,path ada1s1
与设备 /dev/ada1s1 完全匹配,但 path ada*s*
与每个以 ada
、字符、字母 s
开头的设备节点匹配,可能还有更多字符。通过在命令行中使用通配符,您可以准确地知道哪些设备与之匹配。
xxxxxxxxxx
# ls /dev/ada*s*
这列出了SATA硬盘上的所有MBR切片和分区,但没有列出整个硬盘的设备。
type
关键字表示您希望将规则应用于给定类型的所有设备。有效的关键字是 disk
(磁盘设备)、mem
(内存设备)、tape
(磁带设备)和 tty
(终端设备,包括伪终端)。type
关键字很少被使用,因为它太笼统了。
如果既不包含path
也不包含 type
,devfs会将规则末尾的操作应用于所有设备节点。在几乎所有情况下,这都是不可取的。
规则集操作可以是group
、user
、mode
、hide
和 unhide
中的任何一个。group
操作允许您设置设备的组所有者,作为附加参数给出。同样,user
操作会指定设备所有者。在这里,我们将 da 磁盘的所有权设置为用户名 desktop 和组 usb :
xxxxxxxxxx
add path da* user desktop
add path da* group usb
mode
操作允许您以标准八进制形式为设备分配权限。
xxxxxxxxxx
add path da* mode 664
hide
关键字允许您使设备节点消失,unhide
则使其重新出现。由于如果设备不可见,则任何程序都不能使用设备节点,因此除非系统使用 jail(8)
,否则其效用有限。在规则中包含规则时,隐藏和取消隐藏最有意义。
与系统管理的许多部分一样,将devfs规则模块化以便重用是减少问题的好方法。默认的jail规则通过 include
关键字准确地显示了FreeBSD的devfs如何支持重用。
以下是默认配置的开始:
x➊ [devfsrules_hide_all=1]
➋ add hide
➌ [devfsrules_unhide_basic=2]
➍ add path log unhide
➎ add path null unhide
➏ add path zero unhide
➐ add path crypto unhide
--snip--
第一条规则,devfsrules_hide_all
➊,隐藏所有设备节点➋。
第二条规则,devfsrules_unhide_basic
➌,仅包含一系列取消隐藏语句。此规则只会取消隐藏关键的Unix设备节点,如/dev/log➍,/dev/null➎,/dev/zero➏,/dev/crypto➐,等等。没有这些设备,大多数进程都无法运行。这些设备节点已经在标准系统中公开,那么为什么你需要一个规则来取消隐藏它们呢?同样,第三个规则集 devfsrules_unhide_login
只会为登录用户取消隐藏设备节点。
最后一个规则集利用了所有这些。
xxxxxxxxxx
[devfsrules_jail=4]
add include $devfsrules_hide_all
add include $devfsrules_unhide_basic
add include $devfsrules_unhide_login
add path zfs unhide
此规则集 devfsrules_mail
使用 include
语句通过引用引入前面的规则集。最后一条语句还取消了 /dev/zfs 的隐藏,允许zfs工具在jail中工作。
如果你想在所有jail中提供额外的设备节点,你可以将该设备节点添加到jail规则集中。或者,你可以定义一个新的规则集,并将其用于所有jail。更好的是,你可以为绝对需要该设备的jail定义一个规则集,并将该规则集分配给这些jail。
最后,让我们来看看动态设备。
热插拔硬件现在已成为常规。FreeBSD的devfs在插入此硬件时动态创建新的设备节点,并在移除硬件时擦除节点,使使用这些动态设备变得更加简单。devd(8)
守护进程更进一步,允许您在硬件出现和消失时运行用户空间程序。
FreeBSD的默认配置 /etc/devd.conf 可以很好地处理大多数现代硬件。如果需要自定义devd(8)
,请将配置文件放在 /usr/local/etc/devd/ 下以简化升级。如果您发现 devd(8)
配置变得非常复杂,您还可以为不同类型的设备添加不同的规则文件。
您将找到四种类型的 devd(8)
规则:attach
(附加)、detach
(分离)、nomatch
(不匹配)和 notify
(通知)。
当匹配的硬件连接到系统时,会触发attach
规则。当您插入网卡时,attach
规则会为该卡配置IP地址并打开网络。
当从系统中删除匹配的硬件时,会触发 detach
规则。detach
规则并不常见,因为当底层硬件消失时,内核会自动标记资源不可用,但您可能会找到它们的用途。
当安装了新硬件但未连接到设备驱动程序时,会触发 nomatch
规则。这些设备在当前内核中没有设备驱动程序。
当内核向用户区发送匹配事件通知时,devd(8)
应用 notify
规则。例如,网络接口出现的控制台消息是一个通知事件。通知通常出现在控制台上或 /var/log/messages 中。
规则也有优先级,0是最低的。只处理最高的匹配规则,而跳过较低优先级的匹配规则。下面是一个示例 devd(8)
规则:
xxxxxxxxxx
➊notify ➋0 {
match "system" ➌"IFNET";
match "subsystem" ➍"!usbus[0-9]";
match "type" ➎"ATTACH";
action ➏"/etc/pccard_ether $subsystem start";
};
这是一条 notify
规则➊,这意味着当内核向用户区发送消息时,它会激活。作为优先级0规则➋,只有当没有更高优先级的规则符合我们指定的标准时,才能触发此规则。只有当通知在网络系统 IFNET
➌(网络)上,并且只有当子系统➍与表达式 usbus[0-9]
不匹配时,才会触发此规则。它不包括USB网卡。通知类型为 ATTACH
➎——换言之,这仅在有人插入网络接口时匹配。如果这三个匹配都匹配,devd(8)
将运行一个命令来配置网络接口➏。
阅读 devd(8)
手册页,了解可以在规则中添加的所有选项。如果你想在某个挂载点自动挂载特定的USB闪存盘,可以通过检查你放入的每个USB设备的序列号来实现。如果你想配置与Atheros网卡不同的Intel网卡,可以通过查看供应商来实现。无论你需要写什么规则,它可能就在那里的某个地方。
FreeBSD支持几个鲜为人知的文件系统。它们中的大多数只在奇怪的情况下有用,但在系统管理中每天都会出现奇怪的情况。
进程文件系统 procfs(5)
包含大量关于进程的信息。它被认为是一种安全风险,在现代FreeBSD版本中被正式弃用。但是,您可以从挂载的进程文件系统中了解很多关于进程的信息。一些较旧的应用程序仍然需要安装在 /proc 上的进程文件系统;如果服务器应用程序需要procfs,请尝试找到一个不需要它就能完成工作的类似应用程序。
如果你使用的是Linux模式(见第17章),你可能需要Linux进程文件系统 linprocfs(5)
。许多Linux软件需要进程文件系统,FreeBSD建议在安装Linux模式时在 /compat/Linux/proc 安装linprocfs。我建议只有当某个软件抱怨它不存在时才安装linprocfs。
文件描述符文件系统 fdesc(5)
为每个进程提供文件描述符的文件系统视图。一些软件,特别是Java和流行的Bash shell,需要 fdescfs(5)
。它的安全风险比procfs小,但仍然不受欢迎。当你安装一个需要安装 fdescfs(5)
的包时,你会得到关于安装它的说明。
现在我们已经讨论了本地文件系统,让我们看看网络。
网络文件系统允许通过网络访问另一台机器上的文件。最常用的两种网络文件系统是Unix中实现的原始网络文件系统(Network File System——NFS)和Microsoft Windows普及的CIFS(又名SMB)文件系统。我们将讨论这两个问题,但从NFS的旧Unix标准开始。
在类Unix系统之间共享目录和分区可能是你能找到的最简单的网络文件系统。FreeBSD支持Unix标准的网络文件系统。配置NFS会让许多初级系统管理员感到害怕,但在设置了一两个文件共享后,你会发现它并没有那么难。
NFS不是作为安全协议设计的。不要在没有数据包过滤器或防火墙的情况下将NFS服务器放在互联网上。仅在NFS级别限制访问是完全不够的——您必须防止随机主机窥探主机的远程过程调用(remote procedure call——RPC)服务。通过IP地址和端口号限制对主机的访问。
此外,标准NFS没有加密。任何拥有数据包嗅探器并可以访问您的线路的人都可以看到所有文件系统活动。部署Kerberos后,您可以加密NFS,但Kerberos需要自己的书。
每个NFS连接都使用客户端-服务器模型。一台计算机是服务器;它为其他计算机提供文件系统。这称为 NFS exporting ,提供的文件系统称为 export 。客户端可以以与装载本地文件系统几乎相同的方式装载服务器导出。
NFS的一个有趣之处是它的无状态性。NFS不会跟踪连接的状态。您可以重新启动NFS服务器,客户端不会崩溃。当服务器停机时,它将无法访问服务器导出上的文件,但一旦它恢复,您将在中断的地方重新开始。其他网络文件共享系统并不总是那么有弹性。当然,无国籍状态也会造成问题;例如,客户端无法知道他们当前打开的文件何时被另一个客户端修改。
NFS互操作性 每个NFS实现都略有不同。您会发现Solaris、Linux、BSD和其他类Unix系统之间存在细微的NFS差异。NFS应该在它们之间工作,但可能需要偶尔进行调整。如果您在使用其他类Unix操作系统时遇到问题,请查看FreeBSD网络邮件列表存档;这个问题几乎肯定已经在那里讨论过了。
NFS服务器和客户端都需要内核选项,但各种NFS命令会动态加载相应的内核模块。FreeBSD的GENERIC内核支持NFS,因此对于任何不自定义内核的人来说,这都不是问题。
NFS是其中一个有整本书都写过的主题。我们不会深入探讨NFS的细节,而是专注于让基本的NFS操作正常工作。如果你正在部署复杂的NFS设置,你需要做进一步的研究。即使是这种基本设置也可以让你完成许多复杂的任务。
现代NFS有三个版本:NFSv2、NFSv3和NFSv4。FreeBSD可以透明地自动检测并与版本2和3互操作。
NFSv2相当小,可以追溯到人们很高兴文件共享工作的时候。
NFSv3比NFSv2有许多增量改进,性能也要好得多。这些改进中的大多数甚至不需要特殊的配置。
NFSv4是一个完全不同且高度复杂的协议,它打破了NFS的许多长期规则。它被有意设计成类似于微软的文件共享。了解NFSv4需要了解文件系统扩展ACL、在网络上同步用户ID以及其他令人头疼的问题。
当人们说“NFS”时,他们几乎总是指NFSv2或NFSv3。有些人称这些协议为“传统NFS”。指NFSv4的人通常会说“NFSv4”。
本书坚持使用常用的NFSv2和NFSv3。我在《FreeBSD Mastery: Specialty Filesystems》(Tilted Windmill Press,2016)中用了几章来介绍NFSv4和相关主题。
使用以下 rc.conf 选项打开NFS服务器支持。虽然并非所有这些选项对所有环境都是绝对必要的,但将它们全部打开可以提供最广泛的NFS兼容性和出色的开箱即用性能。
xxxxxxxxxx
➊ nfs_server_enable="YES"
➋ rpcbind_enable="YES"
➌ mountd_enable="YES"
➍ rpc_lockd_enable="YES"
➎ rpc_statd_enable="YES"
首先,告诉FreeBSD加载 nfsserver.ko ➊内核模块。如果内核不支持NFS,一切都会失败。rpcbind(8)
➋守护进程将远程过程调用(RPC)映射到本地网络地址。每个NFS客户端都会询问服务器的 rpcbind(8)
守护进程在哪里可以找到一个mountd(8)
后台进程进行连接。mountd(8)
➌守护进程监听来自客户端的高编号端口的装载请求。启用NFS服务器也会启动nfsd(8)
,它处理实际的文件请求。NFS使用rpc.lockd(8)➍确保文件锁定顺畅,rpc.statd(8)➎监控NFS客户端,以便NFS服务器在主机消失时释放资源。
虽然您可以在命令行启动所有这些服务,但如果您只是在学习NFS,最好在启用NFS服务器后重新启动系统。NFS运行后,sockstat(1)
的输出将显示 rpc.lockd
、rpc.statd
、nfsd
、mountd
和 rpcbind
侦听。如果您没有看到所有这些守护进程都在监听网络,请检查 /var/log/messages 中的错误。
NFS服务器旨在无缝地互操作一大堆不同的NFS实现。虽然它应该透明地自动协商连接,但您可能会发现需要调整NFS服务器 nfsd(8)
以最适合您的客户端。在启动时使用 rc.conf 选项 nfs_server_flags
调整 nfsd(8)
。
NFS可以在TCP或UDP上运行。UDP是传统的NFS传输协议。TCP在有损网络上工作得更好,可以更好地应对不规则的网络速度。FreeBSD提供这两种协议,但默认使用TCP挂载。一些客户端在使用一种或另一种协议时表现更好。您可以使用-t显式启用TCP,使用 -u
显式启用UDP。
NFS服务器默认监听计算机上的所有IP地址。当服务器有多个IP地址时,对UDP请求的回复可以来自这些地址中的任何一个。这可能会混淆NFS客户端。如果您的NFS服务器有多个IP地址,并且您的客户端更喜欢UDP,请告诉NFS服务器只使用一个带有 -h
和服务器IP的地址。
虽然 nfsd(8)
运行良好,但高负载的服务器可能需要额外的 nfsd(9)
进程。虽然FreeBSD默认启动四个 nfsd(8)
进程,但您可以使用 -n
标志和所需数量的进程启动其他进程。
这个 rc.conf 条目告诉NFS只使用UDP,绑定到IP地址198.51.100.71,并运行 nfsd(8)
的六个实例。
xxxxxxxxxx
nfs_server_flags="-uh 198.51.100.71 -n 6"
不过,在开始调整服务器行为之前,您确实应该有一些导出。
现在告诉您的服务器它可以共享或 export 什么。您可以导出整个服务器上的所有目录和文件系统,但任何有能力的安全管理员都会(合理地)适合。与所有服务器配置一样,允许尽可能少的访问,同时仍然让服务器履行其职责。例如,在大多数环境中,客户端不需要远程挂载NFS服务器的根文件系统。
FreeBSD允许您通过两条不同的路径配置导出。传统的方法是文件 /etc/exports 。基于ZFS的服务器可以通过每个数据集的 sharenfs
属性配置导出。服务器将根据这些属性创建ZFS导出文件 /etc/zfs/exports 。两个导出文件的格式相同。
选择一种管理NFS导出的方法。要么编辑 /etc/exports ,要么使用 zfs(8)
。同时使用这两种方法可能只会让你感到困惑,但可能会破坏一切。如果使用ZFS方法,切勿手动编辑 /etc/zfs/exports 。坚持一种方法。
不管你选择哪种方法,/etc/exports 都必须存在。如果您通过 zfs(8)
管理NFS,我建议创建一行 /etc/exports ,其中只包含一条注释,告诉人们使用 zfs(8)
。
那么,如何配置导出呢?我将从导出文件 /etc/exports 开始,但大多数内容也适用于使用ZFS。我将在第308页的“使用zfs管理NFS(8)”中讨论差异,但要了解这些限制,需要了解 /etc/exports 。
每个导出条目最多有三个部分:
客户端和磁盘设备的每种组合在导出文件中只能有一行。这意味着,如果 /usr/ports 和 /usr/home 位于同一分区上,并且您想将它们都导出到特定的客户端,则它们必须都出现在同一行中。您不能将 /usr/ports 和 /usr/home 导出到具有不同权限的一个客户端。请注意,您不必导出整个磁盘设备;您可以导出分区内的单个目录。此目录不能包含符号链接或双点或单点。
NFS挂载不会跨分区。如果主机对 /usr 和 /usr/src 有单独的UFS分区,则导出 /usr 不会自动导出 /usr/src 。
在 /etc/exports 条目的三个部分中,只有目录是必需的。导出行不能包含符号链接或句点。要将我的主目录导出到互联网上的每个主机,我可以使用 /etc/exports 行,该行完全由以下部分组成:
xxxxxxxxxx
/home/mwlucas
这没有选项,也没有主机限制。当然,这样的export是愚蠢的,但我可以做到。
编辑 export 文件后,告诉 mountd(8)
重新读取它:
xxxxxxxxxx
# service mountd reload
mountd(8)
的任何问题都会出现在 /var/log/messages 中。日志消息通常是神秘的:虽然mountd(8)
会通知你一行有问题,但它通常不会说明原因。我遇到的最常见的错误涉及符号链接。在目录中使用 pwd(1)
获取目录的实际路径。
NFSv2和NFSv3通过UID识别用户。(NFSv4使用用户名,因为它假设你已经在整个网络上同步了用户名。)例如,在我的笔记本电脑上,用户mwlucas的UID为1001。在NFS服务器上,mwlucas还具有UID 1001。这让我的生活变得轻松,因为我不必太担心文件所有权;我在服务器上的权限与在笔记本电脑上的权限相同。
在用户在自己的机器上拥有root的大型网络上,这可能是一个问题。解决这个问题的最佳方法是通过Kerberos创建一个授权用户的中央存储库。在小型网络或NFS用户数量有限的网络上,这通常不是问题;您可以在系统上同步/etc/master.passwd,也可以为每个系统上的每个用户分配相同的UID。
但是,对root用户的处理略有不同。NFS服务器不信任其他计算机上的root以服务器上的root身份执行命令。毕竟,如果入侵者闯入NFS客户端,您不希望服务器自动崩溃。NFS默认将客户端根帐户的请求映射到服务器上的UID和GID为-2。这就是高度无特权的nobody帐户的起源。
许多其他服务器程序的作者认为nobody帐户是一个好主意,所以他们没有占用nobody供自己使用。多个安全实体同时以无人身份运行会造成安全问题。FreeBSD的软件包为所有需要特权的应用程序创建了无特权用户。我认为无名氏用户受到了污染,建议你不要允许使用它。
您可以将请求从root映射到任何其他用户名。例如,您可能会说,客户端上root的所有请求都将以服务器上nfsroot用户的身份运行。通过谨慎使用组,您可以允许此nfsroot用户具有有限的文件访问权限。使用 maproot
选项将根映射到另一个用户。在这里,我们将客户端上的UID 0(root)映射到服务器上的UID 5000:
xxxxxxxxxx
/usr/home/mwlucas -maproot=5000
如果您真的希望客户端上的root在服务器上拥有root权限,请使用 -maproot
将root映射到UID 0。这可能适用于您的家庭网络或测试系统。
您不能任意将用户帐户相互重新映射。在复杂的环境中,请确保同步网络上所有计算机上的用户帐户和UID。
NFS用户最多只能属于16个组。一些操作系统可以突破这一限制,但这样做违反了NFS协议。如果用户无法通过基于组的访问控制访问文件,请检查他们所在的组数。
编辑导出文件后,记得重新启动mountd(8)。
标准的FreeBSD UFS安装将所有文件放在一个分区上。您可能希望导出该分区上的多个目录。在/etc/exports的同一行列出同一分区上的所有目录,就在第一个导出目录之后,用空格隔开。以下是一个具有多个导出的/etc/exports示例:
xxxxxxxxxx
/usr/home/mwlucas /usr/src /var/log /usr/ports/distfiles -maproot=nfsroot
客户端可以挂载这些目录中的任何一个,并且来自root的请求会被映射到nfsroot。
此行的各部分之间没有标识符(identifiers)、分隔符(separators)或分隔符(delimiters)。是的,如果我们能把每个共享目录放在自己的行上,会更容易阅读,但我们不能——它们都在同一个分区上。FreeBSD团队可以重写它,使其具有更多的结构,但FreeBSD的 /etc/export 将与任何其他Unix的导出不兼容。
也许您希望客户端能够挂载分区上的任何目录。使用 -alldirs
选项允许此操作。我不会在具有单个分区的主机上执行此操作。
xxxxxxxxxx
/home -alldirs
您只能使用 -alldirs
指定分区装载点。
与许多其他配置文件一样,您可以使用反斜杠将单行配置拆分为多行。您可能会发现前面的配置更易读,如下所示:
xxxxxxxxxx
/usr/home/mwlucas \
/usr/src \
/usr/obj \
/usr/ports/distfiles \
-maproot = 5000
一旦你的导出行足够长,这种风格突然比其他风格更具可读性。
要只允许特定客户端访问NFS导出,请在/etc/exports条目末尾列出它们。在这里,我们将前面的共享限制为一个IP地址:
xxxxxxxxxx
/usr/home/mwlucas /usr/src /usr/obj /usr/ports/distfiles \
-maproot=5000 203.0.113.200
您还可以使用 -network
和 -mask
限定符将文件共享限制在特定网络上的客户端:
xxxxxxxxxx
/usr/home/mwlucas /usr/src /usr/obj /usr/ports/distfiles \
-maproot=5000 -network 203.0.113 -mask 255.255.255.0
这允许任何IP地址以203.0.113开头的客户端访问您的NFS服务器。我使用类似这样的设置来快速升级客户端。我在NFS服务器上构建了一个新的world和内核,然后让客户端挂载这些分区并通过NFS安装二进制文件。
要导出到IPv6网络,请在地址中包含斜线。
xxxxxxxxxx
/usr/home/mwlucas -network 2001:db8:bad:c0de::/64
您还可以列出主机名而不是IP地址,但这会产生对名称解析的依赖。如果您丢失DNS,您将失去文件共享。此外,NFS服务器在您开始装载时会查找每个主机的IP地址。更改客户端的IP意味着重新加载DNS和 mountd(8)
。如果你必须列出主机名,把它们放在行尾。
xxxxxxxxxx
/usr/home/mwlucas www1 www2 www3
在每个主机的基础上分配NFS需要更多的工作。在不损害安全性的情况下,尽可能广泛地分配NFS权限。
/etc/exports
中的每一行都指定了从一个分区到一个网络、地址或一组主机的导出。不同的主机需要完全不同的导出语句。如果你愿意,你可以更改每个选项。
xxxxxxxxxx
/usr/home/mwlucas /usr/src /usr/obj /usr/ports/distfiles \
-maproot=5000 203.0.113.200
/usr -maproot=0 203.0.113.201
在这里,我将 /usr 的几个子目录导出到203.0.113.200的NFS客户端。203.0.113.201的NFS客户端可以挂载整个 /usr,甚至可以以root身份挂载。
NFS以不喜欢防火墙而闻名。mountd(8)
、rpc.lockd(8)
和 rpc.statd(8)
等服务的动态端口分配使得数据包过滤几乎是不可能的。您可以使用 -p
标志为这些服务中的每一个分配一个特定的TCP端口。在这里,我使用 rc.conf
条目将 mountd(8)
固定到端口4046,将 rpc.lockd(8)
固定到端口4045,将 rpc.statd(8)
固定到端口4047:
xxxxxxxxxx
mountd_flags="-r -p 4046"
rpc_lockd_flags="-p 4045"
rpc_statd_flags="-p 4047"
我可以在我的数据包过滤规则中使用这些端口,为我的NFS服务器提供一些保护。
zfs(8)
管理NFS使用 zfs(8)
管理NFS既有优点也有缺点。您可以在每个数据集的基础上配置NFS,并且不需要在每次更改后手动重新启动 mountd(8)
。命令行配置更容易自动化,许多人也发现它更容易打字。
使用 sharenfs
属性启用、禁用和配置NFS导出。将此属性设置为启用,以全局共享数据集及其所有后代。这相当于在/etc/exports中单独列出数据集。世界上任何人都可以挂载此数据集或其任何子数据集,没有限制也没有选择,除非您有其他访问控制,如防火墙。
xxxxxxxxxx
# zfs set sharenfs=on zroot/home
同样,将其设置为 off
以取消共享数据集。
不过,您可能希望在导出时使用一些NFS选项。将 sharenfs
设置为数据集所需的选项。此示例设置了一个maproot用户,并将客户端限制在我的本地网络。将选项放在引号中。
xxxxxxxxxx
# zfs set sharenfs="-network 203.0.113.0/24 -maproot=nfsroot" zroot/home
使用ZFS管理NFS导出的问题是,所有允许的主机都有相同的选项。也就是说,如果您的大多数主机需要使用 -maproot=nfsroot
挂载 /home,但您有一个主机需要root以root身份挂载该数据集,则不能使用ZFS属性。同样,您只能定义一个具有ZFS属性的允许网络。
配置NFS客户端要简单得多。在/etc/rc.conf中添加以下行:
xxxxxxxxxx
nfs_client_enable="YES"
您可以重新启动或运行 service nfsclient start
启动NFS客户端功能。
NFS客户端要问的一个明显问题是,“我可以从该服务器装载什么?” showmount(8)
命令列出了客户端可用的所有导出。给出 -e
标志和NFS服务器的名称。在这里,我问storm服务器它提供了什么导出:
xxxxxxxxxx
# showmount -e storm
Exports list on storm:
/usr/home 203.0.113.0
根据允许网络203.0.113.0的规则,允许此客户端挂载 /usr/home 。
运行 showmount(8)
不提供任何服务器端选项,如 -maproot
。尽管touch(1)
可以让您轻松测试只读导出,但这些详细信息并不容易提供给客户端。
现在,您可以挂载NFS服务器导出的目录或文件系统。使用NFS服务器的主机名和要装载的目录,而不是使用设备名称。例如,要将我的storm服务器上的/home/mwlucas目录挂载到/mnt目录上,我将运行:
xxxxxxxxxx
# mount storm:/usr/home/mwlucas /mnt
然后,用 df(1)
测试你的挂载。
xxxxxxxxxx
# df -h
Filesystem Size Used Avail Capacity Mounted on
--snip--
storm:/usr/home 891G 2.7G 888G 0% /mnt
NFS挂载的目录显示为普通分区,我可以随意读写其中的文件。
FreeBSD使用保守的NFS默认值,以便它可以与任何其他类Unix操作系统互操作。您可以使用挂载选项来调整FreeBSD挂载NFS导出的方式。在命令行中用 -o
使用这些选项,或将它们添加到/etc/fstab条目中。
如果需要访问仅UDP的NFS服务器,请使用mount选项 udp
使用UDP而不是默认TCP。
程序希望文件系统不会消失,但当您使用NFS时,服务器可能会从网络中消失。这使得客户端上试图访问NFS文件系统的程序永远挂起。通过使NFS挂载interruptible(可中断),您将能够使用CTRL-C中断挂在不可用NFS挂载上的进程。使用 intr
设置可中断性。
通过使用软挂载,FreeBSD将通知程序他们正在处理的文件不再可用。程序如何处理这些信息取决于程序,但它们不会永远挂起。使用 soft
选项启用软安装。
如果您想要只读挂载,请使用 ro
挂载选项。
将所有内容放在一起,我可能会将我的主目录挂载为可中断的软挂载。
xxxxxxxxxx
# mount -o soft,intr storm:/usr/home/mwlucas /mnt
我可以将其添加到/etc/fstab中,如下所示:
xxxxxxxxxx
storm:/usr/home/mwlucas /mnt nfs rw,soft,intr 0 0
虽然NFS对于简单的使用来说非常简单,但你可以花很多时间来调整、调优和增强它。如果你想构建一个复杂的NFS环境,不要完全依赖这个简短的介绍,而是花时间阅读一本关于这个主题的好书。
现在,让我们来看看如何阅读Windows共享。
如果你在一个典型的办公网络上,标准的网络文件共享协议是微软的通用互联网文件系统(Common Internet File System —— CIFS)。您可能知道CIFS是服务器消息块(Server Message Block —— SMB)、“网上邻居”或“为什么我不能挂载那个驱动器?”虽然最初仅由Microsoft Windows系统提供,但此协议已成为一种伪标准(pseudostandard)。
FreeBSD包含 smbutil(8)
程序,用于查找、挂载和使用CIFS共享作为CIFS客户端。FreeBSD在基础系统中不包含CIFS服务器,但开源CIFS服务器Samba(https://www.samba.org/)在FreeBSD上运行良好。
使用FreeBSD的CIFS支持与现有的Microsoft基础架构进行互操作。不要部署CIFS来支持类Unix系统。
在开始使用Microsoft文件共享之前,请收集有关Windows网络的以下信息:
FreeBSD使用几个内核模块来支持CIFS。smbfs.ko模块支持基本的CIFS操作。libmchain.ko和libiconv.ko模块提供支持功能,并在加载smbfs.ko时自动加载。您可以在内核中静态编译这些代码:
xxxxxxxxxx
options NETSMB
options LIBMCHAIN
options LIBICONV
options SMBFS
您可以在启动时使用boot/loader.conf条目自动加载这些文件:
xxxxxxxxxx
smbfs_load=YES
现在可以配置CIFS。
CIFS依赖于一个配置文件,可以是$HOME/.nsmbc 或 /etc/nsmb.conf。/etc/nsmbconf中的所有设置都会覆盖用户主目录中的设置。配置文件由方括号中的标签划分为多个部分。例如,适用于每个CIFS连接的设置位于 [default]
部分。创建自己的部分,以以下格式之一指定服务器、用户和共享:
xxxxxxxxxx
[servername]
[servername:username]
[servername:username:sharename]
适用于整个服务器的信息将进入以服务器命名的部分。适用于特定用户的信息保存在用户名部分,而仅适用于单个共享的信息则保存在包含共享名的部分。如果没有更具体的每个用户或每个共享的信息,您可以将所有共享的信息合并到一个普通的 [servername]
条目下。
配置条目使用CIFS系统中的值——例如,Bert的Windows用户名是bertjw,但他的FreeBSD用户名是xistence,所以我在nsmb.conf中使用bertjw。
在相应部分下使用关键字和值指定nsmb.conf配置。例如,服务器有IP地址,而用户没有,因此您只能在服务器部分使用IP地址分配。要使用关键字,请指定一个带等号的值,如keyword=value。以下是常见的关键词;有关完整列表,请参阅 nsmb.conf(5)
。
workgroup
关键字指定要访问的Windows域或工作组的名称。这通常是用于所有服务器的默认设置。
xxxxxxxxxx
workgroup=MegaCorp
addr
关键字设置CIFS服务器的IP地址。此关键字只能出现在普通的 [servername]
标签下。如果你有可用的CIFS名称解析,你不应该需要这个,但现实有时会不一样。
nbns
关键字设置NetBIOS(WINS)名称服务器的IP地址。您可以将此行放在默认部分或特定服务器下。如果您有Active Directory(基于DNS),则可以使用DNS主机名。但是,添加WINS服务器不会影响您的配置,并且有助于测试基本的CIFS设置。
password
关键字为用户或共享设置明文密码。如果必须将密码存储在 /etc/nsmb.conf中,请绝对确保只有root可以读取该文件。在多用户系统中,将密码存储在 $HOME/.nsbrc 中是一个坏主意。
您可以使用 smbutil crypt
对Windows密码进行加密,生成一个可用于此关键字的字符串。加密后的字符串前面有双美元符号($$)。虽然这有助于防止有人意外发现密码,但恶意用户可以很容易地解密它。
xxxxxxxxxx
# smbutil crypt superSecretPassword
$$1624a53302a6d
如果服务器需要访问CIFS共享来完成其日常工作,请不要使用您的帐户。请向Windows团队为您的服务器申请一个帐户,这样您的帐户问题就不会中断服务器的功能。
在这里,我构建了一个 nsmb.conf,允许Bert访问公司CIFS文件服务器上的文件。
xxxxxxxxxx
[default]
nbns=203.0.113.12
workgroup=BigCorp
[FILESERVER:bertjw]
password=$$1624a53302a6d
通过这种配置,Bert应该能够访问那些专制的Windows管理员允许的CIFS共享的任何内容。
FreeBSD在挂载CIFS共享之前,需要识别共享所在的主机。虽然微软已经使用DNS几十年了,但典型的Windows环境通常支持一整套遗留协议。验证 smbutil(1)
是否可以通过 smbutil lookup
找到CIFS服务器。
xxxxxxxxxx
# smbutil lookup fileserver1
Got response from 203.0.113.12
IP address of ntserv1: 203.0.113.4
如果此方法有效,则您具有基本的CIFS功能。
您可以在命令行中查看主机上的共享。首先登录到您的主机。
xxxxxxxxxx
# smbutil login //unix@fileserver1
Password:
因此,我们的配置是正确的。让我们看看这个服务器通过 smbutil
的 view
命令提供了什么资源。
xxxxxxxxxx
# smbutil view //unix@fileserver1
Password:
Share Type Comment
-------------------------------
IPC$ pipe Remote IPC
ADMIN$ disk Remote Admin
C$ disk Default share
unix disk
4 shares listed from 4 available
您将获得CIFS服务器上每个共享资源的列表。现在,假设您已经完成,请注销服务器。
xxxxxxxxxx
# smbutil logout //unix@fileserver
现在您已经完成了调查,使用 mount_smbfs(8)
挂载一个共享。语法如下:
xxxxxxxxxx
# mount_smbfs //username@servername/share /mount/point
我有一个名为 MP3 的Windows盒子,我想从我的FreeBSD系统访问它。要将其挂载为 /home/mwlucas/smbmount,我会这样做:
xxxxxxxxxx
# mount_smbfs //unix@fileserver1/MP3 /home/mwlucas/smbmount
mount(8)
和 df(1)
程序显示此共享连接到您的系统,您可以像访问任何其他文件系统一样访问此服务器上的文档。使用 umount(8)
断开与服务器的连接。
mount_smbfs包括几个选项来调整已挂载的CIFS文件系统的行为。使用 -f
选项选择其他文件权限模式,使用 -d
选项选择其他目录权限模式。例如,要设置一个挂载,以便只有我可以访问目录的内容,我将使用 mount_smbfs -d 700
。这将使FreeBSD权限比Windows权限严格得多,但这对我来说完全没问题。我可以用 -u
选项更改文件的所有者,用 -g
选项更改组。
Microsoft文件系统不区分大小写,但类Unix操作系统区分大小写。CIFS默认情况下保持原样,但这可能并不可取。-c
标志使 mount_smbfs(8)
改变文件系统上的大小写:-c l
将所有内容都更改为小写,-c u
将所有内容更改为大写。
以下是针对不同情况的nsmb.conf条目示例。它们都假设它们是配置的一部分,在该配置中,您已经定义了一个工作组、NetBIOS名称服务器和一个具有访问CIFS共享权限的用户名。
如果你有一台名为 desktop 的机器,并且有密码保护的共享,你可以使用以下内容。许多独立的Windows系统都有这种密码保护功能。
xxxxxxxxxx
[desktop:shareusername]
password=$$1789324874ea87
在这个例子中,我们正在访问名为 development 的第二个域。此域的用户名和密码与我们的默认域不同。
xxxxxxxxxx
[development]
workgroup=development
username=support
类Unix和Windows系统之间的文件所有权可能存在问题。首先,你的FreeBSD用户名可能不会映射到Windows用户名,而且Unix的权限方案与Windows非常不同。
由于您使用单个Windows用户名访问共享,因此您可以访问该帐户对Windows资源的任何访问权限,但您必须为已挂载的共享分配适当的FreeBSD权限。默认情况下, mount_smbfs(8)
为新共享分配与装载点相同的权限。在前面的示例中,/home/mwlucas/smbmount 目录归用户mwlucas所有,权限为755。这些权限表示mwlucas可以编辑此目录中的内容,但其他人不能。尽管FreeBSD表示该用户可以编辑这些文件,但Windows可能仍然不允许该特定用户编辑其共享的文件。
正如FreeBSD可以访问CIFS共享一样,它也可以使用Samba将它们提供给CIFS客户端。您可以在packages集合中找到Samba的几个最新版本。Samba网站http://www.samba.org/包含许多有用的教程。从FreeBSD提供CIFS共享比访问它们要复杂得多,所以我们将在这本书变得更厚之前结束我们的讨论。
我们现在已经完成了FreeBSD文件系统的教程。虽然我在这个主题上花了几章时间,但FreeBSD还有几个额外的文件系统选项、一个自动挂载器,甚至还有用户空间文件系统(FUSE)支持,用于访问NTFS、Linux的extfs等。它具有特殊的iSCSI支持和特殊的文件系统,如 nullfs(5)
,这使得大规模管理监狱变得非常强大。不过,如果我在文件系统上花更多的时间,你会找到我,用一种直截了当的方式表达你的不满,所以让我们继续讨论FreeBSD的一些高级安全功能。