162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * fs/hmdfs/hmdfs_dentryfile.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "hmdfs_dentryfile.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/ctype.h>
1162306a36Sopenharmony_ci#include <linux/file.h>
1262306a36Sopenharmony_ci#include <linux/mount.h>
1362306a36Sopenharmony_ci#include <linux/pagemap.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/xattr.h>
1662306a36Sopenharmony_ci#include <linux/err.h>
1762306a36Sopenharmony_ci#include <linux/filelock.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "authority/authentication.h"
2062306a36Sopenharmony_ci#include "comm/transport.h"
2162306a36Sopenharmony_ci#include "hmdfs_client.h"
2262306a36Sopenharmony_ci#include "hmdfs_device_view.h"
2362306a36Sopenharmony_ci#include "hmdfs_merge_view.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Hashing code copied from f2fs */
2662306a36Sopenharmony_ci#define HMDFS_HASH_COL_BIT ((0x1ULL) << 63)
2762306a36Sopenharmony_ci#define DELTA		   0x9E3779B9
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic bool is_dot_dotdot(const unsigned char *name, __u32 len)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	if (len == 1 && name[0] == '.')
3262306a36Sopenharmony_ci		return true;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (len == 2 && name[0] == '.' && name[1] == '.')
3562306a36Sopenharmony_ci		return true;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	return false;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic void str2hashbuf(const unsigned char *msg, size_t len, unsigned int *buf,
4162306a36Sopenharmony_ci			int num, bool case_sense)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	unsigned int pad, val;
4462306a36Sopenharmony_ci	int i;
4562306a36Sopenharmony_ci	unsigned char c;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	pad = (__u32)len | ((__u32)len << 8);
4862306a36Sopenharmony_ci	pad |= pad << 16;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	val = pad;
5162306a36Sopenharmony_ci	if (len > (size_t)num * 4)
5262306a36Sopenharmony_ci		len = (size_t)num * 4;
5362306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
5462306a36Sopenharmony_ci		if ((i % 4) == 0)
5562306a36Sopenharmony_ci			val = pad;
5662306a36Sopenharmony_ci		c = msg[i];
5762306a36Sopenharmony_ci		if (!case_sense)
5862306a36Sopenharmony_ci			c = tolower(c);
5962306a36Sopenharmony_ci		val = c + (val << 8);
6062306a36Sopenharmony_ci		if ((i % 4) == 3) {
6162306a36Sopenharmony_ci			*buf++ = val;
6262306a36Sopenharmony_ci			val = pad;
6362306a36Sopenharmony_ci			num--;
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci	if (--num >= 0)
6762306a36Sopenharmony_ci		*buf++ = val;
6862306a36Sopenharmony_ci	while (--num >= 0)
6962306a36Sopenharmony_ci		*buf++ = pad;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic void tea_transform(unsigned int buf[4], unsigned int const in[])
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	__u32 sum = 0;
7562306a36Sopenharmony_ci	__u32 b0 = buf[0], b1 = buf[1];
7662306a36Sopenharmony_ci	__u32 a = in[0], b = in[1], c = in[2], d = in[3];
7762306a36Sopenharmony_ci	int n = 16;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	do {
8062306a36Sopenharmony_ci		sum += DELTA;
8162306a36Sopenharmony_ci		b0 += ((b1 << 4) + a) ^ (b1 + sum) ^ ((b1 >> 5) + b);
8262306a36Sopenharmony_ci		b1 += ((b0 << 4) + c) ^ (b0 + sum) ^ ((b0 >> 5) + d);
8362306a36Sopenharmony_ci	} while (--n);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	buf[0] += b0;
8662306a36Sopenharmony_ci	buf[1] += b1;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci__u32 hmdfs_dentry_hash(const struct qstr *qstr, bool case_sense)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	__u32 hash;
9262306a36Sopenharmony_ci	__u32 hmdfs_hash;
9362306a36Sopenharmony_ci	const unsigned char *p = qstr->name;
9462306a36Sopenharmony_ci	__u32 len = qstr->len;
9562306a36Sopenharmony_ci	__u32 in[8], buf[4];
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (is_dot_dotdot(p, len))
9862306a36Sopenharmony_ci		return 0;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	/* Initialize the default seed for the hash checksum functions */
10162306a36Sopenharmony_ci	buf[0] = 0x67452301;
10262306a36Sopenharmony_ci	buf[1] = 0xefcdab89;
10362306a36Sopenharmony_ci	buf[2] = 0x98badcfe;
10462306a36Sopenharmony_ci	buf[3] = 0x10325476;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	while (1) {
10762306a36Sopenharmony_ci		str2hashbuf(p, len, in, 4, case_sense);
10862306a36Sopenharmony_ci		tea_transform(buf, in);
10962306a36Sopenharmony_ci		p += 16;
11062306a36Sopenharmony_ci		if (len <= 16)
11162306a36Sopenharmony_ci			break;
11262306a36Sopenharmony_ci		len -= 16;
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci	hash = buf[0];
11562306a36Sopenharmony_ci	hmdfs_hash = hash & ~HMDFS_HASH_COL_BIT;
11662306a36Sopenharmony_ci	return hmdfs_hash;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic atomic_t curr_ino = ATOMIC_INIT(INUNUMBER_START);
12062306a36Sopenharmony_ciint get_inonumber(void)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	return atomic_inc_return(&curr_ino);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int hmdfs_get_root_dentry_type(struct dentry *dentry, int *is_root)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = hmdfs_d(dentry);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	*is_root = 1;
13062306a36Sopenharmony_ci	switch (d_info->dentry_type) {
13162306a36Sopenharmony_ci	case HMDFS_LAYER_OTHER_LOCAL:
13262306a36Sopenharmony_ci		*is_root = 0;
13362306a36Sopenharmony_ci		fallthrough;
13462306a36Sopenharmony_ci	case HMDFS_LAYER_SECOND_LOCAL:
13562306a36Sopenharmony_ci		return HMDFS_LAYER_SECOND_LOCAL;
13662306a36Sopenharmony_ci	case HMDFS_LAYER_OTHER_CLOUD:
13762306a36Sopenharmony_ci		*is_root = 0;
13862306a36Sopenharmony_ci		fallthrough;
13962306a36Sopenharmony_ci	case HMDFS_LAYER_SECOND_CLOUD:
14062306a36Sopenharmony_ci		return HMDFS_LAYER_SECOND_CLOUD;
14162306a36Sopenharmony_ci	case HMDFS_LAYER_OTHER_REMOTE:
14262306a36Sopenharmony_ci		*is_root = 0;
14362306a36Sopenharmony_ci		fallthrough;
14462306a36Sopenharmony_ci	case HMDFS_LAYER_SECOND_REMOTE:
14562306a36Sopenharmony_ci		return HMDFS_LAYER_SECOND_REMOTE;
14662306a36Sopenharmony_ci	default:
14762306a36Sopenharmony_ci		hmdfs_info("Unexpected dentry type %d", d_info->dentry_type);
14862306a36Sopenharmony_ci		return -EINVAL;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic int prepend(char **buffer, int *buflen, const char *str, int namelen)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	*buflen -= namelen;
15562306a36Sopenharmony_ci	if (*buflen < 0)
15662306a36Sopenharmony_ci		return -ENAMETOOLONG;
15762306a36Sopenharmony_ci	*buffer -= namelen;
15862306a36Sopenharmony_ci	memcpy(*buffer, str, namelen);
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int prepend_name(char **buffer, int *buflen, const struct qstr *name)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	const char *dname = name->name;
16562306a36Sopenharmony_ci	u32 dlen = name->len;
16662306a36Sopenharmony_ci	char *p = NULL;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	*buflen -= dlen + 1;
16962306a36Sopenharmony_ci	if (*buflen < 0)
17062306a36Sopenharmony_ci		return -ENAMETOOLONG;
17162306a36Sopenharmony_ci	p = *buffer -= dlen + 1;
17262306a36Sopenharmony_ci	*p++ = '/';
17362306a36Sopenharmony_ci	while (dlen--) {
17462306a36Sopenharmony_ci		char c = *dname++;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		if (!c)
17762306a36Sopenharmony_ci			break;
17862306a36Sopenharmony_ci		*p++ = c;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic char *hmdfs_dentry_path_raw(struct dentry *d, char *buf, int buflen)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct dentry *dentry = NULL;
18662306a36Sopenharmony_ci	char *end = NULL;
18762306a36Sopenharmony_ci	char *retval = NULL;
18862306a36Sopenharmony_ci	unsigned int len;
18962306a36Sopenharmony_ci	unsigned int seq = 0;
19062306a36Sopenharmony_ci	int root_flag = 0;
19162306a36Sopenharmony_ci	int error = 0;
19262306a36Sopenharmony_ci	struct hmdfs_dentry_info *di = hmdfs_d(d);
19362306a36Sopenharmony_ci	int hmdfs_root_dentry_type = 0;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	di->time = jiffies;
19662306a36Sopenharmony_ci	hmdfs_root_dentry_type = hmdfs_get_root_dentry_type(d, &root_flag);
19762306a36Sopenharmony_ci	if (hmdfs_root_dentry_type < 0)
19862306a36Sopenharmony_ci		return NULL;
19962306a36Sopenharmony_ci	if (root_flag) {
20062306a36Sopenharmony_ci		strcpy(buf, "/");
20162306a36Sopenharmony_ci		return buf;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci	rcu_read_lock();
20462306a36Sopenharmony_cirestart:
20562306a36Sopenharmony_ci	dentry = d;
20662306a36Sopenharmony_ci	di = hmdfs_d(dentry);
20762306a36Sopenharmony_ci	di->time = jiffies;
20862306a36Sopenharmony_ci	end = buf + buflen;
20962306a36Sopenharmony_ci	len = buflen;
21062306a36Sopenharmony_ci	prepend(&end, &len, "\0", 1);
21162306a36Sopenharmony_ci	retval = end - 1;
21262306a36Sopenharmony_ci	*retval = '/';
21362306a36Sopenharmony_ci	read_seqbegin_or_lock(&rename_lock, &seq);
21462306a36Sopenharmony_ci	while (di->dentry_type != hmdfs_root_dentry_type) {
21562306a36Sopenharmony_ci		struct dentry *parent = dentry->d_parent;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		prefetch(parent);
21862306a36Sopenharmony_ci		error = prepend_name(&end, &len, &dentry->d_name);
21962306a36Sopenharmony_ci		if (error)
22062306a36Sopenharmony_ci			break;
22162306a36Sopenharmony_ci		retval = end;
22262306a36Sopenharmony_ci		dentry = parent;
22362306a36Sopenharmony_ci		di = hmdfs_d(dentry);
22462306a36Sopenharmony_ci		di->time = jiffies;
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci	if (!(seq & 1))
22762306a36Sopenharmony_ci		rcu_read_unlock();
22862306a36Sopenharmony_ci	if (need_seqretry(&rename_lock, seq)) {
22962306a36Sopenharmony_ci		seq = 1;
23062306a36Sopenharmony_ci		goto restart;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci	done_seqretry(&rename_lock, seq);
23362306a36Sopenharmony_ci	if (error)
23462306a36Sopenharmony_ci		goto Elong;
23562306a36Sopenharmony_ci	return retval;
23662306a36Sopenharmony_ciElong:
23762306a36Sopenharmony_ci	return ERR_PTR(-ENAMETOOLONG);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cichar *hmdfs_get_dentry_relative_path(struct dentry *dentry)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	char *final_buf = NULL;
24362306a36Sopenharmony_ci	char *buf = NULL;
24462306a36Sopenharmony_ci	char *p = NULL;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	buf = kzalloc(PATH_MAX, GFP_KERNEL);
24762306a36Sopenharmony_ci	if (!buf)
24862306a36Sopenharmony_ci		return NULL;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	final_buf = kzalloc(PATH_MAX, GFP_KERNEL);
25162306a36Sopenharmony_ci	if (!final_buf) {
25262306a36Sopenharmony_ci		kfree(buf);
25362306a36Sopenharmony_ci		return NULL;
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/* NULL dentry return root dir */
25762306a36Sopenharmony_ci	if (!dentry) {
25862306a36Sopenharmony_ci		strcpy(final_buf, "/");
25962306a36Sopenharmony_ci		kfree(buf);
26062306a36Sopenharmony_ci		return final_buf;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci	p = hmdfs_dentry_path_raw(dentry, buf, PATH_MAX);
26362306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(p)) {
26462306a36Sopenharmony_ci		kfree(buf);
26562306a36Sopenharmony_ci		kfree(final_buf);
26662306a36Sopenharmony_ci		return NULL;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (strlen(p) >= PATH_MAX) {
27062306a36Sopenharmony_ci		kfree(buf);
27162306a36Sopenharmony_ci		kfree(final_buf);
27262306a36Sopenharmony_ci		return NULL;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci	strcpy(final_buf, p);
27562306a36Sopenharmony_ci	kfree(buf);
27662306a36Sopenharmony_ci	return final_buf;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic char *hmdfs_merge_dentry_path_raw(struct dentry *d, char *buf, int buflen)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	struct dentry *dentry = NULL;
28262306a36Sopenharmony_ci	char *end = NULL;
28362306a36Sopenharmony_ci	char *retval = NULL;
28462306a36Sopenharmony_ci	unsigned int len;
28562306a36Sopenharmony_ci	unsigned int seq = 0;
28662306a36Sopenharmony_ci	int error = 0;
28762306a36Sopenharmony_ci	struct hmdfs_dentry_info_merge *mdi = NULL;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	rcu_read_lock();
29062306a36Sopenharmony_cirestart:
29162306a36Sopenharmony_ci	mdi = hmdfs_dm(d);
29262306a36Sopenharmony_ci	dentry = d;
29362306a36Sopenharmony_ci	end = buf + buflen;
29462306a36Sopenharmony_ci	len = buflen;
29562306a36Sopenharmony_ci	prepend(&end, &len, "\0", 1);
29662306a36Sopenharmony_ci	retval = end - 1;
29762306a36Sopenharmony_ci	*retval = '/';
29862306a36Sopenharmony_ci	read_seqbegin_or_lock(&rename_lock, &seq);
29962306a36Sopenharmony_ci	while (mdi->dentry_type != HMDFS_LAYER_FIRST_MERGE &&
30062306a36Sopenharmony_ci	       mdi->dentry_type != HMDFS_LAYER_FIRST_MERGE_CLOUD) {
30162306a36Sopenharmony_ci		struct dentry *parent = dentry->d_parent;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci		prefetch(parent);
30462306a36Sopenharmony_ci		error = prepend_name(&end, &len, &dentry->d_name);
30562306a36Sopenharmony_ci		if (error)
30662306a36Sopenharmony_ci			break;
30762306a36Sopenharmony_ci		retval = end;
30862306a36Sopenharmony_ci		dentry = parent;
30962306a36Sopenharmony_ci		mdi = hmdfs_dm(dentry);
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci	if (!(seq & 1))
31262306a36Sopenharmony_ci		rcu_read_unlock();
31362306a36Sopenharmony_ci	if (need_seqretry(&rename_lock, seq)) {
31462306a36Sopenharmony_ci		seq = 1;
31562306a36Sopenharmony_ci		goto restart;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci	done_seqretry(&rename_lock, seq);
31862306a36Sopenharmony_ci	if (error)
31962306a36Sopenharmony_ci		goto Elong;
32062306a36Sopenharmony_ci	return retval;
32162306a36Sopenharmony_ciElong:
32262306a36Sopenharmony_ci	return ERR_PTR(-ENAMETOOLONG);
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cichar *hmdfs_merge_get_dentry_relative_path(struct dentry *dentry)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	char *final_buf = NULL;
32862306a36Sopenharmony_ci	char *buf = NULL;
32962306a36Sopenharmony_ci	char *p = NULL;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	buf = kzalloc(PATH_MAX, GFP_KERNEL);
33262306a36Sopenharmony_ci	if (!buf)
33362306a36Sopenharmony_ci		return NULL;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	final_buf = kzalloc(PATH_MAX, GFP_KERNEL);
33662306a36Sopenharmony_ci	if (!final_buf) {
33762306a36Sopenharmony_ci		kfree(buf);
33862306a36Sopenharmony_ci		return NULL;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* NULL dentry return root dir */
34262306a36Sopenharmony_ci	if (!dentry) {
34362306a36Sopenharmony_ci		strcpy(final_buf, "/");
34462306a36Sopenharmony_ci		kfree(buf);
34562306a36Sopenharmony_ci		return final_buf;
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci	p = hmdfs_merge_dentry_path_raw(dentry, buf, PATH_MAX);
34862306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(p)) {
34962306a36Sopenharmony_ci		kfree(buf);
35062306a36Sopenharmony_ci		kfree(final_buf);
35162306a36Sopenharmony_ci		return NULL;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (strlen(p) >= PATH_MAX) {
35562306a36Sopenharmony_ci		kfree(buf);
35662306a36Sopenharmony_ci		kfree(final_buf);
35762306a36Sopenharmony_ci		return NULL;
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci	strcpy(final_buf, p);
36062306a36Sopenharmony_ci	kfree(buf);
36162306a36Sopenharmony_ci	return final_buf;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cichar *hmdfs_get_dentry_absolute_path(const char *rootdir,
36562306a36Sopenharmony_ci				     const char *relative_path)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	char *buf = 0;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	if (!rootdir || !relative_path)
37062306a36Sopenharmony_ci		return NULL;
37162306a36Sopenharmony_ci	if (strlen(rootdir) + strlen(relative_path) >= PATH_MAX)
37262306a36Sopenharmony_ci		return NULL;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	buf = kzalloc(PATH_MAX, GFP_KERNEL);
37562306a36Sopenharmony_ci	if (!buf)
37662306a36Sopenharmony_ci		return NULL;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	strcpy(buf, rootdir);
37962306a36Sopenharmony_ci	strcat(buf, relative_path);
38062306a36Sopenharmony_ci	return buf;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cichar *hmdfs_connect_path(const char *path, const char *name)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	char *buf = 0;
38662306a36Sopenharmony_ci	size_t path_len, name_len;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (!path || !name)
38962306a36Sopenharmony_ci		return NULL;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	path_len = strnlen(path, PATH_MAX);
39262306a36Sopenharmony_ci	name_len = strnlen(name, PATH_MAX);
39362306a36Sopenharmony_ci	if (path_len + name_len + 1 >= PATH_MAX)
39462306a36Sopenharmony_ci		return NULL;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	buf = kzalloc(PATH_MAX, GFP_KERNEL);
39762306a36Sopenharmony_ci	if (!buf)
39862306a36Sopenharmony_ci		return NULL;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	strncpy(buf, path, path_len);
40162306a36Sopenharmony_ci	strcat(buf, "/");
40262306a36Sopenharmony_ci	strncat(buf, name, name_len);
40362306a36Sopenharmony_ci	return buf;
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ciint hmdfs_metainfo_read_nocred(struct file *filp,
40762306a36Sopenharmony_ci		void *buffer, int size, int bidx)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	loff_t pos = get_dentry_group_pos(bidx);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	return kernel_read(filp, buffer, (size_t)size, &pos);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ciint hmdfs_metainfo_read(struct hmdfs_sb_info *sbi, struct file *filp,
41562306a36Sopenharmony_ci			void *buffer, int size, int bidx)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	loff_t pos = get_dentry_group_pos(bidx);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return cache_file_read(sbi, filp, buffer, (size_t)size, &pos);
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ciint hmdfs_metainfo_write(struct hmdfs_sb_info *sbi, struct file *filp,
42362306a36Sopenharmony_ci			 const void *buffer, int size, int bidx)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	loff_t pos = get_dentry_group_pos(bidx);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	return cache_file_write(sbi, filp, buffer, (size_t)size, &pos);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci/* for each level */
43162306a36Sopenharmony_ci/* bucketseq start offset by 0,for example
43262306a36Sopenharmony_ci * level0  bucket0(0)
43362306a36Sopenharmony_ci * level1  bucket0(1) bucket1(2)
43462306a36Sopenharmony_ci * level2  bucket0(3) bucket1(4) bucket2(5) bucket3(6)
43562306a36Sopenharmony_ci * return bucket number.
43662306a36Sopenharmony_ci */
43762306a36Sopenharmony_ci__u64 get_bucketaddr(unsigned int level, __u64 buckoffset)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	__u64 all_level_bucketaddr = 0;
44062306a36Sopenharmony_ci	__u64 curlevelmaxbucks;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (level >= MAX_BUCKET_LEVEL) {
44362306a36Sopenharmony_ci		hmdfs_err("level = %d overflow", level);
44462306a36Sopenharmony_ci		return all_level_bucketaddr;
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci	curlevelmaxbucks = ((__u64)1 << level);
44762306a36Sopenharmony_ci	if (buckoffset >= curlevelmaxbucks) {
44862306a36Sopenharmony_ci		hmdfs_err("buckoffset %llu overflow, level %d has %llu buckets max",
44962306a36Sopenharmony_ci			  buckoffset, level, curlevelmaxbucks);
45062306a36Sopenharmony_ci		return all_level_bucketaddr;
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci	all_level_bucketaddr = curlevelmaxbucks + buckoffset - 1;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	return all_level_bucketaddr;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci__u64 get_bucket_by_level(unsigned int level)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	__u64 buckets = 0;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (level >= MAX_BUCKET_LEVEL) {
46262306a36Sopenharmony_ci		hmdfs_err("level = %d overflow", level);
46362306a36Sopenharmony_ci		return buckets;
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	buckets = ((__u64)1 << level);
46762306a36Sopenharmony_ci	return buckets;
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic __u64 get_overall_bucket(unsigned int level)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	__u64 buckets = 0;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (level >= MAX_BUCKET_LEVEL) {
47562306a36Sopenharmony_ci		hmdfs_err("level = %d overflow", level);
47662306a36Sopenharmony_ci		return buckets;
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci	buckets = ((__u64)1 << (level + 1)) - 1;
47962306a36Sopenharmony_ci	return buckets;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic inline loff_t get_dcache_file_size(unsigned int level)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	loff_t buckets = get_overall_bucket(level);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return buckets * DENTRYGROUP_SIZE * BUCKET_BLOCKS + DENTRYGROUP_HEADER;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic char *get_relative_path(struct hmdfs_sb_info *sbi, char *from)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	char *relative;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (strncmp(from, sbi->local_src, strlen(sbi->local_src))) {
49462306a36Sopenharmony_ci		hmdfs_warning("orig path do not start with local_src");
49562306a36Sopenharmony_ci		return NULL;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci	relative = from + strlen(sbi->local_src);
49862306a36Sopenharmony_ci	if (*relative == '/')
49962306a36Sopenharmony_ci		relative++;
50062306a36Sopenharmony_ci	return relative;
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistruct file *hmdfs_get_or_create_dents(struct hmdfs_sb_info *sbi, char *name)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	struct path root_path, path;
50662306a36Sopenharmony_ci	struct file *filp = NULL;
50762306a36Sopenharmony_ci	char *relative;
50862306a36Sopenharmony_ci	int err;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	err = kern_path(sbi->local_src, 0, &root_path);
51162306a36Sopenharmony_ci	if (err) {
51262306a36Sopenharmony_ci		hmdfs_err("kern_path failed err = %d", err);
51362306a36Sopenharmony_ci		return NULL;
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci	relative = get_relative_path(sbi, name);
51662306a36Sopenharmony_ci	if (!relative) {
51762306a36Sopenharmony_ci		hmdfs_err("get relative path failed");
51862306a36Sopenharmony_ci		goto err_root_path;
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci	err = vfs_path_lookup(root_path.dentry, root_path.mnt, relative, 0,
52162306a36Sopenharmony_ci			      &path);
52262306a36Sopenharmony_ci	if (err) {
52362306a36Sopenharmony_ci		hmdfs_err("lookup failed err = %d", err);
52462306a36Sopenharmony_ci		goto err_root_path;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	filp = hmdfs_server_cache_revalidate(sbi, relative, &path);
52862306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(filp)) {
52962306a36Sopenharmony_ci		filp = hmdfs_server_rebuild_dents(sbi, &path, NULL, relative);
53062306a36Sopenharmony_ci		if (IS_ERR_OR_NULL(filp))
53162306a36Sopenharmony_ci			goto err_lookup_path;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cierr_lookup_path:
53562306a36Sopenharmony_ci	path_put(&path);
53662306a36Sopenharmony_cierr_root_path:
53762306a36Sopenharmony_ci	path_put(&root_path);
53862306a36Sopenharmony_ci	return filp;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci/* read all dentry in target path directory */
54262306a36Sopenharmony_ciint read_dentry(struct hmdfs_sb_info *sbi, char *file_name,
54362306a36Sopenharmony_ci		struct dir_context *ctx)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	unsigned long pos = (unsigned long)(ctx->pos);
54662306a36Sopenharmony_ci	unsigned long group_id = (pos << (1 + DEV_ID_BIT_NUM)) >>
54762306a36Sopenharmony_ci				 (POS_BIT_NUM - GROUP_ID_BIT_NUM);
54862306a36Sopenharmony_ci	unsigned long offset = pos & OFFSET_BIT_MASK;
54962306a36Sopenharmony_ci	struct hmdfs_dentry_group *dentry_group = NULL;
55062306a36Sopenharmony_ci	struct file *handler = NULL;
55162306a36Sopenharmony_ci	int group_num = 0;
55262306a36Sopenharmony_ci	int iterate_result = 0;
55362306a36Sopenharmony_ci	int i, j;
55462306a36Sopenharmony_ci	const struct cred *saved_cred;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	saved_cred = hmdfs_override_fsids(false);
55762306a36Sopenharmony_ci	if (!saved_cred) {
55862306a36Sopenharmony_ci		hmdfs_err("prepare cred failed!");
55962306a36Sopenharmony_ci		return -ENOMEM;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (!file_name)
56462306a36Sopenharmony_ci		return -EINVAL;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	dentry_group = kzalloc(sizeof(*dentry_group), GFP_KERNEL);
56762306a36Sopenharmony_ci	if (!dentry_group)
56862306a36Sopenharmony_ci		return -ENOMEM;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	handler = hmdfs_get_or_create_dents(sbi, file_name);
57162306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(handler)) {
57262306a36Sopenharmony_ci		kfree(dentry_group);
57362306a36Sopenharmony_ci		return -ENOENT;
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	group_num = get_dentry_group_cnt(file_inode(handler));
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	for (i = group_id; i < group_num; i++) {
57962306a36Sopenharmony_ci		hmdfs_metainfo_read(sbi, handler, dentry_group,
58062306a36Sopenharmony_ci				    sizeof(struct hmdfs_dentry_group), i);
58162306a36Sopenharmony_ci		for (j = offset; j < DENTRY_PER_GROUP; j++) {
58262306a36Sopenharmony_ci			int len;
58362306a36Sopenharmony_ci			int file_type = 0;
58462306a36Sopenharmony_ci			bool is_continue;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci			len = le16_to_cpu(dentry_group->nsl[j].namelen);
58762306a36Sopenharmony_ci			if (!test_bit_le(j, dentry_group->bitmap) || len == 0)
58862306a36Sopenharmony_ci				continue;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci			if (S_ISDIR(le16_to_cpu(dentry_group->nsl[j].i_mode)))
59162306a36Sopenharmony_ci				file_type = DT_DIR;
59262306a36Sopenharmony_ci			else if (S_ISREG(le16_to_cpu(
59362306a36Sopenharmony_ci					 dentry_group->nsl[j].i_mode)))
59462306a36Sopenharmony_ci				file_type = DT_REG;
59562306a36Sopenharmony_ci			else if (S_ISLNK(le16_to_cpu(
59662306a36Sopenharmony_ci					 dentry_group->nsl[j].i_mode)))
59762306a36Sopenharmony_ci				file_type = DT_LNK;
59862306a36Sopenharmony_ci			else
59962306a36Sopenharmony_ci				continue;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci			pos = hmdfs_set_pos(0, i, j);
60262306a36Sopenharmony_ci			is_continue = dir_emit(
60362306a36Sopenharmony_ci				ctx, dentry_group->filename[j], len,
60462306a36Sopenharmony_ci				le64_to_cpu(dentry_group->nsl[j].i_ino),
60562306a36Sopenharmony_ci				file_type);
60662306a36Sopenharmony_ci			if (!is_continue) {
60762306a36Sopenharmony_ci				ctx->pos = pos;
60862306a36Sopenharmony_ci				iterate_result = 1;
60962306a36Sopenharmony_ci				goto done;
61062306a36Sopenharmony_ci			}
61162306a36Sopenharmony_ci		}
61262306a36Sopenharmony_ci		offset = 0;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_cidone:
61662306a36Sopenharmony_ci	hmdfs_revert_fsids(saved_cred);
61762306a36Sopenharmony_ci	kfree(dentry_group);
61862306a36Sopenharmony_ci	fput(handler);
61962306a36Sopenharmony_ci	return iterate_result;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ciunsigned int get_max_depth(struct file *filp)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	size_t isize;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	isize = get_dentry_group_cnt(file_inode(filp)) / BUCKET_BLOCKS;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	return get_count_order(isize + 1);
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistruct hmdfs_dentry_group *find_dentry_page(struct hmdfs_sb_info *sbi,
63262306a36Sopenharmony_ci					    pgoff_t index, struct file *filp)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	int size;
63562306a36Sopenharmony_ci	struct hmdfs_dentry_group *dentry_blk = NULL;
63662306a36Sopenharmony_ci	loff_t pos = get_dentry_group_pos(index);
63762306a36Sopenharmony_ci	int err;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	dentry_blk = kmalloc(sizeof(*dentry_blk), GFP_KERNEL);
64062306a36Sopenharmony_ci	if (!dentry_blk)
64162306a36Sopenharmony_ci		return NULL;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	err = hmdfs_wlock_file(filp, pos, DENTRYGROUP_SIZE);
64462306a36Sopenharmony_ci	if (err) {
64562306a36Sopenharmony_ci		hmdfs_err("lock file pos %lld failed", pos);
64662306a36Sopenharmony_ci		kfree(dentry_blk);
64762306a36Sopenharmony_ci		return NULL;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	size = cache_file_read(sbi, filp, dentry_blk, (size_t)DENTRYGROUP_SIZE,
65162306a36Sopenharmony_ci			       &pos);
65262306a36Sopenharmony_ci	if (size != DENTRYGROUP_SIZE) {
65362306a36Sopenharmony_ci		hmdfs_unlock_file(filp, pos, DENTRYGROUP_SIZE);
65462306a36Sopenharmony_ci		kfree(dentry_blk);
65562306a36Sopenharmony_ci		dentry_blk = NULL;
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return dentry_blk;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic ssize_t write_dentry_page(struct file *filp, const void *buffer,
66262306a36Sopenharmony_ci				 int buffersize, loff_t position)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	ssize_t size;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	size = kernel_write(filp, buffer, (size_t)buffersize, &position);
66762306a36Sopenharmony_ci	if (size != buffersize)
66862306a36Sopenharmony_ci		hmdfs_err("write failed, ret = %zd", size);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	return size;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic struct hmdfs_dentry *find_in_block(struct hmdfs_dentry_group *dentry_blk,
67462306a36Sopenharmony_ci					  __u32 namehash,
67562306a36Sopenharmony_ci					  const struct qstr *qstr,
67662306a36Sopenharmony_ci					  struct hmdfs_dentry **insense_de,
67762306a36Sopenharmony_ci					  bool case_sense)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct hmdfs_dentry *de;
68062306a36Sopenharmony_ci	unsigned long bit_pos = 0;
68162306a36Sopenharmony_ci	int max_len = 0;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	while (bit_pos < DENTRY_PER_GROUP) {
68462306a36Sopenharmony_ci		if (!test_bit_le(bit_pos, dentry_blk->bitmap)) {
68562306a36Sopenharmony_ci			bit_pos++;
68662306a36Sopenharmony_ci			max_len++;
68762306a36Sopenharmony_ci			continue;
68862306a36Sopenharmony_ci		}
68962306a36Sopenharmony_ci		de = &dentry_blk->nsl[bit_pos];
69062306a36Sopenharmony_ci		if (unlikely(!de->namelen)) {
69162306a36Sopenharmony_ci			bit_pos++;
69262306a36Sopenharmony_ci			continue;
69362306a36Sopenharmony_ci		}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci		if (le32_to_cpu(de->hash) == namehash &&
69662306a36Sopenharmony_ci		    le16_to_cpu(de->namelen) == qstr->len &&
69762306a36Sopenharmony_ci		    !memcmp(qstr->name, dentry_blk->filename[bit_pos],
69862306a36Sopenharmony_ci			    le16_to_cpu(de->namelen)))
69962306a36Sopenharmony_ci			goto found;
70062306a36Sopenharmony_ci		if (!(*insense_de) && !case_sense &&
70162306a36Sopenharmony_ci		    le32_to_cpu(de->hash) == namehash &&
70262306a36Sopenharmony_ci		    le16_to_cpu(de->namelen) == qstr->len &&
70362306a36Sopenharmony_ci		    str_n_case_eq(qstr->name, dentry_blk->filename[bit_pos],
70462306a36Sopenharmony_ci				  le16_to_cpu(de->namelen)))
70562306a36Sopenharmony_ci			*insense_de = de;
70662306a36Sopenharmony_ci		max_len = 0;
70762306a36Sopenharmony_ci		bit_pos += get_dentry_slots(le16_to_cpu(de->namelen));
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci	de = NULL;
71062306a36Sopenharmony_cifound:
71162306a36Sopenharmony_ci	return de;
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cistatic struct hmdfs_dentry *hmdfs_in_level(struct dentry *child_dentry,
71562306a36Sopenharmony_ci					   unsigned int level,
71662306a36Sopenharmony_ci					   struct hmdfs_dcache_lookup_ctx *ctx)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	unsigned long nbucket;
71962306a36Sopenharmony_ci	unsigned long bidx, end_block;
72062306a36Sopenharmony_ci	struct hmdfs_dentry *de = NULL;
72162306a36Sopenharmony_ci	struct hmdfs_dentry *tmp_insense_de = NULL;
72262306a36Sopenharmony_ci	struct hmdfs_dentry_group *dentry_blk;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	nbucket = get_bucket_by_level(level);
72562306a36Sopenharmony_ci	if (!nbucket)
72662306a36Sopenharmony_ci		return de;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	bidx = get_bucketaddr(level, ctx->hash % nbucket) * BUCKET_BLOCKS;
72962306a36Sopenharmony_ci	end_block = bidx + BUCKET_BLOCKS;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	for (; bidx < end_block; bidx++) {
73262306a36Sopenharmony_ci		dentry_blk = find_dentry_page(ctx->sbi, bidx, ctx->filp);
73362306a36Sopenharmony_ci		if (!dentry_blk)
73462306a36Sopenharmony_ci			break;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		de = find_in_block(dentry_blk, ctx->hash, ctx->name,
73762306a36Sopenharmony_ci				   &tmp_insense_de, ctx->sbi->s_case_sensitive);
73862306a36Sopenharmony_ci		if (!de && !(ctx->insense_de) && tmp_insense_de) {
73962306a36Sopenharmony_ci			ctx->insense_de = tmp_insense_de;
74062306a36Sopenharmony_ci			ctx->insense_page = dentry_blk;
74162306a36Sopenharmony_ci			ctx->insense_bidx = bidx;
74262306a36Sopenharmony_ci		} else if (!de) {
74362306a36Sopenharmony_ci			hmdfs_unlock_file(ctx->filp, get_dentry_group_pos(bidx),
74462306a36Sopenharmony_ci					  DENTRYGROUP_SIZE);
74562306a36Sopenharmony_ci			kfree(dentry_blk);
74662306a36Sopenharmony_ci		} else {
74762306a36Sopenharmony_ci			ctx->page = dentry_blk;
74862306a36Sopenharmony_ci			break;
74962306a36Sopenharmony_ci		}
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci	ctx->bidx = bidx;
75262306a36Sopenharmony_ci	return de;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistruct hmdfs_dentry *hmdfs_find_dentry(struct dentry *child_dentry,
75662306a36Sopenharmony_ci				       struct hmdfs_dcache_lookup_ctx *ctx)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	struct hmdfs_dentry *de = NULL;
75962306a36Sopenharmony_ci	unsigned int max_depth;
76062306a36Sopenharmony_ci	unsigned int level;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (!ctx->filp)
76362306a36Sopenharmony_ci		return NULL;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	ctx->hash = hmdfs_dentry_hash(ctx->name, ctx->sbi->s_case_sensitive);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	max_depth = get_max_depth(ctx->filp);
76862306a36Sopenharmony_ci	for (level = 0; level < max_depth; level++) {
76962306a36Sopenharmony_ci		de = hmdfs_in_level(child_dentry, level, ctx);
77062306a36Sopenharmony_ci		if (de) {
77162306a36Sopenharmony_ci			if (ctx->insense_page) {
77262306a36Sopenharmony_ci				hmdfs_unlock_file(ctx->filp,
77362306a36Sopenharmony_ci					get_dentry_group_pos(ctx->insense_bidx),
77462306a36Sopenharmony_ci					DENTRYGROUP_SIZE);
77562306a36Sopenharmony_ci				kfree(ctx->insense_page);
77662306a36Sopenharmony_ci				ctx->insense_page = NULL;
77762306a36Sopenharmony_ci			}
77862306a36Sopenharmony_ci			return de;
77962306a36Sopenharmony_ci		}
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci	if (ctx->insense_de) {
78262306a36Sopenharmony_ci		ctx->bidx = ctx->insense_bidx;
78362306a36Sopenharmony_ci		ctx->page = ctx->insense_page;
78462306a36Sopenharmony_ci		ctx->insense_bidx = 0;
78562306a36Sopenharmony_ci		ctx->insense_page = NULL;
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci	return ctx->insense_de;
78862306a36Sopenharmony_ci}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_civoid update_dentry(struct hmdfs_dentry_group *d, struct dentry *child_dentry,
79162306a36Sopenharmony_ci		   		   struct inode *inode, struct super_block *hmdfs_sb,
79262306a36Sopenharmony_ci		  		   __u32 name_hash, unsigned int bit_pos)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	struct hmdfs_dentry *de;
79562306a36Sopenharmony_ci	struct hmdfs_dentry_info *gdi;
79662306a36Sopenharmony_ci	const struct qstr name = child_dentry->d_name;
79762306a36Sopenharmony_ci	int slots = get_dentry_slots(name.len);
79862306a36Sopenharmony_ci	int i;
79962306a36Sopenharmony_ci	unsigned long ino;
80062306a36Sopenharmony_ci	__u32 igen;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	gdi = hmdfs_sb == child_dentry->d_sb ? hmdfs_d(child_dentry) : NULL;
80362306a36Sopenharmony_ci	if (!gdi && S_ISLNK(d_inode(child_dentry)->i_mode)) {
80462306a36Sopenharmony_ci		ino = d_inode(child_dentry)->i_ino;
80562306a36Sopenharmony_ci		igen = d_inode(child_dentry)->i_generation;
80662306a36Sopenharmony_ci	} else {
80762306a36Sopenharmony_ci		ino = inode->i_ino;
80862306a36Sopenharmony_ci		igen = inode->i_generation;
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	de = &d->nsl[bit_pos];
81262306a36Sopenharmony_ci	de->hash = cpu_to_le32(name_hash);
81362306a36Sopenharmony_ci	de->namelen = cpu_to_le16(name.len);
81462306a36Sopenharmony_ci	memcpy(d->filename[bit_pos], name.name, name.len);
81562306a36Sopenharmony_ci	de->i_mtime = cpu_to_le64(inode->i_mtime.tv_sec);
81662306a36Sopenharmony_ci	de->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
81762306a36Sopenharmony_ci	de->i_size = cpu_to_le64(inode->i_size);
81862306a36Sopenharmony_ci	de->i_ino = cpu_to_le64(generate_u64_ino(ino, igen));
81962306a36Sopenharmony_ci	de->i_flag = 0;
82062306a36Sopenharmony_ci	if (gdi && hm_islnk(gdi->file_type))
82162306a36Sopenharmony_ci		de->i_mode = cpu_to_le16(S_IFLNK);
82262306a36Sopenharmony_ci	else if (!gdi && S_ISLNK(d_inode(child_dentry)->i_mode))
82362306a36Sopenharmony_ci		de->i_mode = d_inode(child_dentry)->i_mode;
82462306a36Sopenharmony_ci	else
82562306a36Sopenharmony_ci		de->i_mode = cpu_to_le16(inode->i_mode);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	for (i = 0; i < slots; i++) {
82862306a36Sopenharmony_ci		__set_bit_le(bit_pos + i, d->bitmap);
82962306a36Sopenharmony_ci		/* avoid wrong garbage data for readdir */
83062306a36Sopenharmony_ci		if (i)
83162306a36Sopenharmony_ci			(de + i)->namelen = 0;
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ciint room_for_filename(const void *bitmap, int slots, int max_slots)
83662306a36Sopenharmony_ci{
83762306a36Sopenharmony_ci	int bit_start = 0;
83862306a36Sopenharmony_ci	int zero_start, zero_end;
83962306a36Sopenharmony_cinext:
84062306a36Sopenharmony_ci	zero_start = find_next_zero_bit_le(bitmap, max_slots, bit_start);
84162306a36Sopenharmony_ci	if (zero_start >= max_slots)
84262306a36Sopenharmony_ci		return max_slots;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	zero_end = find_next_bit_le(bitmap, max_slots, zero_start);
84562306a36Sopenharmony_ci	if (zero_end - zero_start >= slots)
84662306a36Sopenharmony_ci		return zero_start;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	bit_start = zero_end + 1;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	if (zero_end + 1 >= max_slots)
85162306a36Sopenharmony_ci		return max_slots;
85262306a36Sopenharmony_ci	goto next;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_civoid create_in_cache_file(uint64_t dev_id, struct dentry *dentry)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	struct clearcache_item *item = NULL;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	item = hmdfs_find_cache_item(dev_id, dentry->d_parent);
86062306a36Sopenharmony_ci	if (item) {
86162306a36Sopenharmony_ci		if (d_inode(dentry))
86262306a36Sopenharmony_ci			create_dentry(dentry, d_inode(dentry), item->filp,
86362306a36Sopenharmony_ci				      hmdfs_sb(dentry->d_sb));
86462306a36Sopenharmony_ci		else
86562306a36Sopenharmony_ci			hmdfs_err("inode is null!");
86662306a36Sopenharmony_ci		kref_put(&item->ref, release_cache_item);
86762306a36Sopenharmony_ci	} else {
86862306a36Sopenharmony_ci		hmdfs_info("find cache item failed, device_id:%llu", dev_id);
86962306a36Sopenharmony_ci	}
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ciint create_dentry(struct dentry *child_dentry, struct inode *inode,
87362306a36Sopenharmony_ci		  struct file *file, struct hmdfs_sb_info *sbi)
87462306a36Sopenharmony_ci{
87562306a36Sopenharmony_ci	unsigned int bit_pos, level;
87662306a36Sopenharmony_ci	unsigned long bidx, end_block;
87762306a36Sopenharmony_ci	const struct qstr qstr = child_dentry->d_name;
87862306a36Sopenharmony_ci	__u32 namehash;
87962306a36Sopenharmony_ci	loff_t pos;
88062306a36Sopenharmony_ci	ssize_t size;
88162306a36Sopenharmony_ci	int ret = 0;
88262306a36Sopenharmony_ci	struct hmdfs_dentry_group *dentry_blk = NULL;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	level = 0;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	namehash = hmdfs_dentry_hash(&qstr, sbi->s_case_sensitive);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	dentry_blk = kmalloc(sizeof(*dentry_blk), GFP_KERNEL);
88962306a36Sopenharmony_ci	if (!dentry_blk) {
89062306a36Sopenharmony_ci		ret = -ENOMEM;
89162306a36Sopenharmony_ci		goto out_err;
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_cifind:
89462306a36Sopenharmony_ci	if (level == MAX_BUCKET_LEVEL) {
89562306a36Sopenharmony_ci		ret = -ENOSPC;
89662306a36Sopenharmony_ci		goto out;
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci	bidx = BUCKET_BLOCKS *
89962306a36Sopenharmony_ci	       get_bucketaddr(level, namehash % get_bucket_by_level(level));
90062306a36Sopenharmony_ci	end_block = bidx + BUCKET_BLOCKS;
90162306a36Sopenharmony_ci	if (end_block > get_dentry_group_cnt(file_inode(file))) {
90262306a36Sopenharmony_ci		if (cache_file_truncate(sbi, &(file->f_path),
90362306a36Sopenharmony_ci					get_dcache_file_size(level))) {
90462306a36Sopenharmony_ci			ret = -ENOSPC;
90562306a36Sopenharmony_ci			goto out;
90662306a36Sopenharmony_ci		}
90762306a36Sopenharmony_ci	}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	for (; bidx < end_block; bidx++) {
91062306a36Sopenharmony_ci		int size;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci		pos = get_dentry_group_pos(bidx);
91362306a36Sopenharmony_ci		ret = hmdfs_wlock_file(file, pos, DENTRYGROUP_SIZE);
91462306a36Sopenharmony_ci		if (ret)
91562306a36Sopenharmony_ci			goto out;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci		size = cache_file_read(sbi, file, dentry_blk,
91862306a36Sopenharmony_ci				       (size_t)DENTRYGROUP_SIZE, &pos);
91962306a36Sopenharmony_ci		if (size != DENTRYGROUP_SIZE) {
92062306a36Sopenharmony_ci			ret = -ENOSPC;
92162306a36Sopenharmony_ci			hmdfs_unlock_file(file, pos, DENTRYGROUP_SIZE);
92262306a36Sopenharmony_ci			goto out;
92362306a36Sopenharmony_ci		}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci		bit_pos = room_for_filename(&dentry_blk->bitmap,
92662306a36Sopenharmony_ci					    get_dentry_slots(qstr.len),
92762306a36Sopenharmony_ci					    DENTRY_PER_GROUP);
92862306a36Sopenharmony_ci		if (bit_pos < DENTRY_PER_GROUP)
92962306a36Sopenharmony_ci			goto add;
93062306a36Sopenharmony_ci		hmdfs_unlock_file(file, pos, DENTRYGROUP_SIZE);
93162306a36Sopenharmony_ci	}
93262306a36Sopenharmony_ci	++level;
93362306a36Sopenharmony_ci	goto find;
93462306a36Sopenharmony_ciadd:
93562306a36Sopenharmony_ci	pos = get_dentry_group_pos(bidx);
93662306a36Sopenharmony_ci	update_dentry(dentry_blk, child_dentry, inode, sbi->sb, namehash,
93762306a36Sopenharmony_ci				  bit_pos);
93862306a36Sopenharmony_ci	size = cache_file_write(sbi, file, dentry_blk,
93962306a36Sopenharmony_ci				sizeof(struct hmdfs_dentry_group), &pos);
94062306a36Sopenharmony_ci	if (size != sizeof(struct hmdfs_dentry_group))
94162306a36Sopenharmony_ci		hmdfs_err("cache file write failed!, ret = %zd", size);
94262306a36Sopenharmony_ci	hmdfs_unlock_file(file, pos, DENTRYGROUP_SIZE);
94362306a36Sopenharmony_ciout:
94462306a36Sopenharmony_ci	kfree(dentry_blk);
94562306a36Sopenharmony_ciout_err:
94662306a36Sopenharmony_ci	return ret;
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_civoid hmdfs_init_dcache_lookup_ctx(struct hmdfs_dcache_lookup_ctx *ctx,
95062306a36Sopenharmony_ci				  struct hmdfs_sb_info *sbi,
95162306a36Sopenharmony_ci				  const struct qstr *qstr, struct file *filp)
95262306a36Sopenharmony_ci{
95362306a36Sopenharmony_ci	ctx->sbi = sbi;
95462306a36Sopenharmony_ci	ctx->name = qstr;
95562306a36Sopenharmony_ci	ctx->filp = filp;
95662306a36Sopenharmony_ci	ctx->bidx = 0;
95762306a36Sopenharmony_ci	ctx->page = NULL;
95862306a36Sopenharmony_ci	ctx->insense_de = NULL;
95962306a36Sopenharmony_ci	ctx->insense_bidx = 0;
96062306a36Sopenharmony_ci	ctx->insense_page = NULL;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ciint update_inode_to_dentry(struct dentry *child_dentry, struct inode *inode)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = d_inode(child_dentry)->i_sb->s_fs_info;
96662306a36Sopenharmony_ci	struct hmdfs_dentry *de = NULL;
96762306a36Sopenharmony_ci	loff_t ipos;
96862306a36Sopenharmony_ci	struct dentry *parent_dentry;
96962306a36Sopenharmony_ci	struct cache_file_node *cfn = NULL;
97062306a36Sopenharmony_ci	char *relative_path = NULL;
97162306a36Sopenharmony_ci	struct hmdfs_dcache_lookup_ctx ctx;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	parent_dentry = child_dentry->d_parent;
97462306a36Sopenharmony_ci	if (hmdfs_d(parent_dentry)->dentry_type == HMDFS_LAYER_FIRST_DEVICE)
97562306a36Sopenharmony_ci		return 0;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	relative_path = hmdfs_get_dentry_relative_path(parent_dentry);
97862306a36Sopenharmony_ci	if (!relative_path)
97962306a36Sopenharmony_ci		return -ENOMEM;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	cfn = find_cfn(sbi, HMDFS_SERVER_CID, relative_path, true);
98262306a36Sopenharmony_ci	if (!cfn)
98362306a36Sopenharmony_ci		goto out;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	hmdfs_init_dcache_lookup_ctx(&ctx, sbi, &child_dentry->d_name,
98662306a36Sopenharmony_ci				     cfn->filp);
98762306a36Sopenharmony_ci	de = hmdfs_find_dentry(child_dentry, &ctx);
98862306a36Sopenharmony_ci	if (!de)
98962306a36Sopenharmony_ci		goto out_cfn;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	de->i_mtime = cpu_to_le64(inode->i_mtime.tv_sec);
99262306a36Sopenharmony_ci	de->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
99362306a36Sopenharmony_ci	de->i_size = cpu_to_le64(inode->i_size);
99462306a36Sopenharmony_ci	de->i_ino = cpu_to_le64(
99562306a36Sopenharmony_ci		generate_u64_ino(inode->i_ino, inode->i_generation));
99662306a36Sopenharmony_ci	de->i_flag = 0;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	ipos = get_dentry_group_pos(ctx.bidx);
99962306a36Sopenharmony_ci	write_dentry_page(cfn->filp, ctx.page,
100062306a36Sopenharmony_ci			  sizeof(struct hmdfs_dentry_group), ipos);
100162306a36Sopenharmony_ci	hmdfs_unlock_file(cfn->filp, ipos, DENTRYGROUP_SIZE);
100262306a36Sopenharmony_ci	kfree(ctx.page);
100362306a36Sopenharmony_ciout_cfn:
100462306a36Sopenharmony_ci	release_cfn(cfn);
100562306a36Sopenharmony_ciout:
100662306a36Sopenharmony_ci	kfree(relative_path);
100762306a36Sopenharmony_ci	return 0;
100862306a36Sopenharmony_ci}
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_civoid hmdfs_delete_dentry(struct dentry *d, struct file *filp)
101162306a36Sopenharmony_ci{
101262306a36Sopenharmony_ci	struct hmdfs_dentry *de = NULL;
101362306a36Sopenharmony_ci	unsigned int bit_pos;
101462306a36Sopenharmony_ci	int slots, i;
101562306a36Sopenharmony_ci	loff_t ipos;
101662306a36Sopenharmony_ci	ssize_t size;
101762306a36Sopenharmony_ci	struct hmdfs_dcache_lookup_ctx ctx;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	hmdfs_init_dcache_lookup_ctx(&ctx, hmdfs_sb(d->d_sb), &d->d_name, filp);
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	de = hmdfs_find_dentry(d, &ctx);
102262306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(de)) {
102362306a36Sopenharmony_ci		hmdfs_info("find dentry failed!, err=%ld", PTR_ERR(de));
102462306a36Sopenharmony_ci		return;
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci	slots = get_dentry_slots(le16_to_cpu(de->namelen));
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	bit_pos = de - ctx.page->nsl;
102962306a36Sopenharmony_ci	for (i = 0; i < slots; i++)
103062306a36Sopenharmony_ci		__clear_bit_le(bit_pos + i, &ctx.page->bitmap);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	ipos = get_dentry_group_pos(ctx.bidx);
103362306a36Sopenharmony_ci	size = cache_file_write(hmdfs_sb(d->d_sb), filp, ctx.page,
103462306a36Sopenharmony_ci				sizeof(struct hmdfs_dentry_group), &ipos);
103562306a36Sopenharmony_ci	if (size != sizeof(struct hmdfs_dentry_group))
103662306a36Sopenharmony_ci		hmdfs_err("cache file write failed!, ret = %zd", size);
103762306a36Sopenharmony_ci	hmdfs_unlock_file(filp, ipos, DENTRYGROUP_SIZE);
103862306a36Sopenharmony_ci	kfree(ctx.page);
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_cistatic int hmdfs_get_cache_path(struct hmdfs_sb_info *sbi, struct path *dir)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	struct hmdfs_dentry_info *di = hmdfs_d(sbi->sb->s_root);
104462306a36Sopenharmony_ci	int err;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	if (!sbi->s_dentry_cache) {
104762306a36Sopenharmony_ci		*dir = di->lower_path;
104862306a36Sopenharmony_ci		return 0;
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	err = kern_path(sbi->cache_dir, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, dir);
105262306a36Sopenharmony_ci	if (err)
105362306a36Sopenharmony_ci		hmdfs_err("open failed, errno = %d", err);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	return err;
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_cistatic void hmdfs_put_cache_path(struct hmdfs_sb_info *sbi, struct path *dir)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	if (!sbi->s_dentry_cache)
106162306a36Sopenharmony_ci		return;
106262306a36Sopenharmony_ci	path_put(dir);
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_cistruct file *create_local_dentry_file_cache(struct hmdfs_sb_info *sbi)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	struct file *filp = NULL;
106862306a36Sopenharmony_ci	const struct cred *old_cred = hmdfs_override_creds(sbi->system_cred);
106962306a36Sopenharmony_ci	struct path cache_dir;
107062306a36Sopenharmony_ci	int err;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	err = hmdfs_get_cache_path(sbi, &cache_dir);
107362306a36Sopenharmony_ci	if (err) {
107462306a36Sopenharmony_ci		filp = ERR_PTR(err);
107562306a36Sopenharmony_ci		goto out;
107662306a36Sopenharmony_ci	}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	filp = file_open_root(&cache_dir, ".",
107962306a36Sopenharmony_ci			      O_RDWR | O_LARGEFILE | O_TMPFILE,
108062306a36Sopenharmony_ci			      DENTRY_FILE_PERM);
108162306a36Sopenharmony_ci	if (IS_ERR(filp))
108262306a36Sopenharmony_ci		hmdfs_err("dentryfile open failed and exit err=%ld",
108362306a36Sopenharmony_ci			  PTR_ERR(filp));
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	hmdfs_put_cache_path(sbi, &cache_dir);
108662306a36Sopenharmony_ciout:
108762306a36Sopenharmony_ci	hmdfs_revert_creds(old_cred);
108862306a36Sopenharmony_ci	return filp;
108962306a36Sopenharmony_ci}
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_cistatic int hmdfs_linkat(struct path *old_path, const char *newname)
109262306a36Sopenharmony_ci{
109362306a36Sopenharmony_ci	struct dentry *new_dentry = NULL;
109462306a36Sopenharmony_ci	struct path new_path;
109562306a36Sopenharmony_ci	int error;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	new_dentry = kern_path_create(AT_FDCWD, newname, &new_path, 0);
109862306a36Sopenharmony_ci	if (IS_ERR(new_dentry)) {
109962306a36Sopenharmony_ci		hmdfs_err("create kernel path failed, error: %ld",
110062306a36Sopenharmony_ci			  PTR_ERR(new_dentry));
110162306a36Sopenharmony_ci		return PTR_ERR(new_dentry);
110262306a36Sopenharmony_ci	}
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	error = -EXDEV;
110562306a36Sopenharmony_ci	if (old_path->mnt != new_path.mnt)
110662306a36Sopenharmony_ci		goto out_dput;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	error = vfs_link(old_path->dentry, &nop_mnt_idmap, new_path.dentry->d_inode, new_dentry,
110962306a36Sopenharmony_ci			 NULL);
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ciout_dput:
111262306a36Sopenharmony_ci	done_path_create(&new_path, new_dentry);
111362306a36Sopenharmony_ci	return error;
111462306a36Sopenharmony_ci}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cistatic int cache_file_mkdir(const char *name, umode_t mode)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	struct dentry *dentry;
111962306a36Sopenharmony_ci	struct path path;
112062306a36Sopenharmony_ci	int err;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY);
112362306a36Sopenharmony_ci	if (IS_ERR(dentry))
112462306a36Sopenharmony_ci		return PTR_ERR(dentry);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	err = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode);
112762306a36Sopenharmony_ci	if (err && err != -EEXIST)
112862306a36Sopenharmony_ci		hmdfs_err("vfs_mkdir failed, err = %d", err);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	done_path_create(&path, dentry);
113162306a36Sopenharmony_ci	return err;
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cistatic int cache_file_create_path(const char *fullpath)
113562306a36Sopenharmony_ci{
113662306a36Sopenharmony_ci	char *path;
113762306a36Sopenharmony_ci	char *s;
113862306a36Sopenharmony_ci	int err = 0;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	path = kstrdup(fullpath, GFP_KERNEL);
114162306a36Sopenharmony_ci	if (!path)
114262306a36Sopenharmony_ci		return -ENOMEM;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	s = path + 1;
114562306a36Sopenharmony_ci	while (true) {
114662306a36Sopenharmony_ci		s = strchr(s, '/');
114762306a36Sopenharmony_ci		if (!s)
114862306a36Sopenharmony_ci			break;
114962306a36Sopenharmony_ci		s[0] = '\0';
115062306a36Sopenharmony_ci		err = cache_file_mkdir(path, 0755);
115162306a36Sopenharmony_ci		if (err && err != -EEXIST)
115262306a36Sopenharmony_ci			break;
115362306a36Sopenharmony_ci		s[0] = '/';
115462306a36Sopenharmony_ci		s++;
115562306a36Sopenharmony_ci	}
115662306a36Sopenharmony_ci	kfree(path);
115762306a36Sopenharmony_ci	return err;
115862306a36Sopenharmony_ci}
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_cistatic void hmdfs_cache_path_create(char *s, const char *dir, bool server)
116162306a36Sopenharmony_ci{
116262306a36Sopenharmony_ci	if (server)
116362306a36Sopenharmony_ci		snprintf(s, PATH_MAX, "%s/dentry_cache/server/", dir);
116462306a36Sopenharmony_ci	else
116562306a36Sopenharmony_ci		snprintf(s, PATH_MAX, "%s/dentry_cache/client/", dir);
116662306a36Sopenharmony_ci}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_cistatic void concat_cachefile_name(char *s, uint64_t hash, const char *id,
116962306a36Sopenharmony_ci				    bool server)
117062306a36Sopenharmony_ci{
117162306a36Sopenharmony_ci	int offset = strlen(s);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	if (server)
117462306a36Sopenharmony_ci		snprintf(s + offset, PATH_MAX - offset, "%016llx", hash);
117562306a36Sopenharmony_ci	else
117662306a36Sopenharmony_ci		snprintf(s + offset, PATH_MAX - offset, "%s_%016llx", id, hash);
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ciint cache_file_name_generate(char *fullname, struct hmdfs_peer *con,
118062306a36Sopenharmony_ci			     const char *relative_path, bool server)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = con->sbi;
118362306a36Sopenharmony_ci	uint64_t  hash;
118462306a36Sopenharmony_ci	char cid[HMDFS_CFN_CID_SIZE];
118562306a36Sopenharmony_ci	int err;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	hmdfs_cache_path_create(fullname, sbi->cache_dir, server);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	err = cache_file_create_path(fullname);
119062306a36Sopenharmony_ci	if (err && err != -EEXIST) {
119162306a36Sopenharmony_ci		hmdfs_err("making dir failed %d", err);
119262306a36Sopenharmony_ci		return err;
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	strncpy(cid, con->cid, HMDFS_CFN_CID_SIZE - 1);
119662306a36Sopenharmony_ci	cid[HMDFS_CFN_CID_SIZE - 1] = '\0';
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	hash = path_hash(relative_path, strlen(relative_path),
119962306a36Sopenharmony_ci			 sbi->s_case_sensitive);
120062306a36Sopenharmony_ci	concat_cachefile_name(fullname, hash, cid, server);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	return 0;
120362306a36Sopenharmony_ci}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_cistatic void free_cfn(struct cache_file_node *cfn)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(cfn->filp))
120862306a36Sopenharmony_ci		filp_close(cfn->filp, NULL);
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	kfree(cfn->relative_path);
121162306a36Sopenharmony_ci	kfree(cfn);
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_cistatic bool path_cmp(const char *path1, const char *path2, bool case_sensitive)
121562306a36Sopenharmony_ci{
121662306a36Sopenharmony_ci	int ret;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	if (case_sensitive)
121962306a36Sopenharmony_ci		ret = strcmp(path1, path2);
122062306a36Sopenharmony_ci	else
122162306a36Sopenharmony_ci		ret = strcasecmp(path1, path2);
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	return !ret;
122462306a36Sopenharmony_ci}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_cistatic bool dentry_file_match(struct cache_file_node *cfn, const char *id,
122762306a36Sopenharmony_ci			      const char *path)
122862306a36Sopenharmony_ci{
122962306a36Sopenharmony_ci	return (path_cmp(cfn->relative_path, path, cfn->sbi->s_case_sensitive) &&
123062306a36Sopenharmony_ci		!strncmp((cfn)->cid, id, HMDFS_CFN_CID_SIZE - 1));
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_cistruct cache_file_node *__find_cfn(struct hmdfs_sb_info *sbi, const char *cid,
123462306a36Sopenharmony_ci				   const char *path, bool server)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	struct cache_file_node *cfn = NULL;
123762306a36Sopenharmony_ci	struct list_head *head = NULL;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	head = get_list_head(sbi, server);
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	list_for_each_entry(cfn, head, list) {
124262306a36Sopenharmony_ci		if (dentry_file_match(cfn, cid, path)) {
124362306a36Sopenharmony_ci			refcount_inc(&cfn->ref);
124462306a36Sopenharmony_ci			return cfn;
124562306a36Sopenharmony_ci		}
124662306a36Sopenharmony_ci	}
124762306a36Sopenharmony_ci	return NULL;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_cistruct cache_file_node *create_cfn(struct hmdfs_sb_info *sbi, const char *path,
125162306a36Sopenharmony_ci				   const char *cid, bool server)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci	struct cache_file_node *cfn = kzalloc(sizeof(*cfn), GFP_KERNEL);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	if (!cfn)
125662306a36Sopenharmony_ci		return NULL;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	cfn->relative_path = kstrdup(path, GFP_KERNEL);
125962306a36Sopenharmony_ci	if (!cfn->relative_path)
126062306a36Sopenharmony_ci		goto out;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	refcount_set(&cfn->ref, 1);
126362306a36Sopenharmony_ci	strncpy(cfn->cid, cid, HMDFS_CFN_CID_SIZE - 1);
126462306a36Sopenharmony_ci	cfn->cid[HMDFS_CFN_CID_SIZE - 1] = '\0';
126562306a36Sopenharmony_ci	cfn->sbi = sbi;
126662306a36Sopenharmony_ci	cfn->server = server;
126762306a36Sopenharmony_ci	return cfn;
126862306a36Sopenharmony_ciout:
126962306a36Sopenharmony_ci	free_cfn(cfn);
127062306a36Sopenharmony_ci	return NULL;
127162306a36Sopenharmony_ci}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_cistatic struct file *insert_cfn(struct hmdfs_sb_info *sbi, const char *filename,
127462306a36Sopenharmony_ci	       const char *path, const char *cid, bool server)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	const struct cred *old_cred = NULL;
127762306a36Sopenharmony_ci	struct cache_file_node *cfn = NULL;
127862306a36Sopenharmony_ci	struct cache_file_node *exist = NULL;
127962306a36Sopenharmony_ci	struct list_head *head = NULL;
128062306a36Sopenharmony_ci	struct file *filp = NULL;
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	cfn = create_cfn(sbi, path, cid, server);
128362306a36Sopenharmony_ci	if (!cfn)
128462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	old_cred = hmdfs_override_creds(sbi->system_cred);
128762306a36Sopenharmony_ci	filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
128862306a36Sopenharmony_ci	hmdfs_revert_creds(old_cred);
128962306a36Sopenharmony_ci	if (IS_ERR(filp)) {
129062306a36Sopenharmony_ci		hmdfs_err("open file failed, err=%ld", PTR_ERR(filp));
129162306a36Sopenharmony_ci		goto out;
129262306a36Sopenharmony_ci	}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	head = get_list_head(sbi, server);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	mutex_lock(&sbi->cache_list_lock);
129762306a36Sopenharmony_ci	exist = __find_cfn(sbi, cid, path, server);
129862306a36Sopenharmony_ci	if (!exist) {
129962306a36Sopenharmony_ci		cfn->filp = filp;
130062306a36Sopenharmony_ci		list_add_tail(&cfn->list, head);
130162306a36Sopenharmony_ci	} else {
130262306a36Sopenharmony_ci		mutex_unlock(&sbi->cache_list_lock);
130362306a36Sopenharmony_ci		release_cfn(exist);
130462306a36Sopenharmony_ci		filp_close(filp, NULL);
130562306a36Sopenharmony_ci		filp = ERR_PTR(-EEXIST);
130662306a36Sopenharmony_ci		goto out;
130762306a36Sopenharmony_ci	}
130862306a36Sopenharmony_ci	mutex_unlock(&sbi->cache_list_lock);
130962306a36Sopenharmony_ci	return filp;
131062306a36Sopenharmony_ciout:
131162306a36Sopenharmony_ci	free_cfn(cfn);
131262306a36Sopenharmony_ci	return filp;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ciint hmdfs_rename_dentry(struct dentry *old_dentry, struct dentry *new_dentry,
131662306a36Sopenharmony_ci			struct file *old_filp, struct file *new_filp)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	int ret;
131962306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = hmdfs_sb(new_dentry->d_sb);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	/*
132262306a36Sopenharmony_ci	 * Try to delete first, because stale dentry might exist after
132362306a36Sopenharmony_ci	 * coverwrite.
132462306a36Sopenharmony_ci	 */
132562306a36Sopenharmony_ci	hmdfs_delete_dentry(new_dentry, new_filp);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	ret = create_dentry(new_dentry, d_inode(old_dentry), new_filp, sbi);
132862306a36Sopenharmony_ci	if (ret) {
132962306a36Sopenharmony_ci		hmdfs_err("create dentry failed!, err=%d", ret);
133062306a36Sopenharmony_ci		return ret;
133162306a36Sopenharmony_ci	}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	hmdfs_delete_dentry(old_dentry, old_filp);
133462306a36Sopenharmony_ci	return 0;
133562306a36Sopenharmony_ci}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci/**
133862306a36Sopenharmony_ci * cache_file_persistent - link the tmpfile to the cache dir
133962306a36Sopenharmony_ci * @con:	the connection peer
134062306a36Sopenharmony_ci * @filp:	the file handler of the tmpfile
134162306a36Sopenharmony_ci * @relative_path: the relative path which the tmpfile belongs
134262306a36Sopenharmony_ci * @server:	server or client
134362306a36Sopenharmony_ci *
134462306a36Sopenharmony_ci * Return value: the new file handler of the persistent file if the
134562306a36Sopenharmony_ci * persistent operation succeed. Otherwise will return the original handler
134662306a36Sopenharmony_ci * of the tmpfile passed in, so that the caller does not have to check
134762306a36Sopenharmony_ci * the returned handler.
134862306a36Sopenharmony_ci *
134962306a36Sopenharmony_ci */
135062306a36Sopenharmony_cistruct file *cache_file_persistent(struct hmdfs_peer *con, struct file *filp,
135162306a36Sopenharmony_ci			   const char *relative_path, bool server)
135262306a36Sopenharmony_ci{
135362306a36Sopenharmony_ci	struct cache_file_node *cfn = NULL;
135462306a36Sopenharmony_ci	char *fullname = NULL;
135562306a36Sopenharmony_ci	char *cid = server ? HMDFS_SERVER_CID : (char *)con->cid;
135662306a36Sopenharmony_ci	struct file *newf = NULL;
135762306a36Sopenharmony_ci	int i = 0;
135862306a36Sopenharmony_ci	int len;
135962306a36Sopenharmony_ci	int err;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	if (!con->sbi->s_dentry_cache)
136262306a36Sopenharmony_ci		return filp;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	cfn = find_cfn(con->sbi, cid, relative_path, server);
136562306a36Sopenharmony_ci	if (cfn) {
136662306a36Sopenharmony_ci		release_cfn(cfn);
136762306a36Sopenharmony_ci		return filp;
136862306a36Sopenharmony_ci	}
136962306a36Sopenharmony_ci	fullname = kzalloc(PATH_MAX, GFP_KERNEL);
137062306a36Sopenharmony_ci	if (!fullname)
137162306a36Sopenharmony_ci		return filp;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	err = cache_file_name_generate(fullname, con, relative_path, server);
137462306a36Sopenharmony_ci	if (err)
137562306a36Sopenharmony_ci		goto out;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	err = __vfs_setxattr(&nop_mnt_idmap, file_dentry(filp), file_inode(filp),
137862306a36Sopenharmony_ci			     DENTRY_FILE_XATTR_NAME, relative_path,
137962306a36Sopenharmony_ci			     strlen(relative_path), 0);
138062306a36Sopenharmony_ci	if (err) {
138162306a36Sopenharmony_ci		hmdfs_err("setxattr for file failed, err=%d", err);
138262306a36Sopenharmony_ci		goto out;
138362306a36Sopenharmony_ci	}
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	len = strlen(fullname);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	do {
138862306a36Sopenharmony_ci		err = hmdfs_linkat(&filp->f_path, fullname);
138962306a36Sopenharmony_ci		if (!err)
139062306a36Sopenharmony_ci			break;
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci		snprintf(fullname + len, PATH_MAX - len, "_%d", i);
139362306a36Sopenharmony_ci	} while (i++ < DENTRY_FILE_NAME_RETRY);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	if (err) {
139662306a36Sopenharmony_ci		hmdfs_err("link for file failed, err=%d", err);
139762306a36Sopenharmony_ci		goto out;
139862306a36Sopenharmony_ci	}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	newf = insert_cfn(con->sbi, fullname, relative_path, cid, server);
140162306a36Sopenharmony_ci	if (!IS_ERR(newf))
140262306a36Sopenharmony_ci		filp = newf;
140362306a36Sopenharmony_ciout:
140462306a36Sopenharmony_ci	kfree(fullname);
140562306a36Sopenharmony_ci	return filp;
140662306a36Sopenharmony_ci}
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ciint get_cloud_cache_file(struct dentry *dentry, struct hmdfs_sb_info *sbi)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	int ret;
141162306a36Sopenharmony_ci	ssize_t res;
141262306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = hmdfs_d(dentry);
141362306a36Sopenharmony_ci	struct clearcache_item *item;
141462306a36Sopenharmony_ci	struct file *filp = NULL;
141562306a36Sopenharmony_ci	uint64_t  hash;
141662306a36Sopenharmony_ci	char *relative_path = NULL;
141762306a36Sopenharmony_ci	char *dirname = NULL;
141862306a36Sopenharmony_ci	char *fullname = NULL;
141962306a36Sopenharmony_ci	char *cache_file_name = NULL;
142062306a36Sopenharmony_ci	char *kvalue = NULL;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	item = hmdfs_find_cache_item(CLOUD_DEVICE, dentry);
142362306a36Sopenharmony_ci	if (item) {
142462306a36Sopenharmony_ci		kref_put(&item->ref, release_cache_item);
142562306a36Sopenharmony_ci		return 0;
142662306a36Sopenharmony_ci	}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	relative_path = hmdfs_get_dentry_relative_path(dentry);
142962306a36Sopenharmony_ci	if (unlikely(!relative_path)) {
143062306a36Sopenharmony_ci		hmdfs_err("get relative path failed %d", -ENOMEM);
143162306a36Sopenharmony_ci		ret = -ENOMEM;
143262306a36Sopenharmony_ci		goto out;
143362306a36Sopenharmony_ci	}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	dirname = kzalloc(PATH_MAX, GFP_KERNEL);
143662306a36Sopenharmony_ci	if (!dirname) {
143762306a36Sopenharmony_ci		ret = -ENOMEM;
143862306a36Sopenharmony_ci		goto out;
143962306a36Sopenharmony_ci	}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	cache_file_name = kzalloc(PATH_MAX, GFP_KERNEL);
144262306a36Sopenharmony_ci	if (!cache_file_name) {
144362306a36Sopenharmony_ci		ret = -ENOMEM;
144462306a36Sopenharmony_ci		goto out;
144562306a36Sopenharmony_ci	}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	fullname = kzalloc(PATH_MAX, GFP_KERNEL);
144862306a36Sopenharmony_ci	if (!fullname) {
144962306a36Sopenharmony_ci		ret = -ENOMEM;
145062306a36Sopenharmony_ci		goto out;
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	kvalue = kzalloc(PATH_MAX, GFP_KERNEL);
145462306a36Sopenharmony_ci	if (!kvalue) {
145562306a36Sopenharmony_ci		ret = -ENOMEM;
145662306a36Sopenharmony_ci		goto out;
145762306a36Sopenharmony_ci	}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	hash = path_hash(relative_path, strlen(relative_path),
146062306a36Sopenharmony_ci			 sbi->s_case_sensitive);
146162306a36Sopenharmony_ci	concat_cachefile_name(cache_file_name, hash, CLOUD_CID, false);
146262306a36Sopenharmony_ci	snprintf(dirname, PATH_MAX, "%s/dentry_cache/cloud/",
146362306a36Sopenharmony_ci		 sbi->cache_dir);
146462306a36Sopenharmony_ci	snprintf(fullname, PATH_MAX, "%s%s", dirname, cache_file_name);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	filp = filp_open(fullname, O_RDWR | O_LARGEFILE, 0);
146762306a36Sopenharmony_ci	if (IS_ERR(filp)) {
146862306a36Sopenharmony_ci		hmdfs_debug("open fail %ld", PTR_ERR(filp));
146962306a36Sopenharmony_ci		ret = PTR_ERR(filp);
147062306a36Sopenharmony_ci		goto out;
147162306a36Sopenharmony_ci	}
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	res = __vfs_getxattr(file_dentry(filp), file_inode(filp),
147462306a36Sopenharmony_ci			       DENTRY_FILE_XATTR_NAME, kvalue, PATH_MAX);
147562306a36Sopenharmony_ci	if (res <= 0 || res >= PATH_MAX) {
147662306a36Sopenharmony_ci		hmdfs_err("getxattr return: %zd", res);
147762306a36Sopenharmony_ci		filp_close(filp, NULL);
147862306a36Sopenharmony_ci		ret = -ENOENT;
147962306a36Sopenharmony_ci		goto out;
148062306a36Sopenharmony_ci	}
148162306a36Sopenharmony_ci	kvalue[res] = '\0';
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	if (!path_cmp(relative_path, kvalue, sbi->s_case_sensitive)) {
148462306a36Sopenharmony_ci		hmdfs_err("relative path from xattr do not match");
148562306a36Sopenharmony_ci		filp_close(filp, NULL);
148662306a36Sopenharmony_ci		ret = -ENOENT;
148762306a36Sopenharmony_ci		goto out;
148862306a36Sopenharmony_ci	}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	mutex_lock(&d_info->cache_pull_lock);
149162306a36Sopenharmony_ci	hmdfs_add_cache_list(CLOUD_DEVICE, dentry, filp);
149262306a36Sopenharmony_ci	mutex_unlock(&d_info->cache_pull_lock);
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	ret = 0;
149562306a36Sopenharmony_ciout:
149662306a36Sopenharmony_ci	kfree(relative_path);
149762306a36Sopenharmony_ci	kfree(dirname);
149862306a36Sopenharmony_ci	kfree(fullname);
149962306a36Sopenharmony_ci	kfree(cache_file_name);
150062306a36Sopenharmony_ci	kfree(kvalue);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	return ret;
150362306a36Sopenharmony_ci}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_civoid __destroy_cfn(struct list_head *head)
150662306a36Sopenharmony_ci{
150762306a36Sopenharmony_ci	struct cache_file_node *cfn = NULL;
150862306a36Sopenharmony_ci	struct cache_file_node *n = NULL;
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	list_for_each_entry_safe(cfn, n, head, list) {
151162306a36Sopenharmony_ci		list_del_init(&cfn->list);
151262306a36Sopenharmony_ci		release_cfn(cfn);
151362306a36Sopenharmony_ci	}
151462306a36Sopenharmony_ci}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_civoid hmdfs_cfn_destroy(struct hmdfs_sb_info *sbi)
151762306a36Sopenharmony_ci{
151862306a36Sopenharmony_ci	mutex_lock(&sbi->cache_list_lock);
151962306a36Sopenharmony_ci	__destroy_cfn(&sbi->client_cache);
152062306a36Sopenharmony_ci	__destroy_cfn(&sbi->server_cache);
152162306a36Sopenharmony_ci	mutex_unlock(&sbi->cache_list_lock);
152262306a36Sopenharmony_ci}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_cistruct cache_file_node *find_cfn(struct hmdfs_sb_info *sbi, const char *cid,
152562306a36Sopenharmony_ci				 const char *path, bool server)
152662306a36Sopenharmony_ci{
152762306a36Sopenharmony_ci	struct cache_file_node *cfn = NULL;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	mutex_lock(&sbi->cache_list_lock);
153062306a36Sopenharmony_ci	cfn = __find_cfn(sbi, cid, path, server);
153162306a36Sopenharmony_ci	mutex_unlock(&sbi->cache_list_lock);
153262306a36Sopenharmony_ci	return cfn;
153362306a36Sopenharmony_ci}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_civoid release_cfn(struct cache_file_node *cfn)
153662306a36Sopenharmony_ci{
153762306a36Sopenharmony_ci	if (refcount_dec_and_test(&cfn->ref))
153862306a36Sopenharmony_ci		free_cfn(cfn);
153962306a36Sopenharmony_ci}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_civoid remove_cfn(struct cache_file_node *cfn)
154262306a36Sopenharmony_ci{
154362306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = cfn->sbi;
154462306a36Sopenharmony_ci	bool deleted;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	mutex_lock(&sbi->cache_list_lock);
154762306a36Sopenharmony_ci	deleted = list_empty(&cfn->list);
154862306a36Sopenharmony_ci	if (!deleted)
154962306a36Sopenharmony_ci		list_del_init(&cfn->list);
155062306a36Sopenharmony_ci	mutex_unlock(&sbi->cache_list_lock);
155162306a36Sopenharmony_ci	if (!deleted) {
155262306a36Sopenharmony_ci		delete_dentry_file(cfn->filp);
155362306a36Sopenharmony_ci		release_cfn(cfn);
155462306a36Sopenharmony_ci	}
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ciint hmdfs_do_lock_file(struct file *filp, unsigned char fl_type, loff_t start,
155862306a36Sopenharmony_ci		       loff_t len)
155962306a36Sopenharmony_ci{
156062306a36Sopenharmony_ci	struct file_lock fl;
156162306a36Sopenharmony_ci	int err;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	locks_init_lock(&fl);
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	fl.fl_type = fl_type;
156662306a36Sopenharmony_ci	fl.fl_flags = FL_POSIX | FL_CLOSE | FL_SLEEP;
156762306a36Sopenharmony_ci	fl.fl_start = start;
156862306a36Sopenharmony_ci	fl.fl_end = start + len - 1;
156962306a36Sopenharmony_ci	fl.fl_owner = filp;
157062306a36Sopenharmony_ci	fl.fl_pid = current->tgid;
157162306a36Sopenharmony_ci	fl.fl_file = filp;
157262306a36Sopenharmony_ci	fl.fl_ops = NULL;
157362306a36Sopenharmony_ci	fl.fl_lmops = NULL;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	err = locks_lock_file_wait(filp, &fl);
157662306a36Sopenharmony_ci	if (err)
157762306a36Sopenharmony_ci		hmdfs_err("lock file wait failed: %d", err);
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	return err;
158062306a36Sopenharmony_ci}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ciint hmdfs_wlock_file(struct file *filp, loff_t start, loff_t len)
158362306a36Sopenharmony_ci{
158462306a36Sopenharmony_ci	return hmdfs_do_lock_file(filp, F_WRLCK, start, len);
158562306a36Sopenharmony_ci}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ciint hmdfs_rlock_file(struct file *filp, loff_t start, loff_t len)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	return hmdfs_do_lock_file(filp, F_RDLCK, start, len);
159062306a36Sopenharmony_ci}
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ciint hmdfs_unlock_file(struct file *filp, loff_t start, loff_t len)
159362306a36Sopenharmony_ci{
159462306a36Sopenharmony_ci	return hmdfs_do_lock_file(filp, F_UNLCK, start, len);
159562306a36Sopenharmony_ci}
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_cilong cache_file_truncate(struct hmdfs_sb_info *sbi, const struct path *path,
159862306a36Sopenharmony_ci			 loff_t length)
159962306a36Sopenharmony_ci{
160062306a36Sopenharmony_ci	const struct cred *old_cred = hmdfs_override_creds(sbi->system_cred);
160162306a36Sopenharmony_ci	long ret = vfs_truncate(path, length);
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	hmdfs_revert_creds(old_cred);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	return ret;
160662306a36Sopenharmony_ci}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_cissize_t cache_file_read(struct hmdfs_sb_info *sbi, struct file *filp, void *buf,
160962306a36Sopenharmony_ci			size_t count, loff_t *pos)
161062306a36Sopenharmony_ci{
161162306a36Sopenharmony_ci	const struct cred *old_cred = hmdfs_override_creds(sbi->system_cred);
161262306a36Sopenharmony_ci	ssize_t ret = kernel_read(filp, buf, count, pos);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	hmdfs_revert_creds(old_cred);
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	return ret;
161762306a36Sopenharmony_ci}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_cissize_t cache_file_write(struct hmdfs_sb_info *sbi, struct file *filp,
162062306a36Sopenharmony_ci			 const void *buf, size_t count, loff_t *pos)
162162306a36Sopenharmony_ci{
162262306a36Sopenharmony_ci	const struct cred *old_cred = hmdfs_override_creds(sbi->system_cred);
162362306a36Sopenharmony_ci	ssize_t ret = kernel_write(filp, buf, count, pos);
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	hmdfs_revert_creds(old_cred);
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	return ret;
162862306a36Sopenharmony_ci}
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ciint read_header(struct hmdfs_sb_info *sbi, struct file *filp,
163262306a36Sopenharmony_ci		struct hmdfs_dcache_header *header)
163362306a36Sopenharmony_ci{
163462306a36Sopenharmony_ci	ssize_t bytes;
163562306a36Sopenharmony_ci	loff_t pos = 0;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	bytes = cache_file_read(sbi, filp, header, sizeof(*header), &pos);
163862306a36Sopenharmony_ci	if (bytes != sizeof(*header)) {
163962306a36Sopenharmony_ci		hmdfs_err("read file failed, err:%zd", bytes);
164062306a36Sopenharmony_ci		return -EIO;
164162306a36Sopenharmony_ci	}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	return 0;
164462306a36Sopenharmony_ci}
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_cistatic unsigned long long cache_get_dentry_count(struct hmdfs_sb_info *sbi,
164762306a36Sopenharmony_ci						 struct file *filp)
164862306a36Sopenharmony_ci{
164962306a36Sopenharmony_ci	struct hmdfs_dcache_header header;
165062306a36Sopenharmony_ci	int overallpage;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	overallpage = get_dentry_group_cnt(file_inode(filp));
165362306a36Sopenharmony_ci	if (overallpage == 0)
165462306a36Sopenharmony_ci		return 0;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	if (read_header(sbi, filp, &header))
165762306a36Sopenharmony_ci		return 0;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	return le64_to_cpu(header.num);
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_cistatic int cache_check_case_sensitive(struct hmdfs_sb_info *sbi,
166362306a36Sopenharmony_ci				struct file *filp)
166462306a36Sopenharmony_ci{
166562306a36Sopenharmony_ci	struct hmdfs_dcache_header header;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	if (read_header(sbi, filp, &header))
166862306a36Sopenharmony_ci		return 0;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	if (sbi->s_case_sensitive != (bool)header.case_sensitive) {
167162306a36Sopenharmony_ci		hmdfs_info("Case sensitive inconsistent, current fs is: %d, cache is %d, will drop cache",
167262306a36Sopenharmony_ci			   sbi->s_case_sensitive, header.case_sensitive);
167362306a36Sopenharmony_ci		return 0;
167462306a36Sopenharmony_ci	}
167562306a36Sopenharmony_ci	return 1;
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ciint write_header(struct file *filp, struct hmdfs_dcache_header *header)
167962306a36Sopenharmony_ci{
168062306a36Sopenharmony_ci	loff_t pos = 0;
168162306a36Sopenharmony_ci	ssize_t size;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	size = kernel_write(filp, header, sizeof(*header), &pos);
168462306a36Sopenharmony_ci	if (size != sizeof(*header)) {
168562306a36Sopenharmony_ci		hmdfs_err("update dcache header failed %zd", size);
168662306a36Sopenharmony_ci		return -EIO;
168762306a36Sopenharmony_ci	}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	return 0;
169062306a36Sopenharmony_ci}
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_civoid add_to_delete_list(struct hmdfs_sb_info *sbi, struct cache_file_node *cfn)
169362306a36Sopenharmony_ci{
169462306a36Sopenharmony_ci	mutex_lock(&sbi->cache_list_lock);
169562306a36Sopenharmony_ci	list_add_tail(&cfn->list, &sbi->to_delete);
169662306a36Sopenharmony_ci	mutex_unlock(&sbi->cache_list_lock);
169762306a36Sopenharmony_ci}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_civoid load_cfn(struct hmdfs_sb_info *sbi, const char *fullname, const char *path,
170062306a36Sopenharmony_ci	      const char *cid, bool server)
170162306a36Sopenharmony_ci{
170262306a36Sopenharmony_ci	struct cache_file_node *cfn = NULL;
170362306a36Sopenharmony_ci	struct cache_file_node *cfn1 = NULL;
170462306a36Sopenharmony_ci	struct list_head *head = NULL;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	cfn = create_cfn(sbi, path, cid, server);
170762306a36Sopenharmony_ci	if (!cfn)
170862306a36Sopenharmony_ci		return;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	cfn->filp = filp_open(fullname, O_RDWR | O_LARGEFILE, 0);
171162306a36Sopenharmony_ci	if (IS_ERR(cfn->filp)) {
171262306a36Sopenharmony_ci		hmdfs_err("open fail %ld", PTR_ERR(cfn->filp));
171362306a36Sopenharmony_ci		goto out;
171462306a36Sopenharmony_ci	}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	if (cache_get_dentry_count(sbi, cfn->filp) < sbi->dcache_threshold && strcmp(cid, CLOUD_CID)) {
171762306a36Sopenharmony_ci		add_to_delete_list(sbi, cfn);
171862306a36Sopenharmony_ci		return;
171962306a36Sopenharmony_ci	}
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	if (!cache_check_case_sensitive(sbi, cfn->filp) && strcmp(cid, CLOUD_CID)) {
172262306a36Sopenharmony_ci		add_to_delete_list(sbi, cfn);
172362306a36Sopenharmony_ci		return;
172462306a36Sopenharmony_ci	}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	head = get_list_head(sbi, server);
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	mutex_lock(&sbi->cache_list_lock);
172962306a36Sopenharmony_ci	cfn1 = __find_cfn(sbi, cid, path, server);
173062306a36Sopenharmony_ci	if (!cfn1) {
173162306a36Sopenharmony_ci		list_add_tail(&cfn->list, head);
173262306a36Sopenharmony_ci	} else {
173362306a36Sopenharmony_ci		release_cfn(cfn1);
173462306a36Sopenharmony_ci		mutex_unlock(&sbi->cache_list_lock);
173562306a36Sopenharmony_ci		add_to_delete_list(sbi, cfn);
173662306a36Sopenharmony_ci		return;
173762306a36Sopenharmony_ci	}
173862306a36Sopenharmony_ci	mutex_unlock(&sbi->cache_list_lock);
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	return;
174162306a36Sopenharmony_ciout:
174262306a36Sopenharmony_ci	free_cfn(cfn);
174362306a36Sopenharmony_ci}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_cistatic int get_cid_and_hash(const char *name, uint64_t *hash, char *cid)
174662306a36Sopenharmony_ci{
174762306a36Sopenharmony_ci	int len;
174862306a36Sopenharmony_ci	char *p = strstr(name, "_");
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	if (!p)
175162306a36Sopenharmony_ci		return -EINVAL;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	len = p - name;
175462306a36Sopenharmony_ci	if (len >= HMDFS_CFN_CID_SIZE)
175562306a36Sopenharmony_ci		return -EINVAL;
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	memcpy(cid, name, len);
175862306a36Sopenharmony_ci	cid[len] = '\0';
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	if (sscanf(++p, "%llx", hash) != 1)
176162306a36Sopenharmony_ci		return -EINVAL;
176262306a36Sopenharmony_ci	return 0;
176362306a36Sopenharmony_ci}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_cistatic void store_one(const char *name, struct cache_file_callback *cb)
176662306a36Sopenharmony_ci{
176762306a36Sopenharmony_ci	struct file *file = NULL;
176862306a36Sopenharmony_ci	char *fullname = NULL;
176962306a36Sopenharmony_ci	char *kvalue = NULL;
177062306a36Sopenharmony_ci	char cid[HMDFS_CFN_CID_SIZE];
177162306a36Sopenharmony_ci	uint64_t hash;
177262306a36Sopenharmony_ci	ssize_t error;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	if (strlen(name) + strlen(cb->dirname) >= PATH_MAX)
177562306a36Sopenharmony_ci		return;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	fullname = kzalloc(PATH_MAX, GFP_KERNEL);
177862306a36Sopenharmony_ci	if (!fullname)
177962306a36Sopenharmony_ci		return;
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	snprintf(fullname, PATH_MAX, "%s%s", cb->dirname, name);
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	file = filp_open(fullname, O_RDWR | O_LARGEFILE, 0);
178462306a36Sopenharmony_ci	if (IS_ERR(file)) {
178562306a36Sopenharmony_ci		hmdfs_err("open fail %ld", PTR_ERR(file));
178662306a36Sopenharmony_ci		goto out;
178762306a36Sopenharmony_ci	}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	kvalue = kzalloc(PATH_MAX, GFP_KERNEL);
179062306a36Sopenharmony_ci	if (!kvalue)
179162306a36Sopenharmony_ci		goto out_file;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	error = __vfs_getxattr(file_dentry(file), file_inode(file),
179462306a36Sopenharmony_ci			       DENTRY_FILE_XATTR_NAME, kvalue, PATH_MAX);
179562306a36Sopenharmony_ci	if (error <= 0 || error >= PATH_MAX) {
179662306a36Sopenharmony_ci		hmdfs_err("getxattr return: %zd", error);
179762306a36Sopenharmony_ci		goto out_kvalue;
179862306a36Sopenharmony_ci	}
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	kvalue[error] = '\0';
180162306a36Sopenharmony_ci	cid[0] = '\0';
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	if (!cb->server) {
180462306a36Sopenharmony_ci		if (get_cid_and_hash(name, &hash, cid)) {
180562306a36Sopenharmony_ci			hmdfs_err("get cid and hash fail");
180662306a36Sopenharmony_ci			goto out_kvalue;
180762306a36Sopenharmony_ci		}
180862306a36Sopenharmony_ci	}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	load_cfn(cb->sbi, fullname, kvalue, cid, cb->server);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ciout_kvalue:
181362306a36Sopenharmony_ci	kfree(kvalue);
181462306a36Sopenharmony_ciout_file:
181562306a36Sopenharmony_ci	filp_close(file, NULL);
181662306a36Sopenharmony_ciout:
181762306a36Sopenharmony_ci	kfree(fullname);
181862306a36Sopenharmony_ci}
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_cistatic bool cache_file_iterate(struct dir_context *ctx, const char *name,
182162306a36Sopenharmony_ci			      int name_len, loff_t offset, u64 ino,
182262306a36Sopenharmony_ci			      unsigned int d_type)
182362306a36Sopenharmony_ci{
182462306a36Sopenharmony_ci	struct cache_file_item *cfi = NULL;
182562306a36Sopenharmony_ci	struct cache_file_callback *cb =
182662306a36Sopenharmony_ci			container_of(ctx, struct cache_file_callback, ctx);
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	if (name_len > NAME_MAX) {
182962306a36Sopenharmony_ci		hmdfs_err("name_len:%d NAME_MAX:%u", name_len, NAME_MAX);
183062306a36Sopenharmony_ci		return true;
183162306a36Sopenharmony_ci	}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	if (d_type != DT_REG)
183462306a36Sopenharmony_ci		return true;
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	cfi = kmalloc(sizeof(*cfi), GFP_KERNEL);
183762306a36Sopenharmony_ci	if (!cfi)
183862306a36Sopenharmony_ci		return false;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	cfi->name = kstrndup(name, name_len, GFP_KERNEL);
184162306a36Sopenharmony_ci	if (!cfi->name) {
184262306a36Sopenharmony_ci		kfree(cfi);
184362306a36Sopenharmony_ci		return false;
184462306a36Sopenharmony_ci	}
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	list_add_tail(&cfi->list, &cb->list);
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	return true;
184962306a36Sopenharmony_ci}
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_civoid hmdfs_do_load(struct hmdfs_sb_info *sbi, const char *fullname, bool server)
185262306a36Sopenharmony_ci{
185362306a36Sopenharmony_ci	struct file *file = NULL;
185462306a36Sopenharmony_ci	struct path dirpath;
185562306a36Sopenharmony_ci	int err;
185662306a36Sopenharmony_ci	struct cache_file_item *cfi = NULL;
185762306a36Sopenharmony_ci	struct cache_file_item *n = NULL;
185862306a36Sopenharmony_ci	struct cache_file_callback cb = {
185962306a36Sopenharmony_ci		.ctx.actor = cache_file_iterate,
186062306a36Sopenharmony_ci		.ctx.pos = 0,
186162306a36Sopenharmony_ci		.dirname = fullname,
186262306a36Sopenharmony_ci		.sbi = sbi,
186362306a36Sopenharmony_ci		.server = server,
186462306a36Sopenharmony_ci	};
186562306a36Sopenharmony_ci	INIT_LIST_HEAD(&cb.list);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	err = kern_path(fullname, LOOKUP_DIRECTORY, &dirpath);
186962306a36Sopenharmony_ci	if (err) {
187062306a36Sopenharmony_ci		hmdfs_info("No file path");
187162306a36Sopenharmony_ci		return;
187262306a36Sopenharmony_ci	}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	file = dentry_open(&dirpath, O_RDONLY, current_cred());
187562306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(file)) {
187662306a36Sopenharmony_ci		hmdfs_err("dentry_open failed, error: %ld", PTR_ERR(file));
187762306a36Sopenharmony_ci		path_put(&dirpath);
187862306a36Sopenharmony_ci		return;
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	err = iterate_dir(file, &cb.ctx);
188262306a36Sopenharmony_ci	if (err)
188362306a36Sopenharmony_ci		hmdfs_err("iterate_dir failed, err: %d", err);
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	list_for_each_entry_safe(cfi, n, &cb.list, list) {
188662306a36Sopenharmony_ci		store_one(cfi->name, &cb);
188762306a36Sopenharmony_ci		list_del_init(&cfi->list);
188862306a36Sopenharmony_ci		kfree(cfi->name);
188962306a36Sopenharmony_ci		kfree(cfi);
189062306a36Sopenharmony_ci	}
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	fput(file);
189362306a36Sopenharmony_ci	path_put(&dirpath);
189462306a36Sopenharmony_ci}
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci/**
189762306a36Sopenharmony_ci * This function just used for delete dentryfile.dat
189862306a36Sopenharmony_ci */
189962306a36Sopenharmony_ciint delete_dentry_file(struct file *filp)
190062306a36Sopenharmony_ci{
190162306a36Sopenharmony_ci	int err = 0;
190262306a36Sopenharmony_ci	struct dentry *dentry = file_dentry(filp);
190362306a36Sopenharmony_ci	struct dentry *parent = lock_parent(dentry);
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	if (dentry->d_parent == parent) {
190662306a36Sopenharmony_ci		dget(dentry);
190762306a36Sopenharmony_ci		err = vfs_unlink(&nop_mnt_idmap, d_inode(parent), dentry, NULL);
190862306a36Sopenharmony_ci		dput(dentry);
190962306a36Sopenharmony_ci	}
191062306a36Sopenharmony_ci	unlock_dir(parent);
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	return err;
191362306a36Sopenharmony_ci}
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_civoid hmdfs_delete_useless_cfn(struct hmdfs_sb_info *sbi)
191662306a36Sopenharmony_ci{
191762306a36Sopenharmony_ci	struct cache_file_node *cfn = NULL;
191862306a36Sopenharmony_ci	struct cache_file_node *n = NULL;
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	mutex_lock(&sbi->cache_list_lock);
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	list_for_each_entry_safe(cfn, n, &sbi->to_delete, list) {
192362306a36Sopenharmony_ci		delete_dentry_file(cfn->filp);
192462306a36Sopenharmony_ci		list_del_init(&cfn->list);
192562306a36Sopenharmony_ci		release_cfn(cfn);
192662306a36Sopenharmony_ci	}
192762306a36Sopenharmony_ci	mutex_unlock(&sbi->cache_list_lock);
192862306a36Sopenharmony_ci}
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_civoid hmdfs_cfn_load(struct hmdfs_sb_info *sbi)
193162306a36Sopenharmony_ci{
193262306a36Sopenharmony_ci	char *fullname = NULL;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	if (!sbi->s_dentry_cache)
193562306a36Sopenharmony_ci		return;
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	fullname = kzalloc(PATH_MAX, GFP_KERNEL);
193862306a36Sopenharmony_ci	if (!fullname)
193962306a36Sopenharmony_ci		return;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	snprintf(fullname, PATH_MAX, "%s/dentry_cache/client/",
194262306a36Sopenharmony_ci		 sbi->cache_dir);
194362306a36Sopenharmony_ci	hmdfs_do_load(sbi, fullname, false);
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	snprintf(fullname, PATH_MAX, "%s/dentry_cache/server/",
194662306a36Sopenharmony_ci		 sbi->cache_dir);
194762306a36Sopenharmony_ci	hmdfs_do_load(sbi, fullname, true);
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	kfree(fullname);
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	hmdfs_delete_useless_cfn(sbi);
195262306a36Sopenharmony_ci}
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_cistatic void __cache_file_destroy_by_path(struct list_head *head,
195562306a36Sopenharmony_ci					 const char *path)
195662306a36Sopenharmony_ci{
195762306a36Sopenharmony_ci	struct cache_file_node *cfn = NULL;
195862306a36Sopenharmony_ci	struct cache_file_node *n = NULL;
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	list_for_each_entry_safe(cfn, n, head, list) {
196162306a36Sopenharmony_ci		if (strcmp(path, cfn->relative_path) != 0)
196262306a36Sopenharmony_ci			continue;
196362306a36Sopenharmony_ci		list_del_init(&cfn->list);
196462306a36Sopenharmony_ci		delete_dentry_file(cfn->filp);
196562306a36Sopenharmony_ci		release_cfn(cfn);
196662306a36Sopenharmony_ci	}
196762306a36Sopenharmony_ci}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_cistatic void cache_file_destroy_by_path(struct hmdfs_sb_info *sbi,
197062306a36Sopenharmony_ci				       const char *path)
197162306a36Sopenharmony_ci{
197262306a36Sopenharmony_ci	mutex_lock(&sbi->cache_list_lock);
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	__cache_file_destroy_by_path(&sbi->server_cache, path);
197562306a36Sopenharmony_ci	__cache_file_destroy_by_path(&sbi->client_cache, path);
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	mutex_unlock(&sbi->cache_list_lock);
197862306a36Sopenharmony_ci}
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_cistatic void cache_file_find_and_delete(struct hmdfs_peer *con,
198162306a36Sopenharmony_ci				       const char *relative_path)
198262306a36Sopenharmony_ci{
198362306a36Sopenharmony_ci	struct cache_file_node *cfn;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	cfn = find_cfn(con->sbi, con->cid, relative_path, false);
198662306a36Sopenharmony_ci	if (!cfn)
198762306a36Sopenharmony_ci		return;
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci	remove_cfn(cfn);
199062306a36Sopenharmony_ci	release_cfn(cfn);
199162306a36Sopenharmony_ci}
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_civoid cache_file_delete_by_dentry(struct hmdfs_peer *con, struct dentry *dentry)
199462306a36Sopenharmony_ci{
199562306a36Sopenharmony_ci	char *relative_path = NULL;
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	relative_path = hmdfs_get_dentry_relative_path(dentry);
199862306a36Sopenharmony_ci	if (unlikely(!relative_path)) {
199962306a36Sopenharmony_ci		hmdfs_err("get relative path failed %d", -ENOMEM);
200062306a36Sopenharmony_ci		return;
200162306a36Sopenharmony_ci	}
200262306a36Sopenharmony_ci	cache_file_find_and_delete(con, relative_path);
200362306a36Sopenharmony_ci	kfree(relative_path);
200462306a36Sopenharmony_ci}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_cistruct file *hmdfs_get_new_dentry_file(struct hmdfs_peer *con,
200762306a36Sopenharmony_ci				       const char *relative_path,
200862306a36Sopenharmony_ci				       struct hmdfs_dcache_header *header)
200962306a36Sopenharmony_ci{
201062306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = con->sbi;
201162306a36Sopenharmony_ci	int len = strlen(relative_path);
201262306a36Sopenharmony_ci	struct file *filp = NULL;
201362306a36Sopenharmony_ci	int err;
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	filp = create_local_dentry_file_cache(sbi);
201662306a36Sopenharmony_ci	if (IS_ERR(filp))
201762306a36Sopenharmony_ci		return filp;
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	err = hmdfs_client_start_readdir(con, filp, relative_path, len, header);
202062306a36Sopenharmony_ci	if (err) {
202162306a36Sopenharmony_ci		if (err != -ENOENT)
202262306a36Sopenharmony_ci			hmdfs_err("readdir failed dev: %llu err: %d",
202362306a36Sopenharmony_ci				  con->device_id, err);
202462306a36Sopenharmony_ci		fput(filp);
202562306a36Sopenharmony_ci		filp = ERR_PTR(err);
202662306a36Sopenharmony_ci	}
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	return filp;
202962306a36Sopenharmony_ci}
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_civoid add_cfn_to_item(struct dentry *dentry, struct hmdfs_peer *con,
203262306a36Sopenharmony_ci		     struct cache_file_node *cfn)
203362306a36Sopenharmony_ci{
203462306a36Sopenharmony_ci	struct file *file = cfn->filp;
203562306a36Sopenharmony_ci	int err;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	err = hmdfs_add_cache_list(con->device_id, dentry, file);
203862306a36Sopenharmony_ci	if (unlikely(err)) {
203962306a36Sopenharmony_ci		hmdfs_err("add cache list failed devid:%llu err:%d",
204062306a36Sopenharmony_ci			  con->device_id, err);
204162306a36Sopenharmony_ci		return;
204262306a36Sopenharmony_ci	}
204362306a36Sopenharmony_ci}
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ciint hmdfs_add_file_to_cache(struct dentry *dentry, struct hmdfs_peer *con,
204662306a36Sopenharmony_ci			    struct file *file, const char *relative_path)
204762306a36Sopenharmony_ci{
204862306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = con->sbi;
204962306a36Sopenharmony_ci	struct file *newf = file;
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	if (cache_get_dentry_count(sbi, file) >= sbi->dcache_threshold)
205262306a36Sopenharmony_ci		newf = cache_file_persistent(con, file, relative_path, false);
205362306a36Sopenharmony_ci	else
205462306a36Sopenharmony_ci		cache_file_find_and_delete(con, relative_path);
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	return hmdfs_add_cache_list(con->device_id, dentry, newf);
205762306a36Sopenharmony_ci}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_cistatic struct file *read_header_and_revalidate(struct hmdfs_peer *con,
206062306a36Sopenharmony_ci					       struct file *filp,
206162306a36Sopenharmony_ci					       const char *relative_path)
206262306a36Sopenharmony_ci{
206362306a36Sopenharmony_ci	struct hmdfs_dcache_header header;
206462306a36Sopenharmony_ci	struct hmdfs_dcache_header *p = NULL;
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	if (read_header(con->sbi, filp, &header) == 0)
206762306a36Sopenharmony_ci		p = &header;
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	return hmdfs_get_new_dentry_file(con, relative_path, p);
207062306a36Sopenharmony_ci}
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_civoid remote_file_revalidate_cfn(struct dentry *dentry, struct hmdfs_peer *con,
207362306a36Sopenharmony_ci				struct cache_file_node *cfn,
207462306a36Sopenharmony_ci				const char *relative_path)
207562306a36Sopenharmony_ci{
207662306a36Sopenharmony_ci	struct file *file = NULL;
207762306a36Sopenharmony_ci	int err;
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	file = read_header_and_revalidate(con, cfn->filp, relative_path);
208062306a36Sopenharmony_ci	if (IS_ERR(file))
208162306a36Sopenharmony_ci		return;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	/*
208462306a36Sopenharmony_ci	 * If the request returned ok but file length is 0, we assume
208562306a36Sopenharmony_ci	 * that the server verified the client cache file is uptodate.
208662306a36Sopenharmony_ci	 */
208762306a36Sopenharmony_ci	if (i_size_read(file->f_inode) == 0) {
208862306a36Sopenharmony_ci		hmdfs_info("The cfn cache for dev:%llu is uptodate",
208962306a36Sopenharmony_ci			    con->device_id);
209062306a36Sopenharmony_ci		fput(file);
209162306a36Sopenharmony_ci		add_cfn_to_item(dentry, con, cfn);
209262306a36Sopenharmony_ci		return;
209362306a36Sopenharmony_ci	}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	/* OK, cfn is not uptodate, let's remove it and add the new file */
209662306a36Sopenharmony_ci	remove_cfn(cfn);
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	err = hmdfs_add_file_to_cache(dentry, con, file, relative_path);
209962306a36Sopenharmony_ci	if (unlikely(err))
210062306a36Sopenharmony_ci		hmdfs_err("add cache list failed devid:%llu err:%d",
210162306a36Sopenharmony_ci			  con->device_id, err);
210262306a36Sopenharmony_ci	fput(file);
210362306a36Sopenharmony_ci}
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_civoid remote_file_revalidate_item(struct dentry *dentry, struct hmdfs_peer *con,
210662306a36Sopenharmony_ci				 struct clearcache_item *item,
210762306a36Sopenharmony_ci				 const char *relative_path)
210862306a36Sopenharmony_ci{
210962306a36Sopenharmony_ci	struct file *file = NULL;
211062306a36Sopenharmony_ci	int err;
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	file = read_header_and_revalidate(con, item->filp, relative_path);
211362306a36Sopenharmony_ci	if (IS_ERR(file))
211462306a36Sopenharmony_ci		return;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	/*
211762306a36Sopenharmony_ci	 * If the request returned ok but file length is 0, we assume
211862306a36Sopenharmony_ci	 * that the server verified the client cache file is uptodate.
211962306a36Sopenharmony_ci	 */
212062306a36Sopenharmony_ci	if (i_size_read(file->f_inode) == 0) {
212162306a36Sopenharmony_ci		hmdfs_info("The item cache for dev:%llu is uptodate",
212262306a36Sopenharmony_ci			    con->device_id);
212362306a36Sopenharmony_ci		item->time = jiffies;
212462306a36Sopenharmony_ci		fput(file);
212562306a36Sopenharmony_ci		return;
212662306a36Sopenharmony_ci	}
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	/* We need to replace the old item */
212962306a36Sopenharmony_ci	remove_cache_item(item);
213062306a36Sopenharmony_ci	cache_file_find_and_delete(con, relative_path);
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	err = hmdfs_add_file_to_cache(dentry, con, file, relative_path);
213362306a36Sopenharmony_ci	if (unlikely(err))
213462306a36Sopenharmony_ci		hmdfs_err("add cache list failed devid:%llu err:%d",
213562306a36Sopenharmony_ci			  con->device_id, err);
213662306a36Sopenharmony_ci	fput(file);
213762306a36Sopenharmony_ci}
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_cibool get_remote_dentry_file(struct dentry *dentry, struct hmdfs_peer *con)
214062306a36Sopenharmony_ci{
214162306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = hmdfs_d(dentry);
214262306a36Sopenharmony_ci	struct cache_file_node *cfn = NULL;
214362306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = con->sbi;
214462306a36Sopenharmony_ci	char *relative_path = NULL;
214562306a36Sopenharmony_ci	int err = 0;
214662306a36Sopenharmony_ci	struct file *filp = NULL;
214762306a36Sopenharmony_ci	struct clearcache_item *item;
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	if (hmdfs_cache_revalidate(READ_ONCE(con->conn_time), con->device_id,
215062306a36Sopenharmony_ci				   dentry))
215162306a36Sopenharmony_ci		return false;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	relative_path = hmdfs_get_dentry_relative_path(dentry);
215462306a36Sopenharmony_ci	if (unlikely(!relative_path)) {
215562306a36Sopenharmony_ci		hmdfs_err("get relative path failed %d", -ENOMEM);
215662306a36Sopenharmony_ci		return false;
215762306a36Sopenharmony_ci	}
215862306a36Sopenharmony_ci	mutex_lock(&d_info->cache_pull_lock);
215962306a36Sopenharmony_ci	if (hmdfs_cache_revalidate(READ_ONCE(con->conn_time), con->device_id,
216062306a36Sopenharmony_ci				   dentry))
216162306a36Sopenharmony_ci		goto out_unlock;
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci	item = hmdfs_find_cache_item(con->device_id, dentry);
216462306a36Sopenharmony_ci	if (item) {
216562306a36Sopenharmony_ci		remote_file_revalidate_item(dentry, con, item, relative_path);
216662306a36Sopenharmony_ci		kref_put(&item->ref, release_cache_item);
216762306a36Sopenharmony_ci		goto out_unlock;
216862306a36Sopenharmony_ci	}
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	cfn = find_cfn(sbi, con->cid, relative_path, false);
217162306a36Sopenharmony_ci	if (cfn) {
217262306a36Sopenharmony_ci		remote_file_revalidate_cfn(dentry, con, cfn, relative_path);
217362306a36Sopenharmony_ci		release_cfn(cfn);
217462306a36Sopenharmony_ci		goto out_unlock;
217562306a36Sopenharmony_ci	}
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	filp = hmdfs_get_new_dentry_file(con, relative_path, NULL);
217862306a36Sopenharmony_ci	if (IS_ERR(filp)) {
217962306a36Sopenharmony_ci		err = PTR_ERR(filp);
218062306a36Sopenharmony_ci		goto out_unlock;
218162306a36Sopenharmony_ci	}
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	err = hmdfs_add_file_to_cache(dentry, con, filp, relative_path);
218462306a36Sopenharmony_ci	if (unlikely(err))
218562306a36Sopenharmony_ci		hmdfs_err("add cache list failed devid:%lu err:%d",
218662306a36Sopenharmony_ci			  (unsigned long)con->device_id, err);
218762306a36Sopenharmony_ci	fput(filp);
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ciout_unlock:
219062306a36Sopenharmony_ci	mutex_unlock(&d_info->cache_pull_lock);
219162306a36Sopenharmony_ci	if (err && err != -ENOENT)
219262306a36Sopenharmony_ci		hmdfs_err("readdir failed dev:%lu err:%d",
219362306a36Sopenharmony_ci			  (unsigned long)con->device_id, err);
219462306a36Sopenharmony_ci	kfree(relative_path);
219562306a36Sopenharmony_ci	return true;
219662306a36Sopenharmony_ci}
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ciint hmdfs_file_type(const char *name)
219962306a36Sopenharmony_ci{
220062306a36Sopenharmony_ci	if (!name)
220162306a36Sopenharmony_ci		return -EINVAL;
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	if (!strcmp(name, CURRENT_DIR) || !strcmp(name, PARENT_DIR))
220462306a36Sopenharmony_ci		return HMDFS_TYPE_DOT;
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	return HMDFS_TYPE_COMMON;
220762306a36Sopenharmony_ci}
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_cistruct clearcache_item *hmdfs_find_cache_item(uint64_t dev_id,
221062306a36Sopenharmony_ci					      struct dentry *dentry)
221162306a36Sopenharmony_ci{
221262306a36Sopenharmony_ci	struct clearcache_item *item = NULL;
221362306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = hmdfs_d(dentry);
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	if (!d_info)
221662306a36Sopenharmony_ci		return NULL;
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	spin_lock(&d_info->cache_list_lock);
221962306a36Sopenharmony_ci	list_for_each_entry(item, &(d_info->cache_list_head), list) {
222062306a36Sopenharmony_ci		if (dev_id == item->dev_id) {
222162306a36Sopenharmony_ci			kref_get(&item->ref);
222262306a36Sopenharmony_ci			spin_unlock(&d_info->cache_list_lock);
222362306a36Sopenharmony_ci			return item;
222462306a36Sopenharmony_ci		}
222562306a36Sopenharmony_ci	}
222662306a36Sopenharmony_ci	spin_unlock(&d_info->cache_list_lock);
222762306a36Sopenharmony_ci	return NULL;
222862306a36Sopenharmony_ci}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_cibool hmdfs_cache_revalidate(unsigned long conn_time, uint64_t dev_id,
223162306a36Sopenharmony_ci			    struct dentry *dentry)
223262306a36Sopenharmony_ci{
223362306a36Sopenharmony_ci	bool ret = false;
223462306a36Sopenharmony_ci	struct clearcache_item *item = NULL;
223562306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = hmdfs_d(dentry);
223662306a36Sopenharmony_ci	unsigned int timeout;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	if (!d_info)
223962306a36Sopenharmony_ci		return ret;
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	timeout = hmdfs_sb(dentry->d_sb)->dcache_timeout;
224262306a36Sopenharmony_ci	spin_lock(&d_info->cache_list_lock);
224362306a36Sopenharmony_ci	list_for_each_entry(item, &(d_info->cache_list_head), list) {
224462306a36Sopenharmony_ci		if (dev_id == item->dev_id) {
224562306a36Sopenharmony_ci			ret = cache_item_revalidate(conn_time, item->time,
224662306a36Sopenharmony_ci						    timeout);
224762306a36Sopenharmony_ci			break;
224862306a36Sopenharmony_ci		}
224962306a36Sopenharmony_ci	}
225062306a36Sopenharmony_ci	spin_unlock(&d_info->cache_list_lock);
225162306a36Sopenharmony_ci	return ret;
225262306a36Sopenharmony_ci}
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_civoid remove_cache_item(struct clearcache_item *item)
225562306a36Sopenharmony_ci{
225662306a36Sopenharmony_ci	bool deleted;
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	spin_lock(&item->d_info->cache_list_lock);
225962306a36Sopenharmony_ci	deleted = list_empty(&item->list);
226062306a36Sopenharmony_ci	if (!deleted)
226162306a36Sopenharmony_ci		list_del_init(&item->list);
226262306a36Sopenharmony_ci	spin_unlock(&item->d_info->cache_list_lock);
226362306a36Sopenharmony_ci	if (!deleted)
226462306a36Sopenharmony_ci		kref_put(&item->ref, release_cache_item);
226562306a36Sopenharmony_ci}
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_civoid release_cache_item(struct kref *ref)
226862306a36Sopenharmony_ci{
226962306a36Sopenharmony_ci	struct clearcache_item *item =
227062306a36Sopenharmony_ci		container_of(ref, struct clearcache_item, ref);
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	if (item->filp)
227362306a36Sopenharmony_ci		fput(item->filp);
227462306a36Sopenharmony_ci	kfree(item);
227562306a36Sopenharmony_ci}
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_civoid hmdfs_remove_cache_filp(struct hmdfs_peer *con, struct dentry *dentry)
227862306a36Sopenharmony_ci{
227962306a36Sopenharmony_ci	struct clearcache_item *item = NULL;
228062306a36Sopenharmony_ci	struct clearcache_item *item_temp = NULL;
228162306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = hmdfs_d(dentry);
228262306a36Sopenharmony_ci	//	struct path *lower_path = NULL;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	if (!d_info)
228562306a36Sopenharmony_ci		return;
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci	spin_lock(&d_info->cache_list_lock);
228862306a36Sopenharmony_ci	list_for_each_entry_safe(item, item_temp, &(d_info->cache_list_head),
228962306a36Sopenharmony_ci				  list) {
229062306a36Sopenharmony_ci		if (con->device_id == item->dev_id) {
229162306a36Sopenharmony_ci			list_del_init(&item->list);
229262306a36Sopenharmony_ci			spin_unlock(&d_info->cache_list_lock);
229362306a36Sopenharmony_ci			cache_file_delete_by_dentry(con, dentry);
229462306a36Sopenharmony_ci			kref_put(&item->ref, release_cache_item);
229562306a36Sopenharmony_ci			return;
229662306a36Sopenharmony_ci		}
229762306a36Sopenharmony_ci	}
229862306a36Sopenharmony_ci	spin_unlock(&d_info->cache_list_lock);
229962306a36Sopenharmony_ci}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ciint hmdfs_add_cache_list(uint64_t dev_id, struct dentry *dentry,
230262306a36Sopenharmony_ci			 struct file *filp)
230362306a36Sopenharmony_ci{
230462306a36Sopenharmony_ci	struct clearcache_item *item = NULL;
230562306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = hmdfs_d(dentry);
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci	if (!d_info)
230862306a36Sopenharmony_ci		return -ENOMEM;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	item = kzalloc(sizeof(*item), GFP_KERNEL);
231162306a36Sopenharmony_ci	if (!item)
231262306a36Sopenharmony_ci		return -ENOMEM;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	item->dev_id = dev_id;
231562306a36Sopenharmony_ci	item->filp = get_file(filp);
231662306a36Sopenharmony_ci	item->time = jiffies;
231762306a36Sopenharmony_ci	item->d_info = d_info;
231862306a36Sopenharmony_ci	kref_init(&item->ref);
231962306a36Sopenharmony_ci	spin_lock(&d_info->cache_list_lock);
232062306a36Sopenharmony_ci	list_add_tail(&(item->list), &(d_info->cache_list_head));
232162306a36Sopenharmony_ci	spin_unlock(&d_info->cache_list_lock);
232262306a36Sopenharmony_ci	return 0;
232362306a36Sopenharmony_ci}
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_civoid hmdfs_add_remote_cache_list(struct hmdfs_peer *con, const char *dir_path)
232662306a36Sopenharmony_ci{
232762306a36Sopenharmony_ci	int err = 0;
232862306a36Sopenharmony_ci	struct remotecache_item *item = NULL;
232962306a36Sopenharmony_ci	struct remotecache_item *item_temp = NULL;
233062306a36Sopenharmony_ci	struct path path, root_path;
233162306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = NULL;
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	err = kern_path(con->sbi->local_dst, 0, &root_path);
233462306a36Sopenharmony_ci	if (err) {
233562306a36Sopenharmony_ci		hmdfs_err("kern_path failed err = %d", err);
233662306a36Sopenharmony_ci		return;
233762306a36Sopenharmony_ci	}
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	err = vfs_path_lookup(root_path.dentry, root_path.mnt, dir_path, 0,
234062306a36Sopenharmony_ci			      &path);
234162306a36Sopenharmony_ci	if (err)
234262306a36Sopenharmony_ci		goto out_put_root;
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	d_info = hmdfs_d(path.dentry);
234562306a36Sopenharmony_ci	if (!d_info) {
234662306a36Sopenharmony_ci		err = -EINVAL;
234762306a36Sopenharmony_ci		goto out;
234862306a36Sopenharmony_ci	}
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	/* find duplicate con */
235162306a36Sopenharmony_ci	mutex_lock(&d_info->remote_cache_list_lock);
235262306a36Sopenharmony_ci	list_for_each_entry_safe(item, item_temp,
235362306a36Sopenharmony_ci				  &(d_info->remote_cache_list_head), list) {
235462306a36Sopenharmony_ci		if (item->con->device_id == con->device_id) {
235562306a36Sopenharmony_ci			mutex_unlock(&d_info->remote_cache_list_lock);
235662306a36Sopenharmony_ci			goto out;
235762306a36Sopenharmony_ci		}
235862306a36Sopenharmony_ci	}
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	item = kzalloc(sizeof(*item), GFP_KERNEL);
236162306a36Sopenharmony_ci	if (!item) {
236262306a36Sopenharmony_ci		err = -ENOMEM;
236362306a36Sopenharmony_ci		mutex_unlock(&d_info->remote_cache_list_lock);
236462306a36Sopenharmony_ci		goto out;
236562306a36Sopenharmony_ci	}
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	item->con = con;
236862306a36Sopenharmony_ci	item->drop_flag = 0;
236962306a36Sopenharmony_ci	list_add(&(item->list), &(d_info->remote_cache_list_head));
237062306a36Sopenharmony_ci	mutex_unlock(&d_info->remote_cache_list_lock);
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ciout:
237362306a36Sopenharmony_ci	path_put(&path);
237462306a36Sopenharmony_ciout_put_root:
237562306a36Sopenharmony_ci	path_put(&root_path);
237662306a36Sopenharmony_ci}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ciint hmdfs_drop_remote_cache_dents(struct dentry *dentry)
237962306a36Sopenharmony_ci{
238062306a36Sopenharmony_ci	struct path lower_path;
238162306a36Sopenharmony_ci	struct inode *lower_inode = NULL;
238262306a36Sopenharmony_ci	struct remotecache_item *item = NULL;
238362306a36Sopenharmony_ci	struct remotecache_item *item_temp = NULL;
238462306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = NULL;
238562306a36Sopenharmony_ci	char *relative_path = NULL;
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	if (!dentry) {
238862306a36Sopenharmony_ci		hmdfs_err("dentry null and return");
238962306a36Sopenharmony_ci		return 0;
239062306a36Sopenharmony_ci	}
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	d_info = hmdfs_d(dentry);
239362306a36Sopenharmony_ci	if (!d_info) {
239462306a36Sopenharmony_ci		hmdfs_err("d_info null and return");
239562306a36Sopenharmony_ci		return 0;
239662306a36Sopenharmony_ci	}
239762306a36Sopenharmony_ci	hmdfs_get_lower_path(dentry, &lower_path);
239862306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(lower_path.dentry)) {
239962306a36Sopenharmony_ci		hmdfs_put_lower_path(&lower_path);
240062306a36Sopenharmony_ci		return 0;
240162306a36Sopenharmony_ci	}
240262306a36Sopenharmony_ci	lower_inode = d_inode(lower_path.dentry);
240362306a36Sopenharmony_ci	hmdfs_put_lower_path(&lower_path);
240462306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(lower_inode))
240562306a36Sopenharmony_ci		return 0;
240662306a36Sopenharmony_ci	/* only for directory */
240762306a36Sopenharmony_ci	if (!S_ISDIR(lower_inode->i_mode))
240862306a36Sopenharmony_ci		return 0;
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	relative_path = hmdfs_get_dentry_relative_path(dentry);
241162306a36Sopenharmony_ci	if (!relative_path) {
241262306a36Sopenharmony_ci		hmdfs_err("get dentry relative path failed");
241362306a36Sopenharmony_ci		return 0;
241462306a36Sopenharmony_ci	}
241562306a36Sopenharmony_ci	mutex_lock(&d_info->remote_cache_list_lock);
241662306a36Sopenharmony_ci	list_for_each_entry_safe(item, item_temp,
241762306a36Sopenharmony_ci				  &(d_info->remote_cache_list_head), list) {
241862306a36Sopenharmony_ci		if (item->drop_flag) {
241962306a36Sopenharmony_ci			item->drop_flag = 0;
242062306a36Sopenharmony_ci			continue;
242162306a36Sopenharmony_ci		}
242262306a36Sopenharmony_ci		mutex_unlock(&d_info->remote_cache_list_lock);
242362306a36Sopenharmony_ci		hmdfs_send_drop_push(item->con, relative_path);
242462306a36Sopenharmony_ci		mutex_lock(&d_info->remote_cache_list_lock);
242562306a36Sopenharmony_ci		list_del(&item->list);
242662306a36Sopenharmony_ci		kfree(item);
242762306a36Sopenharmony_ci	}
242862306a36Sopenharmony_ci	mutex_unlock(&d_info->remote_cache_list_lock);
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	kfree(relative_path);
243162306a36Sopenharmony_ci	return 0;
243262306a36Sopenharmony_ci}
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci/* Clear the dentry cache files of target directory */
243562306a36Sopenharmony_ciint hmdfs_clear_cache_dents(struct dentry *dentry, bool remove_cache)
243662306a36Sopenharmony_ci{
243762306a36Sopenharmony_ci	struct clearcache_item *item = NULL;
243862306a36Sopenharmony_ci	struct clearcache_item *item_temp = NULL;
243962306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = hmdfs_d(dentry);
244062306a36Sopenharmony_ci	char *path = NULL;
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	if (!d_info)
244362306a36Sopenharmony_ci		return 0;
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci	spin_lock(&d_info->cache_list_lock);
244662306a36Sopenharmony_ci	list_for_each_entry_safe(item, item_temp, &(d_info->cache_list_head),
244762306a36Sopenharmony_ci				  list) {
244862306a36Sopenharmony_ci		list_del_init(&item->list);
244962306a36Sopenharmony_ci		kref_put(&item->ref, release_cache_item);
245062306a36Sopenharmony_ci	}
245162306a36Sopenharmony_ci	spin_unlock(&d_info->cache_list_lock);
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	if (!remove_cache)
245462306a36Sopenharmony_ci		return 0;
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	/* it also need confirm that there are no dentryfile_dev*
245762306a36Sopenharmony_ci	 * under this dentry
245862306a36Sopenharmony_ci	 */
245962306a36Sopenharmony_ci	path = hmdfs_get_dentry_relative_path(dentry);
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	if (unlikely(!path)) {
246262306a36Sopenharmony_ci		hmdfs_err("get relative path failed");
246362306a36Sopenharmony_ci		return 0;
246462306a36Sopenharmony_ci	}
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci	cache_file_destroy_by_path(hmdfs_sb(dentry->d_sb), path);
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	kfree(path);
246962306a36Sopenharmony_ci	return 0;
247062306a36Sopenharmony_ci}
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_civoid hmdfs_mark_drop_flag(uint64_t device_id, struct dentry *dentry)
247362306a36Sopenharmony_ci{
247462306a36Sopenharmony_ci	struct remotecache_item *item = NULL;
247562306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = NULL;
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	d_info = hmdfs_d(dentry);
247862306a36Sopenharmony_ci	if (!d_info) {
247962306a36Sopenharmony_ci		hmdfs_err("d_info null and return");
248062306a36Sopenharmony_ci		return;
248162306a36Sopenharmony_ci	}
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	mutex_lock(&d_info->remote_cache_list_lock);
248462306a36Sopenharmony_ci	list_for_each_entry(item, &(d_info->remote_cache_list_head), list) {
248562306a36Sopenharmony_ci		if (item->con->device_id == device_id) {
248662306a36Sopenharmony_ci			item->drop_flag = 1;
248762306a36Sopenharmony_ci			break;
248862306a36Sopenharmony_ci		}
248962306a36Sopenharmony_ci	}
249062306a36Sopenharmony_ci	mutex_unlock(&d_info->remote_cache_list_lock);
249162306a36Sopenharmony_ci}
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_civoid hmdfs_clear_drop_flag(struct dentry *dentry)
249462306a36Sopenharmony_ci{
249562306a36Sopenharmony_ci	struct remotecache_item *item = NULL;
249662306a36Sopenharmony_ci	struct hmdfs_dentry_info *d_info = NULL;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	if (!dentry) {
249962306a36Sopenharmony_ci		hmdfs_err("dentry null and return");
250062306a36Sopenharmony_ci		return;
250162306a36Sopenharmony_ci	}
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_ci	d_info = hmdfs_d(dentry);
250462306a36Sopenharmony_ci	if (!d_info) {
250562306a36Sopenharmony_ci		hmdfs_err("d_info null and return");
250662306a36Sopenharmony_ci		return;
250762306a36Sopenharmony_ci	}
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	mutex_lock(&d_info->remote_cache_list_lock);
251062306a36Sopenharmony_ci	list_for_each_entry(item, &(d_info->remote_cache_list_head), list) {
251162306a36Sopenharmony_ci		if (item->drop_flag)
251262306a36Sopenharmony_ci			item->drop_flag = 0;
251362306a36Sopenharmony_ci	}
251462306a36Sopenharmony_ci	mutex_unlock(&d_info->remote_cache_list_lock);
251562306a36Sopenharmony_ci}
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci#define DUSTBIN_SUFFIX ".hwbk"
251862306a36Sopenharmony_cistatic void hmdfs_rename_bak(struct dentry *dentry)
251962306a36Sopenharmony_ci{
252062306a36Sopenharmony_ci	struct path lower_path;
252162306a36Sopenharmony_ci	struct dentry *lower_parent = NULL;
252262306a36Sopenharmony_ci	struct dentry *lower_dentry = NULL;
252362306a36Sopenharmony_ci	struct dentry *new_dentry = NULL;
252462306a36Sopenharmony_ci	struct renamedata rename_data;
252562306a36Sopenharmony_ci	char *name = NULL;
252662306a36Sopenharmony_ci	int len = 0;
252762306a36Sopenharmony_ci	int err = 0;
252862306a36Sopenharmony_ci
252962306a36Sopenharmony_ci	hmdfs_get_lower_path(dentry, &lower_path);
253062306a36Sopenharmony_ci	lower_dentry = lower_path.dentry;
253162306a36Sopenharmony_ci	len = strlen(lower_dentry->d_name.name) + strlen(DUSTBIN_SUFFIX) + 2;
253262306a36Sopenharmony_ci	if (len >= NAME_MAX) {
253362306a36Sopenharmony_ci		err = -ENAMETOOLONG;
253462306a36Sopenharmony_ci		goto put_lower_path;
253562306a36Sopenharmony_ci	}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	name = kmalloc(len, GFP_KERNEL);
253862306a36Sopenharmony_ci	if (!name) {
253962306a36Sopenharmony_ci		err = -ENOMEM;
254062306a36Sopenharmony_ci		goto put_lower_path;
254162306a36Sopenharmony_ci	}
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci	snprintf(name, len, ".%s%s", lower_dentry->d_name.name, DUSTBIN_SUFFIX);
254462306a36Sopenharmony_ci	err = mnt_want_write(lower_path.mnt);
254562306a36Sopenharmony_ci	if (err) {
254662306a36Sopenharmony_ci		hmdfs_info("get write access failed, err %d", err);
254762306a36Sopenharmony_ci		goto free_name;
254862306a36Sopenharmony_ci	}
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	lower_parent = lock_parent(lower_dentry);
255162306a36Sopenharmony_ci	new_dentry = lookup_one_len(name, lower_parent, strlen(name));
255262306a36Sopenharmony_ci	if (IS_ERR(new_dentry)) {
255362306a36Sopenharmony_ci		err = PTR_ERR(new_dentry);
255462306a36Sopenharmony_ci		hmdfs_info("lookup new dentry failed, err %d", err);
255562306a36Sopenharmony_ci		goto unlock_parent;
255662306a36Sopenharmony_ci	}
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	rename_data.old_mnt_idmap  = &nop_mnt_idmap;
255962306a36Sopenharmony_ci	rename_data.old_dir = d_inode(lower_parent);
256062306a36Sopenharmony_ci	rename_data.old_dentry = lower_dentry;
256162306a36Sopenharmony_ci	rename_data.new_mnt_idmap = &nop_mnt_idmap;
256262306a36Sopenharmony_ci	rename_data.new_dir = d_inode(lower_parent);
256362306a36Sopenharmony_ci	rename_data.new_dentry = new_dentry;
256462306a36Sopenharmony_ci	rename_data.flags = 0;
256562306a36Sopenharmony_ci	err = vfs_rename(&rename_data);
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci	dput(new_dentry);
256862306a36Sopenharmony_ciunlock_parent:
256962306a36Sopenharmony_ci	unlock_dir(lower_parent);
257062306a36Sopenharmony_ci	mnt_drop_write(lower_path.mnt);
257162306a36Sopenharmony_cifree_name:
257262306a36Sopenharmony_ci	kfree(name);
257362306a36Sopenharmony_ciput_lower_path:
257462306a36Sopenharmony_ci	hmdfs_put_lower_path(&lower_path);
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci	if (err)
257762306a36Sopenharmony_ci		hmdfs_err("failed to rename file, err %d", err);
257862306a36Sopenharmony_ci}
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ciint hmdfs_root_unlink(uint64_t device_id, struct path *root_path,
258162306a36Sopenharmony_ci		      const char *unlink_dir, const char *unlink_name)
258262306a36Sopenharmony_ci{
258362306a36Sopenharmony_ci	int err = 0;
258462306a36Sopenharmony_ci	struct path path;
258562306a36Sopenharmony_ci	struct dentry *child_dentry = NULL;
258662306a36Sopenharmony_ci	struct inode *dir = NULL;
258762306a36Sopenharmony_ci	struct inode *child_inode = NULL;
258862306a36Sopenharmony_ci	kuid_t tmp_uid;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	err = vfs_path_lookup(root_path->dentry, root_path->mnt,
259162306a36Sopenharmony_ci			      unlink_dir, LOOKUP_DIRECTORY, &path);
259262306a36Sopenharmony_ci	if (err) {
259362306a36Sopenharmony_ci		hmdfs_err("found path failed err = %d", err);
259462306a36Sopenharmony_ci		return err;
259562306a36Sopenharmony_ci	}
259662306a36Sopenharmony_ci	dir = d_inode(path.dentry);
259762306a36Sopenharmony_ci	inode_lock_nested(dir, I_MUTEX_PARENT);
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci	child_dentry = lookup_one_len(unlink_name, path.dentry,
260062306a36Sopenharmony_ci				      strlen(unlink_name));
260162306a36Sopenharmony_ci	if (IS_ERR(child_dentry)) {
260262306a36Sopenharmony_ci		err = PTR_ERR(child_dentry);
260362306a36Sopenharmony_ci		hmdfs_err("lookup_one_len failed, err = %d", err);
260462306a36Sopenharmony_ci		goto unlock_out;
260562306a36Sopenharmony_ci	}
260662306a36Sopenharmony_ci	if (d_is_negative(child_dentry)) {
260762306a36Sopenharmony_ci		err = -ENOENT;
260862306a36Sopenharmony_ci		dput(child_dentry);
260962306a36Sopenharmony_ci		goto unlock_out;
261062306a36Sopenharmony_ci	}
261162306a36Sopenharmony_ci	child_inode = d_inode(child_dentry);
261262306a36Sopenharmony_ci	if (!child_inode)
261362306a36Sopenharmony_ci		goto unlock_out;
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci	tmp_uid = hmdfs_override_inode_uid(dir);
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	hmdfs_mark_drop_flag(device_id, path.dentry);
261862306a36Sopenharmony_ci	ihold(child_inode);
261962306a36Sopenharmony_ci	err = vfs_unlink(&nop_mnt_idmap, dir, child_dentry, NULL);
262062306a36Sopenharmony_ci	/*
262162306a36Sopenharmony_ci	 * -EOWNERDEAD means we want to put the file in a specail dir instead of
262262306a36Sopenharmony_ci	 *  deleting it, specifically dustbin in phone, so that user can
262362306a36Sopenharmony_ci	 *  recover the deleted images and videos.
262462306a36Sopenharmony_ci	 */
262562306a36Sopenharmony_ci	if (err == -EOWNERDEAD) {
262662306a36Sopenharmony_ci		hmdfs_rename_bak(child_dentry);
262762306a36Sopenharmony_ci		err = 0;
262862306a36Sopenharmony_ci	}
262962306a36Sopenharmony_ci	if (err)
263062306a36Sopenharmony_ci		hmdfs_err("unlink path failed err = %d", err);
263162306a36Sopenharmony_ci	hmdfs_revert_inode_uid(dir, tmp_uid);
263262306a36Sopenharmony_ci	dput(child_dentry);
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ciunlock_out:
263562306a36Sopenharmony_ci	inode_unlock(dir);
263662306a36Sopenharmony_ci	if (child_inode)
263762306a36Sopenharmony_ci		iput(child_inode);
263862306a36Sopenharmony_ci	path_put(&path);
263962306a36Sopenharmony_ci	return err;
264062306a36Sopenharmony_ci}
264162306a36Sopenharmony_ci
264262306a36Sopenharmony_cistruct dentry *hmdfs_root_mkdir(uint64_t device_id, const char *local_dst_path,
264362306a36Sopenharmony_ci				const char *mkdir_dir, const char *mkdir_name,
264462306a36Sopenharmony_ci				umode_t mode)
264562306a36Sopenharmony_ci{
264662306a36Sopenharmony_ci	int err;
264762306a36Sopenharmony_ci	struct path path;
264862306a36Sopenharmony_ci	struct dentry *child_dentry = NULL;
264962306a36Sopenharmony_ci	struct dentry *ret = NULL;
265062306a36Sopenharmony_ci	char *mkdir_path = NULL;
265162306a36Sopenharmony_ci	char *mkdir_abs_path = NULL;
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	mkdir_path = hmdfs_connect_path(mkdir_dir, mkdir_name);
265462306a36Sopenharmony_ci	if (!mkdir_path)
265562306a36Sopenharmony_ci		return ERR_PTR(-EACCES);
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	mkdir_abs_path =
265862306a36Sopenharmony_ci		hmdfs_get_dentry_absolute_path(local_dst_path, mkdir_path);
265962306a36Sopenharmony_ci	if (!mkdir_abs_path) {
266062306a36Sopenharmony_ci		ret = ERR_PTR(-ENOMEM);
266162306a36Sopenharmony_ci		goto out;
266262306a36Sopenharmony_ci	}
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	child_dentry = kern_path_create(AT_FDCWD, mkdir_abs_path,
266562306a36Sopenharmony_ci					&path, LOOKUP_DIRECTORY);
266662306a36Sopenharmony_ci	if (IS_ERR(child_dentry)) {
266762306a36Sopenharmony_ci		ret = child_dentry;
266862306a36Sopenharmony_ci		goto out;
266962306a36Sopenharmony_ci	}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	hmdfs_mark_drop_flag(device_id, child_dentry->d_parent);
267262306a36Sopenharmony_ci	err = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), child_dentry, mode);
267362306a36Sopenharmony_ci	if (err) {
267462306a36Sopenharmony_ci		hmdfs_err("mkdir failed! err=%d", err);
267562306a36Sopenharmony_ci		ret = ERR_PTR(err);
267662306a36Sopenharmony_ci		goto out_put;
267762306a36Sopenharmony_ci	}
267862306a36Sopenharmony_ci	ret = dget(child_dentry);
267962306a36Sopenharmony_ciout_put:
268062306a36Sopenharmony_ci	done_path_create(&path, child_dentry);
268162306a36Sopenharmony_ciout:
268262306a36Sopenharmony_ci	kfree(mkdir_path);
268362306a36Sopenharmony_ci	kfree(mkdir_abs_path);
268462306a36Sopenharmony_ci	return ret;
268562306a36Sopenharmony_ci}
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_cistruct dentry *hmdfs_root_create(uint64_t device_id, const char *local_dst_path,
268862306a36Sopenharmony_ci				 const char *create_dir,
268962306a36Sopenharmony_ci				 const char *create_name,
269062306a36Sopenharmony_ci				 umode_t mode, bool want_excl)
269162306a36Sopenharmony_ci{
269262306a36Sopenharmony_ci	int err;
269362306a36Sopenharmony_ci	struct path path;
269462306a36Sopenharmony_ci	struct dentry *child_dentry = NULL;
269562306a36Sopenharmony_ci	struct dentry *ret = NULL;
269662306a36Sopenharmony_ci	char *create_path = NULL;
269762306a36Sopenharmony_ci	char *create_abs_path = NULL;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	create_path = hmdfs_connect_path(create_dir, create_name);
270062306a36Sopenharmony_ci	if (!create_path)
270162306a36Sopenharmony_ci		return ERR_PTR(-EACCES);
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci	create_abs_path =
270462306a36Sopenharmony_ci		hmdfs_get_dentry_absolute_path(local_dst_path, create_path);
270562306a36Sopenharmony_ci	if (!create_abs_path) {
270662306a36Sopenharmony_ci		ret = ERR_PTR(-ENOMEM);
270762306a36Sopenharmony_ci		goto out;
270862306a36Sopenharmony_ci	}
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	child_dentry = kern_path_create(AT_FDCWD, create_abs_path, &path, 0);
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci	if (IS_ERR(child_dentry)) {
271362306a36Sopenharmony_ci		ret = child_dentry;
271462306a36Sopenharmony_ci		goto out;
271562306a36Sopenharmony_ci	}
271662306a36Sopenharmony_ci	hmdfs_mark_drop_flag(device_id, child_dentry->d_parent);
271762306a36Sopenharmony_ci	err = vfs_create(&nop_mnt_idmap, d_inode(path.dentry), child_dentry, mode, want_excl);
271862306a36Sopenharmony_ci	if (err) {
271962306a36Sopenharmony_ci		hmdfs_err("path create failed! err=%d", err);
272062306a36Sopenharmony_ci		ret = ERR_PTR(err);
272162306a36Sopenharmony_ci		goto out_put;
272262306a36Sopenharmony_ci	}
272362306a36Sopenharmony_ci	ret = dget(child_dentry);
272462306a36Sopenharmony_ciout_put:
272562306a36Sopenharmony_ci	done_path_create(&path, child_dentry);
272662306a36Sopenharmony_ciout:
272762306a36Sopenharmony_ci	kfree(create_path);
272862306a36Sopenharmony_ci	kfree(create_abs_path);
272962306a36Sopenharmony_ci	return ret;
273062306a36Sopenharmony_ci}
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ciint hmdfs_root_rmdir(uint64_t device_id, struct path *root_path,
273362306a36Sopenharmony_ci		     const char *rmdir_dir, const char *rmdir_name)
273462306a36Sopenharmony_ci{
273562306a36Sopenharmony_ci	int err = 0;
273662306a36Sopenharmony_ci	struct path path;
273762306a36Sopenharmony_ci	struct dentry *child_dentry = NULL;
273862306a36Sopenharmony_ci	struct inode *dir = NULL;
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	err = vfs_path_lookup(root_path->dentry, root_path->mnt,
274162306a36Sopenharmony_ci			      rmdir_dir, LOOKUP_DIRECTORY, &path);
274262306a36Sopenharmony_ci	if (err) {
274362306a36Sopenharmony_ci		hmdfs_err("found path failed err = %d", err);
274462306a36Sopenharmony_ci		return err;
274562306a36Sopenharmony_ci	}
274662306a36Sopenharmony_ci	dir = d_inode(path.dentry);
274762306a36Sopenharmony_ci	inode_lock_nested(dir, I_MUTEX_PARENT);
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	child_dentry = lookup_one_len(rmdir_name, path.dentry,
275062306a36Sopenharmony_ci				      strlen(rmdir_name));
275162306a36Sopenharmony_ci	if (IS_ERR(child_dentry)) {
275262306a36Sopenharmony_ci		err = PTR_ERR(child_dentry);
275362306a36Sopenharmony_ci		hmdfs_err("lookup_one_len failed, err = %d", err);
275462306a36Sopenharmony_ci		goto unlock_out;
275562306a36Sopenharmony_ci	}
275662306a36Sopenharmony_ci	if (d_is_negative(child_dentry)) {
275762306a36Sopenharmony_ci		err = -ENOENT;
275862306a36Sopenharmony_ci		dput(child_dentry);
275962306a36Sopenharmony_ci		goto unlock_out;
276062306a36Sopenharmony_ci	}
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci	hmdfs_mark_drop_flag(device_id, path.dentry);
276362306a36Sopenharmony_ci	err = vfs_rmdir(&nop_mnt_idmap, dir, child_dentry);
276462306a36Sopenharmony_ci	if (err)
276562306a36Sopenharmony_ci		hmdfs_err("rmdir failed err = %d", err);
276662306a36Sopenharmony_ci	dput(child_dentry);
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ciunlock_out:
276962306a36Sopenharmony_ci	inode_unlock(dir);
277062306a36Sopenharmony_ci	path_put(&path);
277162306a36Sopenharmony_ci	return err;
277262306a36Sopenharmony_ci}
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ciint hmdfs_root_rename(struct hmdfs_sb_info *sbi, uint64_t device_id,
277562306a36Sopenharmony_ci		      const char *oldpath, const char *oldname,
277662306a36Sopenharmony_ci		      const char *newpath, const char *newname,
277762306a36Sopenharmony_ci		      unsigned int flags)
277862306a36Sopenharmony_ci{
277962306a36Sopenharmony_ci	int err = 0;
278062306a36Sopenharmony_ci	struct path path_dst;
278162306a36Sopenharmony_ci	struct path path_old;
278262306a36Sopenharmony_ci	struct path path_new;
278362306a36Sopenharmony_ci	struct dentry *trap = NULL;
278462306a36Sopenharmony_ci	struct dentry *old_dentry = NULL;
278562306a36Sopenharmony_ci	struct dentry *new_dentry = NULL;
278662306a36Sopenharmony_ci	struct renamedata rename_data;
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci	err = kern_path(sbi->local_dst, 0, &path_dst);
278962306a36Sopenharmony_ci	if (err) {
279062306a36Sopenharmony_ci		hmdfs_err("kern_path for local dst failed %d", err);
279162306a36Sopenharmony_ci		return err;
279262306a36Sopenharmony_ci	}
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci	err = vfs_path_lookup(path_dst.dentry, path_dst.mnt, oldpath, 0,
279562306a36Sopenharmony_ci			      &path_old);
279662306a36Sopenharmony_ci	if (err) {
279762306a36Sopenharmony_ci		hmdfs_info("lookup oldpath from local_dst failed, err %d", err);
279862306a36Sopenharmony_ci		goto put_path_dst;
279962306a36Sopenharmony_ci	}
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci	err = vfs_path_lookup(path_dst.dentry, path_dst.mnt, newpath, 0,
280262306a36Sopenharmony_ci			      &path_new);
280362306a36Sopenharmony_ci	if (err) {
280462306a36Sopenharmony_ci		hmdfs_info("lookup newpath from local_dst failed, err %d", err);
280562306a36Sopenharmony_ci		goto put_path_old;
280662306a36Sopenharmony_ci	}
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci	err = mnt_want_write(path_dst.mnt);
280962306a36Sopenharmony_ci	if (err) {
281062306a36Sopenharmony_ci		hmdfs_info("get write access failed for local_dst, err %d",
281162306a36Sopenharmony_ci			   err);
281262306a36Sopenharmony_ci		goto put_path_new;
281362306a36Sopenharmony_ci	}
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	trap = lock_rename(path_new.dentry, path_old.dentry);
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	old_dentry = lookup_one_len(oldname, path_old.dentry, strlen(oldname));
281862306a36Sopenharmony_ci	if (IS_ERR(old_dentry)) {
281962306a36Sopenharmony_ci		err = PTR_ERR(old_dentry);
282062306a36Sopenharmony_ci		hmdfs_info("lookup old dentry failed, err %d", err);
282162306a36Sopenharmony_ci		goto unlock;
282262306a36Sopenharmony_ci	}
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	/* source should not be ancestor of target */
282562306a36Sopenharmony_ci	if (old_dentry == trap) {
282662306a36Sopenharmony_ci		err = -EINVAL;
282762306a36Sopenharmony_ci		goto put_old_dentry;
282862306a36Sopenharmony_ci	}
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci	new_dentry = lookup_one_len(newname, path_new.dentry, strlen(newname));
283162306a36Sopenharmony_ci	if (IS_ERR(new_dentry)) {
283262306a36Sopenharmony_ci		err = PTR_ERR(new_dentry);
283362306a36Sopenharmony_ci		hmdfs_info("lookup new dentry failed, err %d", err);
283462306a36Sopenharmony_ci		goto put_old_dentry;
283562306a36Sopenharmony_ci	}
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_ci	/*
283862306a36Sopenharmony_ci	 * Exchange rename is not supported, thus target should not be an
283962306a36Sopenharmony_ci	 * ancestor of source.
284062306a36Sopenharmony_ci	 */
284162306a36Sopenharmony_ci	if (trap == new_dentry) {
284262306a36Sopenharmony_ci		err = -ENOTEMPTY;
284362306a36Sopenharmony_ci		goto put_new_dentry;
284462306a36Sopenharmony_ci	}
284562306a36Sopenharmony_ci
284662306a36Sopenharmony_ci	if (d_is_positive(new_dentry) && (flags & RENAME_NOREPLACE)) {
284762306a36Sopenharmony_ci		err = -EEXIST;
284862306a36Sopenharmony_ci		goto put_new_dentry;
284962306a36Sopenharmony_ci	}
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci	hmdfs_mark_drop_flag(device_id, path_old.dentry);
285262306a36Sopenharmony_ci	if (path_old.dentry != path_new.dentry)
285362306a36Sopenharmony_ci		hmdfs_mark_drop_flag(device_id, path_new.dentry);
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	rename_data.old_mnt_idmap = &nop_mnt_idmap;
285662306a36Sopenharmony_ci	rename_data.old_dir = d_inode(path_old.dentry);
285762306a36Sopenharmony_ci	rename_data.old_dentry = old_dentry;
285862306a36Sopenharmony_ci	rename_data.new_mnt_idmap = &nop_mnt_idmap;
285962306a36Sopenharmony_ci	rename_data.new_dir = d_inode(path_new.dentry);
286062306a36Sopenharmony_ci	rename_data.new_dentry = new_dentry;
286162306a36Sopenharmony_ci	rename_data.flags = flags;
286262306a36Sopenharmony_ci	err = vfs_rename(&rename_data);
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ciput_new_dentry:
286562306a36Sopenharmony_ci	dput(new_dentry);
286662306a36Sopenharmony_ciput_old_dentry:
286762306a36Sopenharmony_ci	dput(old_dentry);
286862306a36Sopenharmony_ciunlock:
286962306a36Sopenharmony_ci	unlock_rename(path_new.dentry, path_old.dentry);
287062306a36Sopenharmony_ci	mnt_drop_write(path_dst.mnt);
287162306a36Sopenharmony_ciput_path_new:
287262306a36Sopenharmony_ci	path_put(&path_new);
287362306a36Sopenharmony_ciput_path_old:
287462306a36Sopenharmony_ci	path_put(&path_old);
287562306a36Sopenharmony_ciput_path_dst:
287662306a36Sopenharmony_ci	path_put(&path_dst);
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci	return err;
287962306a36Sopenharmony_ci}
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ciint hmdfs_get_path_in_sb(struct super_block *sb, const char *name,
288262306a36Sopenharmony_ci			 unsigned int flags, struct path *path)
288362306a36Sopenharmony_ci{
288462306a36Sopenharmony_ci	int err;
288562306a36Sopenharmony_ci
288662306a36Sopenharmony_ci	err = kern_path(name, flags, path);
288762306a36Sopenharmony_ci	if (err) {
288862306a36Sopenharmony_ci		hmdfs_err("can't get %s %d\n", name, err);
288962306a36Sopenharmony_ci		return err;
289062306a36Sopenharmony_ci	}
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci	/* should ensure the path is belong sb */
289362306a36Sopenharmony_ci	if (path->dentry->d_sb != sb) {
289462306a36Sopenharmony_ci		err = -EINVAL;
289562306a36Sopenharmony_ci		hmdfs_err("Wrong sb: %s on %s", name,
289662306a36Sopenharmony_ci			  path->dentry->d_sb->s_type->name);
289762306a36Sopenharmony_ci		path_put(path);
289862306a36Sopenharmony_ci	}
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci	return err;
290162306a36Sopenharmony_ci}
2902