1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * This file contians vfs dentry ops for the 9P2000 protocol.
4 *
5 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
6 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
7 */
8
9 #include <linux/module.h>
10 #include <linux/errno.h>
11 #include <linux/fs.h>
12 #include <linux/file.h>
13 #include <linux/pagemap.h>
14 #include <linux/stat.h>
15 #include <linux/string.h>
16 #include <linux/namei.h>
17 #include <linux/sched.h>
18 #include <linux/slab.h>
19 #include <net/9p/9p.h>
20 #include <net/9p/client.h>
21
22 #include "v9fs.h"
23 #include "v9fs_vfs.h"
24 #include "fid.h"
25
26 /**
27 * v9fs_ndentry_is_expired - Check if negative dentry lookup has expired
28 *
29 * This should be called to know if a negative dentry should be removed from
30 * cache.
31 *
32 * @dentry: dentry in question
33 *
34 */
v9fs_ndentry_is_expired(struct dentry const * dentry)35 static bool v9fs_ndentry_is_expired(struct dentry const *dentry)
36 {
37 struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
38 struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
39
40 if (v9ses->ndentry_timeout_ms == NDENTRY_TIMEOUT_NEVER)
41 return false;
42
43 return time_before_eq64(v9fs_dentry->expire_time, get_jiffies_64());
44 }
45
46 /**
47 * v9fs_ndentry_refresh_timeout - Refresh negative dentry lookup cache timeout
48 *
49 * This should be called when a look up yields a negative entry.
50 *
51 * @dentry: dentry in question
52 *
53 */
v9fs_ndentry_refresh_timeout(struct dentry * dentry)54 void v9fs_ndentry_refresh_timeout(struct dentry *dentry)
55 {
56 struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
57 struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
58
59 if (v9ses->ndentry_timeout_ms == NDENTRY_TIMEOUT_NEVER)
60 return;
61
62 v9fs_dentry->expire_time = get_jiffies_64() +
63 msecs_to_jiffies(v9ses->ndentry_timeout_ms);
64 }
65
66 /**
67 * v9fs_cached_dentry_delete - called when dentry refcount equals 0
68 * @dentry: dentry in question
69 *
70 */
v9fs_cached_dentry_delete(const struct dentry * dentry)71 static int v9fs_cached_dentry_delete(const struct dentry *dentry)
72 {
73 p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p)\n",
74 dentry, dentry);
75
76 if (!d_really_is_negative(dentry))
77 return 0;
78
79 return v9fs_ndentry_is_expired(dentry);
80 }
81
__v9fs_dentry_fid_remove(struct dentry * dentry)82 static void __v9fs_dentry_fid_remove(struct dentry *dentry)
83 {
84 struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
85 struct hlist_node *p, *n;
86 struct hlist_head head;
87
88 p9_debug(P9_DEBUG_VFS, " dentry: %pd (%p)\n",
89 dentry, dentry);
90
91 spin_lock(&dentry->d_lock);
92 hlist_move_list(&v9fs_dentry->head, &head);
93 spin_unlock(&dentry->d_lock);
94
95 hlist_for_each_safe(p, n, &head)
96 p9_fid_put(hlist_entry(p, struct p9_fid, dlist));
97 }
98
99 /**
100 * v9fs_dentry_fid_remove - Release all dentry's fids
101 * @dentry: dentry in question
102 *
103 */
v9fs_dentry_fid_remove(struct dentry * dentry)104 void v9fs_dentry_fid_remove(struct dentry *dentry)
105 {
106 __v9fs_dentry_fid_remove(dentry);
107 }
108
109 /**
110 * v9fs_dentry_init - Initialize v9fs dentry data
111 * @dentry: dentry in question
112 *
113 */
v9fs_dentry_init(struct dentry * dentry)114 static int v9fs_dentry_init(struct dentry *dentry)
115 {
116 struct v9fs_dentry *v9fs_dentry = kzalloc_obj(*v9fs_dentry);
117
118 if (!v9fs_dentry)
119 return -ENOMEM;
120
121 INIT_HLIST_HEAD(&v9fs_dentry->head);
122 dentry->d_fsdata = (void *)v9fs_dentry;
123 return 0;
124 }
125
126 /**
127 * v9fs_dentry_release - called when dentry is going to be freed
128 * @dentry: dentry that is being released
129 *
130 */
v9fs_dentry_release(struct dentry * dentry)131 static void v9fs_dentry_release(struct dentry *dentry)
132 {
133 struct v9fs_dentry *v9fs_dentry = to_v9fs_dentry(dentry);
134
135 __v9fs_dentry_fid_remove(dentry);
136 kfree_rcu(v9fs_dentry, rcu);
137 }
138
__v9fs_lookup_revalidate(struct dentry * dentry,unsigned int flags)139 static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
140 {
141 struct p9_fid *fid;
142 struct inode *inode;
143 struct v9fs_inode *v9inode;
144
145 if (flags & LOOKUP_RCU)
146 return -ECHILD;
147
148 inode = d_inode(dentry);
149 if (!inode)
150 return !v9fs_ndentry_is_expired(dentry);
151
152 v9inode = V9FS_I(inode);
153 if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) {
154 int retval;
155 struct v9fs_session_info *v9ses;
156
157 fid = v9fs_fid_lookup(dentry);
158 if (IS_ERR(fid)) {
159 p9_debug(
160 P9_DEBUG_VFS,
161 "v9fs_fid_lookup: dentry = %pd (%p), got error %pe\n",
162 dentry, dentry, fid);
163 return PTR_ERR(fid);
164 }
165
166 v9ses = v9fs_inode2v9ses(inode);
167 if (v9fs_proto_dotl(v9ses))
168 retval = v9fs_refresh_inode_dotl(fid, inode);
169 else
170 retval = v9fs_refresh_inode(fid, inode);
171 p9_fid_put(fid);
172
173 if (retval == -ENOENT) {
174 p9_debug(P9_DEBUG_VFS, "dentry: %pd (%p) invalidated due to ENOENT\n",
175 dentry, dentry);
176 return 0;
177 }
178 if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) {
179 p9_debug(P9_DEBUG_VFS, "dentry: %pd (%p) invalidated due to type change\n",
180 dentry, dentry);
181 return 0;
182 }
183 if (retval < 0) {
184 p9_debug(P9_DEBUG_VFS,
185 "refresh inode: dentry = %pd (%p), got error %pe\n",
186 dentry, dentry, ERR_PTR(retval));
187 return retval;
188 }
189 }
190 p9_debug(P9_DEBUG_VFS, "dentry: %pd (%p) is valid\n", dentry, dentry);
191 return 1;
192 }
193
v9fs_lookup_revalidate(struct inode * dir,const struct qstr * name,struct dentry * dentry,unsigned int flags)194 static int v9fs_lookup_revalidate(struct inode *dir, const struct qstr *name,
195 struct dentry *dentry, unsigned int flags)
196 {
197 return __v9fs_lookup_revalidate(dentry, flags);
198 }
199
v9fs_dentry_unalias_trylock(const struct dentry * dentry)200 static bool v9fs_dentry_unalias_trylock(const struct dentry *dentry)
201 {
202 struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
203 return down_write_trylock(&v9ses->rename_sem);
204 }
205
v9fs_dentry_unalias_unlock(const struct dentry * dentry)206 static void v9fs_dentry_unalias_unlock(const struct dentry *dentry)
207 {
208 struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
209 up_write(&v9ses->rename_sem);
210 }
211
212 const struct dentry_operations v9fs_cached_dentry_operations = {
213 .d_revalidate = v9fs_lookup_revalidate,
214 .d_weak_revalidate = __v9fs_lookup_revalidate,
215 .d_delete = v9fs_cached_dentry_delete,
216 .d_init = v9fs_dentry_init,
217 .d_release = v9fs_dentry_release,
218 .d_unalias_trylock = v9fs_dentry_unalias_trylock,
219 .d_unalias_unlock = v9fs_dentry_unalias_unlock,
220 };
221
222 const struct dentry_operations v9fs_dentry_operations = {
223 .d_init = v9fs_dentry_init,
224 .d_release = v9fs_dentry_release,
225 .d_unalias_trylock = v9fs_dentry_unalias_trylock,
226 .d_unalias_unlock = v9fs_dentry_unalias_unlock,
227 };
228