Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b9ac5c27 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

ovl: hash overlay non-dir inodes by copy up origin

parent 415543d5
Loading
Loading
Loading
Loading
+41 −5
Original line number Diff line number Diff line
@@ -467,6 +467,25 @@ static int ovl_inode_set(struct inode *inode, void *data)
	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 dentry *lowerdentry = ovl_dentry_lower(dentry);
@@ -476,12 +495,25 @@ struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry)
	if (!realinode)
		realinode = d_inode(lowerdentry);

	if (upperdentry && !d_is_dir(upperdentry)) {
		inode = iget5_locked(dentry->d_sb, (unsigned long) realinode,
				     ovl_inode_test, ovl_inode_set, realinode);
	if (!S_ISDIR(realinode->i_mode) &&
	    (upperdentry || (lowerdentry && ovl_indexdir(dentry->d_sb)))) {
		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)
			goto out;
			goto out_nomem;
		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);
			goto out;
		}
@@ -490,7 +522,7 @@ struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry)
	} else {
		inode = new_inode(dentry->d_sb);
		if (!inode)
			goto out;
			goto out_nomem;
	}
	ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev);
	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);
out:
	return inode;

out_nomem:
	inode = ERR_PTR(-ENOMEM);
	goto out;
}
+2 −2
Original line number Diff line number Diff line
@@ -678,9 +678,9 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
		upperdentry = dget(index);

	if (upperdentry || ctr) {
		err = -ENOMEM;
		inode = ovl_get_inode(dentry, upperdentry);
		if (!inode)
		err = PTR_ERR(inode);
		if (IS_ERR(inode))
			goto out_free_oe;

		OVL_I(inode)->redirect = upperredirect;
+1 −2
Original line number Diff line number Diff line
@@ -236,7 +236,6 @@ void ovl_inode_update(struct inode *inode, struct dentry *upperdentry)
{
	struct inode *upperinode = d_inode(upperdentry);

	WARN_ON(!inode_unhashed(inode));
	WARN_ON(!inode_is_locked(upperdentry->d_parent->d_inode));
	WARN_ON(OVL_I(inode)->__upperdentry);

@@ -245,7 +244,7 @@ void ovl_inode_update(struct inode *inode, struct dentry *upperdentry)
	 */
	smp_wmb();
	OVL_I(inode)->__upperdentry = upperdentry;
	if (!S_ISDIR(upperinode->i_mode)) {
	if (!S_ISDIR(upperinode->i_mode) && inode_unhashed(inode)) {
		inode->i_private = upperinode;
		__insert_inode_hash(inode, (unsigned long) upperinode);
	}