LWN.net Logo

Unioning file systems: Architecture, features, and design choices

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 7:34 UTC (Tue) by anselm (subscriber, #2796)
In reply to: Unioning file systems: Architecture, features, and design choices by sunburnt
Parent article: Unioning file systems: Architecture, features, and design choices

Let's assume we have files /a/x and /b/x, and /c is a symbolic link to /a:/b. What happens if the user says »rm /c/x«?


(Log in to post comments)

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 13:44 UTC (Tue) by nix (subscriber, #2304) [Link]

The first time you invoke it, rm /c/x chases the link to /a, because x is present there, and removes /a/x; the second time, it removes /b/x.

A nastier question is what rm -r does in the context of such links. A really nasty question is what wildcard expansion does: what does /c/f* do if there are files matching f* in both /a and /b? As far as I can see, the semantics sunburnt described do not allow for the obvious semantics (expand files in /a and /b) without less-than-obvious changes to every program that does globbing and fnmatching everywhere -- and without those changes, the semantics you seem likely to get are quite bizarre.

Nice idea, torpedoed by harsh reality, I fear. (At least one Unix tried something similar, but it allowed $VARIABLES in the link, not paths, so at least a link could only expand to one thing in a given context.)

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 13:55 UTC (Tue) by anselm (subscriber, #2796) [Link]

The first time you invoke it, rm /c/x chases the link to /a, because x is present there, and removes /a/x; the second time, it removes /b/x.

That's the obvious way of handling this. It does break the (reasonable) assumption that after a successful rm(1) of a file that file will be gone (in the sense of »open("/c/x", O_RDONLY) fails«), rather than replaced by the next one over.

One of the main goals of a union filesystem (or equivalent), in my opinion, is that the files and directories it presents behave as nearly like ones on a non-union filesystem as possible. From that point of view the »paths in links« approach is a complete non-starter.

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 14:49 UTC (Tue) by hummassa (subscriber, #307) [Link]

> From that point of view the »paths in links« approach is a complete non-starter.

Actually, I strongly disagree. This is the way it would work anyway, in any implementation of union fs: "rm /c/f" removing /a/f but /b/f staying in its place for the next open() call (/b and /b/f are readonly, so you can't remove it again). That way, for instance, the readonly "bottom" fs can come with a default "/etc/resolv.conf" but it could be overwritten by user configuration on the readwrite "top" fs. If the user removes all configuration, the default config stays.

I actually think that "path in links" and "junction links" should be the default mounting mechanism instead of "/etc/fstab" because then it would be completely portable (you get a disk with n partitions, organize them with links to one another, disconnect it from one computer, connect it on another and voilá... everything is in its place.) And everything could be done lazily (you only actually mount a device once you access the link)

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 15:03 UTC (Tue) by hummassa (subscriber, #307) [Link]

> It does break the (reasonable) assumption that after a successful rm(1) of a file that file will be gone (in the sense of »open("/c/x", O_RDONLY) fails«), rather than replaced by the next one over.

Why would this assumption be reasonable? It's not a single-process, single-user system. Once you remove a file, other processes are totally permitted to re-create it immediately.

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 14:49 UTC (Tue) by nix (subscriber, #2304) [Link]

Yeah, but of course that reasonable assumption, while often true, is racy and thus not a valid assumption at all: it's only guaranteed safe if you are operating on a disconnected subset of the filesystem and you are certain no other thread or process has that subset as its current directory nor has an fd to any directory in that subset. This seems like an extremely rare case (not least because the subset has to be connected briefly while you're setting it up, and you can't stop something else with cd'ing into it in that time period: even if you tweak permissions appropriately, a root-owned process can still get in there).

So any program that depends on an open() after an unlink() returning -ENOENT is broken in any case, and we don't need to pander to them. (They should probably be using O_CREAT|O_EXCL.)

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 15:15 UTC (Tue) by anselm (subscriber, #2796) [Link]

That's why I said »assumption«, not »guarantee«. It is clear that it is possible to stipulate cases where if you remove a file, another one will immediately pop up in its place – and it is also clear that one shouldn't write programs based on the idea that just because a file was removed just now, another one of the same name cannot have appeared in the meantime.

However, if – like most of the people most of the time – you're just working away in your shell somewhere below $HOME, that sort of thing is highly unlikely. In that context, chances are that if you just removed a file you'd expect it to be gone, not replaced by some older or default version. For example, I often do something like »rm *~« in order to clean up before, e.g., making a tar file, and I don't want this to unearth random files from the layer below.

The other problem is that with this approach it is impossible to make files go away completely if they exist in a read-only layer. This can be a hassle for programs that assume certain defaults if they don't have a certain configuration file. If somebody in your virtualisation base image helpfully supplied a configuration file you don't want, either you're in luck because the program doesn't mind an empty configuration file that you put on top, or else you will have to come up with one that undoes just the stuff you don't want because you can't get rid of the unwanted file altogether.

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 22:22 UTC (Tue) by hummassa (subscriber, #307) [Link]

Why would you mount an unionfs over your /home/x?

What you really want to do is to union mount /etc, /usr/share and other places where you want to have writable configuration or data files shadowing read-only (original) files.

In that case, the semantics you Need from -- for instance -- "rm /etc/resolv.conf" is exactly "substitute /etc/resolv.conf for the default file".

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 22:31 UTC (Tue) by anselm (subscriber, #2796) [Link]

In that case, the semantics you Need from -- for instance -- "rm /etc/resolv.conf" is exactly "substitute /etc/resolv.conf for the default file".

That's not the greatest example – not having an /etc/resolv.conf file at all also means something, and with the »path in symlink« approach you can't make a file that is present in a lower layer appear as if it wasn't there after all, which is something that union filesystems can usually handle.

Unioning file systems: Architecture, features, and design choices

Posted Jan 16, 2013 0:00 UTC (Wed) by hummassa (subscriber, #307) [Link]

You can have "negative filesystem skeletons" like you have in some unionfs implementations. That way, you do "/x -> /a:-/b:/c:-/d" and if you remove a file in /x, the implementation will touch the same name (modulo an extension or prefix) under /b, that will mark said file as inexistent even if it exists in /c...

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 23:48 UTC (Tue) by nix (subscriber, #2304) [Link]

That's why I said »assumption«, not »guarantee«.
Sorry, I tend to read 'assumption of X' as a statement that we had better have a guarantee of X, lest we break the code making that assumption. Miscommunication. :)
However, if – like most of the people most of the time – you're just working away in your shell somewhere below $HOME, that sort of thing is highly unlikely.
Quite. It could perfectly well confuse the heck out of users, and I don't see a way to implement the less-confusing whiteout model using this sort of symlink-path. It just shouldn't break any software that isn't already broken.
The other problem is that with this approach it is impossible to make files go away completely if they exist in a read-only layer.
Yeah -- but, again, it's impossible to make files go away completely (or change in any way) if they exist on a read-only filesystem, and nobody complains about that. I personally don't see this sort of symlink-path model as a viable way to implement union mounts, but they could be interesting in and of themselves regardless. It's worth thinking about -- the sort of experimentation that doesn't happen often in Linux anymore due to the drag of the installed base of software and its tedious demands that we not gratuitously break it :P

Unioning file systems: Architecture, features, and design choices

Posted Jan 16, 2013 0:06 UTC (Wed) by anselm (subscriber, #2796) [Link]

Yeah -- but, again, it's impossible to make files go away completely (or change in any way) if they exist on a read-only filesystem, and nobody complains about that.

That's because read-only filesystems don't pretend to be read-write filesystems.

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 15:00 UTC (Tue) by hummassa (subscriber, #307) [Link]

> A nastier question is what rm -r does in the context of such links.

Exactly what it does in the case of a union fs: removes all files, recursively, from the "top" filesystem (the "bottom" filesystems are read-only), refusing to remove any files present in the "bottom" filesystems.

> A really nasty question is what wildcard expansion does: what does /c/f* do if there are files matching f* in both /a and /b? As far as I can see, the semantics sunburnt described do not allow for the obvious semantics (expand files in /a and /b) without less-than-obvious changes to every program that does globbing and fnmatching everywhere -- and without those changes, the semantics you seem likely to get are quite bizarre.

Again, no nasty question: /c/f* will bring all files that match in the union /c, i.e., a merge with of /a/f* and /b/f*. A file called f1 present both in /a and in /b will come only once, referring obviously to /a/f1.

Unioning file systems: Architecture, features, and design choices

Posted Jan 15, 2013 23:50 UTC (Tue) by nix (subscriber, #2304) [Link]

OK, it sounds like rm will need explicit support for this, then. The semantics you describe certainly don't fall naturally out of the readdir() semantics you suggest.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds