ovl: merge getattr for dir and nondir
authorMiklos Szeredi <mszeredi@redhat.com>
Fri, 5 May 2017 09:38:58 +0000 (11:38 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Fri, 5 May 2017 09:38:58 +0000 (11:38 +0200)
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
fs/overlayfs/dir.c
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h

index 0c5e799..f4cf292 100644 (file)
@@ -138,65 +138,6 @@ static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry)
        return err;
 }
 
-static int ovl_dir_getattr(const struct path *path, struct kstat *stat,
-                          u32 request_mask, unsigned int flags)
-{
-       struct dentry *dentry = path->dentry;
-       int err;
-       enum ovl_path_type type;
-       struct path realpath;
-       const struct cred *old_cred;
-
-       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, 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;
-
-       /*
-        * 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 (OVL_TYPE_MERGE(type))
-               stat->nlink = 1;
-out:
-       revert_creds(old_cred);
-
-       return err;
-}
-
 /* Common operations required to be done after creation of file on upper */
 static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
                            struct dentry *newdentry, bool hardlink)
@@ -1099,7 +1040,7 @@ const struct inode_operations ovl_dir_inode_operations = {
        .create         = ovl_create,
        .mknod          = ovl_mknod,
        .permission     = ovl_permission,
-       .getattr        = ovl_dir_getattr,
+       .getattr        = ovl_getattr,
        .listxattr      = ovl_listxattr,
        .get_acl        = ovl_get_acl,
        .update_time    = ovl_update_time,
index 3dc693a..ad9547f 100644 (file)
@@ -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);
 
index 98af198..caa36cb 100644 (file)
@@ -236,6 +236,8 @@ void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
 
 /* inode.c */
 int ovl_setattr(struct dentry *dentry, struct iattr *attr);
+int ovl_getattr(const struct path *path, struct kstat *stat,
+               u32 request_mask, unsigned int flags);
 int ovl_permission(struct inode *inode, int mask);
 int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
                  size_t size, int flags);