MODULE_PARM_DESC(ovl_redirect_max,
                 "Maximum length of absolute redirect xattr value");
 
-void ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
+int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
 {
        int err;
 
                pr_err("overlayfs: cleanup of '%pd2' failed (%i)\n",
                       wdentry, err);
        }
+
+       return err;
 }
 
 struct dentry *ovl_lookup_temp(struct dentry *workdir)
 
 }
 
 
-static int ovl_check_origin(struct dentry *dentry, struct dentry *upperdentry,
+static int ovl_check_origin(struct dentry *upperdentry,
+                           struct path *lowerstack, unsigned int numlower,
                            struct path **stackp, unsigned int *ctrp)
 {
-       struct ovl_entry *roe = dentry->d_sb->s_root->d_fsdata;
        struct vfsmount *mnt;
        struct dentry *origin = NULL;
        int i;
 
 
-       for (i = 0; i < roe->numlower; i++) {
-               mnt = roe->lowerstack[i].mnt;
+       for (i = 0; i < numlower; i++) {
+               mnt = lowerstack[i].mnt;
                origin = ovl_get_origin(upperdentry, mnt);
                if (IS_ERR(origin))
                        return PTR_ERR(origin);
        if (!origin)
                return 0;
 
-       BUG_ON(*stackp || *ctrp);
-       *stackp = kmalloc(sizeof(struct path), GFP_TEMPORARY);
+       BUG_ON(*ctrp);
+       if (!*stackp)
+               *stackp = kmalloc(sizeof(struct path), GFP_TEMPORARY);
        if (!*stackp) {
                dput(origin);
                return -ENOMEM;
        goto out;
 }
 
+/*
+ * Verify that an index entry name matches the origin file handle stored in
+ * OVL_XATTR_ORIGIN and that origin file handle can be decoded to lower path.
+ * Return 0 on match, -ESTALE on mismatch or stale origin, < 0 on error.
+ */
+int ovl_verify_index(struct dentry *index, struct path *lowerstack,
+                    unsigned int numlower)
+{
+       struct ovl_fh *fh = NULL;
+       size_t len;
+       struct path origin = { };
+       struct path *stack = &origin;
+       unsigned int ctr = 0;
+       int err;
+
+       if (!d_inode(index))
+               return 0;
+
+       err = -EISDIR;
+       if (d_is_dir(index))
+               goto fail;
+
+       err = -EINVAL;
+       if (index->d_name.len < sizeof(struct ovl_fh)*2)
+               goto fail;
+
+       err = -ENOMEM;
+       len = index->d_name.len / 2;
+       fh = kzalloc(len, GFP_TEMPORARY);
+       if (!fh)
+               goto fail;
+
+       err = -EINVAL;
+       if (hex2bin((u8 *)fh, index->d_name.name, len) || len != fh->len)
+               goto fail;
+
+       err = ovl_verify_origin_fh(index, fh);
+       if (err)
+               goto fail;
+
+       err = ovl_check_origin(index, lowerstack, numlower, &stack, &ctr);
+       if (!err && !ctr)
+               err = -ESTALE;
+       if (err)
+               goto fail;
+
+       dput(origin.dentry);
+out:
+       kfree(fh);
+       return err;
+
+fail:
+       pr_warn_ratelimited("overlayfs: failed to verify index (%pd2, err=%i)\n",
+                           index, err);
+       goto out;
+}
+
 /*
  * Lookup in indexdir for the index entry of a lower real inode or a copy up
  * origin inode. The index entry name is the hex representation of the lower
                         * number - it's the same as if we held a reference
                         * to a dentry in lower layer that was moved under us.
                         */
-                       err = ovl_check_origin(dentry, upperdentry,
-                                              &stack, &ctr);
+                       err = ovl_check_origin(upperdentry, roe->lowerstack,
+                                              roe->numlower, &stack, &ctr);
                        if (err)
                                goto out;
                }
 
 /* namei.c */
 int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt,
                      struct dentry *origin, bool is_upper, bool set);
+int ovl_verify_index(struct dentry *index, struct path *lowerstack,
+                    unsigned int numlower);
 int ovl_get_index_name(struct dentry *origin, struct qstr *name);
 int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
 struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags);
 int ovl_check_d_type_supported(struct path *realpath);
 void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
                         struct dentry *dentry, int level);
+int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
+                        struct path *lowerstack, unsigned int numlower);
 
 /* inode.c */
 int ovl_setattr(struct dentry *dentry, struct iattr *attr);
 int ovl_create_real(struct inode *dir, struct dentry *newdentry,
                    struct cattr *attr,
                    struct dentry *hardlink, bool debug);
-void ovl_cleanup(struct inode *dir, struct dentry *dentry);
+int ovl_cleanup(struct inode *dir, struct dentry *dentry);
 
 /* copy_up.c */
 int ovl_copy_up(struct dentry *dentry);
 
                ovl_cleanup(dir, dentry);
        }
 }
+
+int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
+                        struct path *lowerstack, unsigned int numlower)
+{
+       int err;
+       struct inode *dir = dentry->d_inode;
+       struct path path = { .mnt = mnt, .dentry = dentry };
+       LIST_HEAD(list);
+       struct ovl_cache_entry *p;
+       struct ovl_readdir_data rdd = {
+               .ctx.actor = ovl_fill_merge,
+               .dentry = NULL,
+               .list = &list,
+               .root = RB_ROOT,
+               .is_lowest = false,
+       };
+
+       err = ovl_dir_read(&path, &rdd);
+       if (err)
+               goto out;
+
+       inode_lock_nested(dir, I_MUTEX_PARENT);
+       list_for_each_entry(p, &list, l_node) {
+               struct dentry *index;
+
+               if (p->name[0] == '.') {
+                       if (p->len == 1)
+                               continue;
+                       if (p->len == 2 && p->name[1] == '.')
+                               continue;
+               }
+               index = lookup_one_len(p->name, dentry, p->len);
+               if (IS_ERR(index)) {
+                       err = PTR_ERR(index);
+                       break;
+               }
+               if (ovl_verify_index(index, lowerstack, numlower)) {
+                       err = ovl_cleanup(dir, index);
+                       if (err)
+                               break;
+               }
+               dput(index);
+       }
+       inode_unlock(dir);
+out:
+       ovl_cache_free(&list);
+       if (err)
+               pr_err("overlayfs: failed index dir cleanup (%i)\n", err);
+       return err;
+}
 
                                                upperpath.dentry, true, true);
                        if (err)
                                pr_err("overlayfs: failed to verify index dir origin\n");
+
+                       /* Cleanup bad/stale index entries */
+                       if (!err)
+                               err = ovl_indexdir_cleanup(ufs->indexdir,
+                                                          ufs->upper_mnt,
+                                                          stack, numlower);
                }
                if (err || !ufs->indexdir)
                        pr_warn("overlayfs: try deleting index dir or mounting with '-o index=off' to disable inodes index.\n");