* pointer because we hold no lock on the real dentry.
         */
        take_dentry_name_snapshot(&name, real);
+       /*
+        * No mnt_userns handling here: it's an internal lookup.  Could skip
+        * permission checking altogether, but for now just use non-mnt_userns
+        * transformed ids.
+        */
        this = lookup_one_len(name.name.name, connected, name.name.len);
        release_dentry_name_snapshot(&name);
        err = PTR_ERR(this);
 
        return ovl_path_check_dir_xattr(ofs, path, OVL_XATTR_OPAQUE);
 }
 
-static struct dentry *ovl_lookup_positive_unlocked(const char *name,
+static struct dentry *ovl_lookup_positive_unlocked(struct ovl_lookup_data *d,
+                                                  const char *name,
                                                   struct dentry *base, int len,
                                                   bool drop_negative)
 {
-       struct dentry *ret = lookup_one_len_unlocked(name, base, len);
+       struct dentry *ret = lookup_one_unlocked(mnt_user_ns(d->mnt), name, base, len);
 
        if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) {
                if (drop_negative && ret->d_lockref.count == 1) {
        int err;
        bool last_element = !post[0];
 
-       this = ovl_lookup_positive_unlocked(name, base, namelen, drop_negative);
+       this = ovl_lookup_positive_unlocked(d, name, base, namelen, drop_negative);
        if (IS_ERR(this)) {
                err = PTR_ERR(this);
                this = NULL;
        if (err)
                return ERR_PTR(err);
 
-       index = lookup_positive_unlocked(name.name, ofs->indexdir, name.len);
+       index = lookup_one_positive_unlocked(ovl_upper_mnt_userns(ofs), name.name,
+                                            ofs->indexdir, name.len);
        if (IS_ERR(index)) {
                err = PTR_ERR(index);
                if (err == -ENOENT) {
                struct dentry *this;
                struct dentry *lowerdir = poe->lowerstack[i].dentry;
 
-               this = lookup_positive_unlocked(name->name, lowerdir,
-                                              name->len);
+               this = lookup_one_positive_unlocked(mnt_user_ns(poe->lowerstack[i].layer->mnt),
+                                                  name->name, lowerdir, name->len);
                if (IS_ERR(this)) {
                        switch (PTR_ERR(this)) {
                        case -ENOENT:
 
                return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
 }
 
-static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
+static int ovl_check_whiteouts(struct path *path, struct ovl_readdir_data *rdd)
 {
        int err;
        struct ovl_cache_entry *p;
-       struct dentry *dentry;
+       struct dentry *dentry, *dir = path->dentry;
        const struct cred *old_cred;
 
        old_cred = ovl_override_creds(rdd->dentry->d_sb);
                while (rdd->first_maybe_whiteout) {
                        p = rdd->first_maybe_whiteout;
                        rdd->first_maybe_whiteout = p->next_maybe_whiteout;
-                       dentry = lookup_one_len(p->name, dir, p->len);
+                       dentry = lookup_one(mnt_user_ns(path->mnt), p->name, dir, p->len);
                        if (!IS_ERR(dentry)) {
                                p->is_whiteout = ovl_is_whiteout(dentry);
                                dput(dentry);
        } while (!err && rdd->count);
 
        if (!err && rdd->first_maybe_whiteout && rdd->dentry)
-               err = ovl_check_whiteouts(realpath->dentry, rdd);
+               err = ovl_check_whiteouts(realpath, rdd);
 
        fput(realfile);
 
                        goto get;
                }
        }
-       this = lookup_one_len(p->name, dir, p->len);
+       this = lookup_one(mnt_user_ns(path->mnt), p->name, dir, p->len);
        if (IS_ERR_OR_NULL(this) || !this->d_inode) {
                /* Mark a stale entry */
                p->is_whiteout = true;