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