1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * fs/hmdfs/dentry.c
4 *
5 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
6 */
7
8 #include <linux/ctype.h>
9 #include <linux/slab.h>
10
11 #include "comm/connection.h"
12 #include "hmdfs_dentryfile.h"
13 #include "hmdfs_device_view.h"
14 #include "hmdfs_merge_view.h"
15
16 extern struct kmem_cache *hmdfs_dentry_cachep;
17
hmdfs_set_time(struct dentry * dentry,unsigned long time)18 void hmdfs_set_time(struct dentry *dentry, unsigned long time)
19 {
20 struct hmdfs_dentry_info *d_info = dentry->d_fsdata;
21
22 if (d_info)
23 d_info->time = time;
24 }
25
hmdfs_get_time(struct dentry * dentry)26 unsigned long hmdfs_get_time(struct dentry *dentry)
27 {
28 struct hmdfs_dentry_info *d_info = dentry->d_fsdata;
29
30 if (d_info)
31 return (unsigned long)d_info->time;
32 return 0;
33 }
34
hmdfs_d_remote_revalidate(struct hmdfs_peer * conn,struct dentry * target,struct dentry * parent)35 static int hmdfs_d_remote_revalidate(struct hmdfs_peer *conn,
36 struct dentry *target,
37 struct dentry *parent)
38 {
39 unsigned int timeout = hmdfs_sb(target->d_sb)->dcache_timeout;
40 unsigned long dentry_time = hmdfs_get_time(target);
41 struct clearcache_item *item;
42
43 item = hmdfs_find_cache_item(conn->device_id, parent);
44 if (!item)
45 return 0;
46 kref_put(&item->ref, release_cache_item);
47
48 if (cache_item_revalidate(READ_ONCE(conn->conn_time),
49 dentry_time, timeout))
50 return 1;
51
52 return 0;
53 }
54
lock_for_dname_cmp(struct dentry * dentry,struct dentry * lower_dentry)55 static inline void lock_for_dname_cmp(struct dentry *dentry,
56 struct dentry *lower_dentry)
57 {
58 if (dentry < lower_dentry) {
59 spin_lock(&dentry->d_lock);
60 spin_lock_nested(&lower_dentry->d_lock, DENTRY_D_LOCK_NESTED);
61 } else {
62 spin_lock(&lower_dentry->d_lock);
63 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
64 }
65 }
66
unlock_for_dname_cmp(struct dentry * dentry,struct dentry * lower_dentry)67 static inline void unlock_for_dname_cmp(struct dentry *dentry,
68 struct dentry *lower_dentry)
69 {
70 spin_unlock(&dentry->d_lock);
71 spin_unlock(&lower_dentry->d_lock);
72 }
73
hmdfs_dev_d_revalidate(struct dentry * direntry,unsigned int flags)74 static int hmdfs_dev_d_revalidate(struct dentry *direntry, unsigned int flags)
75 {
76 struct inode *dinode = NULL;
77 struct hmdfs_inode_info *info = NULL;
78
79 spin_lock(&direntry->d_lock);
80 if (IS_ROOT(direntry)) {
81 spin_unlock(&direntry->d_lock);
82 return 1;
83 }
84 spin_unlock(&direntry->d_lock);
85
86 dinode = d_inode(direntry);
87 if (!dinode)
88 return 0;
89
90 info = hmdfs_i(dinode);
91 if (info->inode_type == HMDFS_LAYER_SECOND_LOCAL ||
92 info->inode_type == HMDFS_LAYER_FIRST_DEVICE) {
93 return 1;
94 }
95 if (info->conn && info->conn->status == NODE_STAT_ONLINE)
96 return 1;
97
98 return 0;
99 }
100
hmdfs_d_revalidate(struct dentry * direntry,unsigned int flags)101 static int hmdfs_d_revalidate(struct dentry *direntry, unsigned int flags)
102 {
103 struct inode *dinode = NULL;
104 struct hmdfs_inode_info *info = NULL;
105 struct path lower_path, parent_lower_path;
106 struct dentry *parent_dentry = NULL;
107 struct dentry *parent_lower_dentry = NULL;
108 struct dentry *lower_cur_parent_dentry = NULL;
109 struct dentry *lower_dentry = NULL;
110 int ret;
111
112 if (flags & LOOKUP_RCU)
113 return -ECHILD;
114
115 if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET | LOOKUP_REVAL))
116 return 0;
117
118 dinode = d_inode(direntry);
119 if (!dinode)
120 return 0;
121
122 /* remote dentry timeout */
123 info = hmdfs_i(dinode);
124 parent_dentry = dget_parent(direntry);
125 if (info->conn) {
126 ret = hmdfs_d_remote_revalidate(info->conn, direntry,
127 parent_dentry);
128 dput(parent_dentry);
129 return ret;
130 }
131
132 hmdfs_get_lower_path(direntry, &lower_path);
133 lower_dentry = lower_path.dentry;
134 lower_cur_parent_dentry = dget_parent(lower_dentry);
135 hmdfs_get_lower_path(parent_dentry, &parent_lower_path);
136 parent_lower_dentry = parent_lower_path.dentry;
137 if ((lower_dentry->d_flags & DCACHE_OP_REVALIDATE)) {
138 ret = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
139 if (ret == 0)
140 goto out;
141 }
142
143 spin_lock(&lower_dentry->d_lock);
144 if (d_unhashed(lower_dentry)) {
145 spin_unlock(&lower_dentry->d_lock);
146 ret = 0;
147 goto out;
148 }
149 spin_unlock(&lower_dentry->d_lock);
150
151 if (parent_lower_dentry != lower_cur_parent_dentry) {
152 ret = 0;
153 goto out;
154 }
155
156 ret = 1;
157 lock_for_dname_cmp(direntry, lower_dentry);
158 if (!qstr_case_eq(&direntry->d_name, &lower_dentry->d_name))
159 ret = 0;
160 unlock_for_dname_cmp(direntry, lower_dentry);
161
162 out:
163 hmdfs_put_lower_path(&parent_lower_path);
164 dput(lower_cur_parent_dentry);
165 hmdfs_put_lower_path(&lower_path);
166 dput(parent_dentry);
167 return ret;
168 }
169
hmdfs_dev_d_release(struct dentry * dentry)170 static void hmdfs_dev_d_release(struct dentry *dentry)
171 {
172 if (!dentry || !dentry->d_fsdata)
173 return;
174
175 switch (hmdfs_d(dentry)->dentry_type) {
176 case HMDFS_LAYER_SECOND_LOCAL:
177 hmdfs_clear_cache_dents(dentry, false);
178 hmdfs_drop_remote_cache_dents(dentry);
179 path_put(&(hmdfs_d(dentry)->lower_path));
180 break;
181 case HMDFS_LAYER_ZERO:
182 hmdfs_put_reset_lower_path(dentry);
183 break;
184 case HMDFS_LAYER_FIRST_DEVICE:
185 break;
186 case HMDFS_LAYER_SECOND_REMOTE:
187 hmdfs_clear_cache_dents(dentry, false);
188 break;
189 default:
190 hmdfs_err("Unexpected dentry type %d",
191 hmdfs_d(dentry)->dentry_type);
192 return;
193 }
194
195 kmem_cache_free(hmdfs_dentry_cachep, dentry->d_fsdata);
196 dentry->d_fsdata = NULL;
197 }
198
hmdfs_d_release(struct dentry * dentry)199 static void hmdfs_d_release(struct dentry *dentry)
200 {
201 if (!dentry || !dentry->d_fsdata)
202 return;
203
204 hmdfs_clear_cache_dents(dentry, false);
205 hmdfs_drop_remote_cache_dents(dentry);
206 hmdfs_put_reset_lower_path(dentry);
207 kmem_cache_free(hmdfs_dentry_cachep, dentry->d_fsdata);
208 dentry->d_fsdata = NULL;
209 }
210
hmdfs_cmp_ci(const struct dentry * dentry,unsigned int len,const char * str,const struct qstr * name)211 static int hmdfs_cmp_ci(const struct dentry *dentry, unsigned int len,
212 const char *str, const struct qstr *name)
213 {
214 struct hmdfs_sb_info *sbi = hmdfs_sb(dentry->d_sb);
215
216 if (name->len != len)
217 return 1;
218
219 if (!sbi->s_case_sensitive) {
220 if (str_n_case_eq(name->name, str, len))
221 return 0;
222 } else {
223 if (!strncmp(name->name, str, len))
224 return 0;
225 }
226 return 1;
227 }
228
hmdfs_hash_ci(const struct dentry * dentry,struct qstr * qstr)229 static int hmdfs_hash_ci(const struct dentry *dentry, struct qstr *qstr)
230 {
231 const unsigned char *name = qstr->name;
232 unsigned int len = qstr->len;
233 unsigned long hash;
234 struct hmdfs_sb_info *sbi = hmdfs_sb(dentry->d_sb);
235
236 if (sbi->s_case_sensitive)
237 return 0;
238
239 hash = init_name_hash(dentry);
240 while (len--)
241 hash = partial_name_hash(tolower(*name++), hash);
242 qstr->hash = end_name_hash(hash);
243 return 0;
244 }
245
clear_comrades_locked(struct list_head * comrade_list)246 void clear_comrades_locked(struct list_head *comrade_list)
247 {
248 struct hmdfs_dentry_comrade *cc, *nc;
249
250 WARN_ON(!comrade_list);
251 list_for_each_entry_safe(cc, nc, comrade_list, list) {
252 dput(cc->lo_d);
253 kfree(cc);
254 }
255 INIT_LIST_HEAD(comrade_list);
256 }
257
clear_comrades(struct dentry * dentry)258 void clear_comrades(struct dentry *dentry)
259 {
260 struct hmdfs_dentry_info_merge *cdi = hmdfs_dm(dentry);
261
262 wait_event(cdi->wait_queue, !has_merge_lookup_work(cdi));
263 mutex_lock(&cdi->comrade_list_lock);
264 clear_comrades_locked(&cdi->comrade_list);
265 mutex_unlock(&cdi->comrade_list_lock);
266 }
267
268 /**
269 * d_revalidate_merge - revalidate a merge dentry
270 *
271 * Always return 0 to invalidate a dentry for fault-tolerance.
272 * The cost is acceptable for a overlay filesystem.
273 */
d_revalidate_merge(struct dentry * direntry,unsigned int flags)274 static int d_revalidate_merge(struct dentry *direntry, unsigned int flags)
275 {
276 struct hmdfs_dentry_info_merge *dim = hmdfs_dm(direntry);
277 struct hmdfs_dentry_comrade *comrade = NULL;
278 struct dentry *parent_dentry = NULL;
279 struct dentry *lower_cur_parent_dentry = NULL;
280 int ret = 1;
281
282 if (flags & LOOKUP_RCU) {
283 return -ECHILD;
284 }
285
286 if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET | LOOKUP_REVAL)) {
287 return 0;
288 }
289
290 parent_dentry = dget_parent(direntry);
291 mutex_lock(&dim->comrade_list_lock);
292 list_for_each_entry(comrade, &(dim->comrade_list), list) {
293 lower_cur_parent_dentry = dget_parent(comrade->lo_d);
294 if ((comrade->lo_d->d_flags & DCACHE_OP_REVALIDATE)) {
295 ret = comrade->lo_d->d_op->d_revalidate(
296 comrade->lo_d, flags);
297 if (ret == 0) {
298 dput(lower_cur_parent_dentry);
299 goto out;
300 }
301 }
302 dput(lower_cur_parent_dentry);
303 }
304 out:
305 mutex_unlock(&dim->comrade_list_lock);
306 dput(parent_dentry);
307 return ret;
308 }
309
d_release_merge(struct dentry * dentry)310 static void d_release_merge(struct dentry *dentry)
311 {
312 if (!dentry || !dentry->d_fsdata)
313 return;
314
315 clear_comrades(dentry);
316 kmem_cache_free(hmdfs_dentry_merge_cachep, dentry->d_fsdata);
317 dentry->d_fsdata = NULL;
318 }
319
320 const struct dentry_operations hmdfs_dops_merge = {
321 .d_revalidate = d_revalidate_merge,
322 .d_release = d_release_merge,
323 };
324
325 const struct dentry_operations hmdfs_dev_dops = {
326 .d_revalidate = hmdfs_dev_d_revalidate,
327 .d_release = hmdfs_dev_d_release,
328 };
329
330 const struct dentry_operations hmdfs_dops = {
331 .d_revalidate = hmdfs_d_revalidate,
332 .d_release = hmdfs_d_release,
333 .d_compare = hmdfs_cmp_ci,
334 .d_hash = hmdfs_hash_ci,
335 };
336