diff options
Diffstat (limited to 'fs/overlayfs')
-rw-r--r-- | fs/overlayfs/dir.c | 61 | ||||
-rw-r--r-- | fs/overlayfs/inode.c | 31 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 2 |
3 files changed, 30 insertions, 64 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 0c5e79966957..f4cf2928cf8e 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -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, 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); diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 98af19828695..caa36cb9c46d 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -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); |