On Tue, Oct 17, 2017 at 7:44 PM, Amir Goldstein <amir73il@xxxxxxxxx> wrote: > To allow reconnecting of pure upper overlay dentry based on its > real parent, we restrict the implementation to encoding of overlay > dentries with pure upper ancestry up to overlay root. > > Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> > --- > fs/overlayfs/export.c | 70 ++++++++++++++++++++++++++++++++++++++++++++------- > 1 file changed, 61 insertions(+), 9 deletions(-) > > diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c > index 33914f23530e..263415dd929b 100644 > --- a/fs/overlayfs/export.c > +++ b/fs/overlayfs/export.c > @@ -17,15 +17,40 @@ > #include "overlayfs.h" > #include "ovl_entry.h" > > +/* Check if dentry is pure upper ancestry up to root */ > +static bool ovl_is_pure_upper_or_root(struct dentry *dentry, int connectable) > +{ > + struct dentry *parent = NULL; > + > + /* For non-connectable non-dir we don't need to check ancestry */ > + if (!d_is_dir(dentry) && !connectable) > + return !ovl_dentry_lower(dentry); > + > + dget(dentry); > + while (!IS_ROOT(dentry) && !ovl_dentry_lower(dentry)) { > + parent = dget_parent(dentry); > + dput(dentry); > + dentry = parent; > + } > + dput(dentry); > + > + return dentry == dentry->d_sb->s_root; > +} > + > /* TODO: add export_operations method dentry_to_fh() ??? */ > static int ovl_dentry_to_fh(struct dentry *dentry, struct fid *fid, > int *max_len, int connectable) > { > - struct dentry *lower = ovl_dentry_lower(dentry); > int type; > > - /* TODO: handle encoding of non pure upper */ > - if (lower) > + /* > + * Overlay root dir inode is hashed and encoded as pure upper, because > + * root dir dentry is born upper and not indexed. It is not a problem > + * that root dir is not indexed, because root dentry is pinned to cache. > + * > + * TODO: handle encoding of non pure upper. > + */ > + if (!ovl_is_pure_upper_or_root(dentry, connectable)) > return FILEID_INVALID; > > /* > @@ -40,20 +65,47 @@ static int ovl_dentry_to_fh(struct dentry *dentry, struct fid *fid, > return type; > } > > +/* Find an alias of inode. If @dir is non NULL, find a child alias */ > +static struct dentry *ovl_find_alias(struct inode *inode, struct inode *dir) > +{ > + struct dentry *parent, *child; > + struct dentry *alias = NULL; > + > + /* Parent inode is never provided when encoding a directory */ > + if (!dir || WARN_ON(!S_ISDIR(dir->i_mode) || S_ISDIR(inode->i_mode))) > + return d_find_alias(inode); > + > + /* > + * Run all of the dentries associated with this parent. Since this is > + * a directory, there damn well better only be one item on this list. > + */ FYI, this iteration is breaking locking order. I pushed a fix patch to iterate on aliases looking for match with parent to branch ovl-nfs-export-v1. This code was not exercised by my xfstests because name_to_handle_at() does not encode connectable file handles. I use a test patch (at the tip of ovl-nfs-export-v1) to encode connectable file handles from name_to_handle_at() to test this code. > + spin_lock(&dir->i_lock); > + hlist_for_each_entry(parent, &dir->i_dentry, d_u.d_alias) { > + /* Find an alias of inode who is a child of parent */ > + spin_lock(&parent->d_lock); > + list_for_each_entry(child, &parent->d_subdirs, d_child) { > + if (child->d_inode == inode) { > + alias = dget(child); > + break; > + } > + } > + spin_unlock(&parent->d_lock); > + } > + spin_unlock(&dir->i_lock); > + > + return alias; > +} > + > static int ovl_encode_inode_fh(struct inode *inode, u32 *fh, int *max_len, > struct inode *parent) > { > - struct dentry *dentry = d_find_alias(inode); > + struct dentry *dentry = ovl_find_alias(inode, parent); > int type; > > if (!dentry) > return FILEID_INVALID; > > - /* TODO: handle encoding of non-dir connectable file handle */ > - if (parent) > - return FILEID_INVALID; > - > - type = ovl_dentry_to_fh(dentry, (struct fid *)fh, max_len, 0); > + type = ovl_dentry_to_fh(dentry, (struct fid *)fh, max_len, !!parent); > > dput(dentry); > return type; > -- > 2.7.4 >