ovl: merge getattr for dir and nondir
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
72b608f085
commit
5b712091a3
|
@ -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,
|
||||
|
|
|
@ -57,13 +57,14 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue