1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) 2001 Clemson University and The University of Chicago
4  *
5  * See COPYING in top-level directory.
6  */
7 
8 /*
9  *  Implementation of dentry (directory cache) functions.
10  */
11 
12 #include "protocol.h"
13 #include "orangefs-kernel.h"
14 
15 /* Returns 1 if dentry can still be trusted, else 0. */
orangefs_revalidate_lookup(struct dentry * dentry)16 static int orangefs_revalidate_lookup(struct dentry *dentry)
17 {
18 	struct dentry *parent_dentry = dget_parent(dentry);
19 	struct inode *parent_inode = parent_dentry->d_inode;
20 	struct orangefs_inode_s *parent = ORANGEFS_I(parent_inode);
21 	struct inode *inode = dentry->d_inode;
22 	struct orangefs_kernel_op_s *new_op;
23 	int ret = 0;
24 	int err = 0;
25 
26 	gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: attempting lookup.\n", __func__);
27 
28 	new_op = op_alloc(ORANGEFS_VFS_OP_LOOKUP);
29 	if (!new_op) {
30 		ret = -ENOMEM;
31 		goto out_put_parent;
32 	}
33 
34 	new_op->upcall.req.lookup.sym_follow = ORANGEFS_LOOKUP_LINK_NO_FOLLOW;
35 	new_op->upcall.req.lookup.parent_refn = parent->refn;
36 	strncpy(new_op->upcall.req.lookup.d_name,
37 		dentry->d_name.name,
38 		ORANGEFS_NAME_MAX - 1);
39 
40 	gossip_debug(GOSSIP_DCACHE_DEBUG,
41 		     "%s:%s:%d interrupt flag [%d]\n",
42 		     __FILE__,
43 		     __func__,
44 		     __LINE__,
45 		     get_interruptible_flag(parent_inode));
46 
47 	err = service_operation(new_op, "orangefs_lookup",
48 			get_interruptible_flag(parent_inode));
49 
50 	/* Positive dentry: reject if error or not the same inode. */
51 	if (inode) {
52 		if (err) {
53 			gossip_debug(GOSSIP_DCACHE_DEBUG,
54 			    "%s:%s:%d lookup failure.\n",
55 			    __FILE__, __func__, __LINE__);
56 			goto out_drop;
57 		}
58 		if (!match_handle(new_op->downcall.resp.lookup.refn.khandle,
59 		    inode)) {
60 			gossip_debug(GOSSIP_DCACHE_DEBUG,
61 			    "%s:%s:%d no match.\n",
62 			    __FILE__, __func__, __LINE__);
63 			goto out_drop;
64 		}
65 
66 	/* Negative dentry: reject if success or error other than ENOENT. */
67 	} else {
68 		gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: negative dentry.\n",
69 		    __func__);
70 		if (!err || err != -ENOENT) {
71 			if (new_op->downcall.status != 0)
72 				gossip_debug(GOSSIP_DCACHE_DEBUG,
73 				    "%s:%s:%d lookup failure.\n",
74 				    __FILE__, __func__, __LINE__);
75 			goto out_drop;
76 		}
77 	}
78 
79 	orangefs_set_timeout(dentry);
80 	ret = 1;
81 out_release_op:
82 	op_release(new_op);
83 out_put_parent:
84 	dput(parent_dentry);
85 	return ret;
86 out_drop:
87 	gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d revalidate failed\n",
88 	    __FILE__, __func__, __LINE__);
89 	goto out_release_op;
90 }
91 
92 /*
93  * Verify that dentry is valid.
94  *
95  * Should return 1 if dentry can still be trusted, else 0.
96  */
orangefs_d_revalidate(struct dentry * dentry,unsigned int flags)97 static int orangefs_d_revalidate(struct dentry *dentry, unsigned int flags)
98 {
99 	int ret;
100 	unsigned long time = (unsigned long) dentry->d_fsdata;
101 
102 	if (time_before(jiffies, time))
103 		return 1;
104 
105 	if (flags & LOOKUP_RCU)
106 		return -ECHILD;
107 
108 	gossip_debug(GOSSIP_DCACHE_DEBUG, "%s: called on dentry %p.\n",
109 		     __func__, dentry);
110 
111 	/* skip root handle lookups. */
112 	if (dentry->d_inode && is_root_handle(dentry->d_inode))
113 		return 1;
114 
115 	/*
116 	 * If this passes, the positive dentry still exists or the negative
117 	 * dentry still does not exist.
118 	 */
119 	if (!orangefs_revalidate_lookup(dentry))
120 		return 0;
121 
122 	/* We do not need to continue with negative dentries. */
123 	if (!dentry->d_inode) {
124 		gossip_debug(GOSSIP_DCACHE_DEBUG,
125 		    "%s: negative dentry or positive dentry and inode valid.\n",
126 		    __func__);
127 		return 1;
128 	}
129 
130 	/* Now we must perform a getattr to validate the inode contents. */
131 
132 	ret = orangefs_inode_check_changed(dentry->d_inode);
133 	if (ret < 0) {
134 		gossip_debug(GOSSIP_DCACHE_DEBUG, "%s:%s:%d getattr failure.\n",
135 		    __FILE__, __func__, __LINE__);
136 		return 0;
137 	}
138 	return !ret;
139 }
140 
141 const struct dentry_operations orangefs_dentry_operations = {
142 	.d_revalidate = orangefs_d_revalidate,
143 };
144