static int ovl_inode_test(struct inode *inode, void *data)
 {
-       return ovl_inode_real(inode, NULL) == data;
+       return inode->i_private == data;
 }
 
 static int ovl_inode_set(struct inode *inode, void *data)
 {
-       inode->i_private = (void *) (((unsigned long) data) | OVL_ISUPPER_MASK);
+       inode->i_private = data;
        return 0;
 }
 
 
        u8 fid[0];      /* file identifier */
 } __packed;
 
-#define OVL_ISUPPER_MASK 1UL
-
 static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int err = vfs_rmdir(dir, dentry);
        return ret;
 }
 
-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);
-}
-
 /* util.c */
 int ovl_want_write(struct dentry *dentry);
 void ovl_drop_write(struct dentry *dentry);
 struct dentry *ovl_dentry_upper(struct dentry *dentry);
 struct dentry *ovl_dentry_lower(struct dentry *dentry);
 struct dentry *ovl_dentry_real(struct dentry *dentry);
+struct inode *ovl_inode_real(struct inode *inode, bool *is_upper);
 struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry);
 void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache);
 bool ovl_dentry_is_opaque(struct dentry *dentry);
 
 
 struct ovl_inode {
        struct inode vfs_inode;
+       struct inode *upper;
+       struct inode *lower;
 };
 
 static inline struct ovl_inode *OVL_I(struct inode *inode)
 
 {
        struct ovl_inode *oi = kmem_cache_alloc(ovl_inode_cachep, GFP_KERNEL);
 
+       oi->upper = NULL;
+       oi->lower = NULL;
+
        return &oi->vfs_inode;
 }
 
 
        return realdentry;
 }
 
+struct inode *ovl_inode_real(struct inode *inode, bool *is_upper)
+{
+       struct inode *realinode = lockless_dereference(OVL_I(inode)->upper);
+       bool isup = false;
+
+       if (!realinode)
+               realinode = OVL_I(inode)->lower;
+       else
+               isup = true;
+
+       if (is_upper)
+               *is_upper = isup;
+
+       return realinode;
+}
+
 struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry)
 {
        struct ovl_entry *oe = dentry->d_fsdata;
 void ovl_inode_init(struct inode *inode, struct dentry *dentry)
 {
        struct inode *realinode = d_inode(ovl_dentry_real(dentry));
-       bool is_upper = ovl_dentry_upper(dentry);
 
-       WRITE_ONCE(inode->i_private, (unsigned long) realinode |
-                  (is_upper ? OVL_ISUPPER_MASK : 0));
+       if (ovl_dentry_upper(dentry))
+               OVL_I(inode)->upper = realinode;
+       else
+               OVL_I(inode)->lower = realinode;
 
        ovl_copyattr(realinode, inode);
 }
 {
        WARN_ON(!upperinode);
        WARN_ON(!inode_unhashed(inode));
-       WRITE_ONCE(inode->i_private,
-                  (unsigned long) upperinode | OVL_ISUPPER_MASK);
-       if (!S_ISDIR(upperinode->i_mode))
+       /*
+        * Make sure upperinode is consistent before making it visible to
+        * ovl_inode_real();
+        */
+       smp_wmb();
+       OVL_I(inode)->upper = upperinode;
+       if (!S_ISDIR(upperinode->i_mode)) {
+               inode->i_private = upperinode;
                __insert_inode_hash(inode, (unsigned long) upperinode);
+       }
 }
 
 void ovl_dentry_version_inc(struct dentry *dentry)