# Copyright (C) 2017-2020 Junjiro R. Okajima
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
Special handling for renaming a directory (DIRREN)
----------------------------------------------------------------------
First, let's assume we have a simple usecase.
- /u = /rw + /ro
- /rw/dirA exists
- /ro/dirA and /ro/dirA/file exist too
- there is no dirB on both branches
- a user issues rename("dirA", "dirB")
Now, what should aufs behave against this rename(2)?
There are a few possible cases.
A. returns EROFS.
since dirA exists on a readonly branch which cannot be renamed.
B. returns EXDEV.
it is possible to copy-up dirA (only the dir itself), but the child
entries ("file" in this case) should not be. it must be a bad
approach to copy-up recursively.
C. returns a success.
even the branch /ro is readonly, aufs tries renaming it. Obviously it
is a violation of aufs' policy.
D. construct an extra information which indicates that /ro/dirA should
be handled as the name of dirB.
overlayfs has a similar feature called REDIRECT.
Until now, aufs implements the case B only which returns EXDEV, and
expects the userspace application behaves like mv(1) which tries
issueing rename(2) recursively.
A new aufs feature called DIRREN is introduced which implements the case
D. There are several "extra information" added.
1. detailed info per renamed directory
path: /rw/dirB/$AUFS_WH_DR_INFO_PFX.
2. the inode-number list of directories on a branch
path: /rw/dirB/$AUFS_WH_DR_BRHINO
The filename of "detailed info per directory" represents the lower
branch, and its format is
- a type of the branch id
one of these.
+ uuid (not implemented yet)
+ fsid
+ dev
- the inode-number of the branch root dir
And it contains these info in a single regular file.
- magic number
- branch's inode-number of the logically renamed dir
- the name of the before-renamed dir
The "detailed info per directory" file is created in aufs rename(2), and
loaded in any lookup.
The info is considered in lookup for the matching case only. Here
"matching" means that the root of branch (in the info filename) is same
to the current looking-up branch. After looking-up the before-renamed
name, the inode-number is compared. And the matched dentry is used.
The "inode-number list of directories" is a regular file which contains
simply the inode-numbers on the branch. The file is created or updated
in removing the branch, and loaded in adding the branch. Its lifetime is
equal to the branch.
The list is refered in lookup, and when the current target inode is
found in the list, the aufs tries loading the "detailed info per
directory" and get the changed and valid name of the dir.
Theoretically these "extra informaiton" may be able to be put into XATTR
in the dir inode. But aufs doesn't choose this way because
1. XATTR may not be supported by the branch (or its configuration)
2. XATTR may have its size limit.
3. XATTR may be less easy to convert than a regular file, when the
format of the info is changed in the future.
At the same time, I agree that the regular file approach is much slower
than XATTR approach. So, in the future, aufs may take the XATTR or other
better approach.
This DIRREN feature is enabled by aufs configuration, and is activated
by a new mount option.
For the more complicated case, there is a work with UDBA option, which
is to dected the direct access to the branches (by-passing aufs) and to
maintain the cashes in aufs. Since a single cached aufs dentry may
contains two names, before- and after-rename, the name comparision in
UDBA handler may not work correctly. In this case, the behaviour will be
equivalen to udba=reval case.