linux tmpfs
=====
Tmpfs
=====
Tmpfs 是一种文件系统,它将所有文件都存储在虚拟内存中。
就 tmpfs 而言,一切都是临时的,因为不会在硬盘上创建任何文件。如果你卸载一个 tmpfs 实例,那么其中存储的所有内容都会丢失。
tmpfs 会将一切放入内核内部缓存中,并根据所包含的文件进行动态扩容和收缩,并且如果为 tmpfs 挂载启用了交换功能,它还可以将不需要的页面交换到交换空间。tmpfs 还支持透明大页(THP)。
tmpfs 在 ramfs 的基础上扩展了一些可在用户空间配置的选项(如下文所述),其中一些选项可以使用重新挂载(通过 ‘mount -o remount ...’)文件系统的方式动态重新配置。tmpfs 文件系统可以调整大小,但不能将其调整到小于当前使用量的大小。tmpfs 还支持 POSIX ACL(访问控制列表)以及受信任的 .*、安全 .* 和用户 .* 命名空间的扩展属性。而 ramfs 不使用交换空间,且无法修改其任何参数。ramfs 文件系统的大小限制取决于你可用的内存量,因此使用时需谨慎,以免耗尽内存。
作为 tmpfs 和 ramfs 的替代方案,可以使用 brd 来创建 RAM 磁盘(/dev/ram*),这允许你在物理内存中模拟块设备磁盘。要写入数据,只需在这个 ram 磁盘上创建常规文件系统即可。与 ramfs 一样,brd ram 磁盘不能进行交换。brd ram 磁盘也在初始化时配置大小,且无法动态调整大小。与 brd ram 磁盘不同的是,tmpfs 有自己的文件系统,它完全不依赖于块层。
由于 tmpfs 完全存在于页面缓存中(可选地存在于交换空间中),因此所有 tmpfs 页面都将在 /proc/meminfo 中显示为 “Shmem”,在 free(1) 中显示为 “Shared”。请注意,这些计数器还包括共享内存(shmem,参见 ipcs(1))。获取准确计数的最可靠方法是使用 df(1) 和 du(1)。
tmpfs 有以下用途:
1) 始终存在一个内核内部挂载点,你根本看不到它。它用于共享匿名映射和 SYSV 共享内存。
这个挂载点不依赖于 CONFIG_TMPFS。如果未设置 CONFIG_TMPFS,则用户可见的 tmpfs 部分不会被构建。但内部机制始终存在。
2) glibc 2.2 及更高版本期望 tmpfs 挂载在 /dev/shm 上,以实现 POSIX 共享内存(shm_open,shm_unlink)。可以在 /etc/fstab 中添加以下行来满足此要求:
tmpfs /dev/shm tmpfs defaults 0 0
记得在必要时创建你要挂载 tmpfs 的目录。
对于 SYSV 共享内存,不需要此挂载。内部挂载用于该目的。(在 2.3 内核版本中,需要挂载 tmpfs 的前驱(shm fs)才能使用 SYSV 共享内存。)
3) 有些人(包括我)发现将其挂载在例如 /tmp 和 /var/tmp 上并设置一个大的交换分区非常方便。现在,tmpfs 文件的循环挂载可以正常工作,因此大多数发行版提供的 mkinitrd 应该能够成功使用 tmpfs /tmp。
4) 可能还有很多我不知道的用途 :)
tmpfs 有三个用于调整大小的挂载选项:
========= ============================================================
size 此 tmpfs 实例的分配字节上限。默认值是物理内存(不包括交换空间)的一半。如果你过度分配 tmpfs 实例的大小,机器将会死锁,因为 OOM(Out of Memory)处理器无法释放那些内存。
nr_blocks 与 size 相同,但以 PAGE_SIZE 为单位表示块数。
nr_inodes 此实例的最大 inode 数量。默认值是物理内存页数的一半,或者在高内存机器上是低内存页数(取两者中较小的值)。
========= ============================================================
这些参数可以接受 k(千)、m(百万)或 g(十亿)作为后缀,以表示千字节、兆字节或吉字节,并且可以在重新挂载时更改。size 参数还可以接受 % 作为后缀,以将此 tmpfs 实例限制为物理内存的某个百分比;当未指定 size 或 nr_blocks 时,默认值为 size=50%。
如果 nr_blocks=0(或 size=0),则该实例中的块将不受限制;如果 nr_inodes=0,则 inode 将不受限制。通常不建议使用此类选项进行挂载,因为这会让任何有写入权限的用户耗尽机器上的所有内存;但这可以提高该实例在多 CPU 密集使用系统中的可扩展性。
如果 nr_inodes 不为 0,那么有限的 inode 空间也会被扩展属性占用:“df -i”的 IUsed 和 IUse% 会增加,IFree 会减少。
当内存不足时,tmpfs 块可能会被交换出去。tmpfs 有一个挂载选项可以禁用交换功能:
====== ===========================================================
noswap 禁用交换功能。重新挂载必须尊重原始设置。默认情况下启用交换功能。
====== ===========================================================
tmpfs 还支持透明大页,这需要内核配置了 CONFIG_TRANSPARENT_HUGEPAGE 并且你的系统支持 huge(通过 has_transparent_hugepage() 函数检查,这是特定于体系结构的)。其挂载选项如下:
================ ==============================================================
huge=never 不分配大页。这是默认值。
huge=always 每次需要新页面时都尝试分配大页。
huge=within_size 仅在大页完全位于 i_size 内时才分配大页。同时尊重 madvise(2) 的提示。
huge=advise 仅在 madvise(2) 请求时才分配大页。
================ ==============================================================
另请参阅 Documentation/admin-guide/mm/transhuge.rst,它描述了 sysfs 文件 /sys/kernel/mm/transparent_hugepage/shmem_enabled:该文件可用于在紧急情况下拒绝所有 tmpfs 挂载的大页,或强制所有 tmpfs 挂载使用大页进行测试。
tmpfs 还支持配额功能,其挂载选项如下:
======================== =================================================
quota 用户和组配额的记账与执行在挂载点上启用。Tmpfs 使用隐藏的系统配额文件,这些文件在挂载时初始化。
usrquota 在挂载点上启用用户配额的记账与执行。
grpquota 在挂载点上启用组配额的记账与执行。
usrquota_block_hardlimit 设置全局用户配额块硬限制。
usrquota_inode_hardlimit 设置全局用户配额 inode 硬限制。
grpquota_block_hardlimit 设置全局组配额块硬限制。
grpquota_inode_hardlimit 设置全局组配额 inode 硬限制。
======================== =================================================
任何与配额相关的挂载选项都不能在重新挂载时设置或更改。
配额限制参数接受 k(千)、m(兆)或 g(吉)作为后缀,表示千字节、兆字节和吉字节,并且在重新挂载时不能更改。默认的全局配额限制对任何及所有用户/组/项目都有效,除了 root,第一次访问用户/组/项目 ID 的配额条目时会生效——通常是在挂载后首次创建具有特定 ID 所有权的 inode 时。换句话说,这些限制不是初始化为零,而是使用这些挂载选项提供的特定值进行初始化。可以随时为任何用户/组 ID 更改这些限制,就像通常可以更改一样。
请注意,tmpfs 配额不支持用户命名空间,因此如果在用户命名空间内启用了配额,则不会进行 uid/gid 转换。
tmpfs 有一个挂载选项可以设置该实例中所有文件的 NUMA 内存分配策略(如果启用了 CONFIG_NUMA)——可以通过 'mount -o remount ...' 动态调整。
======================== ==============================================
mpol=default 使用进程分配策略(参见 set_mempolicy(2))。
mpol=prefer:Node 优先从给定节点分配内存。
mpol=bind:NodeList 仅从 NodeList 中的节点分配内存。
mpol=interleave 优先轮流从每个节点分配。
mpol=interleave:NodeList 轮流从 NodeList 中的每个节点分配。
mpol=local 优先从本地节点分配内存。
======================== ==============================================
NodeList 格式是由逗号分隔的数字和范围列表,范围由两个连字符分隔的数字组成,表示范围内的最小和最大节点号。例如,mpol=bind:0-3,5,7,9-15。
具有有效 NodeList 的内存策略将按指定保存,以便在文件创建时使用。当任务在文件系统中分配文件时,挂载选项内存策略将与调用任务的 cpuset 约束一起应用[参见 Documentation/admin-guide/cgroup-v1/cpusets.rst]以及下面列出的任何可选标志一起修改 NodeList。如果结果 NodeList 为空集,则该文件的有效内存策略将恢复为“默认”策略。
NUMA 内存分配策略有可选标志,可以与它们的模式一起使用。这些可选标志可以在挂载 tmpfs 时通过在 NodeList 之前追加它们来指定。有关可用的所有内存分配策略模式标志及其对内存策略的影响列表,请参见 Documentation/admin-guide/mm/numa_memory_policy.rst。
::
=static 等同于 MPOL_F_STATIC_NODES。
=relative 等同于 MPOL_F_RELATIVE_NODES。
例如,mpol=bind=static:NodeList 等效于 MPOL_BIND | MPOL_F_STATIC_NODES 分配策略。
请注意,如果运行的内核不支持 NUMA,尝试使用 mpol 选项挂载 tmpfs 将会失败;如果其 nodelist 指定的节点不在线也会失败。如果您的系统依赖于该 tmpfs 的挂载,但有时会运行没有 NUMA 功能的内核构建(可能是安全恢复内核)或在线节点较少的内核,那么建议从自动挂载选项中省略 mpol 选项。当 tmpfs 已经挂载到 MountPoint 上时,可以通过 'mount -o remount,mpol=Policy:NodeList MountPoint' 添加它。
要指定初始根目录,您可以使用以下挂载选项:
==== ==================================
mode 权限(以八进制数字表示)。
uid 用户 ID。
gid 组 ID。
==== ==================================
这些选项在重新挂载时没有任何影响。您可以使用 chmod(1)、chown(1) 和 chgrp(1) 更改已挂载文件系统的这些参数。
tmpfs 有一个挂载选项可以选择是否使用 32 位或 64 位 inode 编号:
======= ========================
inode64 使用 64 位 inode 编号。
inode32 使用 32 位 inode 编号。
======= ========================
在 32 位内核上,inode32 是隐式的,而 inode64 在挂载时被拒绝。在 64 位内核上,CONFIG_TMPFS_INODE64 设置了默认值。inode64 避免了单个设备上多个文件具有相同 inode 编号的可能性;但一旦达到 33 位 inode 编号,glibc 就会因 EOVERFLOW 而失败——如果长时间运行的 tmpfs 被如此古老的 32 位应用程序访问,以至于打开大于 2GiB 的文件时会因 EINVAL 而失败。
所以,命令 'mount -t tmpfs -o size=10G,nr_inodes=10k,mode=700 tmpfs /mytmpfs' 将在 /mytmpfs 上创建一个 tmpfs 实例,它可以在 10240 个 inode 中分配 10GB RAM/SWAP,并且只有 root 用户可以访问它。
Documentation/filesystems/tmpfs.rst
:Author:
Christoph Rohland <cr@sap.com>, 1.12.01
:Updated:
Hugh Dickins, 4 June 2007
:Updated:
KOSAKI Motohiro, 16 Mar 2010
:Updated:
Chris Down, 13 July 2020
更多推荐

所有评论(0)