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

Reply via email to