@@ -118,9 +118,50 @@ static struct dentry *shiftfs_d_real(struct dentry *dentry,
return real;
}
+static int shiftfs_d_weak_revalidate(struct dentry *dentry, unsigned int flags)
+{
+ struct dentry *real = dentry->d_fsdata;
+
+ if (d_unhashed(real))
+ return 0;
+
+ if (!(real->d_flags & DCACHE_OP_WEAK_REVALIDATE))
+ return 1;
+
+ return real->d_op->d_weak_revalidate(real, flags);
+}
+
+static int shiftfs_d_revalidate(struct dentry *dentry, unsigned int flags)
+{
+ struct dentry *real = dentry->d_fsdata;
+ int ret;
+
+ if (d_unhashed(real))
+ return 0;
+
+ /*
+ * inode state of underlying changed from positive to negative
+ * or vice versa; force a lookup to update our view
+ */
+ if (d_is_negative(real) != d_is_negative(dentry))
+ return 0;
+
+ if (!(real->d_flags & DCACHE_OP_REVALIDATE))
+ return 1;
+
+ ret = real->d_op->d_revalidate(real, flags);
+
+ if (ret == 0 && !(flags & LOOKUP_RCU))
+ d_invalidate(real);
+
+ return ret;
+}
+
static const struct dentry_operations shiftfs_dentry_ops = {
.d_release = shiftfs_d_release,
.d_real = shiftfs_d_real,
+ .d_revalidate = shiftfs_d_revalidate,
+ .d_weak_revalidate = shiftfs_d_weak_revalidate,
};
static int shiftfs_readlink(struct dentry *dentry, char __user *data,
@@ -423,7 +464,7 @@ static struct dentry *shiftfs_lookup(struct inode *dir, struct dentry *dentry,
dentry->d_fsdata = new;
if (!new->d_inode)
- return NULL;
+ goto out;
newi = shiftfs_new_inode(dentry->d_sb, new->d_inode->i_mode, new);
if (!newi) {
@@ -431,9 +472,8 @@ static struct dentry *shiftfs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(-ENOMEM);
}
- d_splice_alias(newi, dentry);
-
- return NULL;
+ out:
+ return d_splice_alias(newi, dentry);
}
static int shiftfs_permission(struct inode *inode, int mask)