On Fri, Mar 4, 2016 at 5:17 AM, Miklos Szeredi <miklos@xxxxxxxxxx> wrote: > On Thu, Mar 03, 2016 at 09:16:33AM +0100, Miklos Szeredi wrote: >> My plan was to introduce a file_dentry() helper that MUST be used by >> filesystems to get the dentry from the file and that makes sure it's >> the right one (check against file_inode()). If not, then we could >> call into overlayfs to return the right one, similar to >> ->d_select_inode(), except we want to have a dentry and we want to >> have *a particular dentry* matching file_inode() (the file could have >> been copied up in the mean time). > > Something like the following (untested, against overlayfs-next.git) > > Thanks, > Miklos > > --- > fs/nfs/dir.c | 6 +++--- > fs/nfs/inode.c | 2 +- > fs/nfs/nfs4file.c | 4 ++-- > fs/open.c | 11 +++++++++++ > fs/overlayfs/super.c | 16 ++++++++++++++++ > include/linux/dcache.h | 1 + > include/linux/fs.h | 2 ++ > 7 files changed, 36 insertions(+), 6 deletions(-) > > --- a/fs/nfs/dir.c > +++ b/fs/nfs/dir.c > @@ -377,7 +377,7 @@ int nfs_readdir_xdr_filler(struct page * > again: > timestamp = jiffies; > gencount = nfs_inc_attr_generation_counter(); > - error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, entry->cookie, pages, > + error = NFS_PROTO(inode)->readdir(file_dentry(file), cred, entry->cookie, pages, > NFS_SERVER(inode)->dtsize, desc->plus); > if (error < 0) { > /* We requested READDIRPLUS, but the server doesn't grok it */ > @@ -560,7 +560,7 @@ int nfs_readdir_page_filler(nfs_readdir_ > count++; > > if (desc->plus != 0) > - nfs_prime_dcache(desc->file->f_path.dentry, entry); > + nfs_prime_dcache(file_dentry(desc->file), entry); > > status = nfs_readdir_add_to_array(entry, page); > if (status != 0) > @@ -864,7 +864,7 @@ static bool nfs_dir_mapping_need_revalid > */ > static int nfs_readdir(struct file *file, struct dir_context *ctx) > { > - struct dentry *dentry = file->f_path.dentry; > + struct dentry *dentry = file_dentry(file); > struct inode *inode = d_inode(dentry); > nfs_readdir_descriptor_t my_desc, > *desc = &my_desc; > --- a/fs/nfs/inode.c > +++ b/fs/nfs/inode.c > @@ -940,7 +940,7 @@ int nfs_open(struct inode *inode, struct > { > struct nfs_open_context *ctx; > > - ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode); > + ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode); > if (IS_ERR(ctx)) > return PTR_ERR(ctx); > nfs_file_set_open_context(filp, ctx); > --- a/fs/nfs/nfs4file.c > +++ b/fs/nfs/nfs4file.c > @@ -26,7 +26,7 @@ static int > nfs4_file_open(struct inode *inode, struct file *filp) > { > struct nfs_open_context *ctx; > - struct dentry *dentry = filp->f_path.dentry; > + struct dentry *dentry = file_dentry(filp); > struct dentry *parent = NULL; > struct inode *dir; > unsigned openflags = filp->f_flags; > @@ -57,7 +57,7 @@ nfs4_file_open(struct inode *inode, stru > parent = dget_parent(dentry); > dir = d_inode(parent); > > - ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode); > + ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode); > err = PTR_ERR(ctx); > if (IS_ERR(ctx)) > goto out; > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -1234,6 +1234,8 @@ static inline struct inode *file_inode(c > return f->f_inode; > } > > +extern struct dentry *file_dentry(const struct file *file); > + > static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl) > { > return locks_lock_inode_wait(file_inode(filp), fl); > --- a/fs/open.c > +++ b/fs/open.c > @@ -831,6 +831,17 @@ char *file_path(struct file *filp, char > } > EXPORT_SYMBOL(file_path); > > +struct dentry *file_dentry(const struct file *file) > +{ > + struct dentry *dentry = file->f_path.dentry; > + > + if (d_inode(dentry) == file_inode(file)) > + return dentry; > + else > + return dentry->d_op->d_select_dentry(dentry, file_inode(file)); > +} > +EXPORT_SYMBOL(file_dentry); > + > /** > * vfs_open - open the file at the given path > * @path: path to open > --- a/fs/overlayfs/super.c > +++ b/fs/overlayfs/super.c > @@ -336,14 +336,30 @@ static int ovl_dentry_weak_revalidate(st > return ret; > } > > +static struct dentry *ovl_d_select_dentry(struct dentry *dentry, > + struct inode *inode) > +{ > + struct ovl_entry *oe = dentry->d_fsdata; > + struct dentry *realentry = ovl_upperdentry_dereference(oe); > + > + if (realentry && inode == d_inode(realentry)) > + return realentry; > + realentry = __ovl_dentry_lower(oe); > + if (realentry && inode == d_inode(realentry)) > + return realentry; > + BUG(); > +} > + > static const struct dentry_operations ovl_dentry_operations = { > .d_release = ovl_dentry_release, > .d_select_inode = ovl_d_select_inode, > + .d_select_dentry = ovl_d_select_dentry, > }; > > static const struct dentry_operations ovl_reval_dentry_operations = { > .d_release = ovl_dentry_release, > .d_select_inode = ovl_d_select_inode, > + .d_select_dentry = ovl_d_select_dentry, > .d_revalidate = ovl_dentry_revalidate, > .d_weak_revalidate = ovl_dentry_weak_revalidate, > }; > --- a/include/linux/dcache.h > +++ b/include/linux/dcache.h > @@ -161,6 +161,7 @@ struct dentry_operations { > struct vfsmount *(*d_automount)(struct path *); > int (*d_manage)(struct dentry *, bool); > struct inode *(*d_select_inode)(struct dentry *, unsigned); > + struct dentry *(*d_select_dentry)(struct dentry *, struct inode *); > } ____cacheline_aligned; > > /* Thanks Miklos! That looks reasonable, assuming it tests out correctly. Cheers Trond -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html