Subject: Re: union fs changes
To: der Mouse <mouse@Collatz.McRCIM.McGill.EDU>
From: Jan-Simon Pendry <jsp@sequent.com>
List: tech-kern
Date: 12/30/1994 12:53:31
% > it seems to be that the name undelete is ok.  would you have both a
% > file available for undeletion, and a whiteout in existence at the
% > same time?
% 
% You certainly could.  It might even happen relatively often.  As
% someone else already noted, if you modify a file, you then have the RO
% copy in the lower layer and the new copy in the upper layer.  If you
% then rm it, the upper-layer copy is blown away and a whiteout created.
% Then when you unwhiteout() it, the lower-layer file reappears.  I would
% expect undelete() to resurrect the upper-layer copy - ie, what was
% there before the unlink().

ok.  this sounds reasonable.  i think "undelete" is a bad
choice of name for either system call.  there are two orthogonal
operations going on here:

	* name removal
	* whiteout creation.

both of these (potentially) need inverse operations.

here's the complete set of operations which the kernel
(currently) implements relating to whiteouts:

        operation       remove    create    remove     create
                        name      name      whiteout   whiteout

        unlink          yes       -         -         possibly
        rmdir           yes       -         -         possibly
        open(CREATE)    -         yes       possibly   -
        "undelete"      -         -         yes       -
        mknod(WHT)      -         -         -         yes
        rename          yes       possibly  possibly  possibly

for the sake of some clarity, i'm going to use "remove" and "unremove"
to talk about removing a file, and then resurrecting it.  that's
remove as in the sense of remove(3).

suppose we have a filesystem which supports "unremove" - ie the total
inverse to "remove".  the real problem to be solved is how to name
the file and how to get from the name to the flat-store representation.
the user will undoubtedly want to use the name of the file itself,
so that

	remove(pathname);
	unremove(pathname);

works as expected (whatever that might be).

either the filesystem maintains the "removed" name in the
directory structure and marks it in some special way, or
the tail component-name (pathname?) is stored somewhere else
in the filesystem and the unremove operation goes there
and looks for it.

if i was changing UFS to implement this stuff i imagine i'd
go for approach #2.  any file remove converts the file to
"removed" status.  some cleaner process would need to garbage
collect whenever free disk space gets low.  that all makes "unremove"
a very special operation - not playing the standard namespace
game at all.  in this case it might well be better to have two
system calls:

	int fd = funremove(const char *pathname)

which returns an open readonly fd referencing the "removed" file,
and then

	int rc = flink(int fd, const char *pathname)

which takes a file descriptor and links it to the given pathname.
unremove would then just call these two (and close).

funremove would undoubtedly end up calling falloc, then
namei(CREATE) followed by VOP_UNREMOVE which would return
a vnode for the "removed" file (and change it to be a normal
file once more).  turning that into an fd is straightforward.
sort-of like calling VOP_CREATE.  flink(2) is trival to
implement - no new VOPs are required.

enough rambling...
either way, undelete should probably revert to the name unwhiteout.
whether you want an unremove system call, or an unremove library
routine is debatable.

jan-simon.