162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * fs/hmdfs/hmdfs_server.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "hmdfs_server.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/file.h>
1162306a36Sopenharmony_ci#include <linux/xattr.h>
1262306a36Sopenharmony_ci#include <linux/namei.h>
1362306a36Sopenharmony_ci#include <linux/statfs.h>
1462306a36Sopenharmony_ci#include <linux/mount.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "authority/authentication.h"
1762306a36Sopenharmony_ci#include "hmdfs.h"
1862306a36Sopenharmony_ci#include "hmdfs_dentryfile.h"
1962306a36Sopenharmony_ci#include "hmdfs_share.h"
2062306a36Sopenharmony_ci#include "hmdfs_trace.h"
2162306a36Sopenharmony_ci#include "server_writeback.h"
2262306a36Sopenharmony_ci#include "comm/node_cb.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define HMDFS_MAX_HIDDEN_DIR	1
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistruct hmdfs_open_info {
2762306a36Sopenharmony_ci	struct file *file;
2862306a36Sopenharmony_ci	struct inode *inode;
2962306a36Sopenharmony_ci	bool stat_valid;
3062306a36Sopenharmony_ci	struct kstat stat;
3162306a36Sopenharmony_ci	uint64_t real_ino;
3262306a36Sopenharmony_ci	int file_id;
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic void find_first_no_slash(const char **name, int *len)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	const char *s = *name;
3862306a36Sopenharmony_ci	int l = *len;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	while (l > 0 && *s == '/') {
4162306a36Sopenharmony_ci		s++;
4262306a36Sopenharmony_ci		l--;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	*name = s;
4662306a36Sopenharmony_ci	*len = l;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic void find_first_slash(const char **name, int *len)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	const char *s = *name;
5262306a36Sopenharmony_ci	int l = *len;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	while (l > 0 && *s != '/') {
5562306a36Sopenharmony_ci		s++;
5662306a36Sopenharmony_ci		l--;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	*name = s;
6062306a36Sopenharmony_ci	*len = l;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic bool path_contain_dotdot(const char *name, int len)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	while (true) {
6662306a36Sopenharmony_ci		find_first_no_slash(&name, &len);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci		if (len == 0)
6962306a36Sopenharmony_ci			return false;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci		if (len >= 2 && name[0] == '.' && name[1] == '.' &&
7262306a36Sopenharmony_ci		    (len == 2 || name[2] == '/'))
7362306a36Sopenharmony_ci			return true;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		find_first_slash(&name, &len);
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic int insert_file_into_conn(struct hmdfs_peer *conn, struct file *file)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	struct idr *idr = &(conn->file_id_idr);
8262306a36Sopenharmony_ci	int ret;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	idr_preload(GFP_KERNEL);
8562306a36Sopenharmony_ci	spin_lock(&(conn->file_id_lock));
8662306a36Sopenharmony_ci	ret = idr_alloc_cyclic(idr, file, 0, 0, GFP_NOWAIT);
8762306a36Sopenharmony_ci	spin_unlock(&(conn->file_id_lock));
8862306a36Sopenharmony_ci	idr_preload_end();
8962306a36Sopenharmony_ci	return ret;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/*
9362306a36Sopenharmony_ci * get_file_from_conn - get file from conn by file_id. It should be noted that
9462306a36Sopenharmony_ci * an additional reference will be acquired for returned file, the called should
9562306a36Sopenharmony_ci * put it after the file is not used anymore.
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_cistatic struct file *get_file_from_conn(struct hmdfs_peer *conn, __u32 file_id)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct file *file;
10062306a36Sopenharmony_ci	struct idr *idr = &(conn->file_id_idr);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	rcu_read_lock();
10362306a36Sopenharmony_ci	file = idr_find(idr, file_id);
10462306a36Sopenharmony_ci	if (file && !get_file_rcu(file))
10562306a36Sopenharmony_ci		file = NULL;
10662306a36Sopenharmony_ci	rcu_read_unlock();
10762306a36Sopenharmony_ci	return file;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ciint remove_file_from_conn(struct hmdfs_peer *conn, __u32 file_id)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	spinlock_t *lock = &(conn->file_id_lock);
11362306a36Sopenharmony_ci	struct idr *idr = &(conn->file_id_idr);
11462306a36Sopenharmony_ci	struct file *file;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	spin_lock(lock);
11762306a36Sopenharmony_ci	file = idr_remove(idr, file_id);
11862306a36Sopenharmony_ci	spin_unlock(lock);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	if (!file) {
12162306a36Sopenharmony_ci		return -ENOENT;
12262306a36Sopenharmony_ci	} else {
12362306a36Sopenharmony_ci		return 0;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistruct file *hmdfs_open_link(struct hmdfs_sb_info *sbi,
12862306a36Sopenharmony_ci					 const char *path)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct file *file;
13162306a36Sopenharmony_ci	int err;
13262306a36Sopenharmony_ci	const char *root_name = sbi->local_dst;
13362306a36Sopenharmony_ci	char *real_path;
13462306a36Sopenharmony_ci	int path_len;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	path_len = strlen(root_name) + strlen(path) + 2;
13762306a36Sopenharmony_ci	if (path_len > PATH_MAX) {
13862306a36Sopenharmony_ci		err = -EINVAL;
13962306a36Sopenharmony_ci		return ERR_PTR(err);
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci	real_path = kzalloc(path_len, GFP_KERNEL);
14262306a36Sopenharmony_ci	if (!real_path) {
14362306a36Sopenharmony_ci		err = -ENOMEM;
14462306a36Sopenharmony_ci		return ERR_PTR(err);
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	sprintf(real_path, "%s%s", root_name, path);
14862306a36Sopenharmony_ci	file = filp_open(real_path, O_RDWR | O_LARGEFILE, 0644);
14962306a36Sopenharmony_ci	if (IS_ERR(file)) {
15062306a36Sopenharmony_ci		hmdfs_info("filp_open failed: %ld", PTR_ERR(file));
15162306a36Sopenharmony_ci	} else {
15262306a36Sopenharmony_ci		hmdfs_info("get file with magic %lu",
15362306a36Sopenharmony_ci				file->f_inode->i_sb->s_magic);
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	kfree(real_path);
15762306a36Sopenharmony_ci	return file;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistruct file *hmdfs_open_path(struct hmdfs_sb_info *sbi, const char *path)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct path root_path;
16362306a36Sopenharmony_ci	struct file *file;
16462306a36Sopenharmony_ci	int err;
16562306a36Sopenharmony_ci	const char *root_name = sbi->local_dst;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	err = kern_path(root_name, 0, &root_path);
16862306a36Sopenharmony_ci	if (err) {
16962306a36Sopenharmony_ci		hmdfs_info("kern_path failed: %d", err);
17062306a36Sopenharmony_ci		return ERR_PTR(err);
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci	file = file_open_root(&root_path, path,
17362306a36Sopenharmony_ci			      O_RDWR | O_LARGEFILE, 0644);
17462306a36Sopenharmony_ci	path_put(&root_path);
17562306a36Sopenharmony_ci	if (IS_ERR(file)) {
17662306a36Sopenharmony_ci		hmdfs_err(
17762306a36Sopenharmony_ci			"GRAPERR sb->s_readonly_remount %d sb_flag %lu",
17862306a36Sopenharmony_ci			sbi->sb->s_readonly_remount, sbi->sb->s_flags);
17962306a36Sopenharmony_ci		hmdfs_info("file_open_root failed: %ld", PTR_ERR(file));
18062306a36Sopenharmony_ci	} else {
18162306a36Sopenharmony_ci		hmdfs_info("get file with magic %lu",
18262306a36Sopenharmony_ci			   file->f_inode->i_sb->s_magic);
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci	return file;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ciinline void hmdfs_close_path(struct file *file)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	fput(file);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/* After offline server close all files opened by client */
19362306a36Sopenharmony_civoid hmdfs_server_offline_notify(struct hmdfs_peer *conn, int evt,
19462306a36Sopenharmony_ci				 unsigned int seq)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	int id;
19762306a36Sopenharmony_ci	int count = 0;
19862306a36Sopenharmony_ci	unsigned int next;
19962306a36Sopenharmony_ci	struct file *filp = NULL;
20062306a36Sopenharmony_ci	struct idr *idr = &conn->file_id_idr;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/* wait all async work complete */
20362306a36Sopenharmony_ci	flush_workqueue(conn->req_handle_wq);
20462306a36Sopenharmony_ci	flush_workqueue(conn->async_wq);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* If there is some open requests in processing,
20762306a36Sopenharmony_ci	 * Maybe, we need to close file when peer offline
20862306a36Sopenharmony_ci	 */
20962306a36Sopenharmony_ci	idr_for_each_entry(idr, filp, id) {
21062306a36Sopenharmony_ci		hmdfs_debug("[%d]Server close: id=%d", count, id);
21162306a36Sopenharmony_ci		hmdfs_close_path(filp);
21262306a36Sopenharmony_ci		count++;
21362306a36Sopenharmony_ci		if (count % HMDFS_IDR_RESCHED_COUNT == 0)
21462306a36Sopenharmony_ci			cond_resched();
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	hmdfs_clear_share_item_offline(conn);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* Reinitialize idr */
22062306a36Sopenharmony_ci	next = idr_get_cursor(idr);
22162306a36Sopenharmony_ci	idr_destroy(idr);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	idr_init(idr);
22462306a36Sopenharmony_ci	idr_set_cursor(idr, next);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/* Make old file id to be stale */
22762306a36Sopenharmony_ci	conn->fid_cookie++;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic struct hmdfs_node_cb_desc server_cb[] = {
23162306a36Sopenharmony_ci	{
23262306a36Sopenharmony_ci		.evt = NODE_EVT_OFFLINE,
23362306a36Sopenharmony_ci		.sync = true,
23462306a36Sopenharmony_ci		.fn = hmdfs_server_offline_notify
23562306a36Sopenharmony_ci	},
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_civoid __init hmdfs_server_add_node_evt_cb(void)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	hmdfs_node_add_evt_cb(server_cb, ARRAY_SIZE(server_cb));
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic int hmdfs_get_inode_by_name(struct hmdfs_peer *con, const char *filename,
24462306a36Sopenharmony_ci					uint64_t *ino)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	int ret = 0;
24762306a36Sopenharmony_ci	struct path root_path;
24862306a36Sopenharmony_ci	struct path dst_path;
24962306a36Sopenharmony_ci	struct inode *inode = NULL;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	ret = kern_path(con->sbi->local_dst, 0, &root_path);
25262306a36Sopenharmony_ci	if (ret) {
25362306a36Sopenharmony_ci		hmdfs_err("kern_path failed err = %d", ret);
25462306a36Sopenharmony_ci		return ret;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	ret = vfs_path_lookup(root_path.dentry, root_path.mnt, filename, 0,
25862306a36Sopenharmony_ci					&dst_path);
25962306a36Sopenharmony_ci	if (ret) {
26062306a36Sopenharmony_ci		path_put(&root_path);
26162306a36Sopenharmony_ci		return ret;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	inode = d_inode(dst_path.dentry);
26562306a36Sopenharmony_ci	if (con->sbi->sb == inode->i_sb)
26662306a36Sopenharmony_ci		inode = hmdfs_i(inode)->lower_inode;
26762306a36Sopenharmony_ci	*ino = generate_u64_ino(inode->i_ino, inode->i_generation);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	path_put(&dst_path);
27062306a36Sopenharmony_ci	path_put(&root_path);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	return 0;
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic const char *datasl_str[] = {
27662306a36Sopenharmony_ci	"s0", "s1", "s2", "s3", "s4"
27762306a36Sopenharmony_ci};
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic int parse_data_sec_level(const char *sl_value, size_t sl_value_len)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	int i;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	for (i = 0; i < sizeof(datasl_str) / sizeof(datasl_str[0]); i++) {
28462306a36Sopenharmony_ci		if (!strncmp(sl_value, datasl_str[i], strlen(datasl_str[i])))
28562306a36Sopenharmony_ci			return i + DATA_SEC_LEVEL0;
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	return DATA_SEC_LEVEL3;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic int check_sec_level(struct hmdfs_peer *node, const char *file_name)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	int err;
29462306a36Sopenharmony_ci	int ret = 0;
29562306a36Sopenharmony_ci	struct path root_path;
29662306a36Sopenharmony_ci	struct path file_path;
29762306a36Sopenharmony_ci	char *value = NULL;
29862306a36Sopenharmony_ci	size_t value_len = DATA_SEC_LEVEL_LENGTH;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (node->devsl <= 0) {
30162306a36Sopenharmony_ci		ret = -EACCES;
30262306a36Sopenharmony_ci		goto out_free;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	value = kzalloc(value_len, GFP_KERNEL);
30662306a36Sopenharmony_ci	if (!value) {
30762306a36Sopenharmony_ci		ret = -ENOMEM;
30862306a36Sopenharmony_ci		goto out_free;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	err = kern_path(node->sbi->local_dst, LOOKUP_DIRECTORY, &root_path);
31262306a36Sopenharmony_ci	if (err) {
31362306a36Sopenharmony_ci		hmdfs_err("get root path error");
31462306a36Sopenharmony_ci		ret = err;
31562306a36Sopenharmony_ci		goto out_free;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	err = vfs_path_lookup(root_path.dentry, root_path.mnt, file_name, 0,
31962306a36Sopenharmony_ci		&file_path);
32062306a36Sopenharmony_ci	if (err) {
32162306a36Sopenharmony_ci		hmdfs_err("get file path error");
32262306a36Sopenharmony_ci		ret = err;
32362306a36Sopenharmony_ci		goto out_err;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	err = vfs_getxattr(&nop_mnt_idmap, file_path.dentry, DATA_SEC_LEVEL_LABEL, value,
32762306a36Sopenharmony_ci		value_len);
32862306a36Sopenharmony_ci	if (err <= 0 && node->devsl >= DATA_SEC_LEVEL3)
32962306a36Sopenharmony_ci		goto out;
33062306a36Sopenharmony_ci	if (err > 0 && node->devsl >= parse_data_sec_level(value, err))
33162306a36Sopenharmony_ci		goto out;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	ret = -EACCES;
33462306a36Sopenharmony_ciout:
33562306a36Sopenharmony_ci	path_put(&file_path);
33662306a36Sopenharmony_ciout_err:
33762306a36Sopenharmony_ci	path_put(&root_path);
33862306a36Sopenharmony_ciout_free:
33962306a36Sopenharmony_ci	kfree(value);
34062306a36Sopenharmony_ci	return ret;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic struct file *hmdfs_open_file(struct hmdfs_peer *con,
34462306a36Sopenharmony_ci				    const char *filename, uint8_t file_type,
34562306a36Sopenharmony_ci				    int *file_id)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	struct file *file = NULL;
34862306a36Sopenharmony_ci	int err = 0;
34962306a36Sopenharmony_ci	int id;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (!filename) {
35262306a36Sopenharmony_ci		hmdfs_err("filename is NULL");
35362306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (check_sec_level(con, filename)) {
35762306a36Sopenharmony_ci		hmdfs_err("devsl permission denied");
35862306a36Sopenharmony_ci		return ERR_PTR(-EACCES);
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (hm_isshare(file_type)) {
36262306a36Sopenharmony_ci		err = hmdfs_check_share_access_permission(con->sbi,
36362306a36Sopenharmony_ci							filename, con->cid);
36462306a36Sopenharmony_ci		if (err)
36562306a36Sopenharmony_ci			return ERR_PTR(err);
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	if (hm_islnk(file_type))
36962306a36Sopenharmony_ci		file = hmdfs_open_link(con->sbi, filename);
37062306a36Sopenharmony_ci	else
37162306a36Sopenharmony_ci		file = hmdfs_open_path(con->sbi, filename);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if (IS_ERR(file)) {
37462306a36Sopenharmony_ci		reset_item_opened_status(con->sbi, filename);
37562306a36Sopenharmony_ci		return file;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	get_file(file);
37962306a36Sopenharmony_ci	id = insert_file_into_conn(con, file);
38062306a36Sopenharmony_ci	if (id < 0) {
38162306a36Sopenharmony_ci		hmdfs_err("file_id alloc failed! err=%d", id);
38262306a36Sopenharmony_ci		reset_item_opened_status(con->sbi, filename);
38362306a36Sopenharmony_ci		hmdfs_close_path(file);
38462306a36Sopenharmony_ci		hmdfs_close_path(file);
38562306a36Sopenharmony_ci		return ERR_PTR(id);
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci	*file_id = id;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	return file;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic struct hmdfs_time_t msec_to_timespec(unsigned int msec)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	struct hmdfs_time_t timespec = {
39562306a36Sopenharmony_ci		.tv_sec = msec / MSEC_PER_SEC,
39662306a36Sopenharmony_ci		.tv_nsec = (msec % MSEC_PER_SEC) * NSEC_PER_MSEC,
39762306a36Sopenharmony_ci	};
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	return timespec;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic struct hmdfs_time_t hmdfs_current_kernel_time(void)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct hmdfs_time_t time;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci#if KERNEL_VERSION(4, 18, 0) < LINUX_VERSION_CODE
40762306a36Sopenharmony_ci	ktime_get_coarse_real_ts64(&time);
40862306a36Sopenharmony_ci#else
40962306a36Sopenharmony_ci	time = current_kernel_time();
41062306a36Sopenharmony_ci#endif
41162306a36Sopenharmony_ci	return time;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci/*
41562306a36Sopenharmony_ci * Generate fid version like following format:
41662306a36Sopenharmony_ci *
41762306a36Sopenharmony_ci * |     boot cookie     |  con cookie |
41862306a36Sopenharmony_ci * |---------------------|-------------|
41962306a36Sopenharmony_ci *           49                15       (bits)
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_cistatic uint64_t hmdfs_server_pack_fid_ver(struct hmdfs_peer *con,
42262306a36Sopenharmony_ci					  struct hmdfs_head_cmd *cmd)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	uint64_t boot_cookie = con->sbi->boot_cookie;
42562306a36Sopenharmony_ci	uint16_t con_cookie = con->fid_cookie;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	return (boot_cookie |
42862306a36Sopenharmony_ci		(con_cookie & ((1 << HMDFS_FID_VER_BOOT_COOKIE_SHIFT) - 1)));
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic struct file *get_file_by_fid_and_ver(struct hmdfs_peer *con,
43262306a36Sopenharmony_ci					    struct hmdfs_head_cmd *cmd,
43362306a36Sopenharmony_ci					    __u32 file_id, __u64 file_ver)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct file *file = NULL;
43662306a36Sopenharmony_ci	__u64 cur_file_ver = hmdfs_server_pack_fid_ver(con, cmd);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (file_ver != cur_file_ver) {
43962306a36Sopenharmony_ci		hmdfs_warning("Stale file version %llu for fid %u",
44062306a36Sopenharmony_ci			      file_ver, file_id);
44162306a36Sopenharmony_ci		return ERR_PTR(-EBADF);
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	file = get_file_from_conn(con, file_id);
44562306a36Sopenharmony_ci	if (!file)
44662306a36Sopenharmony_ci		return ERR_PTR(-EBADF);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return file;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic void hmdfs_update_open_response(struct hmdfs_peer *con,
45262306a36Sopenharmony_ci				       struct hmdfs_head_cmd *cmd,
45362306a36Sopenharmony_ci				       struct hmdfs_open_info *info,
45462306a36Sopenharmony_ci				       struct open_response *resp)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct hmdfs_time_t current_time = hmdfs_current_kernel_time();
45762306a36Sopenharmony_ci	struct hmdfs_time_t ctime = info->stat_valid ? info->stat.ctime :
45862306a36Sopenharmony_ci						       info->inode->__i_ctime;
45962306a36Sopenharmony_ci	struct hmdfs_time_t precision =
46062306a36Sopenharmony_ci		msec_to_timespec(con->sbi->dcache_precision);
46162306a36Sopenharmony_ci	loff_t size = info->stat_valid ? info->stat.size :
46262306a36Sopenharmony_ci					 i_size_read(info->inode);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	resp->ino = cpu_to_le64(info->real_ino);
46562306a36Sopenharmony_ci	resp->file_ver = cpu_to_le64(hmdfs_server_pack_fid_ver(con, cmd));
46662306a36Sopenharmony_ci	resp->file_id = cpu_to_le32(info->file_id);
46762306a36Sopenharmony_ci	resp->file_size = cpu_to_le64(size);
46862306a36Sopenharmony_ci	resp->ctime = cpu_to_le64(ctime.tv_sec);
46962306a36Sopenharmony_ci	resp->ctime_nsec = cpu_to_le32(ctime.tv_nsec);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/*
47262306a36Sopenharmony_ci	 * In server, ctime might stay the same after coverwrite. We introduce a
47362306a36Sopenharmony_ci	 * new value stable_ctime to handle the problem.
47462306a36Sopenharmony_ci	 * - if open rpc time < ctime, stable_ctime = 0;
47562306a36Sopenharmony_ci	 * - if ctime <= open rpc time < ctime + dcache_precision, stable_ctime
47662306a36Sopenharmony_ci	 *   = ctime
47762306a36Sopenharmony_ci	 * - else, stable_ctime = ctime + dcache_precision;
47862306a36Sopenharmony_ci	 */
47962306a36Sopenharmony_ci	precision = hmdfs_time_add(ctime, precision);
48062306a36Sopenharmony_ci	if (hmdfs_time_compare(&current_time, &ctime) < 0) {
48162306a36Sopenharmony_ci		resp->stable_ctime = cpu_to_le64(0);
48262306a36Sopenharmony_ci		resp->stable_ctime_nsec = cpu_to_le32(0);
48362306a36Sopenharmony_ci	} else if (hmdfs_time_compare(&current_time, &ctime) >= 0 &&
48462306a36Sopenharmony_ci		   hmdfs_time_compare(&current_time, &precision) < 0) {
48562306a36Sopenharmony_ci		resp->stable_ctime = resp->ctime;
48662306a36Sopenharmony_ci		resp->stable_ctime_nsec = resp->ctime_nsec;
48762306a36Sopenharmony_ci	} else {
48862306a36Sopenharmony_ci		resp->stable_ctime = cpu_to_le64(precision.tv_sec);
48962306a36Sopenharmony_ci		resp->stable_ctime_nsec = cpu_to_le32(precision.tv_nsec);
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic int hmdfs_get_open_info(struct hmdfs_peer *con, uint8_t file_type,
49462306a36Sopenharmony_ci			       const char *filename,
49562306a36Sopenharmony_ci			       struct hmdfs_open_info *info)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	int ret = 0;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	info->inode = file_inode(info->file);
50062306a36Sopenharmony_ci	info->stat_valid = false;
50162306a36Sopenharmony_ci	if (con->sbi->sb == info->inode->i_sb) {
50262306a36Sopenharmony_ci		/* if open a regular file */
50362306a36Sopenharmony_ci		info->inode = hmdfs_i(info->inode)->lower_inode;
50462306a36Sopenharmony_ci	} else if (con->sbi->lower_sb != info->inode->i_sb) {
50562306a36Sopenharmony_ci		/* It's possible that inode is not from lower, for example:
50662306a36Sopenharmony_ci		 * 1. touch /f2fs/file
50762306a36Sopenharmony_ci		 * 2. ln -s /sdcard_fs/file /f2fs/link
50862306a36Sopenharmony_ci		 * 3. cat /hmdfs/link -> generate dentry cache in sdcard_fs
50962306a36Sopenharmony_ci		 * 4. echo hi >> /hmdfs/file -> append write not through
51062306a36Sopenharmony_ci		 *    sdcard_fs
51162306a36Sopenharmony_ci		 * 5. cat /hmdfs/link -> got inode in sdcard, which size is
51262306a36Sopenharmony_ci		 *    still 0
51362306a36Sopenharmony_ci		 *
51462306a36Sopenharmony_ci		 * If src file isn't in lower, use getattr to get
51562306a36Sopenharmony_ci		 * information.
51662306a36Sopenharmony_ci		 */
51762306a36Sopenharmony_ci		ret = vfs_getattr(&info->file->f_path, &info->stat, STATX_BASIC_STATS | STATX_BTIME,
51862306a36Sopenharmony_ci				  0);
51962306a36Sopenharmony_ci		if (ret) {
52062306a36Sopenharmony_ci			hmdfs_err("call vfs_getattr failed, err %d", ret);
52162306a36Sopenharmony_ci			return ret;
52262306a36Sopenharmony_ci		}
52362306a36Sopenharmony_ci		info->stat_valid = true;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (hm_islnk(file_type)) {
52762306a36Sopenharmony_ci		ret = hmdfs_get_inode_by_name(con, filename, &info->real_ino);
52862306a36Sopenharmony_ci		if (ret)
52962306a36Sopenharmony_ci			return ret;
53062306a36Sopenharmony_ci	} else {
53162306a36Sopenharmony_ci		info->real_ino = generate_u64_ino(info->inode->i_ino,
53262306a36Sopenharmony_ci							info->inode->i_generation);
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci	return 0;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_civoid hmdfs_server_open(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
53862306a36Sopenharmony_ci		       void *data)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct open_request *recv = data;
54162306a36Sopenharmony_ci	int sizeread = sizeof(struct open_response);
54262306a36Sopenharmony_ci	struct open_response *resp = NULL;
54362306a36Sopenharmony_ci	struct hmdfs_open_info *info = NULL;
54462306a36Sopenharmony_ci	int ret = 0;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	trace_hmdfs_server_open_enter(con, recv);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	resp = kzalloc(sizeread, GFP_KERNEL);
54962306a36Sopenharmony_ci	info = kmalloc(sizeof(*info), GFP_KERNEL);
55062306a36Sopenharmony_ci	if (!resp || !info) {
55162306a36Sopenharmony_ci		ret = -ENOMEM;
55262306a36Sopenharmony_ci		goto err_free;
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (path_contain_dotdot(recv->buf, recv->path_len)) {
55662306a36Sopenharmony_ci		ret = -EINVAL;
55762306a36Sopenharmony_ci		goto err_free;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	info->file = hmdfs_open_file(con, recv->buf, recv->file_type,
56162306a36Sopenharmony_ci				     &info->file_id);
56262306a36Sopenharmony_ci	if (IS_ERR(info->file)) {
56362306a36Sopenharmony_ci		ret = PTR_ERR(info->file);
56462306a36Sopenharmony_ci		goto err_free;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	ret = hmdfs_get_open_info(con, recv->file_type, recv->buf, info);
56862306a36Sopenharmony_ci	if (ret)
56962306a36Sopenharmony_ci		goto err_close;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	hmdfs_update_open_response(con, cmd, info, resp);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	trace_hmdfs_server_open_exit(con, resp, info->file, 0);
57462306a36Sopenharmony_ci	ret = hmdfs_sendmessage_response(con, cmd, sizeread, resp, 0);
57562306a36Sopenharmony_ci	if (ret) {
57662306a36Sopenharmony_ci		hmdfs_err("sending msg response failed, file_id %d, err %d",
57762306a36Sopenharmony_ci			  info->file_id, ret);
57862306a36Sopenharmony_ci		remove_file_from_conn(con, info->file_id);
57962306a36Sopenharmony_ci		hmdfs_close_path(info->file);
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci	hmdfs_close_path(info->file);
58262306a36Sopenharmony_ci	kfree(resp);
58362306a36Sopenharmony_ci	kfree(info);
58462306a36Sopenharmony_ci	return;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cierr_close:
58762306a36Sopenharmony_ci	hmdfs_close_path(info->file);
58862306a36Sopenharmony_ci	remove_file_from_conn(con, info->file_id);
58962306a36Sopenharmony_ci	hmdfs_close_path(info->file);
59062306a36Sopenharmony_cierr_free:
59162306a36Sopenharmony_ci	kfree(resp);
59262306a36Sopenharmony_ci	kfree(info);
59362306a36Sopenharmony_ci	trace_hmdfs_server_open_exit(con, NULL, NULL, ret);
59462306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, ret);
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic int hmdfs_check_and_create(struct path *path_parent,
59862306a36Sopenharmony_ci				  struct dentry *dentry, uint64_t device_id,
59962306a36Sopenharmony_ci				  umode_t mode, bool is_excl)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	int err = 0;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	/* if inode doesn't exist, create it */
60462306a36Sopenharmony_ci	if (d_is_negative(dentry)) {
60562306a36Sopenharmony_ci		hmdfs_mark_drop_flag(device_id, path_parent->dentry);
60662306a36Sopenharmony_ci		err = vfs_create(&nop_mnt_idmap, d_inode(path_parent->dentry), dentry, mode,
60762306a36Sopenharmony_ci				 is_excl);
60862306a36Sopenharmony_ci		if (err)
60962306a36Sopenharmony_ci			hmdfs_err("create failed, err %d", err);
61062306a36Sopenharmony_ci	} else {
61162306a36Sopenharmony_ci		if (is_excl)
61262306a36Sopenharmony_ci			err = -EEXIST;
61362306a36Sopenharmony_ci		else if (S_ISREG(d_inode(dentry)->i_mode) &&
61462306a36Sopenharmony_ci			 hm_islnk(hmdfs_d(dentry)->file_type))
61562306a36Sopenharmony_ci			err = -EINVAL;
61662306a36Sopenharmony_ci		else if (S_ISDIR(d_inode(dentry)->i_mode))
61762306a36Sopenharmony_ci			err = -EISDIR;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	return err;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_cistatic int hmdfs_lookup_create(struct hmdfs_peer *con,
62362306a36Sopenharmony_ci			       struct atomic_open_request *recv,
62462306a36Sopenharmony_ci			       struct path *child_path, bool *truncate)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	int err = 0;
62762306a36Sopenharmony_ci	struct path path_root;
62862306a36Sopenharmony_ci	struct path path_parent;
62962306a36Sopenharmony_ci	uint32_t open_flags = le32_to_cpu(recv->open_flags);
63062306a36Sopenharmony_ci	char *path = recv->buf;
63162306a36Sopenharmony_ci	char *filename = recv->buf + le32_to_cpu(recv->path_len) + 1;
63262306a36Sopenharmony_ci	struct dentry *dentry = NULL;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	err = kern_path(con->sbi->local_dst, LOOKUP_DIRECTORY, &path_root);
63562306a36Sopenharmony_ci	if (err) {
63662306a36Sopenharmony_ci		hmdfs_err("no path for %s, err %d", con->sbi->local_dst, err);
63762306a36Sopenharmony_ci		return err;
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	err = vfs_path_lookup(path_root.dentry, path_root.mnt, path,
64162306a36Sopenharmony_ci			      LOOKUP_DIRECTORY, &path_parent);
64262306a36Sopenharmony_ci	if (err) {
64362306a36Sopenharmony_ci		hmdfs_info("no dir in %s, err %d", con->sbi->local_dst, err);
64462306a36Sopenharmony_ci		goto put_path_root;
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	inode_lock(d_inode(path_parent.dentry));
64862306a36Sopenharmony_ci	dentry = lookup_one_len(filename, path_parent.dentry, strlen(filename));
64962306a36Sopenharmony_ci	if (IS_ERR(dentry)) {
65062306a36Sopenharmony_ci		err = PTR_ERR(dentry);
65162306a36Sopenharmony_ci		inode_unlock(d_inode(path_parent.dentry));
65262306a36Sopenharmony_ci		goto put_path_parent;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci	/* only truncate if inode already exists */
65562306a36Sopenharmony_ci	*truncate = ((open_flags & HMDFS_O_TRUNC) && d_is_positive(dentry));
65662306a36Sopenharmony_ci	err = hmdfs_check_and_create(&path_parent, dentry, con->device_id,
65762306a36Sopenharmony_ci				     le16_to_cpu(recv->mode),
65862306a36Sopenharmony_ci				     open_flags & HMDFS_O_EXCL);
65962306a36Sopenharmony_ci	inode_unlock(d_inode(path_parent.dentry));
66062306a36Sopenharmony_ci	if (err) {
66162306a36Sopenharmony_ci		dput(dentry);
66262306a36Sopenharmony_ci	} else {
66362306a36Sopenharmony_ci		child_path->dentry = dentry;
66462306a36Sopenharmony_ci		child_path->mnt = mntget(path_parent.mnt);
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ciput_path_parent:
66862306a36Sopenharmony_ci	path_put(&path_parent);
66962306a36Sopenharmony_ciput_path_root:
67062306a36Sopenharmony_ci	path_put(&path_root);
67162306a36Sopenharmony_ci	return err;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic int hmdfs_dentry_open(struct hmdfs_peer *con,
67562306a36Sopenharmony_ci			     const struct path *path,
67662306a36Sopenharmony_ci			     struct hmdfs_open_info *info)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	int err = 0;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	info->file = dentry_open(path, O_RDWR | O_LARGEFILE, current_cred());
68162306a36Sopenharmony_ci	if (IS_ERR(info->file)) {
68262306a36Sopenharmony_ci		err = PTR_ERR(info->file);
68362306a36Sopenharmony_ci		hmdfs_err("open file failed, err %d", err);
68462306a36Sopenharmony_ci		return err;
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	get_file(info->file);
68862306a36Sopenharmony_ci	info->file_id = insert_file_into_conn(con, info->file);
68962306a36Sopenharmony_ci	if (info->file_id < 0) {
69062306a36Sopenharmony_ci		err = info->file_id;
69162306a36Sopenharmony_ci		hmdfs_err("file_id alloc failed! err %d", err);
69262306a36Sopenharmony_ci		hmdfs_close_path(info->file);
69362306a36Sopenharmony_ci		hmdfs_close_path(info->file);
69462306a36Sopenharmony_ci		return err;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	return 0;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic int hmdfs_server_do_atomic_open(struct hmdfs_peer *con,
70162306a36Sopenharmony_ci				       struct hmdfs_head_cmd *cmd,
70262306a36Sopenharmony_ci				       struct atomic_open_request *recv,
70362306a36Sopenharmony_ci				       struct hmdfs_open_info *info,
70462306a36Sopenharmony_ci				       struct atomic_open_response *resp)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	struct path child_path;
70762306a36Sopenharmony_ci	bool truncate = false;
70862306a36Sopenharmony_ci	int err = 0;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	err = hmdfs_lookup_create(con, recv, &child_path, &truncate);
71162306a36Sopenharmony_ci	if (err)
71262306a36Sopenharmony_ci		return err;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	err = hmdfs_dentry_open(con, &child_path, info);
71562306a36Sopenharmony_ci	if (err)
71662306a36Sopenharmony_ci		goto put_child;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	err = hmdfs_get_open_info(con, HM_REG, NULL, info);
71962306a36Sopenharmony_ci	if (err)
72062306a36Sopenharmony_ci		goto fail_close;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	if (truncate) {
72362306a36Sopenharmony_ci		err = vfs_truncate(&child_path, 0);
72462306a36Sopenharmony_ci		if (err) {
72562306a36Sopenharmony_ci			hmdfs_err("truncate failed, err %d", err);
72662306a36Sopenharmony_ci			goto fail_close;
72762306a36Sopenharmony_ci		}
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci	hmdfs_update_open_response(con, cmd, info, &resp->open_resp);
73062306a36Sopenharmony_ci	resp->i_mode = cpu_to_le16(file_inode(info->file)->i_mode);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cifail_close:
73362306a36Sopenharmony_ci	if (err) {
73462306a36Sopenharmony_ci		remove_file_from_conn(con, info->file_id);
73562306a36Sopenharmony_ci		hmdfs_close_path(info->file);
73662306a36Sopenharmony_ci		hmdfs_close_path(info->file);
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ciput_child:
73962306a36Sopenharmony_ci	path_put(&child_path);
74062306a36Sopenharmony_ci	return err;
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_civoid hmdfs_server_atomic_open(struct hmdfs_peer *con,
74462306a36Sopenharmony_ci			      struct hmdfs_head_cmd *cmd, void *data)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	int err;
74762306a36Sopenharmony_ci	struct atomic_open_request *recv = data;
74862306a36Sopenharmony_ci	struct atomic_open_response *resp = NULL;
74962306a36Sopenharmony_ci	struct hmdfs_open_info *info = NULL;
75062306a36Sopenharmony_ci	char *file_path = recv->buf;
75162306a36Sopenharmony_ci	char *file = recv->buf + recv->path_len + 1;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	if (path_contain_dotdot(file_path, recv->path_len)) {
75462306a36Sopenharmony_ci		err = -EINVAL;
75562306a36Sopenharmony_ci		goto out;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci	if (path_contain_dotdot(file, recv->file_len)) {
75862306a36Sopenharmony_ci		err = -EINVAL;
75962306a36Sopenharmony_ci		goto out;
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	info = kmalloc(sizeof(*info), GFP_KERNEL);
76362306a36Sopenharmony_ci	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
76462306a36Sopenharmony_ci	if (!resp || !info) {
76562306a36Sopenharmony_ci		err = -ENOMEM;
76662306a36Sopenharmony_ci		goto out;
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	err = hmdfs_server_do_atomic_open(con, cmd, recv, info, resp);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ciout:
77262306a36Sopenharmony_ci	if (err) {
77362306a36Sopenharmony_ci		hmdfs_send_err_response(con, cmd, err);
77462306a36Sopenharmony_ci	} else {
77562306a36Sopenharmony_ci		err = hmdfs_sendmessage_response(con, cmd, sizeof(*resp), resp,
77662306a36Sopenharmony_ci						 0);
77762306a36Sopenharmony_ci		if (err) {
77862306a36Sopenharmony_ci			hmdfs_err("sending msg response failed, file_id %d, err %d",
77962306a36Sopenharmony_ci				  info->file_id, err);
78062306a36Sopenharmony_ci			remove_file_from_conn(con, info->file_id);
78162306a36Sopenharmony_ci			hmdfs_close_path(info->file);
78262306a36Sopenharmony_ci		}
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci	kfree(info);
78562306a36Sopenharmony_ci	kfree(resp);
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_civoid hmdfs_server_release(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
78962306a36Sopenharmony_ci			  void *data)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	struct release_request *release_recv = data;
79262306a36Sopenharmony_ci	struct file *file = NULL;
79362306a36Sopenharmony_ci	__u32 file_id;
79462306a36Sopenharmony_ci	__u64 file_ver;
79562306a36Sopenharmony_ci	int ret = 0;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	file_id = le32_to_cpu(release_recv->file_id);
79862306a36Sopenharmony_ci	file_ver = le64_to_cpu(release_recv->file_ver);
79962306a36Sopenharmony_ci	file = get_file_by_fid_and_ver(con, cmd, file_id, file_ver);
80062306a36Sopenharmony_ci	if (IS_ERR(file)) {
80162306a36Sopenharmony_ci		hmdfs_err("cannot find %u", file_id);
80262306a36Sopenharmony_ci		ret = PTR_ERR(file);
80362306a36Sopenharmony_ci		goto out;
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	if (hmdfs_is_share_file(file))
80762306a36Sopenharmony_ci		hmdfs_close_share_item(con->sbi, file, con->cid);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	/* put the reference acquired by get_file_by_fid_and_ver() */
81062306a36Sopenharmony_ci	hmdfs_close_path(file);
81162306a36Sopenharmony_ci	hmdfs_info("close %u", file_id);
81262306a36Sopenharmony_ci	ret = remove_file_from_conn(con, file_id);
81362306a36Sopenharmony_ci	if (ret) {
81462306a36Sopenharmony_ci		hmdfs_err("cannot find after close %u", file_id);
81562306a36Sopenharmony_ci		goto out;
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	hmdfs_close_path(file);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ciout:
82162306a36Sopenharmony_ci	trace_hmdfs_server_release(con, file_id, file_ver, ret);
82262306a36Sopenharmony_ci	set_conn_sock_quickack(con);
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_civoid hmdfs_server_fsync(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
82662306a36Sopenharmony_ci			void *data)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	struct fsync_request *fsync_recv = data;
82962306a36Sopenharmony_ci	__s32 datasync = le32_to_cpu(fsync_recv->datasync);
83062306a36Sopenharmony_ci	__s64 start = le64_to_cpu(fsync_recv->start);
83162306a36Sopenharmony_ci	__s64 end = le64_to_cpu(fsync_recv->end);
83262306a36Sopenharmony_ci	struct file *file = NULL;
83362306a36Sopenharmony_ci	__u32 file_id;
83462306a36Sopenharmony_ci	__u64 file_ver;
83562306a36Sopenharmony_ci	int ret = 0;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	file_id = le32_to_cpu(fsync_recv->file_id);
83862306a36Sopenharmony_ci	file_ver = le64_to_cpu(fsync_recv->file_ver);
83962306a36Sopenharmony_ci	file = get_file_by_fid_and_ver(con, cmd, file_id, file_ver);
84062306a36Sopenharmony_ci	if (IS_ERR(file)) {
84162306a36Sopenharmony_ci		hmdfs_err("cannot find %u", file_id);
84262306a36Sopenharmony_ci		ret = PTR_ERR(file);
84362306a36Sopenharmony_ci		goto out;
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	ret = vfs_fsync_range(file, start, end, datasync);
84762306a36Sopenharmony_ci	if (ret)
84862306a36Sopenharmony_ci		hmdfs_err("fsync fail, ret %d", ret);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	hmdfs_close_path(file);
85162306a36Sopenharmony_ciout:
85262306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, ret);
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_civoid hmdfs_server_readpage(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
85662306a36Sopenharmony_ci			   void *data)
85762306a36Sopenharmony_ci{
85862306a36Sopenharmony_ci	struct readpage_request *readpage_recv = data;
85962306a36Sopenharmony_ci	__u64 file_ver;
86062306a36Sopenharmony_ci	__u32 file_id;
86162306a36Sopenharmony_ci	struct file *file = NULL;
86262306a36Sopenharmony_ci	loff_t pos;
86362306a36Sopenharmony_ci	struct readpage_response *readpage = NULL;
86462306a36Sopenharmony_ci	int ret = 0;
86562306a36Sopenharmony_ci	size_t read_len;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	file_id = le32_to_cpu(readpage_recv->file_id);
86862306a36Sopenharmony_ci	file_ver = le64_to_cpu(readpage_recv->file_ver);
86962306a36Sopenharmony_ci	file = get_file_by_fid_and_ver(con, cmd, file_id, file_ver);
87062306a36Sopenharmony_ci	if (IS_ERR(file)) {
87162306a36Sopenharmony_ci		hmdfs_info(
87262306a36Sopenharmony_ci			"file with id %u does not exist, pgindex %llu, devid %llu",
87362306a36Sopenharmony_ci			file_id, le64_to_cpu(readpage_recv->index),
87462306a36Sopenharmony_ci			con->device_id);
87562306a36Sopenharmony_ci		ret = PTR_ERR(file);
87662306a36Sopenharmony_ci		goto fail;
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	read_len = (size_t)le32_to_cpu(readpage_recv->size);
88062306a36Sopenharmony_ci	if (read_len == 0)
88162306a36Sopenharmony_ci		goto fail_put_file;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	readpage = kmalloc(read_len, GFP_KERNEL);
88462306a36Sopenharmony_ci	if (!readpage) {
88562306a36Sopenharmony_ci		ret = -ENOMEM;
88662306a36Sopenharmony_ci		goto fail_put_file;
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	pos = (loff_t)le64_to_cpu(readpage_recv->index) << HMDFS_PAGE_OFFSET;
89062306a36Sopenharmony_ci	ret = kernel_read(file, readpage->buf, read_len, &pos);
89162306a36Sopenharmony_ci	if (ret < 0) {
89262306a36Sopenharmony_ci		hmdfs_send_err_response(con, cmd, -EIO);
89362306a36Sopenharmony_ci	} else {
89462306a36Sopenharmony_ci		if (ret != read_len)
89562306a36Sopenharmony_ci			memset(readpage->buf + ret, 0, read_len - ret);
89662306a36Sopenharmony_ci		hmdfs_sendmessage_response(con, cmd, read_len, readpage, 0);
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	hmdfs_close_path(file);
90062306a36Sopenharmony_ci	kfree(readpage);
90162306a36Sopenharmony_ci	return;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_cifail_put_file:
90462306a36Sopenharmony_ci	hmdfs_close_path(file);
90562306a36Sopenharmony_cifail:
90662306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, ret);
90762306a36Sopenharmony_ci}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_cistatic bool need_rebuild_dcache(struct hmdfs_dcache_header *h,
91062306a36Sopenharmony_ci				struct hmdfs_time_t time,
91162306a36Sopenharmony_ci				unsigned int precision)
91262306a36Sopenharmony_ci{
91362306a36Sopenharmony_ci	struct hmdfs_time_t crtime = { .tv_sec = le64_to_cpu(h->dcache_crtime),
91462306a36Sopenharmony_ci				       .tv_nsec = le64_to_cpu(
91562306a36Sopenharmony_ci					       h->dcache_crtime_nsec) };
91662306a36Sopenharmony_ci	struct hmdfs_time_t ctime = { .tv_sec = le64_to_cpu(h->dentry_ctime),
91762306a36Sopenharmony_ci				      .tv_nsec = le64_to_cpu(
91862306a36Sopenharmony_ci					      h->dentry_ctime_nsec) };
91962306a36Sopenharmony_ci	struct hmdfs_time_t pre_time = { .tv_sec = precision / MSEC_PER_SEC,
92062306a36Sopenharmony_ci					 .tv_nsec = precision % MSEC_PER_SEC *
92162306a36Sopenharmony_ci						    NSEC_PER_MSEC };
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (hmdfs_time_compare(&time, &ctime) != 0)
92462306a36Sopenharmony_ci		return true;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	pre_time = hmdfs_time_add(time, pre_time);
92762306a36Sopenharmony_ci	if (hmdfs_time_compare(&crtime, &pre_time) < 0)
92862306a36Sopenharmony_ci		return true;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	return false;
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_cistatic bool hmdfs_server_cache_validate(struct file *filp, struct inode *inode,
93462306a36Sopenharmony_ci					unsigned long precision)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	struct hmdfs_dcache_header header;
93762306a36Sopenharmony_ci	int overallpage;
93862306a36Sopenharmony_ci	ssize_t bytes;
93962306a36Sopenharmony_ci	loff_t pos = 0;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	overallpage = get_dentry_group_cnt(file_inode(filp));
94262306a36Sopenharmony_ci	if (overallpage == 0) {
94362306a36Sopenharmony_ci		hmdfs_err("cache file size is 0");
94462306a36Sopenharmony_ci		return false;
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	bytes = kernel_read(filp, &header, sizeof(header), &pos);
94862306a36Sopenharmony_ci	if (bytes != sizeof(header)) {
94962306a36Sopenharmony_ci		hmdfs_err("read file failed, err:%zd", bytes);
95062306a36Sopenharmony_ci		return false;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	return !need_rebuild_dcache(&header, inode->__i_ctime, precision);
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistruct file *hmdfs_server_cache_revalidate(struct hmdfs_sb_info *sbi,
95762306a36Sopenharmony_ci					   const char *recvpath,
95862306a36Sopenharmony_ci					   struct path *path)
95962306a36Sopenharmony_ci{
96062306a36Sopenharmony_ci	struct cache_file_node *cfn = NULL;
96162306a36Sopenharmony_ci	struct file *file;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	cfn = find_cfn(sbi, HMDFS_SERVER_CID, recvpath, true);
96462306a36Sopenharmony_ci	if (!cfn)
96562306a36Sopenharmony_ci		return NULL;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	if (!hmdfs_server_cache_validate(cfn->filp, path->dentry->d_inode,
96862306a36Sopenharmony_ci					 sbi->dcache_precision)) {
96962306a36Sopenharmony_ci		remove_cfn(cfn);
97062306a36Sopenharmony_ci		release_cfn(cfn);
97162306a36Sopenharmony_ci		return NULL;
97262306a36Sopenharmony_ci	}
97362306a36Sopenharmony_ci	file = cfn->filp;
97462306a36Sopenharmony_ci	get_file(cfn->filp);
97562306a36Sopenharmony_ci	release_cfn(cfn);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	return file;
97862306a36Sopenharmony_ci}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_cibool hmdfs_client_cache_validate(struct hmdfs_sb_info *sbi,
98162306a36Sopenharmony_ci				 struct readdir_request *readdir_recv,
98262306a36Sopenharmony_ci				 struct path *path)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	struct inode *inode = path->dentry->d_inode;
98562306a36Sopenharmony_ci	struct hmdfs_dcache_header header;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	/* always rebuild dentryfile for small dir */
98862306a36Sopenharmony_ci	if (le64_to_cpu(readdir_recv->num) < sbi->dcache_threshold)
98962306a36Sopenharmony_ci		return false;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	header.dcache_crtime = readdir_recv->dcache_crtime;
99262306a36Sopenharmony_ci	header.dcache_crtime_nsec = readdir_recv->dcache_crtime_nsec;
99362306a36Sopenharmony_ci	header.dentry_ctime = readdir_recv->dentry_ctime;
99462306a36Sopenharmony_ci	header.dentry_ctime_nsec = readdir_recv->dentry_ctime_nsec;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	return !need_rebuild_dcache(&header, inode->__i_ctime,
99762306a36Sopenharmony_ci				    sbi->dcache_precision);
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_cistatic char *server_lower_dentry_path_raw(struct hmdfs_peer *peer,
100162306a36Sopenharmony_ci					  struct dentry *lo_d)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	struct hmdfs_dentry_info *di = hmdfs_d(peer->sbi->sb->s_root);
100462306a36Sopenharmony_ci	struct dentry *lo_d_root = di->lower_path.dentry;
100562306a36Sopenharmony_ci	struct dentry *lo_d_tmp = NULL;
100662306a36Sopenharmony_ci	char *lo_p_buf = NULL;
100762306a36Sopenharmony_ci	char *buf_head = NULL;
100862306a36Sopenharmony_ci	char *buf_tail = NULL;
100962306a36Sopenharmony_ci	size_t path_len = 0;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	lo_p_buf = kzalloc(PATH_MAX, GFP_KERNEL);
101262306a36Sopenharmony_ci	if (unlikely(!lo_p_buf))
101362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	/* To generate a reversed path str */
101662306a36Sopenharmony_ci	for (lo_d_tmp = lo_d; lo_d_tmp != lo_d_root && !IS_ROOT(lo_d_tmp);
101762306a36Sopenharmony_ci	     lo_d_tmp = lo_d_tmp->d_parent) {
101862306a36Sopenharmony_ci		u32 dlen = lo_d_tmp->d_name.len;
101962306a36Sopenharmony_ci		int reverse_index = dlen - 1;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci		/* Considering the appended slash and '\0' */
102262306a36Sopenharmony_ci		if (unlikely(path_len + dlen + 1 > PATH_MAX - 1)) {
102362306a36Sopenharmony_ci			kfree(lo_p_buf);
102462306a36Sopenharmony_ci			return ERR_PTR(-ENAMETOOLONG);
102562306a36Sopenharmony_ci		}
102662306a36Sopenharmony_ci		for (; reverse_index >= 0; --reverse_index)
102762306a36Sopenharmony_ci			lo_p_buf[path_len++] =
102862306a36Sopenharmony_ci				lo_d_tmp->d_name.name[reverse_index];
102962306a36Sopenharmony_ci		lo_p_buf[path_len++] = '/';
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	/* Reverse the reversed path str to get the real path str */
103362306a36Sopenharmony_ci	for (buf_head = lo_p_buf, buf_tail = lo_p_buf + path_len - 1;
103462306a36Sopenharmony_ci	     buf_head < buf_tail; ++buf_head, --buf_tail)
103562306a36Sopenharmony_ci		swap(*buf_head, *buf_tail);
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	if (path_len == 0)
103862306a36Sopenharmony_ci		lo_p_buf[0] = '/';
103962306a36Sopenharmony_ci	return lo_p_buf;
104062306a36Sopenharmony_ci}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_cistatic int server_lookup(struct hmdfs_peer *peer, const char *req_path,
104362306a36Sopenharmony_ci			 struct path *path)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	struct path root_path;
104662306a36Sopenharmony_ci	int err = 0;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	err = kern_path(peer->sbi->local_dst, 0, &root_path);
104962306a36Sopenharmony_ci	if (err)
105062306a36Sopenharmony_ci		goto out_noroot;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	err = vfs_path_lookup(root_path.dentry, root_path.mnt, req_path,
105362306a36Sopenharmony_ci			      LOOKUP_DIRECTORY, path);
105462306a36Sopenharmony_ci	path_put(&root_path);
105562306a36Sopenharmony_ciout_noroot:
105662306a36Sopenharmony_ci	return err;
105762306a36Sopenharmony_ci}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci/**
106062306a36Sopenharmony_ci * server_lookup_lower - lookup lower file-system
106162306a36Sopenharmony_ci * @peer: target device node
106262306a36Sopenharmony_ci * @req_path: abs path (mount point as the root) from the request
106362306a36Sopenharmony_ci * @lo_o: the lower path to return
106462306a36Sopenharmony_ci *
106562306a36Sopenharmony_ci * return the lower path's name, with characters' cases matched
106662306a36Sopenharmony_ci */
106762306a36Sopenharmony_cistatic char *server_lookup_lower(struct hmdfs_peer *peer, const char *req_path,
106862306a36Sopenharmony_ci				 struct path *lo_p)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	char *lo_p_name = ERR_PTR(-ENOENT);
107162306a36Sopenharmony_ci	struct path up_p;
107262306a36Sopenharmony_ci	int err = 0;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	err = server_lookup(peer, req_path, &up_p);
107562306a36Sopenharmony_ci	if (err)
107662306a36Sopenharmony_ci		goto out;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	hmdfs_get_lower_path(up_p.dentry, lo_p);
107962306a36Sopenharmony_ci	path_put(&up_p);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	lo_p_name = server_lower_dentry_path_raw(peer, lo_p->dentry);
108262306a36Sopenharmony_ci	if (IS_ERR(lo_p_name)) {
108362306a36Sopenharmony_ci		err = PTR_ERR(lo_p_name);
108462306a36Sopenharmony_ci		path_put(lo_p);
108562306a36Sopenharmony_ci	}
108662306a36Sopenharmony_ciout:
108762306a36Sopenharmony_ci	return err ? ERR_PTR(err) : lo_p_name;
108862306a36Sopenharmony_ci}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_civoid hmdfs_server_readdir(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
109162306a36Sopenharmony_ci			  void *data)
109262306a36Sopenharmony_ci{
109362306a36Sopenharmony_ci	struct readdir_request *readdir_recv = data;
109462306a36Sopenharmony_ci	struct path lo_p;
109562306a36Sopenharmony_ci	struct file *filp = NULL;
109662306a36Sopenharmony_ci	int err = 0;
109762306a36Sopenharmony_ci	unsigned long long num = 0;
109862306a36Sopenharmony_ci	char *lo_p_name = NULL;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	trace_hmdfs_server_readdir(readdir_recv);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	if (path_contain_dotdot(readdir_recv->path, readdir_recv->path_len)) {
110362306a36Sopenharmony_ci		err = -EINVAL;
110462306a36Sopenharmony_ci		goto send_err;
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	lo_p_name = server_lookup_lower(con, readdir_recv->path, &lo_p);
110862306a36Sopenharmony_ci	if (IS_ERR(lo_p_name)) {
110962306a36Sopenharmony_ci		err = PTR_ERR(lo_p_name);
111062306a36Sopenharmony_ci		hmdfs_info("Failed to get lower path: %d", err);
111162306a36Sopenharmony_ci		goto send_err;
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	if (le32_to_cpu(readdir_recv->verify_cache)) {
111562306a36Sopenharmony_ci		if (hmdfs_client_cache_validate(con->sbi, readdir_recv, &lo_p))
111662306a36Sopenharmony_ci			goto out_response;
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	filp = hmdfs_server_cache_revalidate(con->sbi, lo_p_name, &lo_p);
112062306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(filp)) {
112162306a36Sopenharmony_ci		filp = hmdfs_server_rebuild_dents(con->sbi, &lo_p, &num,
112262306a36Sopenharmony_ci						  lo_p_name);
112362306a36Sopenharmony_ci		if (IS_ERR_OR_NULL(filp)) {
112462306a36Sopenharmony_ci			err = PTR_ERR(filp);
112562306a36Sopenharmony_ci			goto err_lookup_path;
112662306a36Sopenharmony_ci		}
112762306a36Sopenharmony_ci	}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ciout_response:
113062306a36Sopenharmony_ci	err = hmdfs_readfile_response(con, cmd, filp);
113162306a36Sopenharmony_ci	if (!err)
113262306a36Sopenharmony_ci		hmdfs_add_remote_cache_list(con, lo_p_name);
113362306a36Sopenharmony_ci	if (num >= con->sbi->dcache_threshold)
113462306a36Sopenharmony_ci		cache_file_persistent(con, filp, lo_p_name, true);
113562306a36Sopenharmony_ci	if (filp)
113662306a36Sopenharmony_ci		fput(filp);
113762306a36Sopenharmony_cierr_lookup_path:
113862306a36Sopenharmony_ci	path_put(&lo_p);
113962306a36Sopenharmony_ci	kfree(lo_p_name);
114062306a36Sopenharmony_cisend_err:
114162306a36Sopenharmony_ci	if (err)
114262306a36Sopenharmony_ci		hmdfs_send_err_response(con, cmd, err);
114362306a36Sopenharmony_ci}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_civoid hmdfs_server_mkdir(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
114662306a36Sopenharmony_ci			void *data)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	int err = 0;
114962306a36Sopenharmony_ci	struct mkdir_request *mkdir_recv = data;
115062306a36Sopenharmony_ci	struct inode *child_inode = NULL;
115162306a36Sopenharmony_ci	struct dentry *dent = NULL;
115262306a36Sopenharmony_ci	char *mkdir_dir = NULL;
115362306a36Sopenharmony_ci	char *mkdir_name = NULL;
115462306a36Sopenharmony_ci	struct hmdfs_inodeinfo_response *mkdir_resp = NULL;
115562306a36Sopenharmony_ci	int respsize = sizeof(struct hmdfs_inodeinfo_response);
115662306a36Sopenharmony_ci	int path_len = le32_to_cpu(mkdir_recv->path_len);
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	mkdir_resp = kzalloc(respsize, GFP_KERNEL);
115962306a36Sopenharmony_ci	if (!mkdir_resp) {
116062306a36Sopenharmony_ci		err = -ENOMEM;
116162306a36Sopenharmony_ci		goto mkdir_out;
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	mkdir_dir = mkdir_recv->path;
116562306a36Sopenharmony_ci	mkdir_name = mkdir_recv->path + path_len + 1;
116662306a36Sopenharmony_ci	if (path_contain_dotdot(mkdir_dir, mkdir_recv->path_len)) {
116762306a36Sopenharmony_ci		err = -EINVAL;
116862306a36Sopenharmony_ci		goto mkdir_out;
116962306a36Sopenharmony_ci	}
117062306a36Sopenharmony_ci	if (path_contain_dotdot(mkdir_name, mkdir_recv->name_len)) {
117162306a36Sopenharmony_ci		err = -EINVAL;
117262306a36Sopenharmony_ci		goto mkdir_out;
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	dent = hmdfs_root_mkdir(con->device_id, con->sbi->local_dst,
117662306a36Sopenharmony_ci				mkdir_dir, mkdir_name,
117762306a36Sopenharmony_ci				le16_to_cpu(mkdir_recv->mode));
117862306a36Sopenharmony_ci	if (IS_ERR(dent)) {
117962306a36Sopenharmony_ci		err = PTR_ERR(dent);
118062306a36Sopenharmony_ci		hmdfs_err("hmdfs_root_mkdir failed err = %d", err);
118162306a36Sopenharmony_ci		goto mkdir_out;
118262306a36Sopenharmony_ci	}
118362306a36Sopenharmony_ci	child_inode = d_inode(dent);
118462306a36Sopenharmony_ci	mkdir_resp->i_mode = cpu_to_le16(child_inode->i_mode);
118562306a36Sopenharmony_ci	mkdir_resp->i_size = cpu_to_le64(child_inode->i_size);
118662306a36Sopenharmony_ci	mkdir_resp->i_mtime = cpu_to_le64(child_inode->i_mtime.tv_sec);
118762306a36Sopenharmony_ci	mkdir_resp->i_mtime_nsec = cpu_to_le32(child_inode->i_mtime.tv_nsec);
118862306a36Sopenharmony_ci	mkdir_resp->i_ino = cpu_to_le64(child_inode->i_ino);
118962306a36Sopenharmony_ci	dput(dent);
119062306a36Sopenharmony_cimkdir_out:
119162306a36Sopenharmony_ci	hmdfs_sendmessage_response(con, cmd, respsize, mkdir_resp, err);
119262306a36Sopenharmony_ci	kfree(mkdir_resp);
119362306a36Sopenharmony_ci}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_civoid hmdfs_server_create(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
119662306a36Sopenharmony_ci			 void *data)
119762306a36Sopenharmony_ci{
119862306a36Sopenharmony_ci	int err = 0;
119962306a36Sopenharmony_ci	struct create_request *create_recv = data;
120062306a36Sopenharmony_ci	struct inode *child_inode = NULL;
120162306a36Sopenharmony_ci	struct dentry *dent = NULL;
120262306a36Sopenharmony_ci	char *create_dir = NULL;
120362306a36Sopenharmony_ci	char *create_name = NULL;
120462306a36Sopenharmony_ci	struct hmdfs_inodeinfo_response *create_resp = NULL;
120562306a36Sopenharmony_ci	int respsize = sizeof(struct hmdfs_inodeinfo_response);
120662306a36Sopenharmony_ci	int path_len = le32_to_cpu(create_recv->path_len);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	create_resp = kzalloc(respsize, GFP_KERNEL);
120962306a36Sopenharmony_ci	if (!create_resp) {
121062306a36Sopenharmony_ci		err = -ENOMEM;
121162306a36Sopenharmony_ci		goto create_out;
121262306a36Sopenharmony_ci	}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	create_dir = create_recv->path;
121562306a36Sopenharmony_ci	create_name = create_recv->path + path_len + 1;
121662306a36Sopenharmony_ci	if (path_contain_dotdot(create_dir, create_recv->path_len)) {
121762306a36Sopenharmony_ci		err = -EINVAL;
121862306a36Sopenharmony_ci		goto create_out;
121962306a36Sopenharmony_ci	}
122062306a36Sopenharmony_ci	if (path_contain_dotdot(create_name, create_recv->name_len)) {
122162306a36Sopenharmony_ci		err = -EINVAL;
122262306a36Sopenharmony_ci		goto create_out;
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	dent = hmdfs_root_create(con->device_id, con->sbi->local_dst,
122662306a36Sopenharmony_ci				 create_dir, create_name,
122762306a36Sopenharmony_ci				 le16_to_cpu(create_recv->mode),
122862306a36Sopenharmony_ci				 create_recv->want_excl);
122962306a36Sopenharmony_ci	if (IS_ERR(dent)) {
123062306a36Sopenharmony_ci		err = PTR_ERR(dent);
123162306a36Sopenharmony_ci		hmdfs_err("hmdfs_root_create failed err = %d", err);
123262306a36Sopenharmony_ci		goto create_out;
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci	child_inode = d_inode(dent);
123562306a36Sopenharmony_ci	create_resp->i_mode = cpu_to_le16(child_inode->i_mode);
123662306a36Sopenharmony_ci	create_resp->i_size = cpu_to_le64(child_inode->i_size);
123762306a36Sopenharmony_ci	create_resp->i_mtime = cpu_to_le64(child_inode->i_mtime.tv_sec);
123862306a36Sopenharmony_ci	create_resp->i_mtime_nsec = cpu_to_le32(child_inode->i_mtime.tv_nsec);
123962306a36Sopenharmony_ci	/*
124062306a36Sopenharmony_ci	 * keep same as hmdfs_server_open,
124162306a36Sopenharmony_ci	 * to prevent hmdfs_open_final_remote from judging ino errors.
124262306a36Sopenharmony_ci	 */
124362306a36Sopenharmony_ci	create_resp->i_ino = cpu_to_le64(
124462306a36Sopenharmony_ci		generate_u64_ino(hmdfs_i(child_inode)->lower_inode->i_ino,
124562306a36Sopenharmony_ci				 child_inode->i_generation));
124662306a36Sopenharmony_ci	dput(dent);
124762306a36Sopenharmony_cicreate_out:
124862306a36Sopenharmony_ci	hmdfs_sendmessage_response(con, cmd, respsize, create_resp, err);
124962306a36Sopenharmony_ci	kfree(create_resp);
125062306a36Sopenharmony_ci}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_civoid hmdfs_server_rmdir(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
125362306a36Sopenharmony_ci			void *data)
125462306a36Sopenharmony_ci{
125562306a36Sopenharmony_ci	int err = 0;
125662306a36Sopenharmony_ci	struct path root_path;
125762306a36Sopenharmony_ci	char *path = NULL;
125862306a36Sopenharmony_ci	char *name = NULL;
125962306a36Sopenharmony_ci	struct rmdir_request *rmdir_recv = data;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	path = rmdir_recv->path;
126262306a36Sopenharmony_ci	name = rmdir_recv->path + le32_to_cpu(rmdir_recv->path_len) + 1;
126362306a36Sopenharmony_ci	if (path_contain_dotdot(path, rmdir_recv->path_len)) {
126462306a36Sopenharmony_ci		err = -EINVAL;
126562306a36Sopenharmony_ci		goto rmdir_out;
126662306a36Sopenharmony_ci	}
126762306a36Sopenharmony_ci	if (path_contain_dotdot(name, rmdir_recv->name_len)) {
126862306a36Sopenharmony_ci		err = -EINVAL;
126962306a36Sopenharmony_ci		goto rmdir_out;
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	err = kern_path(con->sbi->local_dst, 0, &root_path);
127362306a36Sopenharmony_ci	if (!err) {
127462306a36Sopenharmony_ci		err = hmdfs_root_rmdir(con->device_id, &root_path, path, name);
127562306a36Sopenharmony_ci		path_put(&root_path);
127662306a36Sopenharmony_ci	}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_cirmdir_out:
127962306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, err);
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_civoid hmdfs_server_unlink(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
128362306a36Sopenharmony_ci			 void *data)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	int err = 0;
128662306a36Sopenharmony_ci	struct path root_path;
128762306a36Sopenharmony_ci	char *path = NULL;
128862306a36Sopenharmony_ci	char *name = NULL;
128962306a36Sopenharmony_ci	struct unlink_request *unlink_recv = data;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	path = unlink_recv->path;
129262306a36Sopenharmony_ci	name = unlink_recv->path + le32_to_cpu(unlink_recv->path_len) + 1;
129362306a36Sopenharmony_ci	if (path_contain_dotdot(path, unlink_recv->path_len)) {
129462306a36Sopenharmony_ci		err = -EINVAL;
129562306a36Sopenharmony_ci		goto unlink_out;
129662306a36Sopenharmony_ci	}
129762306a36Sopenharmony_ci	if (path_contain_dotdot(name, unlink_recv->name_len)) {
129862306a36Sopenharmony_ci		err = -EINVAL;
129962306a36Sopenharmony_ci		goto unlink_out;
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	err = kern_path(con->sbi->local_dst, 0, &root_path);
130362306a36Sopenharmony_ci	if (!err) {
130462306a36Sopenharmony_ci		err = hmdfs_root_unlink(con->device_id, &root_path, path, name);
130562306a36Sopenharmony_ci		path_put(&root_path);
130662306a36Sopenharmony_ci	}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ciunlink_out:
130962306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, err);
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_civoid hmdfs_server_rename(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
131362306a36Sopenharmony_ci			 void *data)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	int err = 0;
131662306a36Sopenharmony_ci	int old_path_len;
131762306a36Sopenharmony_ci	int new_path_len;
131862306a36Sopenharmony_ci	int old_name_len;
131962306a36Sopenharmony_ci	int new_name_len;
132062306a36Sopenharmony_ci	unsigned int flags;
132162306a36Sopenharmony_ci	char *path_old = NULL;
132262306a36Sopenharmony_ci	char *name_old = NULL;
132362306a36Sopenharmony_ci	char *path_new = NULL;
132462306a36Sopenharmony_ci	char *name_new = NULL;
132562306a36Sopenharmony_ci	struct rename_request *recv = data;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	old_path_len = le32_to_cpu(recv->old_path_len);
132862306a36Sopenharmony_ci	new_path_len = le32_to_cpu(recv->new_path_len);
132962306a36Sopenharmony_ci	old_name_len = le32_to_cpu(recv->old_name_len);
133062306a36Sopenharmony_ci	new_name_len = le32_to_cpu(recv->new_name_len);
133162306a36Sopenharmony_ci	flags = le32_to_cpu(recv->flags);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	path_old = recv->path;
133462306a36Sopenharmony_ci	path_new = recv->path + old_path_len + 1;
133562306a36Sopenharmony_ci	name_old = recv->path + old_path_len + 1 + new_path_len + 1;
133662306a36Sopenharmony_ci	name_new = recv->path + old_path_len + 1 + new_path_len + 1 +
133762306a36Sopenharmony_ci		   old_name_len + 1;
133862306a36Sopenharmony_ci	if (path_contain_dotdot(path_old, old_path_len)) {
133962306a36Sopenharmony_ci		err = -EINVAL;
134062306a36Sopenharmony_ci		goto rename_out;
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci	if (path_contain_dotdot(path_new, new_path_len)) {
134362306a36Sopenharmony_ci		err = -EINVAL;
134462306a36Sopenharmony_ci		goto rename_out;
134562306a36Sopenharmony_ci	}
134662306a36Sopenharmony_ci	if (path_contain_dotdot(name_old, old_name_len)) {
134762306a36Sopenharmony_ci		err = -EINVAL;
134862306a36Sopenharmony_ci		goto rename_out;
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci	if (path_contain_dotdot(name_new, new_name_len)) {
135162306a36Sopenharmony_ci		err = -EINVAL;
135262306a36Sopenharmony_ci		goto rename_out;
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	err = hmdfs_root_rename(con->sbi, con->device_id, path_old, name_old,
135662306a36Sopenharmony_ci				path_new, name_new, flags);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_cirename_out:
135962306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, err);
136062306a36Sopenharmony_ci}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_cistatic int hmdfs_lookup_symlink(struct path *link_path, const char *path_fmt,
136362306a36Sopenharmony_ci						... )
136462306a36Sopenharmony_ci{
136562306a36Sopenharmony_ci	int ret;
136662306a36Sopenharmony_ci	va_list args;
136762306a36Sopenharmony_ci	char *path = kmalloc(PATH_MAX, GFP_KERNEL);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	if (!path)
137062306a36Sopenharmony_ci		return -ENOMEM;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	va_start(args, path_fmt);
137362306a36Sopenharmony_ci	ret = vsnprintf(path, PATH_MAX, path_fmt, args);
137462306a36Sopenharmony_ci	va_end(args);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	if(ret >= PATH_MAX) {
137762306a36Sopenharmony_ci		ret = -ENAMETOOLONG;
137862306a36Sopenharmony_ci		goto out;
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	ret = kern_path(path, LOOKUP_FOLLOW, link_path);
138262306a36Sopenharmony_ci	if (ret) {
138362306a36Sopenharmony_ci		hmdfs_err("kern_path failed err = %d", ret);
138462306a36Sopenharmony_ci		goto out;
138562306a36Sopenharmony_ci	}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	if (!S_ISREG(d_inode(link_path->dentry)->i_mode)) {
138862306a36Sopenharmony_ci		hmdfs_err("path is dir symlink");
138962306a36Sopenharmony_ci		path_put(link_path);
139062306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
139162306a36Sopenharmony_ci		goto out;
139262306a36Sopenharmony_ci	}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ciout:
139562306a36Sopenharmony_ci	kfree(path);
139662306a36Sopenharmony_ci	return ret;
139762306a36Sopenharmony_ci}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_cistruct dir_entry_info {
140062306a36Sopenharmony_ci	struct list_head list;
140162306a36Sopenharmony_ci	char *name;
140262306a36Sopenharmony_ci	int name_len;
140362306a36Sopenharmony_ci	unsigned int d_type;
140462306a36Sopenharmony_ci};
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_cistatic bool hmdfs_filldir_real(struct dir_context *ctx, const char *name,
140762306a36Sopenharmony_ci			      int name_len, long long offset, unsigned long long ino,
140862306a36Sopenharmony_ci			      unsigned int d_type)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	int res = 0;
141162306a36Sopenharmony_ci	char namestr[NAME_MAX + 1];
141262306a36Sopenharmony_ci	struct getdents_callback_real *gc = NULL;
141362306a36Sopenharmony_ci	struct dentry *child = NULL;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	if (name_len > NAME_MAX) {
141662306a36Sopenharmony_ci		hmdfs_err("name_len:%d NAME_MAX:%u", name_len, NAME_MAX);
141762306a36Sopenharmony_ci		goto out;
141862306a36Sopenharmony_ci	}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	gc = container_of(ctx, struct getdents_callback_real, ctx);
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	memcpy(namestr, name, name_len);
142362306a36Sopenharmony_ci	namestr[name_len] = '\0';
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	if (hmdfs_file_type(namestr) != HMDFS_TYPE_COMMON)
142662306a36Sopenharmony_ci		goto out;
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	/* parent lock already hold by iterate_dir */
142962306a36Sopenharmony_ci	child = lookup_one_len(name, gc->parent_path->dentry, name_len);
143062306a36Sopenharmony_ci	if (IS_ERR(child)) {
143162306a36Sopenharmony_ci		res = PTR_ERR(child);
143262306a36Sopenharmony_ci		hmdfs_err("lookup failed because %d", res);
143362306a36Sopenharmony_ci		goto out;
143462306a36Sopenharmony_ci	}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	if (d_really_is_negative(child)) {
143762306a36Sopenharmony_ci		dput(child);
143862306a36Sopenharmony_ci		hmdfs_err("lookup failed because negative dentry");
143962306a36Sopenharmony_ci		/* just do not fill this entry and continue for next entry */
144062306a36Sopenharmony_ci		goto out;
144162306a36Sopenharmony_ci	}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	if (d_type == DT_REG || d_type == DT_DIR) {
144462306a36Sopenharmony_ci		create_dentry(child, d_inode(child), gc->file, gc->sbi);
144562306a36Sopenharmony_ci		gc->num++;
144662306a36Sopenharmony_ci	} else if (d_type == DT_LNK) {
144762306a36Sopenharmony_ci		struct path link_path;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci		res = hmdfs_lookup_symlink(&link_path, "%s/%s/%s",
145062306a36Sopenharmony_ci						gc->sbi->local_src, gc->dir,
145162306a36Sopenharmony_ci						name);
145262306a36Sopenharmony_ci		if (!res) {
145362306a36Sopenharmony_ci			create_dentry(child, d_inode(link_path.dentry),
145462306a36Sopenharmony_ci						 gc->file, gc->sbi);
145562306a36Sopenharmony_ci			path_put(&link_path);
145662306a36Sopenharmony_ci			gc->num++;
145762306a36Sopenharmony_ci		} else if (res == -ENOENT) {
145862306a36Sopenharmony_ci			create_dentry(child, d_inode(child), gc->file, gc->sbi);
145962306a36Sopenharmony_ci			gc->num++;
146062306a36Sopenharmony_ci		}
146162306a36Sopenharmony_ci	}
146262306a36Sopenharmony_ci	dput(child);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ciout:
146562306a36Sopenharmony_ci	/*
146662306a36Sopenharmony_ci	 * we always return true here, so that the caller can continue to next
146762306a36Sopenharmony_ci	 * dentry even if failed on this dentry somehow.
146862306a36Sopenharmony_ci	 */
146962306a36Sopenharmony_ci	return true;
147062306a36Sopenharmony_ci}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_cistatic void hmdfs_server_set_header(struct hmdfs_dcache_header *header,
147362306a36Sopenharmony_ci				    struct file *file, struct file *dentry_file)
147462306a36Sopenharmony_ci{
147562306a36Sopenharmony_ci	struct inode *inode = NULL;
147662306a36Sopenharmony_ci	struct hmdfs_time_t cur_time;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	inode = file_inode(file);
147962306a36Sopenharmony_ci	cur_time = current_time(file_inode(dentry_file));
148062306a36Sopenharmony_ci	header->dcache_crtime = cpu_to_le64(cur_time.tv_sec);
148162306a36Sopenharmony_ci	header->dcache_crtime_nsec = cpu_to_le64(cur_time.tv_nsec);
148262306a36Sopenharmony_ci	header->dentry_ctime = cpu_to_le64(inode->__i_ctime.tv_sec);
148362306a36Sopenharmony_ci	header->dentry_ctime_nsec = cpu_to_le64(inode->__i_ctime.tv_nsec);
148462306a36Sopenharmony_ci}
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci// Get the dentries of target directory
148762306a36Sopenharmony_cistruct file *hmdfs_server_rebuild_dents(struct hmdfs_sb_info *sbi,
148862306a36Sopenharmony_ci					struct path *path, loff_t *num,
148962306a36Sopenharmony_ci					const char *dir)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	int err = 0;
149262306a36Sopenharmony_ci	struct getdents_callback_real gc = {
149362306a36Sopenharmony_ci		.ctx.actor = hmdfs_filldir_real,
149462306a36Sopenharmony_ci		.ctx.pos = 0,
149562306a36Sopenharmony_ci		.num = 0,
149662306a36Sopenharmony_ci		.sbi = sbi,
149762306a36Sopenharmony_ci		.dir = dir,
149862306a36Sopenharmony_ci	};
149962306a36Sopenharmony_ci	struct file *file = NULL;
150062306a36Sopenharmony_ci	struct file *dentry_file = NULL;
150162306a36Sopenharmony_ci	struct hmdfs_dcache_header header;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	dentry_file = create_local_dentry_file_cache(sbi);
150462306a36Sopenharmony_ci	if (IS_ERR(dentry_file)) {
150562306a36Sopenharmony_ci		hmdfs_err("file create failed err=%ld", PTR_ERR(dentry_file));
150662306a36Sopenharmony_ci		return dentry_file;
150762306a36Sopenharmony_ci	}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	file = dentry_open(path, O_RDONLY | O_DIRECTORY, current_cred());
151062306a36Sopenharmony_ci	if (IS_ERR(file)) {
151162306a36Sopenharmony_ci		err = PTR_ERR(file);
151262306a36Sopenharmony_ci		hmdfs_err("dentry_open failed");
151362306a36Sopenharmony_ci		goto out;
151462306a36Sopenharmony_ci	}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	hmdfs_server_set_header(&header, file, dentry_file);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	gc.parent_path = path;
151962306a36Sopenharmony_ci	gc.file = dentry_file;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	err = iterate_dir(file, &(gc.ctx));
152262306a36Sopenharmony_ci	if (err) {
152362306a36Sopenharmony_ci		hmdfs_err("iterate_dir failed");
152462306a36Sopenharmony_ci		goto out;
152562306a36Sopenharmony_ci	}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	header.case_sensitive = sbi->s_case_sensitive;
152862306a36Sopenharmony_ci	header.num = cpu_to_le64(gc.num);
152962306a36Sopenharmony_ci	if (num)
153062306a36Sopenharmony_ci		*num = gc.num;
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	err = write_header(dentry_file, &header);
153362306a36Sopenharmony_ciout:
153462306a36Sopenharmony_ci	if (!IS_ERR_OR_NULL(file))
153562306a36Sopenharmony_ci		fput(file);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	if (err) {
153862306a36Sopenharmony_ci		fput(dentry_file);
153962306a36Sopenharmony_ci		dentry_file = ERR_PTR(err);
154062306a36Sopenharmony_ci	}
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	trace_hmdfs_server_rebuild_dents(&header, err);
154362306a36Sopenharmony_ci	return dentry_file;
154462306a36Sopenharmony_ci}
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_civoid hmdfs_server_writepage(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
154762306a36Sopenharmony_ci			    void *data)
154862306a36Sopenharmony_ci{
154962306a36Sopenharmony_ci	struct writepage_request *writepage_recv = data;
155062306a36Sopenharmony_ci	struct hmdfs_server_writeback *hswb = NULL;
155162306a36Sopenharmony_ci	__u64 file_ver;
155262306a36Sopenharmony_ci	__u32 file_id;
155362306a36Sopenharmony_ci	struct file *file = NULL;
155462306a36Sopenharmony_ci	loff_t pos;
155562306a36Sopenharmony_ci	__u32 count;
155662306a36Sopenharmony_ci	ssize_t ret;
155762306a36Sopenharmony_ci	int err = 0;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	file_id = le32_to_cpu(writepage_recv->file_id);
156062306a36Sopenharmony_ci	file_ver = le64_to_cpu(writepage_recv->file_ver);
156162306a36Sopenharmony_ci	file = get_file_by_fid_and_ver(con, cmd, file_id, file_ver);
156262306a36Sopenharmony_ci	if (IS_ERR(file)) {
156362306a36Sopenharmony_ci		hmdfs_info(
156462306a36Sopenharmony_ci			"file with id %u does not exist, pgindex %llu, devid %llu",
156562306a36Sopenharmony_ci			file_id, le64_to_cpu(writepage_recv->index),
156662306a36Sopenharmony_ci			con->device_id);
156762306a36Sopenharmony_ci		err = PTR_ERR(file);
156862306a36Sopenharmony_ci		goto out;
156962306a36Sopenharmony_ci	}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	pos = (loff_t)le64_to_cpu(writepage_recv->index) << HMDFS_PAGE_OFFSET;
157262306a36Sopenharmony_ci	count = le32_to_cpu(writepage_recv->count);
157362306a36Sopenharmony_ci	ret = kernel_write(file, writepage_recv->buf, count, &pos);
157462306a36Sopenharmony_ci	if (ret != count)
157562306a36Sopenharmony_ci		err = -EIO;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	hmdfs_close_path(file);
157862306a36Sopenharmony_ciout:
157962306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, err);
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	hswb = con->sbi->h_swb;
158262306a36Sopenharmony_ci	if (!err && hswb->dirty_writeback_control)
158362306a36Sopenharmony_ci		hmdfs_server_check_writeback(hswb);
158462306a36Sopenharmony_ci}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_cistatic int hmdfs_lookup_linkpath(struct hmdfs_sb_info *sbi,
158762306a36Sopenharmony_ci				const char *path_name, struct path *dst_path)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	struct path link_path;
159062306a36Sopenharmony_ci	int err;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	err = hmdfs_lookup_symlink(&link_path, "%s/%s", sbi->local_dst,
159362306a36Sopenharmony_ci				path_name);
159462306a36Sopenharmony_ci	if (err)
159562306a36Sopenharmony_ci		return err;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	if (d_inode(link_path.dentry)->i_sb != sbi->sb) {
159862306a36Sopenharmony_ci		path_put(dst_path);
159962306a36Sopenharmony_ci		*dst_path = link_path;
160062306a36Sopenharmony_ci	} else {
160162306a36Sopenharmony_ci		path_put(&link_path);
160262306a36Sopenharmony_ci	}
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	return 0;
160562306a36Sopenharmony_ci}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_cistatic struct inode *hmdfs_verify_path(struct dentry *dentry, char *recv_buf,
160862306a36Sopenharmony_ci				       struct super_block *sb)
160962306a36Sopenharmony_ci{
161062306a36Sopenharmony_ci	struct inode *inode = d_inode(dentry);
161162306a36Sopenharmony_ci	struct hmdfs_inode_info *info = NULL;
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	/* if we found path from wrong fs */
161462306a36Sopenharmony_ci	if (inode->i_sb != sb) {
161562306a36Sopenharmony_ci		hmdfs_err("super block do not match");
161662306a36Sopenharmony_ci		return NULL;
161762306a36Sopenharmony_ci	}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	info = hmdfs_i(inode);
162062306a36Sopenharmony_ci	/* make sure lower inode is not NULL */
162162306a36Sopenharmony_ci	if (info->lower_inode)
162262306a36Sopenharmony_ci		return info->lower_inode;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	/*
162562306a36Sopenharmony_ci	 * we don't expect lower inode to be NULL in server. However, it's
162662306a36Sopenharmony_ci	 * possible because dentry cache can contain stale data.
162762306a36Sopenharmony_ci	 */
162862306a36Sopenharmony_ci	hmdfs_info("lower inode is NULL, is remote file: %d",
162962306a36Sopenharmony_ci		   info->conn != NULL);
163062306a36Sopenharmony_ci	return NULL;
163162306a36Sopenharmony_ci}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_cistatic int hmdfs_notify_change(struct vfsmount *mnt, struct dentry *dentry,
163462306a36Sopenharmony_ci			       struct iattr *attr,
163562306a36Sopenharmony_ci			       struct inode **delegated_inode)
163662306a36Sopenharmony_ci{
163762306a36Sopenharmony_ci#ifdef CONFIG_SDCARD_FS
163862306a36Sopenharmony_ci	/* sdcard_fs need to call setattr2, notify_change will call setattr */
163962306a36Sopenharmony_ci	return notify_change2(mnt, dentry, attr, delegated_inode);
164062306a36Sopenharmony_ci#else
164162306a36Sopenharmony_ci	return notify_change(&nop_mnt_idmap, dentry, attr, delegated_inode);
164262306a36Sopenharmony_ci#endif
164362306a36Sopenharmony_ci}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_civoid hmdfs_server_setattr(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
164662306a36Sopenharmony_ci			  void *data)
164762306a36Sopenharmony_ci{
164862306a36Sopenharmony_ci	int err = 0;
164962306a36Sopenharmony_ci	struct dentry *dentry = NULL;
165062306a36Sopenharmony_ci	struct inode *inode = NULL;
165162306a36Sopenharmony_ci	struct setattr_request *recv = data;
165262306a36Sopenharmony_ci	struct path root_path, dst_path;
165362306a36Sopenharmony_ci	struct iattr attr;
165462306a36Sopenharmony_ci	__u32 valid = le32_to_cpu(recv->valid);
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	if (path_contain_dotdot(recv->buf, recv->path_len)) {
165762306a36Sopenharmony_ci		err = -EINVAL;
165862306a36Sopenharmony_ci		goto out;
165962306a36Sopenharmony_ci	}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	err = kern_path(con->sbi->local_dst, 0, &root_path);
166262306a36Sopenharmony_ci	if (err) {
166362306a36Sopenharmony_ci		hmdfs_err("kern_path failed err = %d", err);
166462306a36Sopenharmony_ci		goto out;
166562306a36Sopenharmony_ci	}
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	err = vfs_path_lookup(root_path.dentry, root_path.mnt, recv->buf, 0,
166862306a36Sopenharmony_ci			      &dst_path);
166962306a36Sopenharmony_ci	if (err)
167062306a36Sopenharmony_ci		goto out_put_root;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	inode = hmdfs_verify_path(dst_path.dentry, recv->buf, con->sbi->sb);
167362306a36Sopenharmony_ci	if (!inode) {
167462306a36Sopenharmony_ci		err = -ENOENT;
167562306a36Sopenharmony_ci		goto out_put_dst;
167662306a36Sopenharmony_ci	}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	if (S_ISLNK(inode->i_mode)) {
167962306a36Sopenharmony_ci		err = hmdfs_lookup_linkpath(con->sbi, recv->buf, &dst_path);
168062306a36Sopenharmony_ci		if(err == -ENOENT)
168162306a36Sopenharmony_ci			err = 0;
168262306a36Sopenharmony_ci		else if (err)
168362306a36Sopenharmony_ci			goto out_put_dst;
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	dentry = dst_path.dentry;
168762306a36Sopenharmony_ci	memset(&attr, 0, sizeof(attr));
168862306a36Sopenharmony_ci	/* only support size and mtime */
168962306a36Sopenharmony_ci	if (valid & (ATTR_SIZE | ATTR_MTIME))
169062306a36Sopenharmony_ci		attr.ia_valid =
169162306a36Sopenharmony_ci			(valid & (ATTR_MTIME | ATTR_MTIME_SET | ATTR_SIZE));
169262306a36Sopenharmony_ci	attr.ia_size = le64_to_cpu(recv->size);
169362306a36Sopenharmony_ci	attr.ia_mtime.tv_sec = le64_to_cpu(recv->mtime);
169462306a36Sopenharmony_ci	attr.ia_mtime.tv_nsec = le32_to_cpu(recv->mtime_nsec);
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	inode_lock(dentry->d_inode);
169762306a36Sopenharmony_ci	err = hmdfs_notify_change(dst_path.mnt, dentry, &attr, NULL);
169862306a36Sopenharmony_ci	inode_unlock(dentry->d_inode);
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ciout_put_dst:
170162306a36Sopenharmony_ci	path_put(&dst_path);
170262306a36Sopenharmony_ciout_put_root:
170362306a36Sopenharmony_ci	path_put(&root_path);
170462306a36Sopenharmony_ciout:
170562306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, err);
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_cistatic void update_getattr_response(struct hmdfs_peer *con, struct inode *inode,
170962306a36Sopenharmony_ci				    struct kstat *ks,
171062306a36Sopenharmony_ci				    struct getattr_response *resp)
171162306a36Sopenharmony_ci{
171262306a36Sopenharmony_ci	/* if getattr for link, get ino and mode from actual lower inode */
171362306a36Sopenharmony_ci	resp->ino = cpu_to_le64(
171462306a36Sopenharmony_ci		generate_u64_ino(inode->i_ino, inode->i_generation));
171562306a36Sopenharmony_ci	resp->mode = cpu_to_le16(inode->i_mode);
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	/* get other information from vfs_getattr() */
171862306a36Sopenharmony_ci	resp->result_mask = cpu_to_le32(STATX_BASIC_STATS | STATX_BTIME);
171962306a36Sopenharmony_ci	resp->fsid = cpu_to_le64(ks->dev);
172062306a36Sopenharmony_ci	resp->nlink = cpu_to_le32(ks->nlink);
172162306a36Sopenharmony_ci	resp->uid = cpu_to_le32(ks->uid.val);
172262306a36Sopenharmony_ci	resp->gid = cpu_to_le32(ks->gid.val);
172362306a36Sopenharmony_ci	resp->size = cpu_to_le64(ks->size);
172462306a36Sopenharmony_ci	resp->blocks = cpu_to_le64(ks->blocks);
172562306a36Sopenharmony_ci	resp->blksize = cpu_to_le32(ks->blksize);
172662306a36Sopenharmony_ci	resp->atime = cpu_to_le64(ks->atime.tv_sec);
172762306a36Sopenharmony_ci	resp->atime_nsec = cpu_to_le32(ks->atime.tv_nsec);
172862306a36Sopenharmony_ci	resp->mtime = cpu_to_le64(ks->mtime.tv_sec);
172962306a36Sopenharmony_ci	resp->mtime_nsec = cpu_to_le32(ks->mtime.tv_nsec);
173062306a36Sopenharmony_ci	resp->ctime = cpu_to_le64(ks->ctime.tv_sec);
173162306a36Sopenharmony_ci	resp->ctime_nsec = cpu_to_le32(ks->ctime.tv_nsec);
173262306a36Sopenharmony_ci	resp->crtime = cpu_to_le64(ks->btime.tv_sec);
173362306a36Sopenharmony_ci	resp->crtime_nsec = cpu_to_le32(ks->btime.tv_nsec);
173462306a36Sopenharmony_ci}
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_civoid hmdfs_server_getattr(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
173762306a36Sopenharmony_ci			  void *data)
173862306a36Sopenharmony_ci{
173962306a36Sopenharmony_ci	int err = 0;
174062306a36Sopenharmony_ci	struct getattr_request *recv = data;
174162306a36Sopenharmony_ci	int size_read = sizeof(struct getattr_response);
174262306a36Sopenharmony_ci	struct getattr_response *resp = NULL;
174362306a36Sopenharmony_ci	struct kstat ks;
174462306a36Sopenharmony_ci	struct path root_path, dst_path;
174562306a36Sopenharmony_ci	struct inode *inode = NULL;
174662306a36Sopenharmony_ci	unsigned int recv_flags = le32_to_cpu(recv->lookup_flags);
174762306a36Sopenharmony_ci	unsigned int lookup_flags = 0;
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	if (path_contain_dotdot(recv->buf, recv->path_len)) {
175062306a36Sopenharmony_ci		err = -EINVAL;
175162306a36Sopenharmony_ci		goto err;
175262306a36Sopenharmony_ci	}
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	err = hmdfs_convert_lookup_flags(recv_flags, &lookup_flags);
175562306a36Sopenharmony_ci	if (err)
175662306a36Sopenharmony_ci		goto err;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	resp = kzalloc(size_read, GFP_KERNEL);
175962306a36Sopenharmony_ci	if (!resp) {
176062306a36Sopenharmony_ci		err = -ENOMEM;
176162306a36Sopenharmony_ci		goto err;
176262306a36Sopenharmony_ci	}
176362306a36Sopenharmony_ci	err = kern_path(con->sbi->local_dst, 0, &root_path);
176462306a36Sopenharmony_ci	if (err) {
176562306a36Sopenharmony_ci		hmdfs_err("kern_path failed err = %d", err);
176662306a36Sopenharmony_ci		goto err_free_resp;
176762306a36Sopenharmony_ci	}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	err = vfs_path_lookup(root_path.dentry, root_path.mnt, recv->buf,
177062306a36Sopenharmony_ci			      lookup_flags, &dst_path);
177162306a36Sopenharmony_ci	if (err)
177262306a36Sopenharmony_ci		goto out_put_root;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	inode = hmdfs_verify_path(dst_path.dentry, recv->buf, con->sbi->sb);
177562306a36Sopenharmony_ci	if (!inode) {
177662306a36Sopenharmony_ci		err = -ENOENT;
177762306a36Sopenharmony_ci		goto out_put_dst;
177862306a36Sopenharmony_ci	}
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	if (S_ISLNK(inode->i_mode)) {
178162306a36Sopenharmony_ci		err = hmdfs_lookup_linkpath(con->sbi, recv->buf, &dst_path);
178262306a36Sopenharmony_ci		if(err && err != -ENOENT)
178362306a36Sopenharmony_ci			goto out_put_dst;
178462306a36Sopenharmony_ci	}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	err = vfs_getattr(&dst_path, &ks, STATX_BASIC_STATS | STATX_BTIME, 0);
178762306a36Sopenharmony_ci	if (err)
178862306a36Sopenharmony_ci		goto err_put_dst;
178962306a36Sopenharmony_ci	update_getattr_response(con, inode, &ks, resp);
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ciout_put_dst:
179262306a36Sopenharmony_ci	path_put(&dst_path);
179362306a36Sopenharmony_ciout_put_root:
179462306a36Sopenharmony_ci	/*
179562306a36Sopenharmony_ci	 * if path lookup failed, we return with result_mask setting to
179662306a36Sopenharmony_ci	 * zero. So we can be aware of such situation in caller.
179762306a36Sopenharmony_ci	 */
179862306a36Sopenharmony_ci	if (err)
179962306a36Sopenharmony_ci		resp->result_mask = cpu_to_le32(0);
180062306a36Sopenharmony_ci	path_put(&root_path);
180162306a36Sopenharmony_ci	hmdfs_sendmessage_response(con, cmd, size_read, resp, err);
180262306a36Sopenharmony_ci	kfree(resp);
180362306a36Sopenharmony_ci	return;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_cierr_put_dst:
180662306a36Sopenharmony_ci	path_put(&dst_path);
180762306a36Sopenharmony_ci	path_put(&root_path);
180862306a36Sopenharmony_cierr_free_resp:
180962306a36Sopenharmony_ci	kfree(resp);
181062306a36Sopenharmony_cierr:
181162306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, err);
181262306a36Sopenharmony_ci}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_cistatic void init_statfs_response(struct statfs_response *resp,
181562306a36Sopenharmony_ci				 struct kstatfs *st)
181662306a36Sopenharmony_ci{
181762306a36Sopenharmony_ci	resp->f_type = cpu_to_le64(HMDFS_SUPER_MAGIC);
181862306a36Sopenharmony_ci	resp->f_bsize = cpu_to_le64(st->f_bsize);
181962306a36Sopenharmony_ci	resp->f_blocks = cpu_to_le64(st->f_blocks);
182062306a36Sopenharmony_ci	resp->f_bfree = cpu_to_le64(st->f_bfree);
182162306a36Sopenharmony_ci	resp->f_bavail = cpu_to_le64(st->f_bavail);
182262306a36Sopenharmony_ci	resp->f_files = cpu_to_le64(st->f_files);
182362306a36Sopenharmony_ci	resp->f_ffree = cpu_to_le64(st->f_ffree);
182462306a36Sopenharmony_ci	resp->f_fsid_0 = cpu_to_le32(st->f_fsid.val[0]);
182562306a36Sopenharmony_ci	resp->f_fsid_1 = cpu_to_le32(st->f_fsid.val[1]);
182662306a36Sopenharmony_ci	resp->f_namelen = cpu_to_le64(st->f_namelen);
182762306a36Sopenharmony_ci	resp->f_frsize = cpu_to_le64(st->f_frsize);
182862306a36Sopenharmony_ci	resp->f_flags = cpu_to_le64(st->f_flags);
182962306a36Sopenharmony_ci	/* f_spare is not used in f2fs or ext4 */
183062306a36Sopenharmony_ci	resp->f_spare_0 = cpu_to_le64(st->f_spare[0]);
183162306a36Sopenharmony_ci	resp->f_spare_1 = cpu_to_le64(st->f_spare[1]);
183262306a36Sopenharmony_ci	resp->f_spare_2 = cpu_to_le64(st->f_spare[2]);
183362306a36Sopenharmony_ci	resp->f_spare_3 = cpu_to_le64(st->f_spare[3]);
183462306a36Sopenharmony_ci}
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_civoid hmdfs_server_statfs(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
183762306a36Sopenharmony_ci			 void *data)
183862306a36Sopenharmony_ci{
183962306a36Sopenharmony_ci	struct statfs_request *recv = data;
184062306a36Sopenharmony_ci	struct statfs_response *resp = NULL;
184162306a36Sopenharmony_ci	struct path root_path, path;
184262306a36Sopenharmony_ci	struct kstatfs *st = NULL;
184362306a36Sopenharmony_ci	int err = 0;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	if (path_contain_dotdot(recv->path, recv->path_len)) {
184662306a36Sopenharmony_ci		err = -EINVAL;
184762306a36Sopenharmony_ci		goto out;
184862306a36Sopenharmony_ci	}
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	st = kzalloc(sizeof(*st), GFP_KERNEL);
185162306a36Sopenharmony_ci	if (!st) {
185262306a36Sopenharmony_ci		err = -ENOMEM;
185362306a36Sopenharmony_ci		goto out;
185462306a36Sopenharmony_ci	}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	resp = kmalloc(sizeof(*resp), GFP_KERNEL);
185762306a36Sopenharmony_ci	if (!resp) {
185862306a36Sopenharmony_ci		err = -ENOMEM;
185962306a36Sopenharmony_ci		goto free_st;
186062306a36Sopenharmony_ci	}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	err = kern_path(con->sbi->local_src, 0, &root_path);
186362306a36Sopenharmony_ci	if (err) {
186462306a36Sopenharmony_ci		hmdfs_info("kern_path failed err = %d", err);
186562306a36Sopenharmony_ci		goto free_st;
186662306a36Sopenharmony_ci	}
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci	err = vfs_path_lookup(root_path.dentry, root_path.mnt, recv->path, 0,
186962306a36Sopenharmony_ci			      &path);
187062306a36Sopenharmony_ci	if (err) {
187162306a36Sopenharmony_ci		hmdfs_info("recv->path found failed err = %d", err);
187262306a36Sopenharmony_ci		goto put_root;
187362306a36Sopenharmony_ci	}
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	err = vfs_statfs(&path, st);
187662306a36Sopenharmony_ci	if (err)
187762306a36Sopenharmony_ci		hmdfs_info("statfs local dentry failed, err = %d", err);
187862306a36Sopenharmony_ci	init_statfs_response(resp, st);
187962306a36Sopenharmony_ci	path_put(&path);
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ciput_root:
188262306a36Sopenharmony_ci	path_put(&root_path);
188362306a36Sopenharmony_cifree_st:
188462306a36Sopenharmony_ci	kfree(st);
188562306a36Sopenharmony_ciout:
188662306a36Sopenharmony_ci	if (err)
188762306a36Sopenharmony_ci		hmdfs_send_err_response(con, cmd, err);
188862306a36Sopenharmony_ci	else
188962306a36Sopenharmony_ci		hmdfs_sendmessage_response(con, cmd, sizeof(*resp), resp, 0);
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	kfree(resp);
189262306a36Sopenharmony_ci}
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_civoid hmdfs_server_syncfs(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
189562306a36Sopenharmony_ci			 void *data)
189662306a36Sopenharmony_ci{
189762306a36Sopenharmony_ci	/*
189862306a36Sopenharmony_ci	 * Reserved interface. There is a difference compared with traditional
189962306a36Sopenharmony_ci	 * syncfs process. Remote syncfs process in client:
190062306a36Sopenharmony_ci	 * 1. Remote writepages by async call
190162306a36Sopenharmony_ci	 * 2. Remote syncfs calling
190262306a36Sopenharmony_ci	 * 3. Wait all remote async calls(writepages) return in step 1
190362306a36Sopenharmony_ci	 */
190462306a36Sopenharmony_ci	int ret = 0;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, ret);
190762306a36Sopenharmony_ci}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_civoid hmdfs_server_getxattr(struct hmdfs_peer *con,
191062306a36Sopenharmony_ci			   struct hmdfs_head_cmd *cmd, void *data)
191162306a36Sopenharmony_ci{
191262306a36Sopenharmony_ci	struct getxattr_request *recv = data;
191362306a36Sopenharmony_ci	size_t size = le32_to_cpu(recv->size);
191462306a36Sopenharmony_ci	size_t size_read = sizeof(struct getxattr_response) + size;
191562306a36Sopenharmony_ci	struct getxattr_response *resp = NULL;
191662306a36Sopenharmony_ci	struct path root_path;
191762306a36Sopenharmony_ci	struct path path;
191862306a36Sopenharmony_ci	char *file_path = recv->buf;
191962306a36Sopenharmony_ci	char *name = recv->buf + recv->path_len + 1;
192062306a36Sopenharmony_ci	int err = -ENOMEM;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	if (path_contain_dotdot(file_path, recv->path_len)) {
192362306a36Sopenharmony_ci		err = -EINVAL;
192462306a36Sopenharmony_ci		goto err;
192562306a36Sopenharmony_ci	}
192662306a36Sopenharmony_ci	if (path_contain_dotdot(name, recv->name_len)) {
192762306a36Sopenharmony_ci		err = -EINVAL;
192862306a36Sopenharmony_ci		goto err;
192962306a36Sopenharmony_ci	}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	resp = kzalloc(size_read, GFP_KERNEL);
193262306a36Sopenharmony_ci	if (!resp) {
193362306a36Sopenharmony_ci		err = -ENOMEM;
193462306a36Sopenharmony_ci		goto err;
193562306a36Sopenharmony_ci	}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	err = kern_path(con->sbi->local_dst, LOOKUP_DIRECTORY, &root_path);
193862306a36Sopenharmony_ci	if (err) {
193962306a36Sopenharmony_ci		hmdfs_info("kern_path failed err = %d", err);
194062306a36Sopenharmony_ci		goto err_free_resp;
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	err = vfs_path_lookup(root_path.dentry, root_path.mnt,
194462306a36Sopenharmony_ci			      file_path, 0, &path);
194562306a36Sopenharmony_ci	if (err) {
194662306a36Sopenharmony_ci		hmdfs_info("path found failed err = %d", err);
194762306a36Sopenharmony_ci		goto err_put_root;
194862306a36Sopenharmony_ci	}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	if (!size)
195162306a36Sopenharmony_ci		err = vfs_getxattr(&nop_mnt_idmap, path.dentry, name, NULL, size);
195262306a36Sopenharmony_ci	else
195362306a36Sopenharmony_ci		err = vfs_getxattr(&nop_mnt_idmap, path.dentry, name, resp->value, size);
195462306a36Sopenharmony_ci	if (err < 0) {
195562306a36Sopenharmony_ci		hmdfs_info("getxattr failed err %d", err);
195662306a36Sopenharmony_ci		goto err_put_path;
195762306a36Sopenharmony_ci	}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	resp->size = cpu_to_le32(err);
196062306a36Sopenharmony_ci	hmdfs_sendmessage_response(con, cmd, size_read, resp, 0);
196162306a36Sopenharmony_ci	path_put(&path);
196262306a36Sopenharmony_ci	path_put(&root_path);
196362306a36Sopenharmony_ci	kfree(resp);
196462306a36Sopenharmony_ci	return;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_cierr_put_path:
196762306a36Sopenharmony_ci	path_put(&path);
196862306a36Sopenharmony_cierr_put_root:
196962306a36Sopenharmony_ci	path_put(&root_path);
197062306a36Sopenharmony_cierr_free_resp:
197162306a36Sopenharmony_ci	kfree(resp);
197262306a36Sopenharmony_cierr:
197362306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, err);
197462306a36Sopenharmony_ci}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_civoid hmdfs_server_setxattr(struct hmdfs_peer *con,
197762306a36Sopenharmony_ci			   struct hmdfs_head_cmd *cmd, void *data)
197862306a36Sopenharmony_ci{
197962306a36Sopenharmony_ci	struct setxattr_request *recv = data;
198062306a36Sopenharmony_ci	size_t size = le32_to_cpu(recv->size);
198162306a36Sopenharmony_ci	int flags = le32_to_cpu(recv->flags);
198262306a36Sopenharmony_ci	bool del = recv->del;
198362306a36Sopenharmony_ci	struct path root_path;
198462306a36Sopenharmony_ci	struct path path;
198562306a36Sopenharmony_ci	const char *file_path = recv->buf;
198662306a36Sopenharmony_ci	const char *name = recv->buf + recv->path_len + 1;
198762306a36Sopenharmony_ci	const void *value = name + recv->name_len + 1;
198862306a36Sopenharmony_ci	int err;
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci	if (path_contain_dotdot(file_path, recv->path_len)) {
199162306a36Sopenharmony_ci		err = -EINVAL;
199262306a36Sopenharmony_ci		goto err;
199362306a36Sopenharmony_ci	}
199462306a36Sopenharmony_ci	if (path_contain_dotdot(name, recv->name_len)) {
199562306a36Sopenharmony_ci		err = -EINVAL;
199662306a36Sopenharmony_ci		goto err;
199762306a36Sopenharmony_ci	}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	err = kern_path(con->sbi->local_dst, LOOKUP_DIRECTORY, &root_path);
200062306a36Sopenharmony_ci	if (err) {
200162306a36Sopenharmony_ci		hmdfs_info("kern_path failed err = %d", err);
200262306a36Sopenharmony_ci		goto err;
200362306a36Sopenharmony_ci	}
200462306a36Sopenharmony_ci	err = vfs_path_lookup(root_path.dentry, root_path.mnt,
200562306a36Sopenharmony_ci			      file_path, 0, &path);
200662306a36Sopenharmony_ci	if (err) {
200762306a36Sopenharmony_ci		hmdfs_info("path found failed err = %d", err);
200862306a36Sopenharmony_ci		goto err_put_root;
200962306a36Sopenharmony_ci	}
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	if (del) {
201262306a36Sopenharmony_ci		WARN_ON(flags != XATTR_REPLACE);
201362306a36Sopenharmony_ci		err = vfs_removexattr(&nop_mnt_idmap, path.dentry, name);
201462306a36Sopenharmony_ci	} else {
201562306a36Sopenharmony_ci		err = vfs_setxattr(&nop_mnt_idmap, path.dentry, name, value, size, flags);
201662306a36Sopenharmony_ci	}
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	path_put(&path);
201962306a36Sopenharmony_cierr_put_root:
202062306a36Sopenharmony_ci	path_put(&root_path);
202162306a36Sopenharmony_cierr:
202262306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, err);
202362306a36Sopenharmony_ci}
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_civoid hmdfs_server_listxattr(struct hmdfs_peer *con,
202662306a36Sopenharmony_ci			    struct hmdfs_head_cmd *cmd, void *data)
202762306a36Sopenharmony_ci{
202862306a36Sopenharmony_ci	struct listxattr_request *recv = data;
202962306a36Sopenharmony_ci	size_t size = le32_to_cpu(recv->size);
203062306a36Sopenharmony_ci	int size_read = sizeof(struct listxattr_response) + size;
203162306a36Sopenharmony_ci	struct listxattr_response *resp = NULL;
203262306a36Sopenharmony_ci	const char *file_path = recv->buf;
203362306a36Sopenharmony_ci	struct path root_path;
203462306a36Sopenharmony_ci	struct path path;
203562306a36Sopenharmony_ci	int err = 0;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	if (path_contain_dotdot(file_path, recv->path_len)) {
203862306a36Sopenharmony_ci		err = -EINVAL;
203962306a36Sopenharmony_ci		goto err;
204062306a36Sopenharmony_ci	}
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	resp = kzalloc(size_read, GFP_KERNEL);
204362306a36Sopenharmony_ci	if (!resp) {
204462306a36Sopenharmony_ci		err = -ENOMEM;
204562306a36Sopenharmony_ci		goto err;
204662306a36Sopenharmony_ci	}
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	err = kern_path(con->sbi->local_dst, LOOKUP_DIRECTORY, &root_path);
204962306a36Sopenharmony_ci	if (err) {
205062306a36Sopenharmony_ci		hmdfs_info("kern_path failed err = %d", err);
205162306a36Sopenharmony_ci		goto err_free_resp;
205262306a36Sopenharmony_ci	}
205362306a36Sopenharmony_ci	err = vfs_path_lookup(root_path.dentry, root_path.mnt,
205462306a36Sopenharmony_ci			      file_path, 0, &path);
205562306a36Sopenharmony_ci	if (err) {
205662306a36Sopenharmony_ci		hmdfs_info("path found failed err = %d", err);
205762306a36Sopenharmony_ci		goto err_put_root;
205862306a36Sopenharmony_ci	}
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	if (!size)
206162306a36Sopenharmony_ci		err = vfs_listxattr(path.dentry, NULL, size);
206262306a36Sopenharmony_ci	else
206362306a36Sopenharmony_ci		err = vfs_listxattr(path.dentry, resp->list, size);
206462306a36Sopenharmony_ci	if (err < 0) {
206562306a36Sopenharmony_ci		hmdfs_info("listxattr failed err = %d", err);
206662306a36Sopenharmony_ci		goto err_put_path;
206762306a36Sopenharmony_ci	}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	resp->size = cpu_to_le32(err);
207062306a36Sopenharmony_ci	hmdfs_sendmessage_response(con, cmd, size_read, resp, 0);
207162306a36Sopenharmony_ci	path_put(&root_path);
207262306a36Sopenharmony_ci	path_put(&path);
207362306a36Sopenharmony_ci	kfree(resp);
207462306a36Sopenharmony_ci	return;
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_cierr_put_path:
207762306a36Sopenharmony_ci	path_put(&path);
207862306a36Sopenharmony_cierr_put_root:
207962306a36Sopenharmony_ci	path_put(&root_path);
208062306a36Sopenharmony_cierr_free_resp:
208162306a36Sopenharmony_ci	kfree(resp);
208262306a36Sopenharmony_cierr:
208362306a36Sopenharmony_ci	hmdfs_send_err_response(con, cmd, err);
208462306a36Sopenharmony_ci}
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_civoid hmdfs_server_get_drop_push(struct hmdfs_peer *con,
208762306a36Sopenharmony_ci				struct hmdfs_head_cmd *cmd, void *data)
208862306a36Sopenharmony_ci{
208962306a36Sopenharmony_ci	struct drop_push_request *dp_recv = data;
209062306a36Sopenharmony_ci	struct path root_path, path;
209162306a36Sopenharmony_ci	int err;
209262306a36Sopenharmony_ci	char *tmp_path = NULL;
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	if (path_contain_dotdot(dp_recv->path, dp_recv->path_len)) {
209562306a36Sopenharmony_ci		err = -EINVAL;
209662306a36Sopenharmony_ci		goto quickack;
209762306a36Sopenharmony_ci	}
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	err = kern_path(con->sbi->real_dst, 0, &root_path);
210062306a36Sopenharmony_ci	if (err) {
210162306a36Sopenharmony_ci		hmdfs_err("kern_path failed err = %d", err);
210262306a36Sopenharmony_ci		goto quickack;
210362306a36Sopenharmony_ci	}
210462306a36Sopenharmony_ci	tmp_path = kzalloc(PATH_MAX, GFP_KERNEL);
210562306a36Sopenharmony_ci	if (!tmp_path)
210662306a36Sopenharmony_ci		goto out;
210762306a36Sopenharmony_ci	snprintf(tmp_path, PATH_MAX, "/" DEVICE_VIEW_ROOT "/%s%s",
210862306a36Sopenharmony_ci		 con->cid, dp_recv->path);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	err = vfs_path_lookup(root_path.dentry, root_path.mnt, tmp_path, 0,
211162306a36Sopenharmony_ci			      &path);
211262306a36Sopenharmony_ci	if (err) {
211362306a36Sopenharmony_ci		hmdfs_info("path found failed err = %d", err);
211462306a36Sopenharmony_ci		goto free;
211562306a36Sopenharmony_ci	}
211662306a36Sopenharmony_ci	hmdfs_remove_cache_filp(con, path.dentry);
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci	path_put(&path);
211962306a36Sopenharmony_cifree:
212062306a36Sopenharmony_ci	kfree(tmp_path);
212162306a36Sopenharmony_ciout:
212262306a36Sopenharmony_ci	path_put(&root_path);
212362306a36Sopenharmony_ciquickack:
212462306a36Sopenharmony_ci	set_conn_sock_quickack(con);
212562306a36Sopenharmony_ci}
2126