Commit 39b681f8 authored by Miklos Szeredi's avatar Miklos Szeredi

ovl: store real inode pointer in ->i_private

To get from overlay inode to real inode we currently use 'struct
ovl_entry', which has lifetime connected to overlay dentry.  This is okay,
since each overlay dentry had a new overlay inode allocated.

Following patch will break that assumption, so need to leave out ovl_entry.
This patch stores the real inode directly in i_private, with the lowest bit
used to indicate whether the inode is upper or lower.

Lifetime rules remain, using ovl_inode_real() must only be done while
caller holds ref on overlay dentry (and hence on real dentry), or within
RCU protected regions.
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent a999d7e1
...@@ -292,6 +292,7 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, ...@@ -292,6 +292,7 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
goto out_cleanup; goto out_cleanup;
ovl_dentry_update(dentry, newdentry); ovl_dentry_update(dentry, newdentry);
ovl_inode_update(d_inode(dentry), d_inode(newdentry));
newdentry = NULL; newdentry = NULL;
/* /*
......
...@@ -167,6 +167,7 @@ static void ovl_instantiate(struct dentry *dentry, struct inode *inode, ...@@ -167,6 +167,7 @@ static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
{ {
ovl_dentry_version_inc(dentry->d_parent); ovl_dentry_version_inc(dentry->d_parent);
ovl_dentry_update(dentry, newdentry); ovl_dentry_update(dentry, newdentry);
ovl_inode_update(inode, d_inode(newdentry));
ovl_copyattr(newdentry->d_inode, inode); ovl_copyattr(newdentry->d_inode, inode);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
} }
...@@ -416,7 +417,7 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev, ...@@ -416,7 +417,7 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
}; };
err = -ENOMEM; err = -ENOMEM;
inode = ovl_new_inode(dentry->d_sb, mode, dentry->d_fsdata); inode = ovl_new_inode(dentry->d_sb, mode);
if (!inode) if (!inode)
goto out; goto out;
......
...@@ -117,15 +117,12 @@ static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry, ...@@ -117,15 +117,12 @@ static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry,
int ovl_permission(struct inode *inode, int mask) int ovl_permission(struct inode *inode, int mask)
{ {
struct ovl_entry *oe = inode->i_private;
bool is_upper; bool is_upper;
struct dentry *realdentry = ovl_entry_real(oe, &is_upper); struct inode *realinode = ovl_inode_real(inode, &is_upper);
struct inode *realinode;
const struct cred *old_cred; const struct cred *old_cred;
int err; int err;
/* Careful in RCU walk mode */ /* Careful in RCU walk mode */
realinode = d_inode_rcu(realdentry);
if (!realinode) { if (!realinode) {
WARN_ON(!(mask & MAY_NOT_BLOCK)); WARN_ON(!(mask & MAY_NOT_BLOCK));
return -ECHILD; return -ECHILD;
...@@ -312,7 +309,7 @@ int ovl_removexattr(struct dentry *dentry, const char *name) ...@@ -312,7 +309,7 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
struct posix_acl *ovl_get_acl(struct inode *inode, int type) struct posix_acl *ovl_get_acl(struct inode *inode, int type)
{ {
struct inode *realinode = ovl_inode_real(inode); struct inode *realinode = ovl_inode_real(inode, NULL);
const struct cred *old_cred; const struct cred *old_cred;
struct posix_acl *acl; struct posix_acl *acl;
...@@ -412,8 +409,7 @@ static const struct inode_operations ovl_symlink_inode_operations = { ...@@ -412,8 +409,7 @@ static const struct inode_operations ovl_symlink_inode_operations = {
.update_time = ovl_update_time, .update_time = ovl_update_time,
}; };
struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, struct inode *ovl_new_inode(struct super_block *sb, umode_t mode)
struct ovl_entry *oe)
{ {
struct inode *inode; struct inode *inode;
...@@ -424,7 +420,6 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, ...@@ -424,7 +420,6 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
inode->i_ino = get_next_ino(); inode->i_ino = get_next_ino();
inode->i_mode = mode; inode->i_mode = mode;
inode->i_flags |= S_NOCMTIME; inode->i_flags |= S_NOCMTIME;
inode->i_private = oe;
mode &= S_IFMT; mode &= S_IFMT;
switch (mode) { switch (mode) {
......
...@@ -27,6 +27,8 @@ enum ovl_path_type { ...@@ -27,6 +27,8 @@ enum ovl_path_type {
#define OVL_XATTR_PRE_LEN 16 #define OVL_XATTR_PRE_LEN 16
#define OVL_XATTR_OPAQUE OVL_XATTR_PRE_NAME"opaque" #define OVL_XATTR_OPAQUE OVL_XATTR_PRE_NAME"opaque"
#define OVL_ISUPPER_MASK 1UL
static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry) static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry)
{ {
int err = vfs_rmdir(dir, dentry); int err = vfs_rmdir(dir, dentry);
...@@ -131,6 +133,16 @@ static inline int ovl_do_whiteout(struct inode *dir, struct dentry *dentry) ...@@ -131,6 +133,16 @@ static inline int ovl_do_whiteout(struct inode *dir, struct dentry *dentry)
return err; return err;
} }
static inline struct inode *ovl_inode_real(struct inode *inode, bool *is_upper)
{
unsigned long x = (unsigned long) READ_ONCE(inode->i_private);
if (is_upper)
*is_upper = x & OVL_ISUPPER_MASK;
return (struct inode *) (x & ~OVL_ISUPPER_MASK);
}
enum ovl_path_type ovl_path_type(struct dentry *dentry); enum ovl_path_type ovl_path_type(struct dentry *dentry);
u64 ovl_dentry_version_get(struct dentry *dentry); u64 ovl_dentry_version_get(struct dentry *dentry);
void ovl_dentry_version_inc(struct dentry *dentry); void ovl_dentry_version_inc(struct dentry *dentry);
...@@ -141,8 +153,6 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path); ...@@ -141,8 +153,6 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
struct dentry *ovl_dentry_upper(struct dentry *dentry); struct dentry *ovl_dentry_upper(struct dentry *dentry);
struct dentry *ovl_dentry_lower(struct dentry *dentry); struct dentry *ovl_dentry_lower(struct dentry *dentry);
struct dentry *ovl_dentry_real(struct dentry *dentry); struct dentry *ovl_dentry_real(struct dentry *dentry);
struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper);
struct inode *ovl_inode_real(struct inode *inode);
struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode, struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode,
bool is_upper); bool is_upper);
struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry); struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry);
...@@ -155,6 +165,7 @@ void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque); ...@@ -155,6 +165,7 @@ void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
bool ovl_is_whiteout(struct dentry *dentry); bool ovl_is_whiteout(struct dentry *dentry);
const struct cred *ovl_override_creds(struct super_block *sb); const struct cred *ovl_override_creds(struct super_block *sb);
void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry); void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
void ovl_inode_update(struct inode *inode, struct inode *upperinode);
struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags); unsigned int flags);
struct file *ovl_path_open(struct path *path, int flags); struct file *ovl_path_open(struct path *path, int flags);
...@@ -183,8 +194,7 @@ struct posix_acl *ovl_get_acl(struct inode *inode, int type); ...@@ -183,8 +194,7 @@ struct posix_acl *ovl_get_acl(struct inode *inode, int type);
int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags); int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
int ovl_update_time(struct inode *inode, struct timespec *ts, int flags); int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, struct inode *ovl_new_inode(struct super_block *sb, umode_t mode);
struct ovl_entry *oe);
static inline void ovl_copyattr(struct inode *from, struct inode *to) static inline void ovl_copyattr(struct inode *from, struct inode *to)
{ {
to->i_uid = from->i_uid; to->i_uid = from->i_uid;
......
...@@ -145,25 +145,11 @@ struct dentry *ovl_dentry_real(struct dentry *dentry) ...@@ -145,25 +145,11 @@ struct dentry *ovl_dentry_real(struct dentry *dentry)
return realdentry; return realdentry;
} }
struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper) static void ovl_inode_init(struct inode *inode, struct inode *realinode,
bool is_upper)
{ {
struct dentry *realdentry; WRITE_ONCE(inode->i_private, (unsigned long) realinode |
(is_upper ? OVL_ISUPPER_MASK : 0));
realdentry = ovl_upperdentry_dereference(oe);
if (realdentry) {
*is_upper = true;
} else {
realdentry = __ovl_dentry_lower(oe);
*is_upper = false;
}
return realdentry;
}
struct inode *ovl_inode_real(struct inode *inode)
{
bool tmp;
return d_inode(ovl_entry_real(inode->i_private, &tmp));
} }
struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode, struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode,
...@@ -235,7 +221,6 @@ void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry) ...@@ -235,7 +221,6 @@ void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry)
WARN_ON(!inode_is_locked(upperdentry->d_parent->d_inode)); WARN_ON(!inode_is_locked(upperdentry->d_parent->d_inode));
WARN_ON(oe->__upperdentry); WARN_ON(oe->__upperdentry);
BUG_ON(!upperdentry->d_inode);
/* /*
* Make sure upperdentry is consistent before making it visible to * Make sure upperdentry is consistent before making it visible to
* ovl_upperdentry_dereference(). * ovl_upperdentry_dereference().
...@@ -244,6 +229,13 @@ void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry) ...@@ -244,6 +229,13 @@ void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry)
oe->__upperdentry = upperdentry; oe->__upperdentry = upperdentry;
} }
void ovl_inode_update(struct inode *inode, struct inode *upperinode)
{
WARN_ON(!upperinode);
WRITE_ONCE(inode->i_private,
(unsigned long) upperinode | OVL_ISUPPER_MASK);
}
void ovl_dentry_version_inc(struct dentry *dentry) void ovl_dentry_version_inc(struct dentry *dentry)
{ {
struct ovl_entry *oe = dentry->d_fsdata; struct ovl_entry *oe = dentry->d_fsdata;
...@@ -574,14 +566,16 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, ...@@ -574,14 +566,16 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
if (upperdentry || ctr) { if (upperdentry || ctr) {
struct dentry *realdentry; struct dentry *realdentry;
struct inode *realinode;
realdentry = upperdentry ? upperdentry : stack[0].dentry; realdentry = upperdentry ? upperdentry : stack[0].dentry;
realinode = d_inode(realdentry);
err = -ENOMEM; err = -ENOMEM;
inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode, inode = ovl_new_inode(dentry->d_sb, realinode->i_mode);
oe);
if (!inode) if (!inode)
goto out_free_oe; goto out_free_oe;
ovl_inode_init(inode, realinode, !!upperdentry);
ovl_copyattr(realdentry->d_inode, inode); ovl_copyattr(realdentry->d_inode, inode);
} }
...@@ -969,6 +963,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -969,6 +963,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
struct path upperpath = { NULL, NULL }; struct path upperpath = { NULL, NULL };
struct path workpath = { NULL, NULL }; struct path workpath = { NULL, NULL };
struct dentry *root_dentry; struct dentry *root_dentry;
struct inode *realinode;
struct ovl_entry *oe; struct ovl_entry *oe;
struct ovl_fs *ufs; struct ovl_fs *ufs;
struct path *stack = NULL; struct path *stack = NULL;
...@@ -1150,7 +1145,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1150,7 +1145,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
if (!oe) if (!oe)
goto out_put_cred; goto out_put_cred;
root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe)); root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR));
if (!root_dentry) if (!root_dentry)
goto out_free_oe; goto out_free_oe;
...@@ -1169,8 +1164,9 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1169,8 +1164,9 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
root_dentry->d_fsdata = oe; root_dentry->d_fsdata = oe;
ovl_copyattr(ovl_dentry_real(root_dentry)->d_inode, realinode = d_inode(ovl_dentry_real(root_dentry));
root_dentry->d_inode); ovl_inode_init(d_inode(root_dentry), realinode, !!upperpath.dentry);
ovl_copyattr(realinode, d_inode(root_dentry));
sb->s_magic = OVERLAYFS_SUPER_MAGIC; sb->s_magic = OVERLAYFS_SUPER_MAGIC;
sb->s_op = &ovl_super_operations; sb->s_op = &ovl_super_operations;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment