summaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/dir.c
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2017-04-24 08:37:28 +0200
committerMiklos Szeredi <mszeredi@redhat.com>2017-05-05 11:38:58 +0200
commitb7a807dc2010334e62e0afd89d6f7a8913eb14ff (patch)
treec2cb34dce0e3a52ac37fededcc63c835a3138a1c /fs/overlayfs/dir.c
parentovl: set the ORIGIN type flag (diff)
downloadlinux-b7a807dc2010334e62e0afd89d6f7a8913eb14ff.tar.xz
linux-b7a807dc2010334e62e0afd89d6f7a8913eb14ff.zip
ovl: persistent inode number for directories
stat(2) on overlay directories reports the overlay temp inode number, which is constant across copy up, but is not persistent. When all layers are on the same fs, report the copy up origin inode number for directories. This inode number is persistent, unique across the overlay mount and constant across copy up. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/overlayfs/dir.c')
-rw-r--r--fs/overlayfs/dir.c37
1 files changed, 33 insertions, 4 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index bfabc65fdc74..0c5e79966957 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -150,12 +150,39 @@ static int ovl_dir_getattr(const struct path *path, struct kstat *stat,
type = ovl_path_real(dentry, &realpath);
old_cred = ovl_override_creds(dentry->d_sb);
err = vfs_getattr(&realpath, stat, request_mask, flags);
- revert_creds(old_cred);
if (err)
- return err;
+ goto out;
+
+ /*
+ * When all layers are on the same fs, use the copy-up-origin st_ino,
+ * which is persistent, unique and constant across copy up.
+ *
+ * Otherwise the pair {real st_ino; overlay st_dev} is not unique, so
+ * use the non persistent overlay st_ino.
+ */
+ if (ovl_same_sb(dentry->d_sb)) {
+ if (OVL_TYPE_ORIGIN(type)) {
+ struct kstat lowerstat;
+
+ ovl_path_lower(dentry, &realpath);
+ err = vfs_getattr(&realpath, &lowerstat,
+ STATX_INO, flags);
+ if (err)
+ goto out;
+
+ WARN_ON_ONCE(stat->dev != lowerstat.dev);
+ stat->ino = lowerstat.ino;
+ }
+ } else {
+ stat->ino = dentry->d_inode->i_ino;
+ }
+ /*
+ * Always use the overlay st_dev for directories, so 'find -xdev' will
+ * scan the entire overlay mount and won't cross the overlay mount
+ * boundaries.
+ */
stat->dev = dentry->d_sb->s_dev;
- stat->ino = dentry->d_inode->i_ino;
/*
* It's probably not worth it to count subdirs to get the
@@ -164,8 +191,10 @@ static int ovl_dir_getattr(const struct path *path, struct kstat *stat,
*/
if (OVL_TYPE_MERGE(type))
stat->nlink = 1;
+out:
+ revert_creds(old_cred);
- return 0;
+ return err;
}
/* Common operations required to be done after creation of file on upper */