summaryrefslogtreecommitdiffstats
path: root/fs/orangefs/dcache.c
diff options
context:
space:
mode:
authorMartin Brandenburg <martin@omnibond.com>2016-01-28 16:19:40 +0100
committerMike Marshall <hubcap@omnibond.com>2016-01-28 21:08:40 +0100
commit99109822f5cbe6d530eb55193b25aa5348f6134d (patch)
tree5545d59702d9c2c2a28af01849a35f380ce01980 /fs/orangefs/dcache.c
parentorangefs: Util functions shouldn't operate on inode where it can be avoided. (diff)
downloadlinux-99109822f5cbe6d530eb55193b25aa5348f6134d.tar.xz
linux-99109822f5cbe6d530eb55193b25aa5348f6134d.zip
orangefs: Fix revalidate.
Previously, it would update a live inode. This was fixed, but it did not ever check that the inode attributes in the dcache are correct. This checks all inode attributes and rejects any that are not correct, which causes a lookup and thus a new getattr. Perhaps inode_operations->permission should replace or augment some of this. There is no actual caching, and this does a rather excessive amount of network operations back to the filesystem server. Signed-off-by: Martin Brandenburg <martin@omnibond.com> Signed-off-by: Mike Marshall <hubcap@omnibond.com>
Diffstat (limited to 'fs/orangefs/dcache.c')
-rw-r--r--fs/orangefs/dcache.c98
1 files changed, 61 insertions, 37 deletions
diff --git a/fs/orangefs/dcache.c b/fs/orangefs/dcache.c
index 0419981f773e..e8fb79de37c6 100644
--- a/fs/orangefs/dcache.c
+++ b/fs/orangefs/dcache.c
@@ -43,24 +43,34 @@ static int orangefs_revalidate_lookup(struct dentry *dentry)
err = service_operation(new_op, "orangefs_lookup",
get_interruptible_flag(parent_inode));
- if (err)
- goto out_drop;
-
- if (new_op->downcall.status != 0 ||
- !match_handle(new_op->downcall.resp.lookup.refn.khandle, inode)) {
- gossip_debug(GOSSIP_DCACHE_DEBUG,
- "%s:%s:%d "
- "lookup failure |%s| or no match |%s|.\n",
- __FILE__,
- __func__,
- __LINE__,
- new_op->downcall.status ? "true" : "false",
- match_handle(new_op->downcall.resp.lookup.refn.khandle,
- inode) ? "false" : "true");
- gossip_debug(GOSSIP_DCACHE_DEBUG,
- "%s:%s:%d revalidate failed\n",
- __FILE__, __func__, __LINE__);
- goto out_drop;
+
+ /* Positive dentry: reject if error or not the same inode. */
+ if (inode) {
+ if (err) {
+ gossip_debug(GOSSIP_DCACHE_DEBUG,
+ "%s:%s:%d lookup failure.\n",
+ __FILE__, __func__, __LINE__);
+ goto out_drop;
+ }
+ if (!match_handle(new_op->downcall.resp.lookup.refn.khandle,
+ inode)) {
+ gossip_debug(GOSSIP_DCACHE_DEBUG,
+ "%s:%s:%d no match.\n",
+ __FILE__, __func__, __LINE__);
+ goto out_drop;
+ }
+
+ /* Negative dentry: reject if success or error other than ENOENT. */
+ } else {
+ gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: negative dentry.\n",
+ __func__);
+ if (!err || err != -ENOENT) {
+ if (new_op->downcall.status != 0)
+ gossip_debug(GOSSIP_DCACHE_DEBUG,
+ "%s:%s:%d lookup failure.\n",
+ __FILE__, __func__, __LINE__);
+ goto out_drop;
+ }
}
ret = 1;
@@ -70,6 +80,8 @@ out_put_parent:
dput(parent_dentry);
return ret;
out_drop:
+ gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d revalidate failed\n",
+ __FILE__, __func__, __LINE__);
d_drop(dentry);
goto out_release_op;
}
@@ -81,8 +93,7 @@ out_drop:
*/
static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
{
- struct inode *inode;
- int ret = 0;
+ int ret;
if (flags & LOOKUP_RCU)
return -ECHILD;
@@ -90,29 +101,42 @@ static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n",
__func__, dentry);
- /* find inode from dentry */
- if (!dentry->d_inode) {
- gossip_debug(GOSSIP_DCACHE_DEBUG,
- "%s: negative dentry.\n",
- __func__);
- goto out;
+ /* skip root handle lookups. */
+ if (dentry->d_inode && is_root_handle(dentry->d_inode))
+ return 1;
+
+ /*
+ * If this passes, the positive dentry still exists or the negative
+ * dentry still does not exist.
+ */
+ if (!orangefs_revalidate_lookup(dentry)) {
+ d_drop(dentry);
+ return 0;
}
- gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: inode valid.\n", __func__);
- inode = dentry->d_inode;
-
- /* skip root handle lookups. */
- if (is_root_handle(inode)) {
- ret = 1;
+ /* We do not need to continue with negative dentries. */
+ if (!dentry->d_inode)
goto out;
- }
- /* lookup the object. */
- if (orangefs_revalidate_lookup(dentry))
- ret = 1;
+ /* Now we must perform a getattr to validate the inode contents. */
+ ret = orangefs_inode_getattr(dentry->d_inode,
+ ORANGEFS_ATTR_SYS_ALL_NOHINT, 1);
+ if (ret < 0) {
+ gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n",
+ __FILE__, __func__, __LINE__);
+ d_drop(dentry);
+ return 0;
+ }
+ if (ret == 0) {
+ d_drop(dentry);
+ return 0;
+ }
out:
- return ret;
+ gossip_debug(GOSSIP_DCACHE_DEBUG,
+ "%s: negative dentry or positive dentry and inode valid.\n",
+ __func__);
+ return 1;
}
const struct dentry_operations orangefs_dentry_operations = {