Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+38 −1
Original line number Diff line number Diff line
@@ -61,14 +61,51 @@ static int ovl_getattr(const struct path *path, struct kstat *stat,
		       u32 request_mask, unsigned int flags)
{
	struct dentry *dentry = path->dentry;
	enum ovl_path_type type;
	struct path realpath;
	const struct cred *old_cred;
	int err;

	ovl_path_real(dentry, &realpath);
	type = ovl_path_real(dentry, &realpath);
	old_cred = ovl_override_creds(dentry->d_sb);
	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);

	return err;
}