Loading fs/overlayfs/super.c +94 −49 Original line number Diff line number Diff line Loading @@ -333,82 +333,127 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct ovl_entry *oe; struct dentry *upperdir; struct path lowerdir; struct dentry *upperdentry = NULL; struct dentry *lowerdentry = NULL; struct ovl_entry *poe = dentry->d_parent->d_fsdata; struct path *stack = NULL; struct dentry *upperdir, *upperdentry = NULL; unsigned int ctr = 0; struct inode *inode = NULL; bool upperopaque = false; struct dentry *this, *prev = NULL; unsigned int i; int err; err = -ENOMEM; oe = ovl_alloc_entry(1); if (!oe) upperdir = ovl_upperdentry_dereference(poe); if (upperdir) { this = ovl_lookup_real(upperdir, &dentry->d_name); err = PTR_ERR(this); if (IS_ERR(this)) goto out; upperdir = ovl_dentry_upper(dentry->d_parent); ovl_path_lower(dentry->d_parent, &lowerdir); /* * If this is not the lowermost layer, check whiteout and opaque * directory. */ if (poe->numlower && this) { if (ovl_is_whiteout(this)) { dput(this); this = NULL; upperopaque = true; } else if (ovl_is_opaquedir(this)) { upperopaque = true; } } upperdentry = prev = this; } if (upperdir) { upperdentry = ovl_lookup_real(upperdir, &dentry->d_name); err = PTR_ERR(upperdentry); if (IS_ERR(upperdentry)) goto out_put_dir; if (!upperopaque && poe->numlower) { err = -ENOMEM; stack = kcalloc(poe->numlower, sizeof(struct path), GFP_KERNEL); if (!stack) goto out_put_upper; } if (lowerdir.dentry && upperdentry) { if (ovl_is_whiteout(upperdentry)) { dput(upperdentry); upperdentry = NULL; oe->opaque = true; } else if (ovl_is_opaquedir(upperdentry)) { oe->opaque = true; for (i = 0; !upperopaque && i < poe->numlower; i++) { bool opaque = false; struct path lowerpath = poe->lowerstack[i]; opaque = false; this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name); err = PTR_ERR(this); if (IS_ERR(this)) goto out_put; if (!this) continue; /* * If this is not the lowermost layer, check whiteout and opaque * directory. */ if (i < poe->numlower - 1) { if (ovl_is_whiteout(this)) { dput(this); break; } else if (ovl_is_opaquedir(this)) { opaque = true; } } /* * If this is a non-directory then stop here. * * FIXME: check for opaqueness maybe better done in remove code. */ if (!S_ISDIR(this->d_inode->i_mode)) { opaque = true; } else if (prev && (!S_ISDIR(prev->d_inode->i_mode) || !S_ISDIR(this->d_inode->i_mode))) { if (prev == upperdentry) upperopaque = true; dput(this); break; } if (lowerdir.dentry && !oe->opaque) { lowerdentry = ovl_lookup_real(lowerdir.dentry, &dentry->d_name); err = PTR_ERR(lowerdentry); if (IS_ERR(lowerdentry)) goto out_dput_upper; stack[ctr].dentry = this; stack[ctr].mnt = lowerpath.mnt; ctr++; prev = this; if (opaque) break; } if (lowerdentry && upperdentry && (!S_ISDIR(upperdentry->d_inode->i_mode) || !S_ISDIR(lowerdentry->d_inode->i_mode))) { dput(lowerdentry); lowerdentry = NULL; oe->opaque = true; } oe = ovl_alloc_entry(ctr); err = -ENOMEM; if (!oe) goto out_put; if (lowerdentry || upperdentry) { if (upperdentry || ctr) { struct dentry *realdentry; realdentry = upperdentry ? upperdentry : lowerdentry; realdentry = upperdentry ? upperdentry : stack[0].dentry; err = -ENOMEM; inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode, oe); if (!inode) goto out_dput; goto out_free_oe; ovl_copyattr(realdentry->d_inode, inode); } oe->opaque = upperopaque; oe->__upperdentry = upperdentry; if (lowerdentry) { oe->lowerstack[0].dentry = lowerdentry; oe->lowerstack[0].mnt = lowerdir.mnt; } else { oe->numlower = 0; } memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr); kfree(stack); dentry->d_fsdata = oe; d_add(dentry, inode); return NULL; out_dput: dput(lowerdentry); out_dput_upper: dput(upperdentry); out_put_dir: out_free_oe: kfree(oe); out_put: for (i = 0; i < ctr; i++) dput(stack[i].dentry); kfree(stack); out_put_upper: dput(upperdentry); out: return ERR_PTR(err); } Loading Loading
fs/overlayfs/super.c +94 −49 Original line number Diff line number Diff line Loading @@ -333,82 +333,127 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct ovl_entry *oe; struct dentry *upperdir; struct path lowerdir; struct dentry *upperdentry = NULL; struct dentry *lowerdentry = NULL; struct ovl_entry *poe = dentry->d_parent->d_fsdata; struct path *stack = NULL; struct dentry *upperdir, *upperdentry = NULL; unsigned int ctr = 0; struct inode *inode = NULL; bool upperopaque = false; struct dentry *this, *prev = NULL; unsigned int i; int err; err = -ENOMEM; oe = ovl_alloc_entry(1); if (!oe) upperdir = ovl_upperdentry_dereference(poe); if (upperdir) { this = ovl_lookup_real(upperdir, &dentry->d_name); err = PTR_ERR(this); if (IS_ERR(this)) goto out; upperdir = ovl_dentry_upper(dentry->d_parent); ovl_path_lower(dentry->d_parent, &lowerdir); /* * If this is not the lowermost layer, check whiteout and opaque * directory. */ if (poe->numlower && this) { if (ovl_is_whiteout(this)) { dput(this); this = NULL; upperopaque = true; } else if (ovl_is_opaquedir(this)) { upperopaque = true; } } upperdentry = prev = this; } if (upperdir) { upperdentry = ovl_lookup_real(upperdir, &dentry->d_name); err = PTR_ERR(upperdentry); if (IS_ERR(upperdentry)) goto out_put_dir; if (!upperopaque && poe->numlower) { err = -ENOMEM; stack = kcalloc(poe->numlower, sizeof(struct path), GFP_KERNEL); if (!stack) goto out_put_upper; } if (lowerdir.dentry && upperdentry) { if (ovl_is_whiteout(upperdentry)) { dput(upperdentry); upperdentry = NULL; oe->opaque = true; } else if (ovl_is_opaquedir(upperdentry)) { oe->opaque = true; for (i = 0; !upperopaque && i < poe->numlower; i++) { bool opaque = false; struct path lowerpath = poe->lowerstack[i]; opaque = false; this = ovl_lookup_real(lowerpath.dentry, &dentry->d_name); err = PTR_ERR(this); if (IS_ERR(this)) goto out_put; if (!this) continue; /* * If this is not the lowermost layer, check whiteout and opaque * directory. */ if (i < poe->numlower - 1) { if (ovl_is_whiteout(this)) { dput(this); break; } else if (ovl_is_opaquedir(this)) { opaque = true; } } /* * If this is a non-directory then stop here. * * FIXME: check for opaqueness maybe better done in remove code. */ if (!S_ISDIR(this->d_inode->i_mode)) { opaque = true; } else if (prev && (!S_ISDIR(prev->d_inode->i_mode) || !S_ISDIR(this->d_inode->i_mode))) { if (prev == upperdentry) upperopaque = true; dput(this); break; } if (lowerdir.dentry && !oe->opaque) { lowerdentry = ovl_lookup_real(lowerdir.dentry, &dentry->d_name); err = PTR_ERR(lowerdentry); if (IS_ERR(lowerdentry)) goto out_dput_upper; stack[ctr].dentry = this; stack[ctr].mnt = lowerpath.mnt; ctr++; prev = this; if (opaque) break; } if (lowerdentry && upperdentry && (!S_ISDIR(upperdentry->d_inode->i_mode) || !S_ISDIR(lowerdentry->d_inode->i_mode))) { dput(lowerdentry); lowerdentry = NULL; oe->opaque = true; } oe = ovl_alloc_entry(ctr); err = -ENOMEM; if (!oe) goto out_put; if (lowerdentry || upperdentry) { if (upperdentry || ctr) { struct dentry *realdentry; realdentry = upperdentry ? upperdentry : lowerdentry; realdentry = upperdentry ? upperdentry : stack[0].dentry; err = -ENOMEM; inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode, oe); if (!inode) goto out_dput; goto out_free_oe; ovl_copyattr(realdentry->d_inode, inode); } oe->opaque = upperopaque; oe->__upperdentry = upperdentry; if (lowerdentry) { oe->lowerstack[0].dentry = lowerdentry; oe->lowerstack[0].mnt = lowerdir.mnt; } else { oe->numlower = 0; } memcpy(oe->lowerstack, stack, sizeof(struct path) * ctr); kfree(stack); dentry->d_fsdata = oe; d_add(dentry, inode); return NULL; out_dput: dput(lowerdentry); out_dput_upper: dput(upperdentry); out_put_dir: out_free_oe: kfree(oe); out_put: for (i = 0; i < ctr; i++) dput(stack[i].dentry); kfree(stack); out_put_upper: dput(upperdentry); out: return ERR_PTR(err); } Loading