Commit 72b608f0 authored by Amir Goldstein's avatar Amir Goldstein Committed by Miklos Szeredi

ovl: constant st_ino/st_dev across copy up

When all layers are on the same underlying filesystem, let stat(2) return
st_dev/st_ino values of the copy up origin inode if it is known.

This results in constant st_ino/st_dev representation of files in an
overlay mount before and after copy up.

When the underlying filesystem support NFS exportfs, the result is also
persistent st_ino/st_dev representation before and after mount cycle.

Lower hardlinks are broken on copy up to different upper files, so we
cannot use the lower origin st_ino for those different files, even for the
same fs case.

When all overlay layers are on the same fs, use overlay st_dev for non-dirs
to get the correct result from du -x.
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent b7a807dc
...@@ -61,14 +61,51 @@ static int ovl_getattr(const struct path *path, struct kstat *stat, ...@@ -61,14 +61,51 @@ static int ovl_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags) u32 request_mask, unsigned int flags)
{ {
struct dentry *dentry = path->dentry; struct dentry *dentry = path->dentry;
enum ovl_path_type type;
struct path realpath; struct path realpath;
const struct cred *old_cred; const struct cred *old_cred;
int err; int err;
ovl_path_real(dentry, &realpath); type = ovl_path_real(dentry, &realpath);
old_cred = ovl_override_creds(dentry->d_sb); old_cred = ovl_override_creds(dentry->d_sb);
err = vfs_getattr(&realpath, stat, request_mask, flags); err = vfs_getattr(&realpath, stat, request_mask, flags);
if (err)
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.
*
* If filesystem supports NFS export ops, this also guaranties
* persistent st_ino across mount cycle.
*/
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 | STATX_NLINK, flags);
if (err)
goto out;
WARN_ON_ONCE(stat->dev != lowerstat.dev);
/*
* Lower hardlinks are broken on copy up to different
* upper files, so we cannot use the lower origin st_ino
* for those different files, even for the same fs case.
*/
if (lowerstat.nlink == 1)
stat->ino = lowerstat.ino;
}
stat->dev = dentry->d_sb->s_dev;
}
out:
revert_creds(old_cred); revert_creds(old_cred);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment