On Thu, Jan 18, 2018 at 4:39 PM, Miklos Szeredi <miklos@xxxxxxxxxx> wrote: > On Thu, Jan 18, 2018 at 3:34 PM, Amir Goldstein <amir73il@xxxxxxxxx> wrote: >> On Thu, Jan 18, 2018 at 4:09 PM, Miklos Szeredi <miklos@xxxxxxxxxx> wrote: >>> [Added Al Viro] >>> >>> On Thu, Jan 4, 2018 at 6:20 PM, Amir Goldstein <amir73il@xxxxxxxxx> wrote: >>>> Decoding an upper file handle is done by decoding the upper dentry from >>>> underlying upper fs, finding or allocating an overlay inode that is >>>> hashed by the real upper inode and instantiating an overlay dentry with >>>> that inode. >>>> >>>> Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> >>>> --- >>>> fs/overlayfs/export.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ >>>> fs/overlayfs/namei.c | 4 +-- >>>> fs/overlayfs/overlayfs.h | 2 ++ >>>> 3 files changed, 95 insertions(+), 2 deletions(-) >>>> >>>> diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c >>>> index 58c4f5e8a67e..5c72784a0b4d 100644 >>>> --- a/fs/overlayfs/export.c >>>> +++ b/fs/overlayfs/export.c >>>> @@ -93,6 +93,97 @@ static int ovl_encode_inode_fh(struct inode *inode, u32 *fid, int *max_len, >>>> return type; >>>> } >>>> >>>> +/* >>>> + * Find or instantiate an overlay dentry from real dentries. >>>> + */ >>>> +static struct dentry *ovl_obtain_alias(struct super_block *sb, >>>> + struct dentry *upper, >>>> + struct ovl_path *lowerpath) >>>> +{ >>>> + struct inode *inode; >>>> + struct dentry *dentry; >>>> + struct ovl_entry *oe; >>>> + >>>> + /* TODO: obtain non pure-upper */ >>>> + if (lowerpath) >>>> + return ERR_PTR(-EIO); >>>> + >>>> + inode = ovl_get_inode(sb, dget(upper), NULL, NULL, 0); >>>> + if (IS_ERR(inode)) { >>>> + dput(upper); >>>> + return ERR_CAST(inode); >>>> + } >>>> + >>>> + dentry = d_obtain_alias(inode); >>>> + if (IS_ERR(dentry) || dentry->d_fsdata) >>> >>> Racing two instances of this code, each thinking it got a new alias >>> and trying to fill it, results in a memory leak. >>> >>> Haven't checked in too much depth, but apparently other filesystems >>> are not affected, so we need something special here. >>> >>> One solution: split d_instantiate_anon(dentry, inode) out of >>> __d_obtain_alias() and supply that with the already initialized >>> dentry. >>> >> >> Can't we use &OVL_I(inode)->lock to avoid the race? > > We could. But then d_splice_alias() will find our half baked dentry > and return that from ovl_lookup(). No it won't, because we do not obtain dir dentries this way. We actually do in this patch [3/17], but since patch [4/17] we don't, so I only need to fix this patch not to obtain dir dentry and to protect concurrent decode of non-dir with &OVL_I(inode)->lock. > So we do need to have the dentry > fully initialized by the time it's added into the inode's alias list. > The only problems I see with adding a non-dir disconnected alias that is not fully baked are: 1. We can get it in ovl_encode_inode_fh() from d_find_any_alias() 2. nfsd can get it in exportfs_decode_fh() from find_acceptable_alias() in a weird hypothetical case where the fully baked dentry we just returned from ovl_obtain_alias() in NOT acceptable by nfsd but the half baked dentry IS acceptable 3. Another kernel user that uses d_find_any_alias() or one of the use case that only Al can think of... Cases 2 and 3, I don't know if they are for real. Case 1 is only a problem due to lack of export_operations method 'dentry_to_fh'. exportfs_encode_fh() has the right dentry, but it does not pass it to the filesystem for encoding, so I think it should be solved by adding this method. Thanks, Amir. -- To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html