diff options
Diffstat (limited to 'fs/overlayfs/inode.c')
| -rw-r--r-- | fs/overlayfs/inode.c | 20 | 
1 files changed, 16 insertions, 4 deletions
| diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index a619addecafc..321511ed8c42 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -598,18 +598,30 @@ static bool ovl_verify_inode(struct inode *inode, struct dentry *lowerdentry,  	return true;  } -struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry) +struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry, +			    struct dentry *index)  {  	struct dentry *lowerdentry = ovl_dentry_lower(dentry);  	struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL;  	struct inode *inode; +	/* Already indexed or could be indexed on copy up? */ +	bool indexed = (index || (ovl_indexdir(dentry->d_sb) && !upperdentry)); + +	if (WARN_ON(upperdentry && indexed && !lowerdentry)) +		return ERR_PTR(-EIO);  	if (!realinode)  		realinode = d_inode(lowerdentry); -	if (!S_ISDIR(realinode->i_mode) && -	    (upperdentry || (lowerdentry && ovl_indexdir(dentry->d_sb)))) { -		struct inode *key = d_inode(lowerdentry ?: upperdentry); +	/* +	 * Copy up origin (lower) may exist for non-indexed upper, but we must +	 * not use lower as hash key in that case. +	 * Hash inodes that are or could be indexed by origin inode and +	 * non-indexed upper inodes that could be hard linked by upper inode. +	 */ +	if (!S_ISDIR(realinode->i_mode) && (upperdentry || indexed)) { +		struct inode *key = d_inode(indexed ? lowerdentry : +						      upperdentry);  		unsigned int nlink;  		inode = iget5_locked(dentry->d_sb, (unsigned long) key, | 
