Using AUFS to Combine Directories (With AWESOME Benefits)

A stackable or unification filesystem (referred to as a “union” filesystem) is one that combines the contents of many directories into a single directory. Junjiro Okajima’s AUFS (“aufs-tools”, under Ubuntu) is such an FS. However, there are some neat attributes that tools, such as Docker, take advantage of, and this is where it really gets interesting. I’ll discuss only one such feature, here.

AUFS has the concept of “branches”, where each branch is one directory to be combined. In addition, each branch has permissions imposed upon them: essentially “read-only” or “read-write”. By default, the first branch is read-write, and all others are read-only. With this as the foundation, AUFS presents a single, stacked filesystem, but begins to impose special handling on what can be modified, internally, while providing traditional filesystem behavior, externally.

When a delete is performed on a read-only branch, AUFS performs a “whiteout”, where the readonly director[y,ies] are untouched, but hidden files are created in the writable director[y,ies] to record the changes. Similar tracking, along with any, actual, new files, occurs when any change is applied to read-only directories. This also incorporates “copy on write” functionality, where copies of files are made only by necessity, and on demand.

$ mkdir /tmp/dir_a
$ mkdir /tmp/dir_b
$ mkdir /tmp/dir_c
$ touch /tmp/dir_a/file_a
$ touch /tmp/dir_b/file_b
$ touch /tmp/dir_c/file_c

$ sudo mount -t aufs -o br=/tmp/dir_a:/tmp/dir_b:/tmp/dir_c none /mnt/aufs_test/

$ ls -l /mnt/aufs_test/
total 0
-rw-r--r-- 1 dustin dustin 0 Feb 11 23:31 file_a
-rw-r--r-- 1 dustin dustin 0 Feb 11 23:31 file_b
-rw-r--r-- 1 dustin dustin 0 Feb 11 23:31 file_c

$ ls -l /tmp/dir_c
total 0
-rw-r--r-- 1 dustin dustin 0 Feb 11 23:31 file_c

$ touch /mnt/aufs_test/new_file_in_unwritable

$ ls -l /tmp/dir_c
total 0
-rw-r--r-- 1 dustin dustin 0 Feb 11 23:31 file_c

$ ls -l /tmp/dir_a
total 0
-rw-r--r-- 1 dustin dustin 0 Feb 11 23:31 file_a
-rw-r--r-- 1 dustin dustin 0 Feb 11 23:33 new_file_in_unwritable

$ rm /mnt/aufs_test/file_c

$ ls -l /tmp/dir_c
total 0
-rw-r--r-- 1 dustin dustin 0 Feb 11 23:31 file_c

$ ls -l /tmp/dir_a
total 0
-rw-r--r-- 1 dustin dustin 0 Feb 11 23:31 file_a
-rw-r--r-- 1 dustin dustin 0 Feb 11 23:33 new_file_in_unwritable

$ ls -la /tmp/dir_a
total 16
drwxr-xr-x  4 dustin dustin 4096 Feb 11 23:35 .
drwxrwxrwt 17 root   root   4096 Feb 11 23:35 ..
-rw-r--r--  1 dustin dustin    0 Feb 11 23:31 file_a
-rw-r--r--  1 dustin dustin    0 Feb 11 23:33 new_file_in_unwritable
-r--r--r--  2 root   root      0 Feb 11 23:31 .wh.file_c
-r--r--r--  2 root   root      0 Feb 11 23:31 .wh..wh.aufs
drwx------  2 root   root   4096 Feb 11 23:31 .wh..wh.orph
drwx------  2 root   root   4096 Feb 11 23:31 .wh..wh.plnk

Notice that we use mount rather than mount.aufs. It should also be mentioned that some filesystems on which the subordinate directories might be hosted could be problematic if they’re prone to bizarre behavior. cramfs, for example, is specifically mentioned in the manpage to have certain cases under which its behavior might be considered to be undefined.

AUFS seems to especially lend itself to process-containers.

For more information, visit the homepage and Okajima’s original announcement (2008).

Advertisements