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 struct clearcache_item *item;
173 if (!dentry || !dentry->d_fsdata)
174 return;
175
176 switch (hmdfs_d(dentry)->dentry_type) {
177 case HMDFS_LAYER_SECOND_LOCAL:
178 hmdfs_clear_cache_dents(dentry, false);
179 hmdfs_drop_remote_cache_dents(dentry);
180 path_put(&(hmdfs_d(dentry)->lower_path));
181 break;
182 case HMDFS_LAYER_ZERO:
183 hmdfs_put_reset_lower_path(dentry);
184 break;
185 case HMDFS_LAYER_FIRST_DEVICE:
186 break;
187 case HMDFS_LAYER_SECOND_REMOTE:
188 hmdfs_clear_cache_dents(dentry, false);
189 break;
190 case HMDFS_LAYER_SECOND_CLOUD:
191 item = hmdfs_find_cache_item(CLOUD_DEVICE, dentry);
192 if (item) {
193 /* cloud dentryfile didn't link to
194 'struct cache_file_node', so close file here.
195 */
196 filp_close(item->filp, NULL);
197 kref_put(&item->ref, release_cache_item);
198 }
199 hmdfs_clear_cache_dents(dentry, false);
200 break;
201 default:
202 hmdfs_err("Unexpected dentry type %d",
203 hmdfs_d(dentry)->dentry_type);
204 return;
205 }
206
207 kmem_cache_free(hmdfs_dentry_cachep, dentry->d_fsdata);
208 dentry->d_fsdata = NULL;
209 }
210
hmdfs_d_release(struct dentry *dentry)211 static void hmdfs_d_release(struct dentry *dentry)
212 {
213 if (!dentry || !dentry->d_fsdata)
214 return;
215
216 hmdfs_clear_cache_dents(dentry, false);
217 hmdfs_drop_remote_cache_dents(dentry);
218 hmdfs_put_reset_lower_path(dentry);
219 kmem_cache_free(hmdfs_dentry_cachep, dentry->d_fsdata);
220 dentry->d_fsdata = NULL;
221 }
222
hmdfs_cmp_ci(const struct dentry *dentry, unsigned int len, const char *str, const struct qstr *name)223 static int hmdfs_cmp_ci(const struct dentry *dentry, unsigned int len,
224 const char *str, const struct qstr *name)
225 {
226 struct hmdfs_sb_info *sbi = hmdfs_sb(dentry->d_sb);
227
228 if (name->len != len)
229 return 1;
230
231 if (!sbi->s_case_sensitive) {
232 if (str_n_case_eq(name->name, str, len))
233 return 0;
234 } else {
235 if (!strncmp(name->name, str, len))
236 return 0;
237 }
238 return 1;
239 }
240
hmdfs_hash_ci(const struct dentry *dentry, struct qstr *qstr)241 static int hmdfs_hash_ci(const struct dentry *dentry, struct qstr *qstr)
242 {
243 const unsigned char *name = qstr->name;
244 unsigned int len = qstr->len;
245 unsigned long hash;
246 struct hmdfs_sb_info *sbi = hmdfs_sb(dentry->d_sb);
247
248 if (sbi->s_case_sensitive)
249 return 0;
250
251 hash = init_name_hash(dentry);
252 while (len--)
253 hash = partial_name_hash(tolower(*name++), hash);
254 qstr->hash = end_name_hash(hash);
255 return 0;
256 }
257
clear_comrades_locked(struct list_head *comrade_list)258 void clear_comrades_locked(struct list_head *comrade_list)
259 {
260 struct hmdfs_dentry_comrade *cc, *nc;
261
262 WARN_ON(!comrade_list);
263 list_for_each_entry_safe(cc, nc, comrade_list, list) {
264 dput(cc->lo_d);
265 kfree(cc);
266 }
267 INIT_LIST_HEAD(comrade_list);
268 }
269
clear_comrades(struct dentry *dentry)270 void clear_comrades(struct dentry *dentry)
271 {
272 struct hmdfs_dentry_info_merge *cdi = hmdfs_dm(dentry);
273
274 wait_event(cdi->wait_queue, !has_merge_lookup_work(cdi));
275 mutex_lock(&cdi->comrade_list_lock);
276 clear_comrades_locked(&cdi->comrade_list);
277 mutex_unlock(&cdi->comrade_list_lock);
278 }
279
280 /**
281 * d_revalidate_merge - revalidate a merge dentry
282 *
283 * Always return 0 to invalidate a dentry for fault-tolerance.
284 * The cost is acceptable for a overlay filesystem.
285 */
d_revalidate_merge(struct dentry *direntry, unsigned int flags)286 static int d_revalidate_merge(struct dentry *direntry, unsigned int flags)
287 {
288 struct hmdfs_dentry_info_merge *dim = hmdfs_dm(direntry);
289 struct hmdfs_dentry_comrade *comrade = NULL;
290 struct dentry *parent_dentry = NULL;
291 struct dentry *lower_cur_parent_dentry = NULL;
292 struct inode *dinode = NULL;
293 struct hmdfs_inode_info *info = NULL;
294 int ret = 1;
295
296 if (flags & LOOKUP_RCU) {
297 return -ECHILD;
298 }
299
300 if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET | LOOKUP_REVAL)) {
301 return 0;
302 }
303
304 dinode = d_inode(direntry);
305 if (!dinode)
306 return 0;
307
308 info = hmdfs_i(dinode);
309 if (info->inode_type == HMDFS_LAYER_FIRST_MERGE_CLOUD)
310 return 1;
311
312 parent_dentry = dget_parent(direntry);
313 mutex_lock(&dim->comrade_list_lock);
314 list_for_each_entry(comrade, &(dim->comrade_list), list) {
315 lower_cur_parent_dentry = dget_parent(comrade->lo_d);
316 if ((comrade->lo_d->d_flags & DCACHE_OP_REVALIDATE)) {
317 ret = comrade->lo_d->d_op->d_revalidate(
318 comrade->lo_d, flags);
319 if (ret == 0) {
320 dput(lower_cur_parent_dentry);
321 goto out;
322 }
323 }
324 dput(lower_cur_parent_dentry);
325 }
326 out:
327 mutex_unlock(&dim->comrade_list_lock);
328 dput(parent_dentry);
329 return ret;
330 }
331
d_release_merge(struct dentry *dentry)332 static void d_release_merge(struct dentry *dentry)
333 {
334 if (!dentry || !dentry->d_fsdata)
335 return;
336
337 clear_comrades(dentry);
338 kmem_cache_free(hmdfs_dentry_merge_cachep, dentry->d_fsdata);
339 dentry->d_fsdata = NULL;
340 }
341
342 const struct dentry_operations hmdfs_dops_merge = {
343 .d_revalidate = d_revalidate_merge,
344 .d_release = d_release_merge,
345 };
346
347 const struct dentry_operations hmdfs_dev_dops = {
348 .d_revalidate = hmdfs_dev_d_revalidate,
349 .d_release = hmdfs_dev_d_release,
350 };
351
352 const struct dentry_operations hmdfs_dops = {
353 .d_revalidate = hmdfs_d_revalidate,
354 .d_release = hmdfs_d_release,
355 .d_compare = hmdfs_cmp_ci,
356 .d_hash = hmdfs_hash_ci,
357 };
358