On 8/7/25 21:47, Dave Young wrote:
Another question, may need fs people to clarify. If the mount is
tmpfs and it is also rootfs, could it use 100% of the memory by
default,
If you want to softlock the system when rootfs fills up with log files
or something, sure.
That was one of the original motivating reasons for using tmpfs instead
of ramfs for a persistent initramfs you don't pivot off of. Plus things
like ramfs always reporting zero free space (it doesn't rack) so you
can't use things like "rpm install" to add more packages at runtime, and
so on... I had a list of reasons I added initmpfs support back in
2013.... looks like
https://lkml.iu.edu/hypermail/linux/kernel/1306.3/04204.html
(Ok, the REAL reason I did it is A) I'd documented that was how it
worked when I wrote ramfs-rootfs-initramfs back in 2005 because it
seemed deeply silly NOT to support that, and when nobody had made the
obvious fix 7 years later I got guilted into it by an employer who I'd
explained initramfs to and they asked "how do we do the tmpfs version"
so I whipped up a quick patch and they went "you need to upstream this
before we'll use it" so I went through The Process...)
Note that right now initmpfs isn't _specifying_ 50%, it's inheriting the
default value from tmpfs when no arguments are specified. If you're
special casing 100% for rootfs you'd still be passing in an argument to
the mount call to override the 50% default, just as a hardwired string
instead of a user-provided one (and again it would be a terrible idea).
And if you DO change tmpfs itself to globally default to 100% then 'yes
> /dev/shm/blah.txt' could lock your system as a normal user if they
don't change their mount script to specify an explicit constraint. Which
seems a bit of a regression for existing systems.
This new patch is because sometimes people making embedded systems want
to devote more than 50% of memory to rootfs while still having the other
benefits of tmpfs. One of those benefits is not soft-locking the kernel
if something writes too much data to the filesystem.
History time! (It's a hobby of mine. Plus I was here for this part.)
Tmpfs was originally called "swapfs" (because ramfs couldn't use swap as
backing store):
https://lkml.iu.edu/0102.0/0203.html
It was submitted to linux-kernel in 2001 (Peter Anvin was "?!" aghast):
https://lkml.iu.edu/0102.0/0239.html
Tmpfs got added in 2.4.3.3 ala
https://github.com/mpe/linux-fullhistory/commit/ca56c8ee6fa0
And almost immediately people noticed the softlock issue hadn't been fixed:
https://lkml.iu.edu/0103.3/0053.html
So the 50% default limit for tmpfs was introduced in 2001 (release
2.4.7.5) with the description "saner tmpfs mount-time limits", ala:
https://github.com/mpe/linux-fullhistory/commit/80fa70c0ea28
Jeff Garzik wired it up as an alternative to initrd in November 2002:
https://lwn.net/Articles/14448/
Alas, the result was completely undocumented. I thought it sounded like
a cool idea (it resizes automatically!) and reverse engineered how to
use it (ok, mostly a lot of pestering people with questions in email)
and wrote documentation encouraging people to use it in 2005:
https://lwn.net/Articles/157676/
When I converted rootfs to be able to use tmpfs in 2013 (link above)
there was a rootflags= but not a rootfsflags= (ramfs was intentionally a
simple demonstration of libfs that took no arguments) and I didn't add
one because I didn't personally need it: the 50% default was fine for me
and you can mount -o remount to change flags after the fact. (Although I
dunno if you can change this limit after the fact or what would happen
if you reduced it below what the filesystem currently contained,
probably doesn't work.)
Although looking back at my blog entries from the time, it seems I
mostly didn't want to deal with bikeshedding about the name
https://landley.net/notes-2013.html#29-04-2013
A year later somebody asked me why rootflags= wasn't working for
initmpfs (http://www.lightofdawn.org/blog/?viewDetailed=00128) and I
basically went "fixing it's easy, getting a patch into linux-kernel
requires far too much proctology for anyone on the inside to even see
it", and here we are 10 years later with the issue still unaddressed.
(Open source! Fixes everything right up immediately. So responsive. No
problems left to tackle, hard to find stuff worth doing...)
and then no need for an extra param? I feel that there is
no point to reserve memory if it is a fully memory based file system.
You're confusing ramdisk with ramfs (initrd vs initramfs). The 50% isn't
a reservation, it's a constraint. Both ramfs and tmpfs are dynamic ram
backed filesystems.
I wrote documentation about the four types of filesystem
(block/pipe/ram/function backed) 20 years ago back on livejournal, I
still have a copy somewhere...
https://landley.net/toybox/doc/mount.html
Linus invented ramfs by basically just mounting the page cache as a
filesystem with no backing store, so when memory pressure does flush
requests it goes "nope". When you write files it allocates memory, when
you truncate/delete files it frees memory. That's why ramfs was just a
couple hundred lines (at the time he was factoring out libfs so /proc
could stop being only synthetic filesystem everybody dumped every
control knob into, and I recall he mostly did ramfs as an example of how
minimal you could get with the new plumbing). Then tmpfs added some
basic guardrails and the ability to use swap space as backing store in
case of memory pressure (if you have swap, which a lot of embedded
systems don't; note that mmap()ed files have backing store, and
executables are basically mmap(MAP_PRIVATE) with some bells and
whistles, so you can still swap thrash under memory pressure even
without swap by evicting and faulting back in executable pages).
The old ramdisk mechanism from the 1990s created a virtual block device
(/dev/ram0 and friends I think) which you would then format and mount
using a block backed filesystem driver like ext2. This was terrible for
a bunch of reasons, unnecessarily copying all the data to use it and
regularly having two copies of the data in RAM (the one faulted into the
page cache and the one in the ram block device backing store). Heck,
when you had a system running from initramfs, you could configure out
the whole block layer and all the block backed filesystem drivers, which
made the kernel way smaller both in flash and at runtime. Even before
initramfs, ramdisks largely receded into the mists of history (except
for initrd) when loopback mounting became a thing, because you can just
dd if=/dev/zero of=blah.img bs=1m count=16 and then format that and
loopback mount it, and you control the size naturally (no rebooting
needed to change it) and it's got its own built-in backing store
allowing memory usage of the virtual image to be dynamic (ok, you can
mlock() it if you really want to but you could _also_ loopback a file
out of ramfs or tmpfs to accomplish that)...
The point of the 50% constraint in tmpfs is to tell the system "when I
ask how much free space there is, here's what the maximum should be".
Since ramfs doesn't enforce any such constraint, it always reports both
total and free space as 0, which tools like "df" use to indicate
"synthetic filesystem" and thus not show by default when you ask about
"disk free" space. Ramfs will let you keep writing as long as the
kernel's internal malloc() doesn't fail to find the next page, and THAT
is a problem because writes will fill up every last scrap of kernel
memory and then the rest of the kernel loses its lunch when its
allocations fail. (They added the OOM killer to try to cope with the
fact that recognizing you've run out of memory comes not when you mmap()
a range but when you asynchronously fault in pages by reading or
dirtying them, which is at memory access time not a syscall with a
return value. That's a WHOLE SAGA! There really _isn't_ a good answer
but people will happily argue about least bad FOREVER. The younger
generation seems to believe that Rust will do something other than add
abstraction layers and transition boundaries to make this worse.)
Anyway, the perennial complaint about the 50% initmpfs limit was that if
you have a small system that needs 16 gigs of ram to run, but you have a
cpio.gz that expands to 48 megabytes, then 64 megs SHOULD be enough for
the system... but it won't let you. You have to give it 96 megabytes of
ram in order to be able to use 48 megs of root filesystem, or else
extracting the cpio.gz will fail with an out of space error before
launching init. (This was especially common since you're about to free
the cpio.gz after extracting it, so by the time it launches PID 1 the
kernel has MORE memory available. There's a high water mark of memory
usage while he system is basically idle, but once you're past that extra
memory is just adding expense, draining your battery, producing heat...)
The embedded developers have been familiar with the problem for decades,
and (as usual) have repeatedly fixed it locally ignoring linux-kernel
politics. I first got asked to fix it over 10 years ago, I just find the
kernel community unpleasant to interact with these days so mostly only
wander in when cc'd.
The author of this patch asked me off list if I had a current version of
the patch I'd given other people, which I hadn't updated in _years_.
It's been fixed a bunch of times, https://lkml.org/lkml/2021/6/29/783
was the most recent we could find, but the fixes stay out of tree
because Linux dev is aggressively insular ever since the linux
foundation drove away the last of the hobbyists back around
https://lwn.net/Articles/563578/ and became corporate "certificate of
authenticity" signed-off-by-in-triplicate land with a thousand line
patch submission procedure document
https://kernel.org/doc/Documentation/process/submitting-patches.rst and
a 27 step checklist
https://kernel.org/doc/Documentation/process/submit-checklist.rst
(Which will usually still get ignored even when you do that.)
Rob