|
|
@@ -74,6 +74,7 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
|
|
|
struct path realpath;
|
|
|
const struct cred *old_cred;
|
|
|
bool is_dir = S_ISDIR(dentry->d_inode->i_mode);
|
|
|
+ bool samefs = ovl_same_sb(dentry->d_sb);
|
|
|
int err;
|
|
|
|
|
|
type = ovl_path_real(dentry, &realpath);
|
|
|
@@ -83,16 +84,13 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
|
|
|
goto out;
|
|
|
|
|
|
/*
|
|
|
- * When all layers are on the same fs, all real inode number are
|
|
|
- * unique, so we use the overlay st_dev, which is friendly to du -x.
|
|
|
- *
|
|
|
- * We also use st_ino of the copy up origin, if we know it.
|
|
|
- * This guaranties constant st_dev/st_ino across copy up.
|
|
|
+ * For non-dir or same fs, we use st_ino of the copy up origin, if we
|
|
|
+ * know it. This guaranties constant st_dev/st_ino across copy up.
|
|
|
*
|
|
|
* If filesystem supports NFS export ops, this also guaranties
|
|
|
* persistent st_ino across mount cycle.
|
|
|
*/
|
|
|
- if (ovl_same_sb(dentry->d_sb)) {
|
|
|
+ if (!is_dir || samefs) {
|
|
|
if (OVL_TYPE_ORIGIN(type)) {
|
|
|
struct kstat lowerstat;
|
|
|
u32 lowermask = STATX_INO | (!is_dir ? STATX_NLINK : 0);
|
|
|
@@ -103,7 +101,6 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
|
|
|
if (err)
|
|
|
goto out;
|
|
|
|
|
|
- WARN_ON_ONCE(stat->dev != lowerstat.dev);
|
|
|
/*
|
|
|
* Lower hardlinks may be broken on copy up to different
|
|
|
* upper files, so we cannot use the lower origin st_ino
|
|
|
@@ -115,27 +112,39 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
|
|
|
if (is_dir || lowerstat.nlink == 1 ||
|
|
|
ovl_test_flag(OVL_INDEX, d_inode(dentry)))
|
|
|
stat->ino = lowerstat.ino;
|
|
|
+
|
|
|
+ if (samefs)
|
|
|
+ WARN_ON_ONCE(stat->dev != lowerstat.dev);
|
|
|
+ else
|
|
|
+ stat->dev = ovl_get_pseudo_dev(dentry);
|
|
|
}
|
|
|
- stat->dev = dentry->d_sb->s_dev;
|
|
|
- } else if (is_dir) {
|
|
|
+ if (samefs) {
|
|
|
+ /*
|
|
|
+ * When all layers are on the same fs, all real inode
|
|
|
+ * number are unique, so we use the overlay st_dev,
|
|
|
+ * which is friendly to du -x.
|
|
|
+ */
|
|
|
+ stat->dev = dentry->d_sb->s_dev;
|
|
|
+ } else if (!OVL_TYPE_UPPER(type)) {
|
|
|
+ /*
|
|
|
+ * For non-samefs setup, to make sure that st_dev/st_ino
|
|
|
+ * pair is unique across the system, we use a unique
|
|
|
+ * anonymous st_dev for lower layer inode.
|
|
|
+ */
|
|
|
+ stat->dev = ovl_get_pseudo_dev(dentry);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
/*
|
|
|
- * If not all layers are on the same fs the pair {real st_ino;
|
|
|
- * overlay st_dev} is not unique, so use the non persistent
|
|
|
- * overlay st_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.
|
|
|
+ *
|
|
|
+ * If not all layers are on the same fs the pair {real st_ino;
|
|
|
+ * overlay st_dev} is not unique, so use the non persistent
|
|
|
+ * overlay st_ino for directories.
|
|
|
*/
|
|
|
stat->dev = dentry->d_sb->s_dev;
|
|
|
stat->ino = dentry->d_inode->i_ino;
|
|
|
- } else if (!OVL_TYPE_UPPER(type)) {
|
|
|
- /*
|
|
|
- * For non-samefs setup, to make sure that st_dev/st_ino pair
|
|
|
- * is unique across the system, we use a unique anonymous
|
|
|
- * st_dev for lower layer inode.
|
|
|
- */
|
|
|
- stat->dev = ovl_get_pseudo_dev(dentry);
|
|
|
}
|
|
|
|
|
|
/*
|