return ovl_set_opaque_xerr(dentry, upperdentry, -EIO);
}
-/* Common operations required to be done after creation of file on upper */
-static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
- struct dentry *newdentry, bool hardlink)
+/*
+ * Common operations required to be done after creation of file on upper.
+ * If @hardlink is false, then @inode is a pre-allocated inode, we may or
+ * may not use to instantiate the new dentry.
+ */
+static int ovl_instantiate(struct dentry *dentry, struct inode *inode,
+ struct dentry *newdentry, bool hardlink)
{
+ struct ovl_inode_params oip = {
+ .upperdentry = newdentry,
+ .newinode = inode,
+ };
+
ovl_dentry_version_inc(dentry->d_parent, false);
ovl_dentry_set_upper_alias(dentry);
if (!hardlink) {
- ovl_inode_update(inode, newdentry);
- ovl_copyattr(newdentry->d_inode, inode);
+ /*
+ * ovl_obtain_alias() can be called after ovl_create_real()
+ * and before we get here, so we may get an inode from cache
+ * with the same real upperdentry that is not the inode we
+ * pre-allocated. In this case we will use the cached inode
+ * to instantiate the new dentry.
+ *
+ * XXX: if we ever use ovl_obtain_alias() to decode directory
+ * file handles, need to use ovl_get_inode_locked() and
+ * d_instantiate_new() here to prevent from creating two
+ * hashed directory inode aliases.
+ */
+ inode = ovl_get_inode(dentry->d_sb, &oip);
+ if (WARN_ON(IS_ERR(inode)))
+ return PTR_ERR(inode);
} else {
WARN_ON(ovl_inode_real(inode) != d_inode(newdentry));
dput(newdentry);
inc_nlink(inode);
}
+
d_instantiate(dentry, inode);
+ if (inode != oip.newinode) {
+ pr_warn_ratelimited("overlayfs: newly created inode found in cache (%pd2)\n",
+ dentry);
+ }
+
/* Force lookup of new upper hardlink to find its lower */
if (hardlink)
d_drop(dentry);
+
+ return 0;
}
static bool ovl_type_merge(struct dentry *dentry)
ovl_set_opaque(dentry, newdentry);
}
- ovl_instantiate(dentry, inode, newdentry, !!attr->hardlink);
- err = 0;
+ err = ovl_instantiate(dentry, inode, newdentry, !!attr->hardlink);
+ if (err)
+ goto out_cleanup;
out_unlock:
inode_unlock(udir);
return err;
+
+out_cleanup:
+ ovl_cleanup(udir, newdentry);
+ dput(newdentry);
+ goto out_unlock;
}
static struct dentry *ovl_clear_empty(struct dentry *dentry,
if (err)
goto out_cleanup;
}
- ovl_instantiate(dentry, inode, newdentry, hardlink);
- err = 0;
+ err = ovl_instantiate(dentry, inode, newdentry, hardlink);
+ if (err)
+ goto out_cleanup;
out_dput:
dput(upper);
out_unlock:
if (err)
goto out;
+ /* Preallocate inode to be used by ovl_get_inode() */
err = -ENOMEM;
inode = ovl_new_inode(dentry->d_sb, mode, rdev);
if (!inode)
attr.mode = inode->i_mode;
err = ovl_create_or_link(dentry, inode, &attr, false);
- if (err)
+ /* Did we end up using the preallocated inode? */
+ if (inode != d_inode(dentry))
iput(inode);
out_drop_write:
return true;
}
+static struct inode *ovl_iget5(struct super_block *sb, struct inode *newinode,
+ struct inode *key)
+{
+ return newinode ? inode_insert5(newinode, (unsigned long) key,
+ ovl_inode_test, ovl_inode_set, key) :
+ iget5_locked(sb, (unsigned long) key,
+ ovl_inode_test, ovl_inode_set, key);
+}
+
struct inode *ovl_get_inode(struct super_block *sb,
struct ovl_inode_params *oip)
{
upperdentry);
unsigned int nlink = is_dir ? 1 : realinode->i_nlink;
- inode = iget5_locked(sb, (unsigned long) key, ovl_inode_test,
- ovl_inode_set, key);
+ inode = ovl_iget5(sb, oip->newinode, key);
if (!inode)
goto out_nomem;
if (!(inode->i_state & I_NEW)) {