On Sat, 2023-04-08 at 19:43 +0300, Amir Goldstein wrote: > Now that we have the entire lower stack in ovl_inode, we do not > need to hold another reference to the lowerdata inode. > > Instead, use the vacant ovl_inode space as a place holder for > lowerdata > redirect path from the metacopy to lowerdata, which is going to be > used > later on for lazy lowerdata lookup. > > Use accessors to get the lowerdata path and dentry. > > Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> Reviewed-by: Alexander Larsson <alexl@xxxxxxxxxx> > --- > fs/overlayfs/inode.c | 4 ++-- > fs/overlayfs/namei.c | 7 +++++-- > fs/overlayfs/overlayfs.h | 3 ++- > fs/overlayfs/ovl_entry.h | 16 +++++++++++++++- > fs/overlayfs/super.c | 4 ++-- > fs/overlayfs/util.c | 26 ++++++++++++++++---------- > 6 files changed, 42 insertions(+), 18 deletions(-) > > diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c > index 9f29fc3e9fa5..35d51a6dced7 100644 > --- a/fs/overlayfs/inode.c > +++ b/fs/overlayfs/inode.c > @@ -1006,8 +1006,7 @@ void ovl_inode_init(struct inode *inode, struct > ovl_inode_params *oip, > oi->__upperdentry = oip->upperdentry; > oi->oe = *oip->oe; > oi->redirect = oip->redirect; > - if (oip->lowerdata) > - oi->lowerdata = igrab(d_inode(oip->lowerdata)); > + oi->lowerdata_redirect = oip->lowerdata_redirect; > > realinode = ovl_inode_real(inode); > ovl_copyattr(inode); > @@ -1368,6 +1367,7 @@ struct inode *ovl_get_inode(struct super_block > *sb, > dput(upperdentry); > ovl_destroy_entry(oip->oe); > kfree(oip->redirect); > + kfree(oip->lowerdata_redirect); > goto out; > } > > diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c > index cdcb2ac5d95c..b629261324f1 100644 > --- a/fs/overlayfs/namei.c > +++ b/fs/overlayfs/namei.c > @@ -1105,10 +1105,13 @@ struct dentry *ovl_lookup(struct inode *dir, > struct dentry *dentry, > .oe = &oe, > .index = index, > .redirect = upperredirect, > - .lowerdata = (ctr > 1 && !d.is_dir) ? > - stack[ctr - 1].dentry : NULL, > }; > > + /* Store lowerdata redirect for lazy lookup */ > + if (ctr > 1 && !d.is_dir && !stack[ctr - 1].dentry) { > + oip.lowerdata_redirect = d.redirect; > + d.redirect = NULL; > + } > inode = ovl_get_inode(dentry->d_sb, &oip); > err = PTR_ERR(inode); > if (IS_ERR(inode)) > diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h > index 32532342e56a..011b7b466f70 100644 > --- a/fs/overlayfs/overlayfs.h > +++ b/fs/overlayfs/overlayfs.h > @@ -409,6 +409,7 @@ struct inode *ovl_inode_lower(struct inode > *inode); > struct inode *ovl_inode_lowerdata(struct inode *inode); > struct inode *ovl_inode_real(struct inode *inode); > struct inode *ovl_inode_realdata(struct inode *inode); > +const char *ovl_lowerdata_redirect(struct inode *inode); > struct ovl_dir_cache *ovl_dir_cache(struct inode *inode); > void ovl_set_dir_cache(struct inode *inode, struct ovl_dir_cache > *cache); > void ovl_dentry_set_flag(unsigned long flag, struct dentry *dentry); > @@ -660,7 +661,7 @@ struct ovl_inode_params { > struct ovl_entry *oe; > bool index; > char *redirect; > - struct dentry *lowerdata; > + char *lowerdata_redirect; > }; > void ovl_inode_init(struct inode *inode, struct ovl_inode_params > *oip, > unsigned long ino, int fsid); > diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h > index 5d95e937f555..221f0cbe748e 100644 > --- a/fs/overlayfs/ovl_entry.h > +++ b/fs/overlayfs/ovl_entry.h > @@ -125,6 +125,20 @@ static inline struct ovl_path > *ovl_lowerstack(struct ovl_entry *oe) > return oe && oe->__numlower > 1 ? oe->__lowerstack : &oe- > >__lowerpath; > } > > +static inline struct ovl_path *ovl_lowerdata(struct ovl_entry *oe) > +{ > + struct ovl_path *lowerstack = ovl_lowerstack(oe); > + > + return lowerstack ? &lowerstack[oe->__numlower - 1] : NULL; > +} > + > +static inline struct dentry *ovl_lowerdata_dentry(struct ovl_entry > *oe) > +{ > + struct ovl_path *lowerdata = ovl_lowerdata(oe); > + > + return lowerdata ? lowerdata->dentry : NULL; > +} > + > /* private information held for every overlayfs dentry */ > static inline unsigned long *OVL_E_FLAGS(struct dentry *dentry) > { > @@ -134,7 +148,7 @@ static inline unsigned long *OVL_E_FLAGS(struct > dentry *dentry) > struct ovl_inode { > union { > struct ovl_dir_cache *cache; /* directory */ > - struct inode *lowerdata; /* regular file */ > + const char *lowerdata_redirect; /* regular file */ > }; > const char *redirect; > u64 version; > diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c > index e01a76de787c..6e4231799b86 100644 > --- a/fs/overlayfs/super.c > +++ b/fs/overlayfs/super.c > @@ -172,7 +172,7 @@ static struct inode *ovl_alloc_inode(struct > super_block *sb) > oi->flags = 0; > oi->__upperdentry = NULL; > ovl_init_entry(&oi->oe, NULL, 0); > - oi->lowerdata = NULL; > + oi->lowerdata_redirect = NULL; > mutex_init(&oi->lock); > > return &oi->vfs_inode; > @@ -196,7 +196,7 @@ static void ovl_destroy_inode(struct inode > *inode) > if (S_ISDIR(inode->i_mode)) > ovl_dir_cache_free(inode); > else > - iput(oi->lowerdata); > + kfree(oi->lowerdata_redirect); > } > > static void ovl_free_fs(struct ovl_fs *ofs) > diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c > index 540819ac9b9c..fe2e5a8b216b 100644 > --- a/fs/overlayfs/util.c > +++ b/fs/overlayfs/util.c > @@ -245,11 +245,12 @@ void ovl_path_lower(struct dentry *dentry, > struct path *path) > void ovl_path_lowerdata(struct dentry *dentry, struct path *path) > { > struct ovl_entry *oe = OVL_E(dentry); > - struct ovl_path *lowerstack = ovl_lowerstack(oe); > + struct ovl_path *lowerdata = ovl_lowerdata(oe); > + struct dentry *lowerdata_dentry = ovl_lowerdata_dentry(oe); > > - if (ovl_numlower(oe)) { > - path->mnt = lowerstack[ovl_numlower(oe) - 1].layer- > >mnt; > - path->dentry = lowerstack[ovl_numlower(oe) - > 1].dentry; > + if (lowerdata_dentry) { > + path->dentry = lowerdata_dentry; > + path->mnt = lowerdata->layer->mnt; > } else { > *path = (struct path) { }; > } > @@ -308,10 +309,7 @@ const struct ovl_layer *ovl_layer_lower(struct > dentry *dentry) > */ > struct dentry *ovl_dentry_lowerdata(struct dentry *dentry) > { > - struct ovl_entry *oe = OVL_E(dentry); > - > - return ovl_numlower(oe) ? > - ovl_lowerstack(oe)[ovl_numlower(oe) - 1].dentry : > NULL; > + return ovl_lowerdata_dentry(OVL_E(dentry)); > } > > struct dentry *ovl_dentry_real(struct dentry *dentry) > @@ -359,10 +357,12 @@ struct inode *ovl_inode_real(struct inode > *inode) > /* Return inode which contains lower data. Do not return metacopy */ > struct inode *ovl_inode_lowerdata(struct inode *inode) > { > + struct dentry *lowerdata = > ovl_lowerdata_dentry(OVL_I_E(inode)); > + > if (WARN_ON(!S_ISREG(inode->i_mode))) > return NULL; > > - return OVL_I(inode)->lowerdata ?: ovl_inode_lower(inode); > + return lowerdata ? d_inode(lowerdata) : NULL; > } > > /* Return real inode which contains data. Does not return metacopy > inode */ > @@ -377,9 +377,15 @@ struct inode *ovl_inode_realdata(struct inode > *inode) > return ovl_inode_lowerdata(inode); > } > > +const char *ovl_lowerdata_redirect(struct inode *inode) > +{ > + return inode && S_ISREG(inode->i_mode) ? > + OVL_I(inode)->lowerdata_redirect : NULL; > +} > + > struct ovl_dir_cache *ovl_dir_cache(struct inode *inode) > { > - return OVL_I(inode)->cache; > + return inode && S_ISDIR(inode->i_mode) ? OVL_I(inode)->cache > : NULL; > } > > void ovl_set_dir_cache(struct inode *inode, struct ovl_dir_cache > *cache) -- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-= Alexander Larsson Red Hat, Inc alexl@xxxxxxxxxx alexander.larsson@xxxxxxxxx He's a shy one-eyed hairdresser with a robot buddy named Sparky. She's a mentally unstable communist bodyguard with the soul of a mighty warrior. They fight crime!