ovl: merge getattr for dir and nondir

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
Miklos Szeredi 2017-05-05 11:38:58 +02:00
parent 72b608f085
commit 5b712091a3
3 changed files with 30 additions and 64 deletions

View File

@ -138,65 +138,6 @@ static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry)
return err; 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 */ /* Common operations required to be done after creation of file on upper */
static void ovl_instantiate(struct dentry *dentry, struct inode *inode, static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
struct dentry *newdentry, bool hardlink) struct dentry *newdentry, bool hardlink)
@ -1099,7 +1040,7 @@ const struct inode_operations ovl_dir_inode_operations = {
.create = ovl_create, .create = ovl_create,
.mknod = ovl_mknod, .mknod = ovl_mknod,
.permission = ovl_permission, .permission = ovl_permission,
.getattr = ovl_dir_getattr, .getattr = ovl_getattr,
.listxattr = ovl_listxattr, .listxattr = ovl_listxattr,
.get_acl = ovl_get_acl, .get_acl = ovl_get_acl,
.update_time = ovl_update_time, .update_time = ovl_update_time,

View File

@ -57,13 +57,14 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
return err; return err;
} }
static int ovl_getattr(const struct path *path, struct kstat *stat, int ovl_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags) u32 request_mask, unsigned int flags)
{ {
struct dentry *dentry = path->dentry; struct dentry *dentry = path->dentry;
enum ovl_path_type type; enum ovl_path_type type;
struct path realpath; struct path realpath;
const struct cred *old_cred; const struct cred *old_cred;
bool is_dir = S_ISDIR(dentry->d_inode->i_mode);
int err; int err;
type = ovl_path_real(dentry, &realpath); 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_same_sb(dentry->d_sb)) {
if (OVL_TYPE_ORIGIN(type)) { if (OVL_TYPE_ORIGIN(type)) {
struct kstat lowerstat; struct kstat lowerstat;
u32 lowermask = STATX_INO | (!is_dir ? STATX_NLINK : 0);
ovl_path_lower(dentry, &realpath); ovl_path_lower(dentry, &realpath);
err = vfs_getattr(&realpath, &lowerstat, err = vfs_getattr(&realpath, &lowerstat,
STATX_INO | STATX_NLINK, flags); lowermask, flags);
if (err) if (err)
goto out; 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 * upper files, so we cannot use the lower origin st_ino
* for those different files, even for the same fs case. * 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->ino = lowerstat.ino;
} }
stat->dev = dentry->d_sb->s_dev; 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: out:
revert_creds(old_cred); revert_creds(old_cred);

View File

@ -236,6 +236,8 @@ void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
/* inode.c */ /* inode.c */
int ovl_setattr(struct dentry *dentry, struct iattr *attr); 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_permission(struct inode *inode, int mask);
int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value, int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags); size_t size, int flags);