summaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/overlayfs/inode.c')
-rw-r--r--fs/overlayfs/inode.c31
1 files changed, 29 insertions, 2 deletions
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index cfccd91c51e3..51d780898d89 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -63,6 +63,7 @@ static int ovl_map_dev_ino(struct dentry *dentry, struct kstat *stat,
struct ovl_layer *lower_layer)
{
bool samefs = ovl_same_sb(dentry->d_sb);
+ unsigned int xinobits = ovl_xino_bits(dentry->d_sb);
if (samefs) {
/*
@@ -71,7 +72,31 @@ static int ovl_map_dev_ino(struct dentry *dentry, struct kstat *stat,
* which is friendly to du -x.
*/
stat->dev = dentry->d_sb->s_dev;
- } else if (S_ISDIR(dentry->d_inode->i_mode)) {
+ return 0;
+ } else if (xinobits) {
+ unsigned int shift = 64 - xinobits;
+ /*
+ * All inode numbers of underlying fs should not be using the
+ * high xinobits, so we use high xinobits to partition the
+ * overlay st_ino address space. The high bits holds the fsid
+ * (upper fsid is 0). This way overlay inode numbers are unique
+ * and all inodes use overlay st_dev. Inode numbers are also
+ * persistent for a given layer configuration.
+ */
+ if (stat->ino >> shift) {
+ pr_warn_ratelimited("overlayfs: inode number too big (%pd2, ino=%llu, xinobits=%d)\n",
+ dentry, stat->ino, xinobits);
+ } else {
+ if (lower_layer)
+ stat->ino |= ((u64)lower_layer->fsid) << shift;
+
+ stat->dev = dentry->d_sb->s_dev;
+ return 0;
+ }
+ }
+
+ /* The inode could not be mapped to a unified st_ino address space */
+ if (S_ISDIR(dentry->d_inode->i_mode)) {
/*
* Always use the overlay st_dev for directories, so 'find
* -xdev' will scan the entire overlay mount and won't cross the
@@ -118,11 +143,13 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
/*
* For non-dir or same fs, we use st_ino of the copy up origin.
* This guaranties constant st_dev/st_ino across copy up.
+ * With xino feature and non-samefs, we use st_ino of the copy up
+ * origin masked with high bits that represent the layer id.
*
* If lower filesystem supports NFS file handles, this also guaranties
* persistent st_ino across mount cycle.
*/
- if (!is_dir || samefs) {
+ if (!is_dir || samefs || ovl_xino_bits(dentry->d_sb)) {
if (!OVL_TYPE_UPPER(type)) {
lower_layer = ovl_layer_lower(dentry);
} else if (OVL_TYPE_ORIGIN(type)) {