162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * (C) 2001 Clemson University and The University of Chicago
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * See COPYING in top-level directory.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci *  Implementation of dentry (directory cache) functions.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "protocol.h"
1362306a36Sopenharmony_ci#include "orangefs-kernel.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* Returns 1 if dentry can still be trusted, else 0. */
1662306a36Sopenharmony_cistatic int orangefs_revalidate_lookup(struct dentry *dentry)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	struct dentry *parent_dentry = dget_parent(dentry);
1962306a36Sopenharmony_ci	struct inode *parent_inode = parent_dentry->d_inode;
2062306a36Sopenharmony_ci	struct orangefs_inode_s *parent = ORANGEFS_I(parent_inode);
2162306a36Sopenharmony_ci	struct inode *inode = dentry->d_inode;
2262306a36Sopenharmony_ci	struct orangefs_kernel_op_s *new_op;
2362306a36Sopenharmony_ci	int ret = 0;
2462306a36Sopenharmony_ci	int err = 0;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: attempting lookup.\n", __func__);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP);
2962306a36Sopenharmony_ci	if (!new_op) {
3062306a36Sopenharmony_ci		ret = -ENOMEM;
3162306a36Sopenharmony_ci		goto out_put_parent;
3262306a36Sopenharmony_ci	}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW;
3562306a36Sopenharmony_ci	new_op->upcall.req.lookup.parent_refn = parent->refn;
3662306a36Sopenharmony_ci	strncpy(new_op->upcall.req.lookup.d_name,
3762306a36Sopenharmony_ci		dentry->d_name.name,
3862306a36Sopenharmony_ci		ORANGEFS_NAME_MAX - 1);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	gossip_debug(GOSSIP_DCACHE_DEBUG,
4162306a36Sopenharmony_ci		     "%s:%s:%d interrupt flag [%d]\n",
4262306a36Sopenharmony_ci		     __FILE__,
4362306a36Sopenharmony_ci		     __func__,
4462306a36Sopenharmony_ci		     __LINE__,
4562306a36Sopenharmony_ci		     get_interruptible_flag(parent_inode));
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	err = service_operation(new_op, "orangefs_lookup",
4862306a36Sopenharmony_ci			get_interruptible_flag(parent_inode));
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	/* Positive dentry: reject if error or not the same inode. */
5162306a36Sopenharmony_ci	if (inode) {
5262306a36Sopenharmony_ci		if (err) {
5362306a36Sopenharmony_ci			gossip_debug(GOSSIP_DCACHE_DEBUG,
5462306a36Sopenharmony_ci			    "%s:%s:%d lookup failure.\n",
5562306a36Sopenharmony_ci			    __FILE__, __func__, __LINE__);
5662306a36Sopenharmony_ci			goto out_drop;
5762306a36Sopenharmony_ci		}
5862306a36Sopenharmony_ci		if (!match_handle(new_op->downcall.resp.lookup.refn.khandle,
5962306a36Sopenharmony_ci		    inode)) {
6062306a36Sopenharmony_ci			gossip_debug(GOSSIP_DCACHE_DEBUG,
6162306a36Sopenharmony_ci			    "%s:%s:%d no match.\n",
6262306a36Sopenharmony_ci			    __FILE__, __func__, __LINE__);
6362306a36Sopenharmony_ci			goto out_drop;
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* Negative dentry: reject if success or error other than ENOENT. */
6762306a36Sopenharmony_ci	} else {
6862306a36Sopenharmony_ci		gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: negative dentry.\n",
6962306a36Sopenharmony_ci		    __func__);
7062306a36Sopenharmony_ci		if (!err || err != -ENOENT) {
7162306a36Sopenharmony_ci			if (new_op->downcall.status != 0)
7262306a36Sopenharmony_ci				gossip_debug(GOSSIP_DCACHE_DEBUG,
7362306a36Sopenharmony_ci				    "%s:%s:%d lookup failure.\n",
7462306a36Sopenharmony_ci				    __FILE__, __func__, __LINE__);
7562306a36Sopenharmony_ci			goto out_drop;
7662306a36Sopenharmony_ci		}
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	orangefs_set_timeout(dentry);
8062306a36Sopenharmony_ci	ret = 1;
8162306a36Sopenharmony_ciout_release_op:
8262306a36Sopenharmony_ci	op_release(new_op);
8362306a36Sopenharmony_ciout_put_parent:
8462306a36Sopenharmony_ci	dput(parent_dentry);
8562306a36Sopenharmony_ci	return ret;
8662306a36Sopenharmony_ciout_drop:
8762306a36Sopenharmony_ci	gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d revalidate failed\n",
8862306a36Sopenharmony_ci	    __FILE__, __func__, __LINE__);
8962306a36Sopenharmony_ci	goto out_release_op;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/*
9362306a36Sopenharmony_ci * Verify that dentry is valid.
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * Should return 1 if dentry can still be trusted, else 0.
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_cistatic int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	int ret;
10062306a36Sopenharmony_ci	unsigned long time = (unsigned long) dentry->d_fsdata;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (time_before(jiffies, time))
10362306a36Sopenharmony_ci		return 1;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (flags & LOOKUP_RCU)
10662306a36Sopenharmony_ci		return -ECHILD;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n",
10962306a36Sopenharmony_ci		     __func__, dentry);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* skip root handle lookups. */
11262306a36Sopenharmony_ci	if (dentry->d_inode && is_root_handle(dentry->d_inode))
11362306a36Sopenharmony_ci		return 1;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/*
11662306a36Sopenharmony_ci	 * If this passes, the positive dentry still exists or the negative
11762306a36Sopenharmony_ci	 * dentry still does not exist.
11862306a36Sopenharmony_ci	 */
11962306a36Sopenharmony_ci	if (!orangefs_revalidate_lookup(dentry))
12062306a36Sopenharmony_ci		return 0;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* We do not need to continue with negative dentries. */
12362306a36Sopenharmony_ci	if (!dentry->d_inode) {
12462306a36Sopenharmony_ci		gossip_debug(GOSSIP_DCACHE_DEBUG,
12562306a36Sopenharmony_ci		    "%s: negative dentry or positive dentry and inode valid.\n",
12662306a36Sopenharmony_ci		    __func__);
12762306a36Sopenharmony_ci		return 1;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* Now we must perform a getattr to validate the inode contents. */
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	ret = orangefs_inode_check_changed(dentry->d_inode);
13362306a36Sopenharmony_ci	if (ret < 0) {
13462306a36Sopenharmony_ci		gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n",
13562306a36Sopenharmony_ci		    __FILE__, __func__, __LINE__);
13662306a36Sopenharmony_ci		return 0;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci	return !ret;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ciconst struct dentry_operations orangefs_dentry_operations = {
14262306a36Sopenharmony_ci	.d_revalidate = orangefs_d_revalidate,
14362306a36Sopenharmony_ci};
144