aboutsummaryrefslogtreecommitdiffstats
path: root/fs/overlayfs/inode.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2017-05-05 11:38:58 +0200
committerMiklos Szeredi <mszeredi@redhat.com>2017-05-05 11:38:58 +0200
commit5b712091a3a3904b0ae8311e18e6b540a070d464 (patch)
tree5322c5ac759d7cf3d3884adb9c0778f0377745f8 /fs/overlayfs/inode.c
parentovl: constant st_ino/st_dev across copy up (diff)
downloadlinux-dev-5b712091a3a3904b0ae8311e18e6b540a070d464.tar.xz
linux-dev-5b712091a3a3904b0ae8311e18e6b540a070d464.zip
ovl: merge getattr for dir and nondir
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/overlayfs/inode.c')
-rw-r--r--fs/overlayfs/inode.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 3dc693a78de2..ad9547f82da5 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -57,13 +57,14 @@ out:
return err;
}
-static int ovl_getattr(const struct path *path, struct kstat *stat,
- u32 request_mask, unsigned int flags)
+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;
+ bool is_dir = S_ISDIR(dentry->d_inode->i_mode);
int err;
type = ovl_path_real(dentry, &realpath);
@@ -85,10 +86,11 @@ static int ovl_getattr(const struct path *path, struct kstat *stat,
if (ovl_same_sb(dentry->d_sb)) {
if (OVL_TYPE_ORIGIN(type)) {
struct kstat lowerstat;
+ u32 lowermask = STATX_INO | (!is_dir ? STATX_NLINK : 0);
ovl_path_lower(dentry, &realpath);
err = vfs_getattr(&realpath, &lowerstat,
- STATX_INO | STATX_NLINK, flags);
+ lowermask, flags);
if (err)
goto out;
@@ -98,11 +100,32 @@ static int ovl_getattr(const struct path *path, struct kstat *stat,
* 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)
+ if (is_dir || lowerstat.nlink == 1)
stat->ino = lowerstat.ino;
}
stat->dev = dentry->d_sb->s_dev;
+ } else if (is_dir) {
+ /*
+ * 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.
+ */
+ 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
+ * correct link count. nlink=1 seems to pacify 'find' and
+ * other utilities.
+ */
+ if (is_dir && OVL_TYPE_MERGE(type))
+ stat->nlink = 1;
+
out:
revert_creds(old_cred);