목차

tmpfs와 /tmp

이강우 2024/10/17 07:36

tmpfs란 간단히 말해 메모리 기반 파일시스템이다. 메모리의 여유영역을 램드라이브처럼 활용하는 기능이라고 보면 된다.
관련링크 : https://www.kernel.org/doc/html/v6.6/filesystems/tmpfs.html

당연하게도 메모리 영역이므로 데이터가 영구적으로 보관되지 않으며 실제로는 파일시스템으로 마운트 하여 사용하는동안에만 데이터가 유지되고 마운트를 해제하는 즉시 내용이 소실되는 형태로 동작한다.

그래서 /tmp 같은 임시 영역을 tmpfs로 구성하여 사용하는 방식이 나왔다.

RHEL

/usr/lib/systemd/system/tmp.mount 파일의 내용을 보면 아래와 같다.

#  SPDX-License-Identifier: LGPL-2.1-or-later
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Temporary Directory /tmp
Documentation=https://systemd.io/TEMPORARY_DIRECTORIES
Documentation=man:file-hierarchy(7)
Documentation=https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems
ConditionPathIsSymbolicLink=!/tmp
DefaultDependencies=no
Conflicts=umount.target
Before=local-fs.target umount.target
After=swap.target

[Mount]
What=tmpfs
Where=/tmp
Type=tmpfs
Options=mode=1777,strictatime,nosuid,nodev,size=50%%,nr_inodes=1m

# Make 'systemctl enable tmp.mount' work:
[Install]
WantedBy=local-fs.target

위와 같이 해당 systemd 설정에 /tmptmpfs타입으로 마운트 하여 쓰게 설정되어있다.

사용하려면

$ systemctl enable tmp.mount

하게 되면 바로 /tmp 경로가 tmpfs타입으로 변경된다.

하지만 이것은 권장되는 방식이 아니며 시스템에 이미 자동으로 사용할 수 있도록 구성되어있다.

/usr/lib/systemd/system/basic.target 내용을 보게되면 아래와 같다.

#  SPDX-License-Identifier: LGPL-2.1-or-later
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Basic System
Documentation=man:systemd.special(7)
Requires=sysinit.target
Wants=sockets.target timers.target paths.target slices.target
After=sysinit.target sockets.target paths.target slices.target tmp.mount

# We support /var, /tmp, /var/tmp, being on NFS, but we don't pull in
# remote-fs.target by default, hence pull them in explicitly here. Note that we
# require /var and /var/tmp, but only add a Wants= type dependency on /tmp, as
# we support that unit being masked, and this should not be considered an error.
RequiresMountsFor=/var /var/tmp
# RHEL-only: Disable /tmp on tmpfs.
#Wants=tmp.mount

맨 아래쪽을 보면

# RHEL-only: Disable /tmp on tmpfs.
#Wants=tmp.mount

와 같이 설정되어있다. RHEL은 기본적으로 /tmptmpfs타입을 사용하지 않도록 되어있다.
Wants=tmp.mount 부분의 주석만 해제하면 자동으로 /tmptmpfs타입으로 사용할 수 있다.

이런경우 관리자가 수동으로 umount /tmp를 하거나 systemctl stop tmp.mount를 한다 하여도 일정 시간 뒤에 systemd가 자동으로 감지하여 다시 tmp.mount를 수행하게 되므로 주의하기 바란다.

또한 /tmp경로의 용량이 부족하거나 크게 필요한 경우에는 메모리가 허용하는 한 실시간으로 확장해서 사용이 가능하다.

[root@localhost ~]# df -hP
Filesystem           Size  Used Avail Use% Mounted on
devtmpfs             4.0M     0  4.0M   0% /dev
tmpfs                636M     0  636M   0% /dev/shm
tmpfs                255M  3.8M  251M   2% /run
/dev/mapper/rl-root   17G  1.3G   16G   8% /
/dev/vda1            960M  225M  736M  24% /boot
tmpfs                128M     0  128M   0% /run/user/0
tmpfs                636M     0  636M   0% /tmp

[root@localhost ~]# mount -o remount,size=10G /tmp

[root@localhost ~]# df -hP
Filesystem           Size  Used Avail Use% Mounted on
devtmpfs             4.0M     0  4.0M   0% /dev
tmpfs                636M     0  636M   0% /dev/shm
tmpfs                255M  3.8M  251M   2% /run
/dev/mapper/rl-root   17G  1.3G   16G   8% /
/dev/vda1            960M  225M  736M  24% /boot
tmpfs                128M     0  128M   0% /run/user/0
tmpfs                 10G     0   10G   0% /tmp

[root@localhost ~]# free -m
               total        used        free      shared  buff/cache   available
Mem:            1271         306         865           7         249         964
Swap:           2047           0        2047

위의 예제에서는 /tmp용량을 10G로 늘렸는데, 이 시스템의 메모리는 1271M밖에 되지 않는다.
용량을 늘리는 것 자체는 성공했지만 실수로라도 /tmp영역의 데이터가 물리 메모리 용량을 넘게 쌓이면 시스템이 멈춘다. 매우 위험하다!!

[root@localhost ~]# cd /tmp/
[root@localhost tmp]# ll
total 0
[root@localhost tmp]# dd if=/dev/zero of=data bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.00415868 s, 2.5 GB/s
[root@localhost tmp]# dd if=/dev/zero of=data bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.0360715 s, 2.9 GB/s
[root@localhost tmp]# ll -h
total 100M
-rw-r--r--. 1 root root 100M Oct 17 17:05 data
[root@localhost tmp]# dd if=/dev/zero of=data bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB, 1000 MiB) copied, 0.375854 s, 2.8 GB/s
[root@localhost tmp]# ll -h
total 1000M
-rw-r--r--. 1 root root 1000M Oct 17 17:05 data
[root@localhost tmp]# free -m
               total        used        free      shared  buff/cache   available
Mem:            1271        1192          75         916        1064          79
Swap:           2047          91        1956
[root@localhost tmp]# dd if=/dev/zero of=data bs=1M count=3000
3000+0 records in
3000+0 records out
3145728000 bytes (3.1 GB, 2.9 GiB) copied, 2.35655 s, 1.3 GB/s
[root@localhost tmp]# ll -h
total 3.0G
-rw-r--r--. 1 root root 3.0G Oct 17 17:05 data
[root@localhost tmp]# free -m
               total        used        free      shared  buff/cache   available
Mem:            1271        1228          64         969        1068          42
Swap:           2047        2047           0

실제 물리 메모리 용량 이상으로 3000M파일을 생성해도 멀쩡한 이유는 스왑영역까지 끌어다 쓰기 때문이다.
위에 보는 바와 같이 free 메모리는 64메가밖에 남지 않았고 스왑영역은 모두 사용하는것을 볼 수 있다.

여기서 용량을 더 사용하면 어떻게 될까?

[root@localhost tmp]# dd if=/dev/zero of=data bs=1M count=4000
Connection closing...Socket close.

Connection closed by foreign host.

Disconnected from remote host(192.168.0.203:22) at 17:05:39.

Type `help' to learn how to use Xshell prompt.
[C:\~]$ 

이와 같이 해당 시스템은 먹통이 되며 강제 리부팅하지 않는 이상 복구 되지 않는다.

Amazon AWS EC2

EC2 인스턴스의 경우는 이 /tmp가 기본적으로 tmpfs 타입으로 구성되어있다.

[root@ip-172-31-17-98 system]# df -hP
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        4.0M     0  4.0M   0% /dev
tmpfs           475M     0  475M   0% /dev/shm
tmpfs           190M  448K  190M   1% /run
/dev/xvda1      8.0G  1.6G  6.4G  20% /
/dev/xvda128     10M  1.3M  8.7M  13% /boot/efi
tmpfs            95M     0   95M   0% /run/user/1000
tmpfs           475M     0  475M   0% /tmp

이것을 비활성화 하고 싶다면 /usr/lib/systemd/system/basic.target 에서 Wants=tmp.mount를 주석처리 하면 된다.

[root@ip-172-31-17-98 system]# cat basic.target
#  SPDX-License-Identifier: LGPL-2.1-or-later
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Basic System
Documentation=man:systemd.special(7)
Requires=sysinit.target
Wants=sockets.target timers.target paths.target slices.target
After=sysinit.target sockets.target paths.target slices.target tmp.mount

# We support /var, /tmp, /var/tmp, being on NFS, but we don't pull in
# remote-fs.target by default, hence pull them in explicitly here. Note that we
# require /var and /var/tmp, but only add a Wants= type dependency on /tmp, as
# we support that unit being masked, and this should not be considered an error.
RequiresMountsFor=/var /var/tmp
#Wants=tmp.mount    # <<< 주석처리

그리고 tmp.mount 를 종료하면 된다.

[root@ip-172-31-17-98 ~]# systemctl disable --now tmp.mount

혹시라도 /tmp영역을 사용중이 프로그램이 있는경우 실패 할 수 있다.
이런경우 해당 서비스나 프로그램을 먼저 종료한 후 수행하거나

아니면 systemctl disable tmp.mount 명령어만 실행하고 리부팅 진행하도록 한다.