forked from mirrors/linux
		
	ovl: hash overlay non-dir inodes by copy up origin
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
		
							parent
							
								
									415543d5c6
								
							
						
					
					
						commit
						b9ac5c274b
					
				
					 3 changed files with 44 additions and 9 deletions
				
			
		| 
						 | 
					@ -467,6 +467,25 @@ static int ovl_inode_set(struct inode *inode, void *data)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool ovl_verify_inode(struct inode *inode, struct dentry *lowerdentry,
 | 
				
			||||||
 | 
								     struct dentry *upperdentry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct inode *lowerinode = lowerdentry ? d_inode(lowerdentry) : NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Lower (origin) inode must match, even if NULL */
 | 
				
			||||||
 | 
						if (ovl_inode_lower(inode) != lowerinode)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Allow non-NULL __upperdentry in inode even if upperdentry is NULL.
 | 
				
			||||||
 | 
						 * This happens when finding a lower alias for a copied up hard link.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (upperdentry && ovl_inode_upper(inode) != d_inode(upperdentry))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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 *lowerdentry = ovl_dentry_lower(dentry);
 | 
						struct dentry *lowerdentry = ovl_dentry_lower(dentry);
 | 
				
			||||||
| 
						 | 
					@ -476,12 +495,25 @@ struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry)
 | 
				
			||||||
	if (!realinode)
 | 
						if (!realinode)
 | 
				
			||||||
		realinode = d_inode(lowerdentry);
 | 
							realinode = d_inode(lowerdentry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (upperdentry && !d_is_dir(upperdentry)) {
 | 
						if (!S_ISDIR(realinode->i_mode) &&
 | 
				
			||||||
		inode = iget5_locked(dentry->d_sb, (unsigned long) realinode,
 | 
						    (upperdentry || (lowerdentry && ovl_indexdir(dentry->d_sb)))) {
 | 
				
			||||||
				     ovl_inode_test, ovl_inode_set, realinode);
 | 
							struct inode *key = d_inode(lowerdentry ?: upperdentry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inode = iget5_locked(dentry->d_sb, (unsigned long) key,
 | 
				
			||||||
 | 
									     ovl_inode_test, ovl_inode_set, key);
 | 
				
			||||||
		if (!inode)
 | 
							if (!inode)
 | 
				
			||||||
			goto out;
 | 
								goto out_nomem;
 | 
				
			||||||
		if (!(inode->i_state & I_NEW)) {
 | 
							if (!(inode->i_state & I_NEW)) {
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * Verify that the underlying files stored in the inode
 | 
				
			||||||
 | 
								 * match those in the dentry.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (!ovl_verify_inode(inode, lowerdentry, upperdentry)) {
 | 
				
			||||||
 | 
									iput(inode);
 | 
				
			||||||
 | 
									inode = ERR_PTR(-ESTALE);
 | 
				
			||||||
 | 
									goto out;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			dput(upperdentry);
 | 
								dput(upperdentry);
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -490,7 +522,7 @@ struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		inode = new_inode(dentry->d_sb);
 | 
							inode = new_inode(dentry->d_sb);
 | 
				
			||||||
		if (!inode)
 | 
							if (!inode)
 | 
				
			||||||
			goto out;
 | 
								goto out_nomem;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev);
 | 
						ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev);
 | 
				
			||||||
	ovl_inode_init(inode, upperdentry, lowerdentry);
 | 
						ovl_inode_init(inode, upperdentry, lowerdentry);
 | 
				
			||||||
| 
						 | 
					@ -502,4 +534,8 @@ struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry)
 | 
				
			||||||
		unlock_new_inode(inode);
 | 
							unlock_new_inode(inode);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	return inode;
 | 
						return inode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_nomem:
 | 
				
			||||||
 | 
						inode = ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
						goto out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -678,9 +678,9 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
 | 
				
			||||||
		upperdentry = dget(index);
 | 
							upperdentry = dget(index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (upperdentry || ctr) {
 | 
						if (upperdentry || ctr) {
 | 
				
			||||||
		err = -ENOMEM;
 | 
					 | 
				
			||||||
		inode = ovl_get_inode(dentry, upperdentry);
 | 
							inode = ovl_get_inode(dentry, upperdentry);
 | 
				
			||||||
		if (!inode)
 | 
							err = PTR_ERR(inode);
 | 
				
			||||||
 | 
							if (IS_ERR(inode))
 | 
				
			||||||
			goto out_free_oe;
 | 
								goto out_free_oe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		OVL_I(inode)->redirect = upperredirect;
 | 
							OVL_I(inode)->redirect = upperredirect;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -236,7 +236,6 @@ void ovl_inode_update(struct inode *inode, struct dentry *upperdentry)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct inode *upperinode = d_inode(upperdentry);
 | 
						struct inode *upperinode = d_inode(upperdentry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	WARN_ON(!inode_unhashed(inode));
 | 
					 | 
				
			||||||
	WARN_ON(!inode_is_locked(upperdentry->d_parent->d_inode));
 | 
						WARN_ON(!inode_is_locked(upperdentry->d_parent->d_inode));
 | 
				
			||||||
	WARN_ON(OVL_I(inode)->__upperdentry);
 | 
						WARN_ON(OVL_I(inode)->__upperdentry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -245,7 +244,7 @@ void ovl_inode_update(struct inode *inode, struct dentry *upperdentry)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	smp_wmb();
 | 
						smp_wmb();
 | 
				
			||||||
	OVL_I(inode)->__upperdentry = upperdentry;
 | 
						OVL_I(inode)->__upperdentry = upperdentry;
 | 
				
			||||||
	if (!S_ISDIR(upperinode->i_mode)) {
 | 
						if (!S_ISDIR(upperinode->i_mode) && inode_unhashed(inode)) {
 | 
				
			||||||
		inode->i_private = upperinode;
 | 
							inode->i_private = upperinode;
 | 
				
			||||||
		__insert_inode_hash(inode, (unsigned long) upperinode);
 | 
							__insert_inode_hash(inode, (unsigned long) upperinode);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue