diff options
author | Martin Brandenburg <martin@omnibond.com> | 2016-01-28 10:19:40 -0500 |
---|---|---|
committer | Mike Marshall <hubcap@omnibond.com> | 2016-01-28 15:08:40 -0500 |
commit | 99109822f5cbe6d530eb55193b25aa5348f6134d (patch) | |
tree | 5545d59702d9c2c2a28af01849a35f380ce01980 /fs/orangefs/dcache.c | |
parent | 394f647e3ad073dab19ba081501e4a0ca05302c4 (diff) |
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.c | 98 |
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 = { |