@@ -134,6 +134,7 @@ static int shiftfs_d_weak_revalidate(struct dentry *dentry, unsigned int flags)
static int shiftfs_d_revalidate(struct dentry *dentry, unsigned int flags)
{
struct dentry *real = dentry->d_fsdata;
+ struct inode *reali = d_inode(real), *inode = d_inode(dentry);
int ret;
if (d_unhashed(real))
@@ -146,6 +147,15 @@ static int shiftfs_d_revalidate(struct dentry *dentry, unsigned int flags)
if (d_is_negative(real) != d_is_negative(dentry))
return 0;
+ /*
+ * non dir link count is > 1 and our inode is currently not in
+ * the inode hash => need to drop and reget our dentry to make
+ * sure we're aliasing it correctly.
+ */
+ if (reali &&!S_ISDIR(reali->i_mode) && reali->i_nlink > 1 &&
+ (!inode || inode_unhashed(inode)))
+ return 0;
+
if (!(real->d_flags & DCACHE_OP_REVALIDATE))
return 1;
@@ -285,7 +295,8 @@ static int shiftfs_make_object(struct inode *dir, struct dentry *dentry,
umode_t mode, const char *symlink,
struct dentry *hardlink, bool excl)
{
- struct dentry *real = dir->i_private, *new = dentry->d_fsdata;
+ struct dentry *real = dir->i_private, *new = dentry->d_fsdata,
+ *realhardlink = NULL;
struct inode *reali = real->d_inode, *newi;
const struct inode_operations *iop = reali->i_op;
int err;
@@ -293,6 +304,7 @@ static int shiftfs_make_object(struct inode *dir, struct dentry *dentry,
bool op_ok = false;
if (hardlink) {
+ realhardlink = hardlink->d_fsdata;
op_ok = iop->link;
} else {
switch (mode & S_IFMT) {
@@ -310,7 +322,7 @@ static int shiftfs_make_object(struct inode *dir, struct dentry *dentry,
return -EINVAL;
- newi = shiftfs_new_inode(dentry->d_sb, mode, NULL);
+ newi = shiftfs_new_inode(dentry->d_sb, mode, realhardlink);
if (!newi)
return -ENOMEM;
@@ -320,8 +332,6 @@ static int shiftfs_make_object(struct inode *dir, struct dentry *dentry,
err = -EINVAL; /* shut gcc up about uninit var */
if (hardlink) {
- struct dentry *realhardlink = hardlink->d_fsdata;
-
err = vfs_link(realhardlink, reali, new, NULL);
} else {
switch (mode & S_IFMT) {
@@ -341,7 +351,16 @@ static int shiftfs_make_object(struct inode *dir, struct dentry *dentry,
if (err)
goto out_dput;
- shiftfs_fill_inode(newi, new);
+ if (!hardlink)
+ shiftfs_fill_inode(newi, new);
+ else if (inode_unhashed(newi) && !S_ISDIR(newi->i_mode))
+ /*
+ * although dentry and hardlink now each point to
+ * newi, the link count was 1 when they were created,
+ * so insert into the inode cache now that the link
+ * count has gone above one.
+ */
+ __insert_inode_hash(newi, (unsigned long)d_inode(new));
d_instantiate(dentry, newi);
@@ -569,12 +588,55 @@ static const struct inode_operations shiftfs_inode_ops = {
.listxattr = shiftfs_listxattr,
};
+static int shiftfs_test(struct inode *inode, void *data)
+{
+ struct dentry *d1 = inode->i_private, *d2 = data;
+ struct inode *i1 = d_inode(d1), *i2 = d_inode(d2);
+
+ return i1 && i1 == i2;
+}
+
+static int shiftfs_set(struct inode *inode, void *data)
+{
+ struct dentry *dentry = data;
+
+ shiftfs_fill_inode(inode, dentry);
+
+ return 0;
+}
+
static struct inode *shiftfs_new_inode(struct super_block *sb, umode_t mode,
struct dentry *dentry)
{
struct inode *inode;
+ struct inode *reali = dentry ? d_inode(dentry): NULL;
+ bool use_inode_hash = false;
+
+ /*
+ * Here we hash the inode only if the underlying link count is
+ * greater than one and it's not a directory (meaning the hash
+ * contains all items that might be aliases). We keep this
+ * accurate by checking the underlying link count on
+ * revalidation and forcing a new lookup if the underlying
+ * link count is raised.
+ *
+ * Note: if the link count drops again, we don't remove the
+ * inode from the hash, so the hash contains all inodes that
+ * may be aliases plus a few others.
+ */
+ if (reali)
+ use_inode_hash = ACCESS_ONCE(reali->i_nlink) > 1 &&
+ !S_ISDIR(reali->i_mode);
+
+ if (use_inode_hash) {
+ inode = iget5_locked(sb, (unsigned long)reali, shiftfs_test,
+ shiftfs_set, dentry);
+ if (inode && !(inode->i_state & I_NEW))
+ return inode;
+ } else {
+ inode = new_inode(sb);
+ }
- inode = new_inode(sb);
if (!inode)
return NULL;
@@ -586,7 +648,10 @@ static struct inode *shiftfs_new_inode(struct super_block *sb, umode_t mode,
inode->i_op = &shiftfs_inode_ops;
- shiftfs_fill_inode(inode, dentry);
+ if (use_inode_hash)
+ unlock_new_inode(inode);
+ else
+ shiftfs_fill_inode(inode, dentry);
return inode;
}