Provided by: aufs-tools_4.14+20190211-1ubuntu1_amd64 bug

NAME

       aufs - advanced multi layered unification filesystem. version 5.x-rcN-20191021

DESCRIPTION

       Aufs  is  a  stackable  unification  filesystem  such  as  Unionfs, which unifies several directories and
       provides a merged single directory.  In the early days, aufs was entirely re-designed and  re-implemented
       Unionfs  Version  1.x  series. After many original ideas, approaches and improvements, it becomes totally
       different from Unionfs while keeping the basic features.  See Unionfs Version 1.x series  for  the  basic
       features.  Recently, Unionfs Version 2.x series begin taking some of same approaches to aufs's.

MOUNT OPTIONS

       At mount-time, the order of interpreting options is,

              •   simple flags, except xino/noxino and udba=notify

              •   branches

              •   xino/noxino

              •   udba=notify

       At remount-time, the options are interpreted in the given order, e.g. left to right.

              •   create or remove whiteout-base(.wh..wh.aufs) and whplink-dir(.wh..wh.plnk) if necessary

       br:BRANCH[:BRANCH ...] (dirs=BRANCH[:BRANCH ...])
              Adds new branches.  (cf. Branch Syntax).

              Aufs  rejects  the  branch  which  is  an ancestor or a descendant of another branch. It is called
              overlapped. When the branch is loopback-mounted directory, aufs also checks  the  source  fs-image
              file of loopback device. If the source file is a descendant of another branch, it will be rejected
              too.

              After mounting aufs or adding a branch, if you move a branch under  another  branch  and  make  it
              descendant  of  another  branch,  aufs  will not work correctly. By default (since linux-3.2 until
              linux-3.18-rc1), aufs prohibits such operation internally, but there  left  a  way  to  do.   (cf.
              Branch Syntax).

       [ add | ins ]:index:BRANCH
              Adds  a  new  branch.   The  index  begins  with  0.  Aufs creates whiteout-base(.wh..wh.aufs) and
              whplink-dir(.wh..wh.plnk) if necessary.

              If there is the same named file on the lower branch (larger index), aufs will hide the lower file.
              You  can  only  see  the  highest  file.   You  will be confused if the added branch has whiteouts
              (including diropq), they may or may not hide the lower entries.  (cf. DIAGNOSTICS).

              Even if a process have once mapped a file by mmap(2) with  MAP_SHARED  and  the  same  named  file
              exists  on  the  lower branch, the process still refers the file on the lower(hidden) branch after
              adding the branch.  If you want to update the contents of a process address  space  after  adding,
              you need to restart your process or open/mmap the file again.  (cf. Branch Syntax).

       del:dir
              Removes  a branch.  Aufs does not remove whiteout-base(.wh..wh.aufs) and whplink-dir(.wh..wh.plnk)
              automatically.  For example, when you add a RO branch which  was  unified  as  RW,  you  will  see
              whiteout-base or whplink-dir on the added RO branch.

              If  a  process  is  referencing  the file/directory on the deleting branch (by open, mmap, current
              working directory, etc.), aufs will return an error EBUSY. In this case,  a  script  ‘aubusy’  (in
              aufs-util.git  and  aufs2-util.git) is useful to identify which process (and which file) makes the
              branch busy.

       mod:BRANCH
              Modifies the permission flags of the branch.  Aufs creates or removes  whiteout-base(.wh..wh.aufs)
              and/or whplink-dir(.wh..wh.plnk) if necessary.

              If the branch permission is been changing ‘rw’ to ‘ro’, and a process is mapping a file by mmap(2)
              on the branch, the process may or may not be  able  to  modify  its  mapped  memory  region  after
              modifying  branch  permission flags.  Additionally when you enable CONFIG_IMA (in linux-2.6.30 and
              later), IMA may produce some wrong messages. But this is equivalent when the filesystem is changed
              ‘ro’ in emergency.  (cf. Branch Syntax).

       append:BRANCH
              equivalent to ‘add:(last index + 1):BRANCH’.  (cf. Branch Syntax).

       prepend:BRANCH
              equivalent to ‘add:0:BRANCH.’  (cf. Branch Syntax).

       xino=filename
              Use  external  inode  number  bitmap  and  translation table.  When CONFIG_AUFS_EXPORT is enabled,
              external inode generation table too.  It is set to <FirstWritableBranch>/.aufs.xino by default, or
              /tmp/.aufs.xino.  Comma character in filename is not allowed.

              The  files  are  created per an aufs and per a branch filesystem, and unlinked. So you cannot find
              this file, but it exists and is read/written frequently by aufs.  When the specified file  already
              exists,  then mount(8) returns an error.  (cf. External Inode Number Bitmap, Translation Table and
              Generation Table).

              If you enable CONFIG_SYSFS, the path of xino files are not shown in /proc/mounts (and  /etc/mtab),
              instead  it  is  shown in <sysfs>/fs/aufs/si_<id>/xi_path.  Otherwise, it is shown in /proc/mounts
              unless it is not the default path.

       noxino Stop using external inode number bitmap and translation table.

              If you use this option, Some applications will not work correctly.   (cf.  External  Inode  Number
              Bitmap, Translation Table and Generation Table).

       trunc_xib
              Truncate  the  external  inode  number  bitmap file. The truncation is done automatically when you
              delete a branch unless you do not  specify  ‘notrunc_xib’  option.   (cf.  External  Inode  Number
              Bitmap, Translation Table and Generation Table).

       notrunc_xib
              Stop  truncating  the  external  inode number bitmap file when you delete a branch.  (cf. External
              Inode Number Bitmap, Translation Table and Generation Table).

       trunc_xino_path=BRANCH | itrunc_xino=INDEX
              Truncate the external inode number translation table per branch. The branch can  be  specified  by
              path  or  index  (its origin is 0).  Sometimes the size of a xino file for tmpfs branch grows very
              big. If you don't like such situation, try "mount  -o  remount,trunc_xino_path=BRANCH  /your/aufs"
              (or  itrunc_xino=INDEX).  It  will  shrink  the  xino  file for BRANCH. These options are one time
              actions. So the size may grow again. In order to make it work automatically  when  necessary,  try
              trunc_xino  option.   These  options  are  already  implemented,  but its design is not fixed (cf.
              External Inode Number Bitmap, Translation Table and Generation Table).

       trunc_xino | notrunc_xino
              Enable (or disable) the automatic truncation of xino files.  The truncation is done by  discarding
              the  internal  "hole"  (unused  blocks).   The default is notrunc_xino.  These options are already
              implemented, but its design is not fixed (cf. External Inode Number Bitmap, Translation Table  and
              Generation Table).

              TODO: customizable two values for upper limit

       acl
       noacl  Enable or disable POSIX Access Control List. This feature is totally depending upon the branch fs.
              If your branch fs doesn't support POSIX ACL, these options are meaningless. CONFIG_FS_POSIX_ACL is
              required.

       create_policy | create=CREATE_POLICY
       copyup_policy | copyup | cpup=COPYUP_POLICY
              Policies  to  select one among multiple writable branches. The default values are ‘create=tdp’ and
              ‘cpup=tdp’.  link(2) and rename(2) systemcalls have an exception. In aufs, they try keeping  their
              operations  in  the  branch  where  the source exists.  (cf. Policies to Select One among Multiple
              Writable Branches).

       dio    Enable Direct I/O support (including Linux AIO), and always make open(2)  with  O_DIRECT  success.
              But  if  your  branch filesystem doesn't support it, then the succeeding I/O will fail (cf, Direct
              I/O).

       nodio  Disable Direct I/O (including Linux AIO), and always make open(2) with  O_DIRECT  fail.   This  is
              default value (cf, Direct I/O).

       verbose | v
              Print some information.  Currently, it is only busy file (or inode) at deleting a branch.

       noverbose | quiet | q | silent
              Disable ‘verbose’ option.  This is default value.

       sum    df(1)/statfs(2)  returns  the  total  number of blocks and inodes of all branches.  When the block
              size of all branches are not equal, aufs chooses the smallest one  and  calculate  the  number  of
              blocks  (including  bavail  and  bfree).   Note  that  there are cases that systemcalls may return
              ENOSPC, even if df(1)/statfs(2) shows that aufs has some free space/inode.

       nosum  Disable ‘sum’ option.  This is default value.

       dirwh=N
              Watermark to remove a dir actually at rmdir(2) and rename(2).

              If the target dir which is being removed or  renamed  (destination  dir)  has  a  huge  number  of
              whiteouts,  i.e.  the  dir is empty logically but physically, the cost to remove/rename the single
              dir may be very high.  It is required  to  unlink  all  of  whiteouts  internally  before  issuing
              rmdir/rename  to the branch.  To reduce the cost of single systemcall, aufs renames the target dir
              to a whiteout-ed temporary name and invokes a pre-created  kernel  thread  to  remove  whiteout-ed
              children and the target dir.  The rmdir/rename systemcall returns just after kicking the thread.

              When  the  number  of  whiteout-ed children is less than the value of dirwh, aufs remove them in a
              single systemcall instead of passing another thread.  This value is ignored  when  the  branch  is
              NFS.  The default value is 3.

       rdblk=N
              Specifies a size of internal VDIR block which is allocated at a time in byte.  The VDIR block will
              be allocated several times when necessary. If your directory has tens of thousands of  files,  you
              may want to expand this size.  The default value is defined as 512.  The size has to be lager than
              NAME_MAX (usually 255) and kmalloc-able (the maximum limit depends on your system. at least  128KB
              is  available  for  every  system).   If  you set it to zero, then the internal estimation for the
              directory size becomes ON, and aufs sets the value for the directory individually.  Sometimes  the
              estimated value may be inappropriate since the estimation is not so clever. Setting zero is useful
              when you use RDU (cf. VDIR/readdir(3) in user-space (RDU).  Otherwise it may  be  a  pressure  for
              kernel  memory  space.   Anytime you can reset the value to default by specifying rdblk=def.  (cf.
              Virtual or Vertical Directory Block).

       rdhash=N
              Specifies a size of internal VDIR hash table which is used to compare the  file  names  under  the
              same   named  directory  on  multiple  branches.   The  VDIR  hash  table  will  be  allocated  in
              readdir(3)/getdents(2), rmdir(2)  and  rename(2)  for  the  existing  target  directory.  If  your
              directory  has tens of thousands of files, you may want to expand this size.  The default value is
              defined as 32.  The size has to be lager than zero, and it will be  multiplied  by  4  or  8  (for
              32-bit  and  64-bit  respectively,  currently). The result must be kmalloc-able (the maximum limit
              depends on your system. at least 128KB is available for every system).  If you  set  it  to  zero,
              then  the  internal  estimation  for  the  directory  becomes  ON, and aufs sets the value for the
              directory individually.  Sometimes the estimated value may be inappropriate since  the  estimation
              is  not  so  clever.  Setting  zero  is useful when you use RDU (cf. VDIR/readdir(3) in user-space
              (RDU).  Otherwise it may be a pressure for kernel memory space.  Anytime you can reset  the  value
              to default by specifying rdhash=def.  (cf. Virtual or Vertical Directory Block).

       plink
       noplink
              Specifies  to  use  ‘pseudo  link’  feature  or  not.  The default is ‘plink’ which means use this
              feature.  (cf. Pseudo Link)

       clean_plink
              Removes all pseudo-links in memory.  In order to make pseudo-link permanent, use ‘auplink’ utility
              just  before  one  of  these  operations,  unmounting  aufs, using ‘ro’ or ‘noplink’ mount option,
              deleting a branch from aufs, adding a branch into  aufs,  or  changing  your  writable  branch  as
              readonly.   If you installed both of /sbin/mount.aufs and /sbin/umount.aufs, and your mount(8) and
              umount(8) support them, ‘auplink’ utility will be executed automatically and  flush  pseudo-links.
              (cf. Pseudo Link)

       udba=none | reval | notify
              Specifies  the level of UDBA (User's Direct Branch Access) test.  (cf. User's Direct Branch Access
              and Inotify Limitation).

       diropq=whiteouted | w | always | a
              Specifies whether mkdir(2) and rename(2) dir case make the created directory ‘opaque’ or not.   In
              other  words,  to  create ‘.wh..wh..opq’ under the created or renamed directory, or not to create.
              When you specify diropq=w or diropq=whiteouted, aufs will not create it if the directory  was  not
              whiteout-ed  or  opaqued.  If  the  directory  was  whiteout-ed or opaqued, the created or renamed
              directory will be opaque.  When you specify diropq=a or diropq==always, aufs will always create it
              regardless  the directory was whiteout-ed/opaqued or not.  The default value is diropq=w, it means
              not to create when it is unnecessary.

       warn_perm
       nowarn_perm
              Adding a branch, aufs  will  issue  a  warning  about  uid/gid/permission  of  the  adding  branch
              directory,  when  they  differ from the existing branch's. This difference may or may not impose a
              security risk.  If you are sure that there is no  problem  and  want  to  stop  the  warning,  use
              ‘nowarn_perm’ option.  The default is ‘warn_perm’ (cf. DIAGNOSTICS).

       shwh
       noshwh By  default (noshwh), aufs doesn't show the whiteouts and they just hide the same named entries in
              the lower branches. The whiteout itself also never be appeared.  If  you  enable  CONFIG_AUFS_SHWH
              and  specify  ‘shwh’  option, aufs will show you the name of whiteouts with keeping its feature to
              hide the lowers.  Honestly speaking, I am rather confused with this ‘visible  whiteouts.’   But  a
              user  who  originally  requested this feature wrote a nice how-to document about this feature. See
              Tips file in the aufs CVS tree.

       dirperm1
       nodirperm1
              By default (nodirperm1), aufs respects the directory permission  bits  on  all  branches  equally,
              which  means  if  the  permission bits for a directory on a lower readonly branch prohibits you to
              read, then you cannot read even if you run "chmod a+rx" (and aufs copies it up).  With this option
              (dirperm1),  the  behavior  changes  and  aufs  checks the permission bits of the directory on the
              topmost branch and the permission bits on all lower branches are ignored.   In  other  words,  you
              read a directory even if the lower readonly branch fs prohibits it by its permission bits.

              This  feature may invite a security risk similar to the world writable upper branch. As this case,
              dirperm1 option will produce a warning too.

       dirren
       nodirren
              Activates or deactivates the special handling for renaming a directory (DIRREN) feature.  In order
              to  use  this  feature,  CONFIG_AUFS_DIRREN  has to be enabled and ‘dirren’ mount option has to be
              specified too.

              By default (nodirren), aufs returns an error with EXDEV for the  case  of  rename(2)  a  directory
              which  exists  on  the  multiple  branches.  Note  that DIRREN is slow (I have not yet measured it
              though) since it loads and saves the list  of  the  inode-numbers  per  branch  and  the  detailed
              information per branch.

              Note  that  ‘udba=notify’  option may not work with DIRREN, since it is based upon the name, while
              DIRREN handles both of before- and after-renamed names. The internal name comparison may not  work
              correctly. In this case, aufs behaves like the default ‘udba=reval’ is specified.

Module Parameters

       brs=1 | 0
              Specifies to use the branch path data file under sysfs or not.

              If  the  number  of  your  branches  is large or their path is long and you meet the limitation of
              mount(8) ro /etc/mtab, you need to enable CONFIG_SYSFS and set aufs module parameter brs=1.

              When this parameter is set as 1, aufs  does  not  show  ‘br:’  (or  dirs=)  mount  option  through
              /proc/mounts  (and  /etc/mtab).  So  you can keep yourself from the page limitation of mount(8) or
              /etc/mtab.  Aufs shows branch paths through <sysfs>/fs/aufs/si_XXX/brNNN.  Actually the file under
              sysfs has also a size limitation, but I don't think it is harmful.

              There  is  one  more  side  effect in setting 1 to this parameter.  If you rename your branch, the
              branch path written in /etc/mtab will be obsoleted and the future remount will meet some error due
              to  the  unmatched parameters (Remember that mount(8) may take the options from /etc/mtab and pass
              them to the systemcall).  If you set 1, /etc/mtab will not hold the branch path and you  will  not
              meet  such  trouble.  On the other hand, the entries for the branch path under sysfs are generated
              dynamically. So it must not be obsoleted.  But I don't think users  want  to  rename  branches  so
              often.

              If CONFIG_SYSFS is disable, this parameter is always set to 0.

       allow_userns= Y | N
              Allows  an  unprivileged  mount  under  user  namespace.   Userns  mount to put AUFS into a chroot
              environment can be useful while it as a security worry.  This  parameter  sets  an  internal  flag
              FS_USERNS_MOUNT and allows userns unconditionally.

              See  the  discussion in http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg04266.html
              and its thread.

              The default is ‘N’.  If CONFIG_USER_NS is disabled, this parameter is meaningless.

       sysrq=key
              Specifies MagicSysRq key for debugging aufs.  You need to enable both  of  CONFIG_MAGIC_SYSRQ  and
              CONFIG_AUFS_DEBUG.  Currently this is for developers only.  The default is ‘a’.

       debug= 0 | 1
              Specifies disable(0) or enable(1) debug print in aufs.  This parameter can be changed dynamically.
              You need to enable CONFIG_AUFS_DEBUG.  Currently this is for developers only.  The default is  ‘0’
              (disable).

Entries under Sysfs and Debugfs

       See linux/Documentation/ABI/*/{sys,debug}fs-aufs.

Gain the performance in return for the features

       In  order  to gain a better performance, there are a few steps. They are essentially to drop the features
       from aufs, and to gain a performance in return for them. You don't have to drop all of them.  It  may  be
       too much. Try step by step with measuring the performance you want using your typical workload.

   Patch file
       As  my  recommendation,  there  is  one  patch  file in aufs[34]-standalone.git tree, tmpfs-idr.patch. It
       introduces IDR for the tmpfs inode-number management, and has an effect to prevent  the  size  of  aufs's
       XINO/XIB files to grow rapidly. If you don't use TMPFS as your branch, the patch won't be necessary.

   Configuration
       Disable  all  unnecessary  ones  except CONFIG_AUFS_RDU (readdir in user-space). RDU requires an external
       user-space library libau.so, but it is so effective particularly for the  directory  which  has  tens  of
       thousands  of  files.  To  use RDU, users have to set LD_PRELOAD environment variable. If he doesn't set,
       this configuration will do no  harm.  The  size  of  aufs  module  will  be  larger  a  little,  but  the
       time-performance (speed) won't be damaged.

   Mount option
       As  a  first step, I'd recommend you to try ‘dirperm1’, ‘udba=none’ and ‘nodirren.’  The former prohibits
       aufs to dig down the lower branches in checking the directory permission bits, and the latter makes  aufs
       not to watch the external modification, eg. by-passing aufs (users' direct branch access).  These options
       are able to be changed and restored anytime.

       For the second step, try ‘notrunc_xino’ and ‘notrunc_xib.’  It is not always when they are so  effective.
       Especially if you have applied tmpfs-idr.patch, then the effect is small since the most of effect is done
       by the patch. But there surely exists their effect. In this case, the size of  XINO  and  XIB  will  grow
       only, not truncated. In other word, it is a time-vs-space issue.

       For  the third and last step, try ‘noplink’ and ‘noxino.’  With these options, aufs behaves un-POSIX-ly a
       little, which means lose the features maintaining the hard-link (pseudo-link) and the inode numbers. Some
       behaviours  may surprise users, but many internal process will be skipped and the result performance will
       be better.

       For your convenience, mount.aufs(8) provides ‘droplvl=N’ mount option. ‘N’ means the  level  (see  above)
       and  you  can  specify  either 1, 2 or 3 (and their negative values, will be described soon). It is not a
       real mount option, which means it is  not  interpreted  by  kernel-space.  When  this  option  is  given,
       mount.aufs(8)  translates  it into several other (real) mount options, and passes them to kernel-space as
       if they were originally specified. Currently there are 3 levels.

              1   noatime,dirperm1,udba=none,nodirren

              2   notrunc_xino,notrunc_xib

              3   noplink,noxino
       For     example,     when     you     give     ‘droplvl=3’,     mount.aufs(8)     converts     it      to
       ‘noatime,dirperm1,udba=none,nodirren,notrunc_xino,notrunc_xib,noplink,noxino’.      Also    mount.aufs(8)
       provides ‘ephemeral’ mount option which is equivalent to ‘droplvl=3’.

       For your more convenience, mount.aufs(8) provides the negative values for each level. Note that there  is
       no  level  0,  and no difference between 2 and -2.  The options in ‘notrunc_xino,notrunc_xib’ are already
       implemented, but their design is not fixed (cf. External  Inode  Number  Bitmap,  Translation  Table  and
       Generation  Table).  And the current default value is ‘notrunc_xino,notrunc_xib’, so technically speaking
       ‘notrunc_xino,notrunc_xib’ is less important.

              -1  relatime,nodirperm1,udba=reval

              -2  notrunc_xino,notrunc_xib

              -3  plink,xino=/tmp/.aufs.xino
       The purpose of the negative values are to revert the effect of the positive values (counter-level).  Note
       the  XINO  path  in ‘-3’. In order to revert ‘noxino’ in ‘droplvl=3’, you need to specify the actual XINO
       path, but it is totally depending upon your environment, and mount.aufs(8) doesn't know about it and does
       nothing  but  provides  the  default  path.  So generally it will be necessary to append ‘xino=<your XINO
       path>’ to ‘droplvl=-3’.

       Reverting ‘noatime’ to ‘relatime’ is rather tricky. It is due to the behaviours of mount(8) and mount(2).
       You need to run ‘remount,strictatime’ before ‘remount,droplvl=-1’.

       Also  note  that  the order of the mount options. For example, if you want to drop some features but keep
       UDBA level as default, then you can specify ‘droplvl=1,udba=reval’. If you write  the  reverse  order  as
       ‘udba=reval,droplvl=1’,  then  ‘udba=none’  in  ‘droplvl=1’ takes its effect and the udba level specified
       before droplvl will lose.

Git work-tree and aufs

       Git has a cache called ‘index’ file. In this cache there are the identity of the files individually. Here
       ‘identity’  means  a  pair of struct stat.st_{dev,ino}. (Git may consider other stat members too. But the
       essential part of the identity is still dev and ino.)

       Since aufs is a virtual filesystem and manages the inode numbers, it provides its own st_dev and  st_ino.
       They  differ  from  the  ‘index’ cache in git, and some git operations have to refresh the ‘index’ cache,
       which may take long time.  For instance,

              •   /branch/ro has 0x0801 for its st_dev

              •   /branch/ro/proj.git/fileA has 100 for its st_ino

              •   /branch/ro/proj.git/.git/index contains {0x0801,100} as fileA's
                    identity

              •   mount /u as /branch/rw + /branch/ro, /u is aufs

              •   we can see the contents of /u/proj.git/.git/index is equivalent to
                    /branch/ro/proj.git/.git/index

       In this case, aufs provides {0x0802,110} (for example) for fileA's  identity,  which  is  different  from
       /branch/ro/proj.git/fileA.  If you run git-diff or something, the behaviour of git differs a little.

              •   git issues stat(2) and gets st_{dev,ino} pair.

              •   git compares the gotten pair and the one in the index file.

              •   when they are different from each other, git opens the file, reads all
                    data, compares it with the cached data, and finds there is nothing
                    changed.

              •   if the gotten pair is equal to the one in the index file, then
                    open/read/compare steps will be skipped.

       This  issue  can  happen when you copy the git working tree to somewhere else. All files identity will be
       changed by the copy and the cached  identity  in  index  file  will  be  obsoleted.   Once  you  complete
       git-status or something, the index file will be updated, and full open/read/compare steps will not happen
       anymore.  This behaviour of git can be controlled by git's configuration core.checkstat.

Branch Syntax

       dir_path[ =permission [ + attribute ] ]
       permission := rw | ro | rr
       attribute := wh | nolwh | unpin | coo_reg | coo_all | moo | fhsm | icexsec | icexsys | icextr | icexusr |
       icexoth | icex
              dir_path  is  a  directory  path.   The  keyword  after ‘dir_path=’ is a permission flags for that
              branch.  Comma, colon and the permission flags string (including ‘=’) in the path are not allowed.

              Any (ordinary) filesystem can be a branch, But some are not accepted such like sysfs,  procfs  and
              unionfs.   If  you specify such filesystems as an aufs branch, aufs will return an error saying it
              is unsupported.  Also aufs expects the writable branch filesystem supports  the  maximum  filename
              length as NAME_MAX. The readonly branch filesystem can be shorter.

              Cramfs in linux stable release has strange inodes and it makes aufs confused. For example,
              $ mkdir -p w/d1 w/d2
              $ > w/z1
              $ > w/z2
              $ mkcramfs w cramfs
              $ sudo mount -t cramfs -o ro,loop cramfs /mnt
              $ find /mnt -ls
                  76    1 drwxr-xr-x   1 jro      232            64 Jan  1  1970 /mnt
                   1    1 drwxr-xr-x   1 jro      232             0 Jan  1  1970 /mnt/d1
                   1    1 drwxr-xr-x   1 jro      232             0 Jan  1  1970 /mnt/d2
                   1    1 -rw-r--r--   1 jro      232             0 Jan  1  1970 /mnt/z1
                   1    1 -rw-r--r--   1 jro      232             0 Jan  1  1970 /mnt/z2

              All  these  two  directories  and two files have the same inode with one as their link count. Aufs
              cannot handle such inode correctly.  Currently, aufs involves a tiny workaround for  such  inodes.
              But  some  applications  may not work correctly since aufs inode number for such inode will change
              silently.  If you do not have any empty files, empty  directories  or  special  files,  inodes  on
              cramfs will be all fine.

              A  branch should not be shared as the writable branch between multiple aufs. A readonly branch can
              be shared.

              The maximum number of branches is configurable at compile time (127 by default).

              When an unknown permission or attribute is given, aufs sets ro to that branch silently.

   Permission
       rw     Readable and writable branch. Set as default for the first branch.  If the  branch  filesystem  is
              mounted as readonly, you cannot set it ‘rw.’

       ro     Readonly  branch  and it has no whiteouts on it.  Set as default for all branches except the first
              one. Aufs never issue both of write operation and lookup operation for whiteout to this branch.

       rr     Real readonly branch, special case of ‘ro’, for natively readonly branch. Assuming the  branch  is
              natively  readonly,  aufs  can  optimize  some  internal  operation.  For  example, if you specify
              ‘udba=notify’ option, aufs does not set fsnotify or inotify for the things on rr branch.   Set  by
              default  for  a  branch whose fs-type is either ‘iso9660’, ‘cramfs’ or ‘romfs’ (and ‘squashfs’ for
              linux-2.6.29 and later).

              When your branch exists on slower device and you have some capacity on your hdd, you may  want  to
              try ulobdev tool in ULOOP sample.  It can cache the contents of the real devices on another faster
              device, so you will be able to get the better access performance.   The  ulobdev  tool  is  for  a
              generic  block  device,  and the ulohttp is for a filesystem image on http server.  If you want to
              spin down your hdd to save the battery life or something, then you may want to use ulobdev to save
              the access to the hdd, too.  See $AufsCVS/sample/uloop in detail.

   Attribute
       wh     Readonly  branch  and it has/might have whiteouts on it.  Aufs never issue write operation to this
              branch, but lookup for whiteout.  Use this as ‘<branch_dir>=ro+wh’.

       nolwh  Usually, aufs creates a whiteout as a hardlink on a writable  branch.  This  attributes  prohibits
              aufs  to  create  the  hardlinked  whiteout,  including the source file of all hardlinked whiteout
              (.wh..wh.aufs.)  If you do not like a hardlink, or your writable branch does not support  link(2),
              then  use  this  attribute.   But I am afraid a filesystem which does not support link(2) natively
              will fail in other place such as copy-up.  Use this as ‘<branch_dir>=rw+nolwh’.  Also you may want
              to try ‘noplink’ mount option, while it is not recommended.

       unpin  By default, aufs sets ‘pin’ to the branch dir, which means that users cannot remove nor rename the
              branch top dir as if it were a mount-point.  In some cases and some users may need to  rename  the
              branch top dir. So this attribute is implemented. If you specify ‘unpin’ as a branch attribute, it
              stops behaving as a mount-point and you can rename the branch top dir.  Needless to  say,  if  you
              remove the branch top dir, then aufs cannot work.

              Since  linux-3.18-rc1,  this attribute became meaningless. It is simply ignored and all branch top
              dir behaves as this attribute is always specified.

       coo_reg | coo_all
              Copy-up on open.  By default the internal copy-up is executed when it is really necessary.  It  is
              not done when a file is opened for writing, but when any writing is done.

              These  attributes are for not only the readonly branches but also the writable branches. ‘coo_reg’
              handles the regular files only and ‘coo_all’ handles the regular files plus the  directories.  All
              special  files  and symlinks will not be copied-up.  Additionally NFS server may not issue open(2)
              when NFS client issues open(2). This behavior means that the file may not be  copied-up  when  NFS
              client issues open(2).

              The  internal  copy-up  operation  by  these  attributes  are  unrelated to the COPYUP_POLICY (cf.
              Policies to Select One among Multiple Writable Branches), which means  ‘copy-up  on  open’  always
              choose  the nearest upper writable branch.  Even if there are multiple writable branches set these
              attributes, the internal copy-up operation is done once, not recursively.

              Users who have many (over 100) branches want to know and analyze when and what file is  copied-up.
              To  insert  a new upper branch which contains such files only may improve the performance of aufs.
              The ‘copy-up on open’ itself may  not  be  so  attractive,  but  combining  with  a  feature  FHSM
              (File-based Hierarchy Storage Management) will be useful.

       moo    Move-up  on  open.   Very similar attribute to coo except moo unlinks the copy-up source after the
              successful operation. This attribute handles the regular  files  only,  and  obviously  cannot  be
              specified to the readonly branch.

              Users  can  specify all these attributes for a single writable branch, but only the last specified
              one has its effect. Other coo/moo attributes are silently ignored.

              The ‘move-up on open’ itself may  not  be  so  attractive,  but  combining  with  a  feature  FHSM
              (File-based Hierarchy Storage Management) will be useful.

       fhsm   File-based  Hierarchy  Storage  Management.   Specifies  that this branch is a participant of aufs
              FHSM. Refer to aufs_fhsm(5) in detail.

       icexsec | icexsys | icextr | icexusr | icexoth | icex
              Ignore the error on copying-up/down XATTR.  When an  internal  copy-up/down  happens,  aufs  tries
              copying  all  XATTRs.  Here an error can happen because of the XATTR support on the dst branch may
              different from the src branch. If you know how the branch supports or unsupports  XATTR,  you  can
              specify these attributes.  ‘icexsec’ means to ignore an error on copying-up/down XATTR categorized
              as "security" (for LSM and capability). And ‘icexsys,’ ‘icextr,’ and ‘icexusr,’ are  for  "system"
              (for  posix  ACL),  "trusted"  and  "user"  categories  individually.   ‘icexoth’ is for any other
              category.     To     be     convenient,     `icex`     sets     them      all.       See      also
              linux/Documentation/filesystems/aufs/design/06xattr.txt.

              These attributes are essentially for the writable branches. But when you use aufs_fhsm(5), you may
              want to specify them to the readonly  branches  too.  So  they  are  available  for  the  readonly
              branches.

External Inode Number Bitmap, Translation Table and Generation Table (xino)

       Aufs  uses one external bitmap file and one external inode number translation table files per an aufs and
       per a branch filesystem by default.  Additionally when CONFIG_AUFS_EXPORT is enabled, one external  inode
       generation  table is added.  The bitmap (and the generation table) is for recycling aufs inode number and
       the others are a table for converting an inode number on a branch to an aufs inode  number.  The  default
       path  is  ‘first  writable  branch’/.aufs.xino.  If there is no writable branch, the default path will be
       /tmp/.aufs.xino.

       If you enable CONFIG_SYSFS, the path of xino files are not shown in /proc/mounts (and /etc/mtab), instead
       it  is shown in <sysfs>/fs/aufs/si_<id>/xi_path.  Otherwise, it is shown in /proc/mounts unless it is not
       the default path.

       Those files are always opened and read/write by aufs frequently.  If your writable  branch  is  on  flash
       memory device, it is recommended to put xino files on other than flash memory by specifying ‘xino=’ mount
       option.

       The maximum file size of the bitmap is, basically, the amount of the number  of  all  the  files  on  all
       branches  divided  by  8  (the number of bits in a byte).  For example, on a 4KB page size system, if you
       have 32,768 (or 2,599,968) files in aufs world, then the maximum file size  of  the  bitmap  is  4KB  (or
       320KB).

       The  maximum  file  size of the table will be ‘max inode number on the branch x size of an inode number’.
       For example in 32bit environment,

       $ df -i /branch_fs
       /dev/hda14           2599968  203127 2396841    8% /branch_fs

       and /branch_fs is an branch of the aufs. When the inode number is assigned contiguously (without ‘hole’),
       the  maximum xino file size for /branch_fs will be 2,599,968 x 4 bytes = about 10 MB. But it might not be
       allocated all of disk blocks.  When the inode number is assigned discontinuously,  the  maximum  size  of
       xino file will be the largest inode number on a branch x 4 bytes.  Additionally, the file size is limited
       to LLONG_MAX or the s_maxbytes in filesystem's superblock (s_maxbytes may be smaller than LLONG_MAX).  So
       the support-able largest inode number on a branch is less than 2305843009213693950 (LLONG_MAX/4-1).  This
       is the current limitation of aufs.  Note that the xino-array feature which was introduced in aufs4.14 and
       later made this limitation obsolete.

       On  64bit environment, this limitation becomes more strict and the supported largest inode number is less
       than LLONG_MAX/8-1.  In order to estimate the size of the table for your readonly branch fs, try

       $ echo $((4 * $(sudo find /branch_fs -xdev -printf "%i\n" |
            sort -n | tail -n 1)))

       For 64bit environment, replace 4 by 8 in above equation.

       The xino files are always hidden, i.e. removed. So you cannot  do  ‘ls  -l  xino_file’.   If  you  enable
       CONFIG_DEBUG_FS, you can check these information through <debugfs>/aufs/<si_id>/{xib,xi[0-9]*,xigen}. xib
       is for the bitmap file, xi0 ix for the first branch, and xi1 is for the next. xigen is for the generation
       table.  xib and xigen are in the format of,

       <blocks>x<block size> <file size>

       Note  that  a  filesystem usually has a feature called pre-allocation, which means a number of blocks are
       allocated automatically, and then deallocated silently when the filesystem thinks they  are  unnecessary.
       You  do  not  have to be surprised the sudden changes of the number of blocks, when your filesystem which
       xino files are placed supports the pre-allocation feature.

       The rests are hidden xino file information in the format of,

       <file count>, <blocks>x<block size> <file size>

       If the file count is larger than 1, it means some of your branches are on the  same  filesystem  and  the
       xino  file  is  shared  by them.  Note that the file size may not be equal to the actual consuming blocks
       since xino file is a sparse file, i.e. a hole in a file which does not consume any disk blocks.

       Once you unmount aufs, the xino files for that aufs are totally gone.  It means that the inode number  is
       not permanent across umount or shutdown.

       The xino files should be created on the filesystem except NFS.  If your first writable branch is NFS, you
       will need to specify xino file path other than NFS.  Also if you are going to  remove  the  branch  where
       xino  files exist or change the branch permission to readonly, you need to use xino option before del/mod
       the branch.

       The bitmap file and the table can be truncated.  For example, if you  delete  a  branch  which  has  huge
       number  of  files,  many inode numbers will be recycled and the bitmap will be truncated to smaller size.
       Aufs does this automatically when a branch is deleted.  You can truncate  it  anytime  you  like  if  you
       specify  ‘trunc_xib’  mount  option.  But when the accessed inode number was not deleted, nothing will be
       truncated.  The truncation is essentially equivalent to

       $ cp --sparse=always <current xino file> <new xino file> &&
            rm <current xino file>

       It means that you have two xino files during the copy, and you should pay attention to the free space  of
       the  filesystem  where  the xino file is located.  If the free space is not large enough to hold two xino
       files temporary during the copy, then the truncation fails and the xino file will go on growing. For such
       case, you should move the xino file to another larger partition, and move it back to where it was (if you
       want). To do this, use ‘xino=’ mount option. During this move, the xino file is truncated automatically.

       If you do not want to truncate it (it may be slow) when you delete a branch, specify ‘notrunc_xib’  after
       ‘del’  mount  option.   For  the  table,  see  trunc_xino_path=BRANCH,  itrunc_xino=INDEX, trunc_xino and
       notrunc_xino option.

       If you do not want to use xino, use noxino mount option. Use this  option  with  care,  since  the  inode
       number  may  be  changed  silently  and  unexpectedly  anytime.   For  example,  rmdir failure, recursive
       chmod/chown/etc to a large and deep directory or anything else.  And  some  applications  will  not  work
       correctly.  If you want to change the xino default path, use xino mount option.

       After  you  add branches, the persistence of inode number may not be guaranteed.  At remount time, cached
       but unused inodes are discarded.  And the newly appeared inode may have different  inode  number  at  the
       next access time. The inodes in use have the persistent inode number.

       When  aufs  assigned an inode number to a file, and if you create the same named file on the upper branch
       directly, then the next time you access the file, aufs may assign another inode number to the  file  even
       if  you  use  xino  option.   Some applications may treat the file whose inode number has been changed as
       totally different file.

Pseudo Link (hardlink over branches)

       Aufs supports ‘pseudo link’ which is a logical hard-link over branches (cf. ln(1) and link(2)).  In other
       words,  a  copied-up  file  by  link(2)  and  a copied-up file which was hard-linked on a readonly branch
       filesystem.

       When you have files named fileA and fileB which are  hardlinked  on  a  readonly  branch,  if  you  write
       something  into  fileA,  aufs copies-up fileA to a writable branch, and write(2) the originally requested
       thing to the copied-up fileA. On the writable branch, fileA is not hardlinked.  But aufs remembers it was
       hardlinked,  and  handles fileB as if it existed on the writable branch, by referencing  fileA's inode on
       the writable branch as fileB's inode.

       Once you unmount aufs, the plink info for that aufs kept in memory are totally gone.  It means  that  the
       pseudo-link is not permanent.  If you want to make plink permanent, try ‘auplink’ utility just before one
       of these operations, unmounting your aufs, using ‘ro’ or ‘noplink’ mount option, deleting a  branch  from
       aufs, adding a branch into aufs, or changing your writable branch to readonly.

       This  utility  will  reproduces  all  real  hardlinks  on  a writable branch by linking them, and removes
       pseudo-link info in memory and temporary link on the writable branch.  Since  this  utility  access  your
       branches directly, you cannot hide them by ‘mount --bind /tmp /branch’ or something.

       If  you  are  willing  to  rebuild your aufs with the same branches later, you should use auplink utility
       before you umount your aufs.  If you installed both of /sbin/mount.aufs and /sbin/umount.aufs,  and  your
       mount(8)  and  umount(8)  support  them,  ‘auplink’  utility  will  be  executed  automatically and flush
       pseudo-links.

       During this utility is running, it puts aufs into the pseudo-link maintenance mode. In  this  mode,  only
       the  process  which  began  the maintenance mode (and its child processes) is allowed to operate in aufs.
       Some other processes which are not related to the pseudo-link will be allowed to run too,  but  the  rest
       have  to  return an error or wait until the maintenance mode ends. If a process already acquires an inode
       mutex (in VFS), it has to return an error.

       Due to the fact that the pseudo-link maintenance mode is operated via  procfs,  the  pseudo-link  feature
       itself (including the related mount options) depends upon CONFIG_PROC_FS too.

       # auplink /your/aufs/root flush
       # umount /your/aufs/root
       or
       # auplink /your/aufs/root flush
       # mount -o remount,mod:/your/writable/branch=ro /your/aufs/root
       or
       # auplink /your/aufs/root flush
       # mount -o remount,noplink /your/aufs/root
       or
       # auplink /your/aufs/root flush
       # mount -o remount,del:/your/aufs/branch /your/aufs/root
       or
       # auplink /your/aufs/root flush
       # mount -o remount,append:/your/aufs/branch /your/aufs/root

       The plinks are kept both in memory and on disk. When they consumes too much resources on your system, you
       can use the ‘auplink’ utility at anytime and throw away the unnecessary pseudo-links in safe.

       Additionally, the ‘auplink’ utility is very useful for some security reasons.  For example, when you have
       a  directory  whose  permission flags are 0700, and a file who is 0644 under the 0700 directory. Usually,
       all files under the 0700 directory are private and no one else can see the file. But when  the  directory
       is 0711 and someone else knows the 0644 filename, he can read the file.

       Basically,  aufs pseudo-link feature creates a temporary link under the directory whose owner is root and
       the permission flags are 0700.  But when the writable branch is NFS, aufs sets  0711  to  the  directory.
       When  the  0644  file is pseudo-linked, the temporary link, of course the contents of the file is totally
       equivalent, will be created under the 0711 directory. The filename will be generated by its inode number.
       While it is hard to know the generated filename, someone else may try peeping the temporary pseudo-linked
       file by his software tool which may try the name from one to MAX_INT or something.   In  this  case,  the
       0644  file  will  be  read  unexpectedly.   I  am afraid that leaving the temporary pseudo-links can be a
       security hole.  It makes sense  to  execute  ‘auplink  /your/aufs/root  flush’  periodically,  when  your
       writable branch is NFS.

       When your writable branch is not NFS, or all users are careful enough to set 0600 to their private files,
       you do not have to worry about this issue.

       If you do not want this feature, use ‘noplink’ mount option.

   The behaviors of plink and noplink
       This sample shows that the ‘f_src_linked2’ with ‘noplink’ option cannot follow the link.

       none on /dev/shm/u type aufs (rw,xino=/dev/shm/rw/.aufs.xino,br:/dev/shm/rw=rw:/dev/shm/ro=ro)
       $ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
       ls: ./copied: No such file or directory
       15 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
       15 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
       22 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ./f_src_linked
       22 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ./f_src_linked2
       $ echo FOO >> f_src_linked
       $ cp f_src_linked copied
       $ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
       15 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
       15 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
       36 -rw-r--r--  2 jro jro 6 Dec 22 11:03 ../rw/f_src_linked
       53 -rw-r--r--  1 jro jro 6 Dec 22 11:03 ./copied
       22 -rw-r--r--  2 jro jro 6 Dec 22 11:03 ./f_src_linked
       22 -rw-r--r--  2 jro jro 6 Dec 22 11:03 ./f_src_linked2
       $ cmp copied f_src_linked2
       $

       none on /dev/shm/u type aufs (rw,xino=/dev/shm/rw/.aufs.xino,noplink,br:/dev/shm/rw=rw:/dev/shm/ro=ro)
       $ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
       ls: ./copied: No such file or directory
       17 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
       17 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
       23 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ./f_src_linked
       23 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ./f_src_linked2
       $ echo FOO >> f_src_linked
       $ cp f_src_linked copied
       $ ls -li ../r?/f_src_linked* ./f_src_linked* ./copied
       17 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked
       17 -rw-r--r--  2 jro jro 2 Dec 22 11:03 ../ro/f_src_linked2
       36 -rw-r--r--  1 jro jro 6 Dec 22 11:03 ../rw/f_src_linked
       53 -rw-r--r--  1 jro jro 6 Dec 22 11:03 ./copied
       23 -rw-r--r--  2 jro jro 6 Dec 22 11:03 ./f_src_linked
       23 -rw-r--r--  2 jro jro 6 Dec 22 11:03 ./f_src_linked2
       $ cmp copied f_src_linked2
       cmp: EOF on f_src_linked2
       $

       If you add a branch which has fileA or fileB, aufs does not follow the pseudo link. The file on the added
       branch  has  no  relation  to  the  same  named file(s) on the lower branch(es).  If you use noxino mount
       option, pseudo link will not work after the kernel shrinks the inode cache.

       This feature will not work for squashfs before version 3.2 since its inode is tricky.  When the inode  is
       hardlinked, squashfs inodes has the same inode number and correct link count, but the inode memory object
       is different. Squashfs inodes (before v3.2) are generated for each, even they are hardlinked.

User's Direct Branch Access (UDBA)

       UDBA means a modification to a branch filesystem manually or directly, e.g. bypassing aufs.   While  aufs
       is  designed and implemented to be safe after UDBA, it can make yourself and your aufs confused. And some
       information like aufs inode will be incorrect.  For example, if you rename a file on a  branch  directly,
       the  file  on  aufs  may  or may not be accessible through both of old and new name.  Because aufs caches
       various information about the files on branches. And the cache still remains after UDBA.

       Aufs has a mount option named ‘udba’ which specifies the test level  at  access  time  whether  UDBA  was
       happened or not.

       udba=none
              Aufs  trusts  the  dentry  and the inode cache on the system, and never test about UDBA. With this
              option, aufs runs fastest, but it may show you incorrect data.  Additionally, if you often  modify
              a branch directly, aufs will not be able to trace the changes of inodes on the branch. It can be a
              cause of wrong behavior, deadlock or anything else.

              It is recommended to use this option only when you are sure that nobody access a file on a branch.
              It  might  be  difficult  for  you to achieve real ‘no UDBA’ world when you cannot stop your users
              doing ‘find / -ls’ or something.  If you really want to forbid all of your users to UDBA, here  is
              a  trick  for  it.   With this trick, users cannot see the branches directly and aufs runs with no
              problem, except ‘auplink’ utility.  But if you are not familiar with aufs,  this  trick  may  make
              yourself confused.

              # d=/tmp/.aufs.hide
              # mkdir $d
              # for i in $branches_you_want_to_hide
              > do
              >    mount -n --bind $d $i
              > done

              When  you  unmount  the  aufs, delete/modify the branch by remount, or you want to show the hidden
              branches again, unmount the bound /tmp/.aufs.hide.

              # umount -n $branches_you_want_to_unbound

              If you use FUSE filesystem as an aufs branch which supports hardlink,  you  should  not  set  this
              option,  since  FUSE  makes inode objects for each hardlinks (at least in linux-2.6.23). When your
              FUSE filesystem maintains them at link/unlinking, it is equivalent to ‘direct branch  access’  for
              aufs.

       udba=reval
              Aufs  tests  only  the existence of the file which existed. If the existed file was removed on the
              branch directly, aufs discard the cache about the file and re-lookup  it.  So  the  data  will  be
              updated.   This  test  is  at  minimum level to keep the performance and ensure the existence of a
              file.  This is default and aufs runs still fast.

              This rule leads to some unexpected situation, but I hope it is harmless. Those are totally depends
              upon cache. Here are just a few examples.

              •   If the file is cached as negative or not-existed, aufs does not test it. And the file is still
                  handled as negative after a user created the file on a branch directly. If  the  file  is  not
                  cached, aufs will lookup normally and find the file.

              •   When  the  file  is  cached  as  positive  or  existed, and a user created the same named file
                  directly on the upper branch. Aufs detects the cached inode of the file is still existing  and
                  will show you the old (cached) file which is on the lower branch.

              •   When  the  file  is  cached  as  positive or existed, and a user renamed the file by rename(2)
                  directly. Aufs detects the inode of the file is still existing. You may or may not see both of
                  the old and new files.  TODO: If aufs also tests the name, we can detect this case.

       If  your outer modification (UDBA) is rare and you can ignore the temporary and minor differences between
       virtual aufs world and real branch filesystem, then try this mount option.

       udba=notify
              Aufs sets either ‘fsnotify’ or ‘inotify’ to all the  accessed  directories  on  its  branches  and
              receives the event about the dir and its children. It consumes resources, cpu and memory. And I am
              afraid that the performance will be hurt, but it is  most  strict  test  level.   There  are  some
              limitations  of  linux  inotify,  see also Inotify Limitation.  So it is recommended to leave udba
              default option usually, and set it to notify by remount when you need it.

              When a user accesses the file which was notified UDBA before, the cached data about the file  will
              be  discarded  and aufs re-lookup it. So the data will be updated.  When an error condition occurs
              between UDBA and aufs operation, aufs will return an error, including EIO.  To  use  this  option,
              you  need to enable CONFIG_INOTIFY and CONFIG_AUFS_HINOTIFY.  In linux-2.6.31, CONFIG_FSNOTIFY was
              introduced  and  CONFIG_INOTIFY  was  listed  in  Documentation/feature-removal-schedule.txt.   In
              aufs2-31 and later (until CONFIG_INOTIFY is removed actually), you can choose either ‘fsnotify’ or
              ‘inotify’ in configuration. Whichever you choose, specify ‘udba=notify’, and aufs interprets it as
              an abstract name.

              To rename/rmdir a directory on a branch directory may reveal the same named directory on the lower
              branch. Aufs tries re-looking up the renamed directory and the revealed  directory  and  assigning
              different  inode  number  to them. But the inode number including their children can be a problem.
              The inode numbers will be changed silently, and aufs may  produce  a  warning.  If  you  rename  a
              directory  repeatedly  and  reveal/hide  the  lower  directory,  then aufs may confuse their inode
              numbers too. It depends upon the system cache.

              When you make a directory in aufs and mount other filesystem on it, the directory in  aufs  cannot
              be  removed  expectedly  because it is a mount point. But the same named directory on the writable
              branch can be removed, if someone wants. It is just an empty directory, instead of a mount  point.
              Aufs cannot stop such direct rmdir, but produces a warning about it.

              If  the  pseudo-linked file is hardlinked or unlinked on the branch directly, its inode link count
              in aufs may be incorrect. It is recommended to flush the pseudo-links by auplink script.

              In linux-4.2 (and later, probably), for the exported aufs, NFS doesn't show the  changes  at  once
              and returns ESTALE even if you set udba=notify.  It is a natural behaviour of linux NFS's and aufs
              can do nothing about it. Probably simple "sleep 1" will help.

Linux Inotify Limitation

       Unfortunately, current inotify (linux-2.6.18) has some limitations, and aufs must derive it.

   IN_DELETE, removing file on NFS
       When a file on a NFS branch is deleted directly, inotify may or may not fire IN_DELETE event. It  depends
       upon  the  status  of  dentry  (DCACHE_NFSFS_RENAMED  flag).   In this case, the file on aufs seems still
       exists. Aufs and any user can see the file.  Since linux-3.15-rc1, this behavior has been changed and NFS
       fires the event from itself.

   IN_IGNORED, deleted rename target
       When  a  file/dir on a branch is unlinked by rename(2) directly, inotify fires IN_IGNORED which means the
       inode is deleted. Actually, in some cases, the inode survives. For example, the rename target  is  linked
       or  opened.  In  this  case,  inotify  watch  set by aufs is removed by VFS and inotify.  And aufs cannot
       receive the events anymore. So aufs may show you incorrect data about the file/dir.

Virtual or Vertical Directory Block (VDIR)

       In order to provide the merged view of file listing, aufs builds internal directory block on memory.  For
       readdir,  aufs  performs  readdir()  internally  for  each  dir  on  branches,  merges their entries with
       eliminating the whiteout-ed ones, and sets it to the opened file (dir) object. So the file object has its
       entry  list  until  it  is  closed.  The  entry  list  will be updated when the file position is zero (by
       rewinddir(3)) and becomes obsoleted.

       The merged result is cached in the corresponding inode object and maintained by a customizable  life-time
       option.   Note: the mount option ‘rdcache=<sec>’ is still under considering and its description is hidden
       from this manual.

       Some people may call it can be a security hole or invite DoS attack since the opened and once  readdir-ed
       dir  (file  object)  holds its entry list and becomes a pressure for system memory. But I would say it is
       similar to files under /proc or /sys. The virtual files in them also  holds  a  memory  page  (generally)
       while  they  are opened. When an idea to reduce memory for them is introduced, it will be applied to aufs
       too.

       The dynamically allocated memory block for the name of entries has  a  unit  of  512  bytes  by  default.
       During  building  dir  blocks,  aufs  creates hash list (hashed and divided by 32 by default) and judging
       whether the entry is whiteout-ed by its upper branch or already listed.

       These values are suitable for normal environments. But you may have tens of thousands of  files  or  very
       long  filenames  under  a  single  directory.  For  such cases, you may need to customize these values by
       specifying rdblk= and rdhash= aufs mount options.

       For instance, there are 97 files under my /bin, and the total name length is 597 bytes.

       $ \ls -1 /bin | wc
            97      97     597

       Strictly speaking, 97 end-of-line codes are included. But it is OK since aufs VDIR also stores  the  name
       length in 1 byte. In this case, you do not need to customize the default values. 597 bytes filenames will
       be stored in 2 VDIR memory blocks (597 < 512 x 2).  And 97 filenames are distributed among 32  lists,  so
       one  list  will  point  4  names  in  average.  To  judge  the names is whiteout-ed or not, the number of
       comparison will be 4. 2 memory allocations and 4 comparison costs low (even if the  directory  is  opened
       for a long time). So you do not need to customize.

       If your directory has tens of thousands of files, the you will need to specify rdblk= and rdhash=.

       $ ls -U /mnt/rotating-rust | wc -l
       1382438

       In  this  case,  assuming the average length of filenames is 6, in order to get better time performance I
       would recommend to set $((128*1024)) or $((64*1024))  for  rdblk,  and  $((8*1024))  or  $((4*1024))  for
       rdhash.  You can change these values of the active aufs mount by "mount -o remount".

       This  customization  is not for reducing the memory space, but for reducing time for the number of memory
       allocation and the name comparison. The larger value is faster, in general.  Of  course,  you  will  need
       system memory. This is a generic "time-vs-space" problem.

Using libau.so

       There  is  a  dynamic  shared  object  library  called libau.so in aufs-util or aufs2-util GIT tree. This
       library provides several useful functions which wrap the standard library functions such as,

              •   readdir, readdir_r, closedir

              •   pathconf, fpathconf

       To use libau.so,

              •   install by "make install_ulib" under aufs-util (or aufs2-util) GIT tree

              •   set the environment variable "LD_PRELOAD=libau.so", or configure /etc/ld.so.preload

              •   set the environment variable "LIBAU=all"

              •   and run your application.

       If you use pathconf(3)/fpathconf(3) with _PC_LINK_MAX for aufs, you need to use libau.so.

   VDIR/readdir(3) in user-space (RDU)
       If you have a directory which has tens of thousands of files, aufs VDIR  consumes  much  memory.  So  the
       program  which reads a huge directory may produce an "out of memory" or "page allocation failure" message
       in the syslog, due to the memory fragmentation or real starvation.  In  this  case,  RDU  (readdir(3)  in
       user-space)  may help you.  Because the kernel memory space cannot be swappable and consuming much can be
       pure memory pressure, while it is not true in user-space.

       If you enable CONFIG_AUFS_RDU at compiling aufs, install libau.so, and set  some  environment  variables,
       then  you  can  use RDU.  Just simply run your application.  The dynamic link library libau.so implements
       another readdir routine, and all readdir(3) calls in your application will be handled by  libau.so.   For
       setting environment variables, you may want to use a shell function or alias such like this.

       $ auls()
       > {
       >    LD_PRELOAD=/your/path/to/libau.so
       >    LIBAU=all
       >    #AUFS_RDU_BLK= set if you want
       >    ls $@
       > }

       $ alias auls="LD_PRELOAD=/your/path/to/libau.so LIBAU=all ls"

       When  you  call  readdir(3), the dynamic linker calls readdir in libau.so.  If it finds the passed dir is
       NOT aufs, it calls the usual readdir(3).  It the dir is aufs, then libau.so gets all filenames under  the
       dir  by  aufs  specific  ioctl(2)s,  instead  of regular readdir(3), and merges them by itself.  In other
       words, libau.so moves the memory consumption in kernel-space to user-space.

       While it is good to stop consuming much memory in kernel-space, sometimes the speed  performance  may  be
       damaged  a  little as a side effect.  It is just a little, I hope. At the same time, I won't be surprised
       if readdir(3) runs faster.

       It is recommended to specify rdblk=0 when you use this library.

       If your directory is not so huge and you don't meet the out of memory situation, probably you don't  need
       this library. The original VDIR in kernel-space is still alive, and you can live without libau.so.

   pathconf(_PC_LINK_MAX)
       Since  some  implementation  of  pathconf(3)  (and  fpathconf(3))  for  _PC_LINK_MAX  decides  the target
       filesystem type and returns the pre-defined constant value, when aufs is unknown to the library, it  will
       return  the  default  value  (127).   Actually  the maximum number of the link count in aufs inherits the
       topmost writable branch filesystem's. But the standard pathconf(3) will not return the correct value.

       To support such case, libau.so provides a wrapper for pathconf(3) (and fpathconf(3)). When the  parameter
       is  _PC_LINK_MAX,  the wrapper checks whether the given parameter refers aufs or not. If it is aufs, then
       it will get the maximum link count from the topmost writable branch internally. Otherwise, it behaves  as
       normal pathconf(3) transparently.

   Note
       Since  this  is a dynamically linked library, it is unavailable if your application is statically linked.
       And ld.so(8) ignores LD_PRELOAD when the application  is  setuid/setgid-ed  unless  the  library  is  not
       setuid/setgid-ed.  It  is  a  generic  rule of dynamically linked library.  Additionally the functions in
       libau.so are unavailable in these cases too.

              •   the application or library issues getdents(2) instead of readdir(3).

              •   the library which calls readdir(3) internally. e.g. scandir(3).

              •   the library which calls pathconf(3) internally.

Copy On Write, or aufs internal copyup and copydown

       Every stackable filesystem which implements copy-on-write supports the copyup feature. The feature is  to
       copy  a file/dir from the lower branch to the upper internally. When you have one readonly branch and one
       upper writable branch, and you append a string to a file which exists on the readonly branch,  then  aufs
       will copy the file from the readonly branch to the writable branch with its directory hierarchy. It means
       one write(2) involves  several  logical/internal  mkdir(2),  creat(2),  read(2),  write(2)  and  close(2)
       systemcalls  before  the  actual  expected  write(2)  is  performed.  Sometimes  it may take a long time,
       particularly when the file is very large.  If CONFIG_AUFS_DEBUG  is  enabled,  aufs  produces  a  message
       saying `copying a large file.'

       You  may  see  the  message  when you change the xino file path or truncate the xino/xib files. Sometimes
       those files can be large and may take a long time to handle them.

Policies to Select One among Multiple Writable Branches

       Aufs has some policies to select one among multiple writable branches when you are going to  write/modify
       something.  There  are  two  kinds  of  policies,  one is for newly create something and the other is for
       internal  copy-up.   You  can  select  them  by  specifying  mount   option   ‘create=CREATE_POLICY’   or
       ‘cpup=COPYUP_POLICY.’  These policies have no meaning when you have only one writable branch. If there is
       some meaning, it must hurt the performance.

   Exceptions for Policies
       In every cases below, even if the policy says that the branch where a new file should be created is /rw2,
       the file will be created on /rw1.

       •   If there is a readonly branch with ‘wh’ attribute above the policy-selected branch and the parent dir
           is marked as opaque, or the target (creating) file is whiteout-ed  on  the  ro+wh  branch,  then  the
           policy  will be ignored and the target file will be created on the nearest upper writable branch than
           the ro+wh branch.
           /aufs = /rw1 + /ro+wh/diropq + /rw2
           /aufs = /rw1 + /ro+wh/wh.tgt + /rw2

       •   If there is a writable branch above the policy-selected branch and the parent dir is marked as opaque
           or  the target file is whiteout-ed on the branch, then the policy will be ignored and the target file
           will be created on the highest one among the upper writable branches who has diropq or  whiteout.  In
           case of whiteout, aufs removes it as usual.
           /aufs = /rw1/diropq + /rw2
           /aufs = /rw1/wh.tgt + /rw2

       •   link(2)  and  rename(2)  systemcalls  are  exceptions in every policy.  They try selecting the branch
           where the source exists as possible since copyup a large file will take long time. If  it  can't  be,
           ie. the branch where the source exists is readonly, then they will follow the copyup policy.

       •   There  is  an  exception  for  rename(2)  when  the target exists.  If the rename target exists, aufs
           compares the index of the branches where the source and the  target  are  existing  and  selects  the
           higher one. If the selected branch is readonly, then aufs follows the copyup policy.

   Policies for Creating
       create=tdp | top-down-parent
              Select  the  highest  branch where the parent dir exists. If this branch is not writable, internal
              copyup will happen.  The policy for this copyup  is  always  ‘bottom-up.’   This  is  the  default
              policy.

       create=tdmfs:low[:second]
              Select  the  highest writable branch regardless the existence of the parent dir. If the free space
              of this branch is less than ‘low’ bytes, then the next highest writable branch will  be  selected.
              If  the  free  space of all writable branches are less than ‘low’ bytes, then create=mfs policy is
              applied.  For the duration (‘second’) parameter, see create=mfs[:second] below.

              FHSM (File-based Hierarchy Storage Management) may bring you the very similar result, and is  more
              flexible than this policy.

       create=rr | round-robin
              Selects  a  writable branch in round robin. When you have two writable branches and creates 10 new
              files, 5 files will be created for each branch.  mkdir(2) systemcall is  an  exception.  When  you
              create 10 new directories, all are created on the same branch.

       create=mfs[:second] | most-free-space[:second]
              Selects  a  writable  branch  which has most free space. In order to keep the performance, you can
              specify the duration (‘second’) which makes aufs hold the index of last selected  writable  branch
              until the specified seconds expires. The seconds is up to 3600 seconds.  The first time you create
              something in aufs after the specified seconds expired, aufs checks the amount of free space of all
              writable  branches by internal statfs call and the held branch index will be updated.  The default
              value is 30 seconds.

       create=mfsrr:low[:second]
              Selects a writable branch in most-free-space  mode  first,  and  then  round-robin  mode.  If  the
              selected branch has less free space than the specified value ‘low’ in bytes, then aufs re-tries in
              round-robin mode.  Try an arithmetic expansion of shell which is defined by POSIX.   For  example,
              $((10  *  1024 * 1024)) for 10M.  You can also specify the duration (‘second’) which is equivalent
              to the ‘mfs’ mode.

       create=pmfs[:second]
              Selects a writable branch where the parent dir exists, such as  tdp  mode.  When  the  parent  dir
              exists  on multiple writable branches, aufs selects the one which has most free space, such as mfs
              mode.

       create=pmfsrr:low[:second]
              Firstly selects a writable branch as the  ‘pmfs  mode.’   If  there  are  less  than  ‘low’  bytes
              available  on  all  branches  where the parent dir exists, aufs selects the one which has the most
              free space regardless the parent dir.

   Policies for Copy-Up
       cpup=tdp | top-down-parent
              Equivalent to the same named policy for create.  This is the default policy.

       cpup=bup | bottom-up-parent
              Selects the writable branch where the parent dir exists and the branch is nearest upper  one  from
              the copyup-source.

       cpup=bu | bottom-up
              Selects  the nearest upper writable branch from the copyup-source, regardless the existence of the
              parent dir.

Exporting Aufs via NFS

       Aufs is supporting NFS-exporting.  Since aufs has no actual block device, you  need  to  add  NFS  ‘fsid’
       option at exporting. Refer to the manual of NFS about the detail of this option.

       There are some limitations or requirements.

              •   The branch filesystem must support NFS-exporting.

              •   NFSv2  is  not supported. When you mount the exported aufs from your NFS client, you will need
                  to some NFS options like v3 or nfsvers=3, especially if it is nfsroot.

              •   If the size of the NFS file handle on your branch filesystem is large, aufs will not  be  able
                  to handle it. The maximum size of NFSv3 file handle for a filesystem is 64 bytes. Aufs uses 24
                  bytes for 32bit system, plus 12 bytes for 64bit system. The rest is a room for a  file  handle
                  of a branch filesystem.

              •   The  External  Inode  Number Bitmap, Translation Table and Generation Table (xino) is required
                  since NFS file handle is based upon inode number.  The  mount  option  ‘xino’  is  enabled  by
                  default.     The    external    inode    generation    table    and    its    debugfs    entry
                  (<debugfs>/aufs/si_*/xigen) is created when CONFIG_AUFS_EXPORT is enabled even  if  you  don't
                  export  aufs  actually.   The size of the external inode generation table grows only, never be
                  truncated. You might need to pay attention to the free space  of  the  filesystem  where  xino
                  files are placed. By default, it is the first writable branch.

              •   The  branch  filesystems  must  be accessible, which means ‘not hidden.’  It means you need to
                  ‘mount --move’ when you use initramfs and switch_root(8), or chroot(8).

              •   Since aufs has several filename prefixes reserved, the maximum filename length is shorter than
                  ordinary 255. Actually 242 (defined as ${AUFS_MAX_NAMELEN}). This value should be specified as
                  ‘namlen=’ when you mount NFS.  The name of the branch top directory has  another  limit.  When
                  you  set  the  module parameter ‘brs’ to 1 (default), then you can see the branch pathname via
                  /sys/fs/aufs/si_XXX/brNNN. Here it is printed with its branch  attributes  such  as  ‘=rw’  or
                  ‘=ro+wh’.  Since  all  the  sysfs entries have the size limit of 4096 bytes, the length of the
                  branch path becomes shorter than 4096. Actually you can specify any branch  with  much  longer
                  names, but you will meet some troubles when you remount later because remounting runs the aufs
                  mount helper internally and it tries reading /sys/fs/aufs/si_XXX/brNNN.

Direct I/O

       The Direct I/O (including Linux AIO) is a filesystem (and its backend  block  device)  specific  feature.
       And there is a minor problem around the aufs internal copyup. Assume you have two branches, lower RO ext2
       and upper RW tmpfs. As you know ext2 supports Direct I/O, but tmpfs doesn't. When a ‘fileA’ exists in the
       lower  ext2,  and you write something into after opening it with O_DIRECT, then aufs behaves like this if
       the mount option ‘dio’ is specified.

              •   The application issues open(O_DIRECT);

                  Aufs opens the file in the lower ext2 and succeeds.

              •   The application issues write("something");

                  Aufs copies-up the file from the lower ext2 to the upper tmpfs, and re-opens the file in tmpfs
                  with O_DIRECT. It fails and returns an error.

       This  behavior  may  be  a  problem since application expects the error should be returned from the first
       open(2) instead of the later write(2), when the filesystem doesn't support Direct  I/O.   (But,  in  real
       world,  I don't think there is an application which doesn't check the error from write(2). So it won't be
       a big problem actually).

       If the file exists in the upper tmpfs, the first open(2) will fail expectedly. So there is no problem  in
       this  case.  But  the  problem may happen when the internal copyup happens and the behavior of the branch
       differs from each other. As long as the feature depends upon the filesystem, this  problem  will  not  be
       solved.  So  aufs  sets  `nodio`  by  default,  which means all Direct I/O are disabled, and open(2) with
       O_DIRECT always fails. If you want to use Direct I/O AND all your  writable  branches  support  it,  then
       specify ‘dio’ option to make it in effect.

       With the similar reason, fcntl(F_SETFL, O_DIRECT) will not work for aufs file descriptor.

Possible problem of the inode number in TMPFS

       Although it is rare to happen, TMPFS has a problem about its inode number management. Actually TMPFS does
       not maintain the inode number at all. Linux kernel has a global 32bit number for general  use   of  inode
       number,  and  TMPFS  uses  it  while  most of (real) filesystem maintains its inode number by itself. The
       global number can wrap around regardless the inode number is still in use. This MAY cause a problem.

       For instance, when /your/tmpfs/fileA has 10 as its inode number, the same value (10) may be assigned to a
       newly  created  file  /your/tmpfs/fileB.  Some applications do not care the duplicated inode numbers, but
       others, including AUFS, will be really confused by this situation.

       If your writable branch FS is TMPFS and the inode number wraps around, aufs will not work  correctly.  It
       is  recommended  to  use one of FS on HDD, ramdisk+ext2 or tmpfs+FSimage+loopback mount, as your writable
       branch FS.  Or apply a patch in aufs4-standalone.git. It addresses this tmpfs-inum-assignment problem  by
       modifying the source file other than aufs.

Dentry and Inode Caches

       If you want to clear caches on your system, there are several tricks for that. If your system ram is low,
       try ‘find /large/dir -ls > /dev/null’.  It will read many inodes and dentries and cache  them.  Then  old
       caches will be discarded.  But when you have large ram or you do not have such large directory, it is not
       effective.

       If you want to discard cache within a certain filesystem,  try  ‘mount  -o  remount  /your/mntpnt’.  Some
       filesystem may return an error of EINVAL or something, but VFS discards the unused dentry/inode caches on
       the specified filesystem.

Compatible/Incompatible with Unionfs Version 1.x Series

       Ignoring ‘delete’ option, and to keep filesystem consistency, aufs tries writing something  to  only  one
       branch  in  a  single  systemcall. It means aufs may copyup even if the copyup-src branch is specified as
       writable.  For example, you have two writable branches and a large regular file  on  the  lower  writable
       branch.  When  you  issue rename(2) to the file on aufs, aufs may copyup it to the upper writable branch.
       If this behavior is not what you want, then you should rename(2) it on the lower branch directly.

       And there is a simple shell script  ‘unionctl’  under  sample  subdirectory,  which  is  compatible  with
       unionctl(8)  in  Unionfs  Version  1.x series, except --query action.  This script executes mount(8) with
       ‘remount’ option and uses add/del/mod aufs mount options.  If you are familiar with Unionfs  Version  1.x
       series  and  want  to  use  unionctl(8),  you  can  try this script instead of using mount -o remount,...
       directly.  Aufs does not support ioctl(2) interface.  This script is highly depending  upon  mount(8)  in
       util-linux-2.12p  package,  and  you  need  to  mount /proc to use this script.  If your mount(8) version
       differs, you can try modifying this script. It is very easy.  The unionctl script is just  for  a  sample
       usage of aufs remount interface.

       Aufs uses the external inode number bitmap and translation table by default.

       The default branch permission for the first branch is ‘rw’, and the rest is ‘ro.’

       The  whiteout  is  for  hiding  files  on  lower branches. Also it is applied to stop readdir going lower
       branches.  The latter case is called ‘opaque directory.’ Any whiteout is an empty file, it means whiteout
       is  just  an  mark.  In the case of hiding lower files, the name of whiteout is ‘.wh.<filename>.’  And in
       the case of stopping readdir, the name  is  ‘.wh..wh..opq’.   All  whiteouts  are  hardlinked,  including
       ‘<writable branch top dir>/.wh..wh.aufs.’

       The  hardlink  on an ordinary (disk based) filesystem does not consume inode resource newly. But in linux
       tmpfs, the number of free inodes will be decremented by link(2). It is recommended to  specify  nr_inodes
       option to your tmpfs if you meet ENOSPC. Use this option after checking by ‘df -i.’

       When  you  rmdir or rename-to the dir who has a number of whiteouts, aufs rename the dir to the temporary
       whiteout-ed name like ‘.wh..wh.<dir>.<4-digits hex>.’  Then remove it after actual operation.  cf.  mount
       option ‘dirwh.’

Incompatible with an Ordinary Filesystem

       stat(2)  returns  the  inode info from the first existence inode among the branches, except the directory
       link count.  Aufs computes the directory link count larger than the exact value usually, in order to keep
       UNIX  filesystem  semantics,  or in order to shut find(1) mouth up.  The size of a directory may be wrong
       too, but it has to do no harm.  The timestamp of a directory will not be updated when a file  is  created
       or removed under it, and it was done on a lower branch.

       The test for permission bits has two cases. One is for a directory, and the other is for a non-directory.
       In the case of a directory, aufs checks the permission bits of all existing  directories.  It  means  you
       need  the  correct  privilege  for  the  directories  including  the  lower  branches.   The  test  for a
       non-directory is more simple. It checks only the topmost inode.

       statfs(2) returns the information of the first branch info except namelen when ‘nosum’ is specified  (the
       default).  The  namelen  is  decreased  by  the  whiteout prefix length.  Although the whiteout prefix is
       essentially ‘.wh.’, to support rmdir(2) and rename(2) (when the target directory  already  existed),  the
       namelen  is decreased more since the name will be renamed to ‘.wh..wh.<dir>.<4-digits hex>’ as previously
       described.  And the block size may differ from st_blksize which is obtained by stat(2).

       The whiteout prefix (.wh.) is reserved on all branches. Users should not handle the filename begins  with
       this  prefix.  In order to future whiteout, the maximum filename length is limited by the longest value -
       4 * 2 - 1 - 4 = 242.  It means you cannot handle such long name in aufs, even if it surely exists on  the
       underlying  branch  fs.  The  readdir(3)/getdents(2)  call  show  you such name, but the d_type is set to
       DT_UNKNOWN.  It may be a violation of POSIX.

       Remember, seekdir(3) and telldir(3) are not defined in POSIX. They  may  not  work  as  you  expect.  Try
       rewinddir(3) or re-open the dir.

       If  you  dislike  the  difference  between the aufs entries in /etc/mtab and /proc/mounts, and if you are
       using mount(8) in util-linux package, then try ./mount.aufs utility. Copy the script to /sbin/mount.aufs.
       This  simple  utility  tries  updating /etc/mtab. If you do not care about /etc/mtab, you can ignore this
       utility.  Remember this utility is highly depending upon mount(8) in util-linux-2.12p  package,  and  you
       need to mount /proc.

       Since  aufs  uses  its own inode and dentry, your system may cache huge number of inodes and dentries. It
       can be as twice as all of the files in your union.  It means that unmounting or  remounting  readonly  at
       shutdown  time  may  take a long time, since mount(2) in VFS tries freeing all of the cache on the target
       filesystem.

       When you open a directory, aufs will open several directories internally.  It means  you  may  reach  the
       limit  of  the number of file descriptor.  And when the lower directory cannot be opened, aufs will close
       all the opened upper directories and return an error.

       The sub-mount under the branch of local filesystem is ignored.  For example, if you  have  mount  another
       filesystem  on  /branch/another/mntpnt,  the  files  under  ‘mntpnt’  will  be  ignored  by  aufs.  It is
       recommended to mount the sub-mount under the mounted aufs.  For example,

       # sudo mount /dev/sdaXX /ro_branch
       # d=another/mntpnt
       # sudo mount /dev/sdbXX /ro_branch/$d
       # mkdir -p /rw_branch/$d
       # sudo mount -t aufs -o br:/rw_branch:/ro_branch none /aufs
       # sudo mount -t aufs -o br:/rw_branch/${d}:/ro_branch/${d} none /aufs/another/$d

       There are several characters which are not allowed to use in a branch directory path and  xino  filename.
       See detail in Branch Syntax and Mount Option.

       The  file-lock  which means fcntl(2) with F_SETLK, F_SETLKW or F_GETLK, flock(2) and lockf(3), is applied
       to virtual aufs file only, not to the file on a branch. It means you can break the lock  by  accessing  a
       branch directly.  TODO: check ‘security’ to hook locks, as inotify does.

       Aufs respects all "security" hooks in kernel, so you can configure LSM for both of virtual aufs files and
       real branch-fs files. But there is one exception, it is the kernel function  "security_mmap_file()."  The
       function  called  inside  aufs  for a branch-fs file may cause a deadlock, so aufs stops calling it.  LSM
       settings for the virtual aufs files works as usual.

       The I/O to the named pipe or local socket are not handled by aufs, even if it exists in aufs.  After  the
       reader  and the writer established their connection if the pipe/socket are copied-up, they keep using the
       old one instead of the copied-up one.

       The fsync(2) and fdatasync(2) systemcalls return 0 which means success, even if the given file descriptor
       is  not  opened for writing.  I am afraid this behavior may violate some standards. Checking the behavior
       of fsync(2) on ext2, aufs decided to return success.

       If you want to use disk quota, you should set it up to your writable branch since aufs does not have  its
       own block device.

       When  your  aufs  is  the root directory of your system, and your system tells you some of the filesystem
       were not unmounted cleanly, try these procedure when you shutdown your system.
       # mount -no remount,ro /
       # for i in $writable_branches
       # do mount -no remount,ro $i
       # done
       If your xino file is on a hard drive, you also need to specify ‘noxino’ option or ‘xino=/your/tmpfs/xino’
       at remounting root directory.

       To  rename(2)  directory may return EXDEV even if both of src and tgt are on the same aufs, when ‘dirren’
       is not  specified.  When  the  rename-src  dir  exists  on  multiple  branches  and  the  lower  dir  has
       child/children,  aufs  has  to copyup all his children. It can be recursive copyup. Current aufs does not
       support such huge copyup operation at one time in kernel space, instead produces a  warning  and  returns
       EXDEV.   Generally, mv(1) detects this error and tries mkdir(2) and rename(2) or copy/unlink recursively.
       So the result is harmless.  If your application which issues rename(2) for a directory does  not  support
       EXDEV,  it  will not work on aufs.  Also this specification is applied to the case when the src directory
       exists on the lower readonly branch and it has child/children.

       While it is rare, users can open a removed file with a little help from procfs.

              •   open a file and get its descriptor

              •   remove the file

              •   generate a string ‘/proc/PID/fd/N’

              •   open the same file using the generated string

              •

       This operation is a little difficult for aufs since aufs allows the direct access to branches (by-passing
       aufs), and it is hard to distinguish the case of this.

              •   remove a file on a branch directly (by-passing aufs)

              •   open the file via aufs

       For  the  latter case, aufs detects the unmatching status between aufs cached info and the real info from
       the branch, and tries refreshing by re-lookup. Finally aufs finds the file is  removed  and  let  open(2)
       return  an  error.   For the former case, currently (linux-3.13-rc7), aufs simply follows the behavior of
       ext2 which supports for opening a non-directory but  returns  an  error  for  a  directory.   Other  than
       open(2), users may chmod(2) and chown(2) similarly (remove the file and then operate it via procfs). Ext2
       supports them too, but aufs doesn't. I don't think it a big disadvantage since users  can  fchmod(2)  and
       fchown(2) instead.

       If  a  sudden  accident such like a power failure happens during aufs is performing, and regular fsck for
       branch filesystems is completed after the disaster, you need to extra fsck for aufs writable branches. It
       is  necessary  to  check  whether  the whiteout remains incorrectly or not, eg. the real filename and the
       whiteout for it under the same parent directory. If such whiteout remains, aufs cannot  handle  the  file
       correctly.   To  check  the  consistency  from the aufs' point of view, you can use a simple shell script
       called /sbin/auchk. Its purpose is a fsck tool for aufs, and it checks the illegal whiteout, the remained
       pseudo-links  and  the  remained  aufs-temp  files.  If  they are found, the utility reports you and asks
       whether to delete or not.  It is recommended to execute /sbin/auchk for every writable branch  filesystem
       before mounting aufs if the system experienced crash.

       In  linux-v4.5, copy_file_range(2) is introduced and aufs supports it.  The systemcall supports only when
       the given two files exist on the same filesystem. In aufs  world,  two  files  must  exist  on  the  same
       physical  filesystem,  not on the logical aufs. The case of two files existing on the logically same aufs
       but physically different file system is not supported.  For example, fileA and fileB are given, and fileA
       exists  on  the lower readonly branch in aufs, and fileB exists on the upper writable branch.  When these
       two branches exist on the same filesystem, then aufs copy_file_range(2) should work.  Otherwise  it  will
       return  an  error.   In other words, aufs copy_file_range(2) doesn't incur the internal copyup since such
       behaviour doesn't fit the original purpose of copy_file_range(2).

EXAMPLES

       The mount options are interpreted from left to right at  remount-time.   These  examples  shows  how  the
       options are handled. (assuming /sbin/mount.aufs was installed)

       # mount -v -t aufs -o br:/day0:/base none /u
       none on /u type aufs (rw,xino=/day0/.aufs.xino,br:/day0=rw:/base=ro)
       # mount -v -o remount,\
            prepend:/day1,\
            xino=/day1/xino,\
            mod:/day0=ro,\
            del:/day0 \
            /u
       none on /u type aufs (rw,xino=/day1/xino,br:/day1=rw:/base=ro)

       # mount -t aufs -o br:/rw none /u
       # mount -o remount,append:/ro /u
       different uid/gid/permission, /ro
       # mount -o remount,del:/ro /u
       # mount -o remount,nowarn_perm,append:/ro /u
       #
       (there is no warning)

       When  you  use  aufs  as  root filesystem, it is recommended to consider to exclude some directories. For
       example, /tmp and /var/log are not need to stack in many cases. They do not usually need to copyup or  to
       whiteout.   Also the swapfile on aufs (a regular file, not a block device) is not supported.  In order to
       exclude the specific dir from aufs, try bind mounting.

       And there is a good sample which is for network booted diskless machines. See sample/ in detail.

DIAGNOSTICS

       When you add a branch to your union, aufs may warn you about the privilege or  security  of  the  branch,
       which is the permission bits, owner and group of the top directory of the branch.  For example, when your
       upper writable branch has a world writable top directory, a malicious user can create any  files  on  the
       writable branch directly, like copyup and modify manually. I am afraid it can be a security issue.

       When  you mount or remount your union without -o ro common mount option and without writable branch, aufs
       will warn you that the first branch should be writable.

       When you set udba other than notify and change something on your branch filesystem directly,  later  aufs
       may detect some mismatches to its cache. If it is a critical mismatch, aufs returns EIO.

       When  an  error  occurs in aufs, aufs prints the kernel message with ‘errno.’ The priority of the message
       (log level) is ERR or WARNING which depends upon the message itself.  You can convert  the  ‘errno’  into
       the  error  message by perror(3), strerror(3) or something.  For example, the ‘errno’ in the message ‘I/O
       Error, write failed (-28)’ is 28 which means ENOSPC or ‘No space left on device.’

       When CONFIG_AUFS_BR_RAMFS is enabled, you can specify ramfs as an aufs branch. Since ramfs is simple,  it
       does  not  set  the  maximum  link  count  originally.  In  aufs,  it is very dangerous, particularly for
       whiteouts. Finally aufs sets the maximum link count for ramfs. The value is 32000 which is borrowed  from
       ext2.

       After  you  prepend  a  branch  which already has some entries, aufs may report an I/O Error with "brabra
       should be negative" or something. For instance, you are going to open(2)  a  regular  file  in  aufs  and
       write(2)  something  to  it.  If  you prepend a branch between open(2) and write(2), and the added branch
       already has a same named entry other than a regular file, then you get a conflict.

              •   a regular file FOO exists in aufs.

              •   open the file FOO.

              •   add a branch which has FOO but it is a directory, and change the permission of the old  branch
                  to RO.

              •   write to the file FOO.

              •   aufs tries copying-up FOO to the upper writable branch which was recently added.

              •   aufs finds a directory FOO on the upper branch, and returns an error.
       In this situation, aufs keeps returning an error during FOO is cached in memory because it remembers that
       FOO is a regular file instead of a directory.  When the system discards the cache  about  FOO,  then  you
       will  see  the directory FOO.  In other words, you will not be able to see the directory FOO on the newly
       added branch during the file FOO on the  lower  branch  is  in  use.   This  situation  may  invite  more
       complicated  issue.  If  you unlink(2) the opened file FOO, then aufs will create a whiteout on the upper
       writable branch. And you get another conflict which is coexisting a whiteout and a real entry on the same
       branch. In this case, aufs also keeps returning an error when you try using FOO.

COPYRIGHT

       Copyright © 2005-2019 Junjiro R. Okajima

AUTHOR

       Junjiro R. Okajima