| Written by: Neil Brown <neilb@suse.de> | 
 |  | 
 | Overlay Filesystem | 
 | ================== | 
 |  | 
 | This document describes a prototype for a new approach to providing | 
 | overlay-filesystem functionality in Linux (sometimes referred to as | 
 | union-filesystems).  An overlay-filesystem tries to present a | 
 | filesystem which is the result over overlaying one filesystem on top | 
 | of the other. | 
 |  | 
 | The result will inevitably fail to look exactly like a normal | 
 | filesystem for various technical reasons.  The expectation is that | 
 | many use cases will be able to ignore these differences. | 
 |  | 
 | This approach is 'hybrid' because the objects that appear in the | 
 | filesystem do not all appear to belong to that filesystem.  In many | 
 | cases an object accessed in the union will be indistinguishable | 
 | from accessing the corresponding object from the original filesystem. | 
 | This is most obvious from the 'st_dev' field returned by stat(2). | 
 |  | 
 | While directories will report an st_dev from the overlay-filesystem, | 
 | all non-directory objects will report an st_dev from the lower or | 
 | upper filesystem that is providing the object.  Similarly st_ino will | 
 | only be unique when combined with st_dev, and both of these can change | 
 | over the lifetime of a non-directory object.  Many applications and | 
 | tools ignore these values and will not be affected. | 
 |  | 
 | Upper and Lower | 
 | --------------- | 
 |  | 
 | An overlay filesystem combines two filesystems - an 'upper' filesystem | 
 | and a 'lower' filesystem.  When a name exists in both filesystems, the | 
 | object in the 'upper' filesystem is visible while the object in the | 
 | 'lower' filesystem is either hidden or, in the case of directories, | 
 | merged with the 'upper' object. | 
 |  | 
 | It would be more correct to refer to an upper and lower 'directory | 
 | tree' rather than 'filesystem' as it is quite possible for both | 
 | directory trees to be in the same filesystem and there is no | 
 | requirement that the root of a filesystem be given for either upper or | 
 | lower. | 
 |  | 
 | The lower filesystem can be any filesystem supported by Linux and does | 
 | not need to be writable.  The lower filesystem can even be another | 
 | overlayfs.  The upper filesystem will normally be writable and if it | 
 | is it must support the creation of trusted.* extended attributes, and | 
 | must provide valid d_type in readdir responses, so NFS is not suitable. | 
 |  | 
 | A read-only overlay of two read-only filesystems may use any | 
 | filesystem type. | 
 |  | 
 | Directories | 
 | ----------- | 
 |  | 
 | Overlaying mainly involves directories.  If a given name appears in both | 
 | upper and lower filesystems and refers to a non-directory in either, | 
 | then the lower object is hidden - the name refers only to the upper | 
 | object. | 
 |  | 
 | Where both upper and lower objects are directories, a merged directory | 
 | is formed. | 
 |  | 
 | At mount time, the two directories given as mount options "lowerdir" and | 
 | "upperdir" are combined into a merged directory: | 
 |  | 
 |   mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,\ | 
 | workdir=/work /merged | 
 |  | 
 | The "workdir" needs to be an empty directory on the same filesystem | 
 | as upperdir. | 
 |  | 
 | Then whenever a lookup is requested in such a merged directory, the | 
 | lookup is performed in each actual directory and the combined result | 
 | is cached in the dentry belonging to the overlay filesystem.  If both | 
 | actual lookups find directories, both are stored and a merged | 
 | directory is created, otherwise only one is stored: the upper if it | 
 | exists, else the lower. | 
 |  | 
 | Only the lists of names from directories are merged.  Other content | 
 | such as metadata and extended attributes are reported for the upper | 
 | directory only.  These attributes of the lower directory are hidden. | 
 |  | 
 | whiteouts and opaque directories | 
 | -------------------------------- | 
 |  | 
 | In order to support rm and rmdir without changing the lower | 
 | filesystem, an overlay filesystem needs to record in the upper filesystem | 
 | that files have been removed.  This is done using whiteouts and opaque | 
 | directories (non-directories are always opaque). | 
 |  | 
 | A whiteout is created as a character device with 0/0 device number. | 
 | When a whiteout is found in the upper level of a merged directory, any | 
 | matching name in the lower level is ignored, and the whiteout itself | 
 | is also hidden. | 
 |  | 
 | A directory is made opaque by setting the xattr "trusted.overlay.opaque" | 
 | to "y".  Where the upper filesystem contains an opaque directory, any | 
 | directory in the lower filesystem with the same name is ignored. | 
 |  | 
 | readdir | 
 | ------- | 
 |  | 
 | When a 'readdir' request is made on a merged directory, the upper and | 
 | lower directories are each read and the name lists merged in the | 
 | obvious way (upper is read first, then lower - entries that already | 
 | exist are not re-added).  This merged name list is cached in the | 
 | 'struct file' and so remains as long as the file is kept open.  If the | 
 | directory is opened and read by two processes at the same time, they | 
 | will each have separate caches.  A seekdir to the start of the | 
 | directory (offset 0) followed by a readdir will cause the cache to be | 
 | discarded and rebuilt. | 
 |  | 
 | This means that changes to the merged directory do not appear while a | 
 | directory is being read.  This is unlikely to be noticed by many | 
 | programs. | 
 |  | 
 | seek offsets are assigned sequentially when the directories are read. | 
 | Thus if | 
 |   - read part of a directory | 
 |   - remember an offset, and close the directory | 
 |   - re-open the directory some time later | 
 |   - seek to the remembered offset | 
 |  | 
 | there may be little correlation between the old and new locations in | 
 | the list of filenames, particularly if anything has changed in the | 
 | directory. | 
 |  | 
 | Readdir on directories that are not merged is simply handled by the | 
 | underlying directory (upper or lower). | 
 |  | 
 |  | 
 | Non-directories | 
 | --------------- | 
 |  | 
 | Objects that are not directories (files, symlinks, device-special | 
 | files etc.) are presented either from the upper or lower filesystem as | 
 | appropriate.  When a file in the lower filesystem is accessed in a way | 
 | the requires write-access, such as opening for write access, changing | 
 | some metadata etc., the file is first copied from the lower filesystem | 
 | to the upper filesystem (copy_up).  Note that creating a hard-link | 
 | also requires copy_up, though of course creation of a symlink does | 
 | not. | 
 |  | 
 | The copy_up may turn out to be unnecessary, for example if the file is | 
 | opened for read-write but the data is not modified. | 
 |  | 
 | The copy_up process first makes sure that the containing directory | 
 | exists in the upper filesystem - creating it and any parents as | 
 | necessary.  It then creates the object with the same metadata (owner, | 
 | mode, mtime, symlink-target etc.) and then if the object is a file, the | 
 | data is copied from the lower to the upper filesystem.  Finally any | 
 | extended attributes are copied up. | 
 |  | 
 | Once the copy_up is complete, the overlay filesystem simply | 
 | provides direct access to the newly created file in the upper | 
 | filesystem - future operations on the file are barely noticed by the | 
 | overlay filesystem (though an operation on the name of the file such as | 
 | rename or unlink will of course be noticed and handled). | 
 |  | 
 |  | 
 | Multiple lower layers | 
 | --------------------- | 
 |  | 
 | Multiple lower layers can now be given using the the colon (":") as a | 
 | separator character between the directory names.  For example: | 
 |  | 
 |   mount -t overlay overlay -olowerdir=/lower1:/lower2:/lower3 /merged | 
 |  | 
 | As the example shows, "upperdir=" and "workdir=" may be omitted.  In | 
 | that case the overlay will be read-only. | 
 |  | 
 | The specified lower directories will be stacked beginning from the | 
 | rightmost one and going left.  In the above example lower1 will be the | 
 | top, lower2 the middle and lower3 the bottom layer. | 
 |  | 
 |  | 
 | Non-standard behavior | 
 | --------------------- | 
 |  | 
 | The copy_up operation essentially creates a new, identical file and | 
 | moves it over to the old name.  The new file may be on a different | 
 | filesystem, so both st_dev and st_ino of the file may change. | 
 |  | 
 | Any open files referring to this inode will access the old data and | 
 | metadata.  Similarly any file locks obtained before copy_up will not | 
 | apply to the copied up file. | 
 |  | 
 | On a file opened with O_RDONLY fchmod(2), fchown(2), futimesat(2) and | 
 | fsetxattr(2) will fail with EROFS. | 
 |  | 
 | If a file with multiple hard links is copied up, then this will | 
 | "break" the link.  Changes will not be propagated to other names | 
 | referring to the same inode. | 
 |  | 
 | Symlinks in /proc/PID/ and /proc/PID/fd which point to a non-directory | 
 | object in overlayfs will not contain valid absolute paths, only | 
 | relative paths leading up to the filesystem's root.  This will be | 
 | fixed in the future. | 
 |  | 
 | Some operations are not atomic, for example a crash during copy_up or | 
 | rename will leave the filesystem in an inconsistent state.  This will | 
 | be addressed in the future. | 
 |  | 
 | Changes to underlying filesystems | 
 | --------------------------------- | 
 |  | 
 | Offline changes, when the overlay is not mounted, are allowed to either | 
 | the upper or the lower trees. | 
 |  | 
 | Changes to the underlying filesystems while part of a mounted overlay | 
 | filesystem are not allowed.  If the underlying filesystem is changed, | 
 | the behavior of the overlay is undefined, though it will not result in | 
 | a crash or deadlock. | 
 |  | 
 | Testsuite | 
 | --------- | 
 |  | 
 | There's testsuite developed by David Howells at: | 
 |  | 
 |   git://git.infradead.org/users/dhowells/unionmount-testsuite.git | 
 |  | 
 | Run as root: | 
 |  | 
 |   # cd unionmount-testsuite | 
 |   # ./run --ov |