|
@@ -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 */
|