162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * fs/hmdfs/inode_remote.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/fs_stack.h>
962306a36Sopenharmony_ci#include <linux/namei.h>
1062306a36Sopenharmony_ci#include <linux/xattr.h>
1162306a36Sopenharmony_ci#include <linux/string.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "comm/socket_adapter.h"
1462306a36Sopenharmony_ci#include "hmdfs.h"
1562306a36Sopenharmony_ci#include "hmdfs_client.h"
1662306a36Sopenharmony_ci#include "hmdfs_dentryfile.h"
1762306a36Sopenharmony_ci#include "hmdfs_share.h"
1862306a36Sopenharmony_ci#include "hmdfs_trace.h"
1962306a36Sopenharmony_ci#include "authority/authentication.h"
2062306a36Sopenharmony_ci#include "stash.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct hmdfs_lookup_ret *lookup_remote_dentry(struct dentry *child_dentry,
2362306a36Sopenharmony_ci					      const struct qstr *qstr,
2462306a36Sopenharmony_ci					      uint64_t dev_id)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct hmdfs_lookup_ret *lookup_ret;
2762306a36Sopenharmony_ci	struct hmdfs_dentry *dentry = NULL;
2862306a36Sopenharmony_ci	struct clearcache_item *cache_item = NULL;
2962306a36Sopenharmony_ci	struct hmdfs_dcache_lookup_ctx ctx;
3062306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	cache_item = hmdfs_find_cache_item(dev_id, child_dentry->d_parent);
3362306a36Sopenharmony_ci	if (!cache_item)
3462306a36Sopenharmony_ci		return NULL;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	lookup_ret = kmalloc(sizeof(*lookup_ret), GFP_KERNEL);
3762306a36Sopenharmony_ci	if (!lookup_ret)
3862306a36Sopenharmony_ci		goto out;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	hmdfs_init_dcache_lookup_ctx(&ctx, sbi, qstr, cache_item->filp);
4162306a36Sopenharmony_ci	dentry = hmdfs_find_dentry(child_dentry, &ctx);
4262306a36Sopenharmony_ci	if (!dentry) {
4362306a36Sopenharmony_ci		kfree(lookup_ret);
4462306a36Sopenharmony_ci		lookup_ret = NULL;
4562306a36Sopenharmony_ci		goto out;
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	lookup_ret->i_mode = le16_to_cpu(dentry->i_mode);
4962306a36Sopenharmony_ci	lookup_ret->i_size = le64_to_cpu(dentry->i_size);
5062306a36Sopenharmony_ci	lookup_ret->i_mtime = le64_to_cpu(dentry->i_mtime);
5162306a36Sopenharmony_ci	lookup_ret->i_mtime_nsec = le32_to_cpu(dentry->i_mtime_nsec);
5262306a36Sopenharmony_ci	lookup_ret->i_ino = le64_to_cpu(dentry->i_ino);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	hmdfs_unlock_file(ctx.filp, get_dentry_group_pos(ctx.bidx),
5562306a36Sopenharmony_ci			  DENTRYGROUP_SIZE);
5662306a36Sopenharmony_ci	kfree(ctx.page);
5762306a36Sopenharmony_ciout:
5862306a36Sopenharmony_ci	kref_put(&cache_item->ref, release_cache_item);
5962306a36Sopenharmony_ci	return lookup_ret;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* get_remote_inode_info - fill hmdfs_lookup_ret by info from remote getattr
6362306a36Sopenharmony_ci *
6462306a36Sopenharmony_ci * @dentry: local dentry
6562306a36Sopenharmony_ci * @hmdfs_peer: which remote devcie
6662306a36Sopenharmony_ci * @flags: lookup flags
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * return allocaed and initialized hmdfs_lookup_ret on success, and NULL on
6962306a36Sopenharmony_ci * failure.
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_cistruct hmdfs_lookup_ret *get_remote_inode_info(struct hmdfs_peer *con,
7262306a36Sopenharmony_ci					       struct dentry *dentry,
7362306a36Sopenharmony_ci					       unsigned int flags)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	int err = 0;
7662306a36Sopenharmony_ci	struct hmdfs_lookup_ret *lookup_ret = NULL;
7762306a36Sopenharmony_ci	struct hmdfs_getattr_ret *getattr_ret = NULL;
7862306a36Sopenharmony_ci	unsigned int expected_flags = 0;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	lookup_ret = kmalloc(sizeof(*lookup_ret), GFP_KERNEL);
8162306a36Sopenharmony_ci	if (!lookup_ret)
8262306a36Sopenharmony_ci		return NULL;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	err = hmdfs_remote_getattr(con, dentry, flags, &getattr_ret);
8562306a36Sopenharmony_ci	if (err) {
8662306a36Sopenharmony_ci		hmdfs_debug("inode info get failed with err %d", err);
8762306a36Sopenharmony_ci		kfree(lookup_ret);
8862306a36Sopenharmony_ci		return NULL;
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci	/* make sure we got everything we need */
9162306a36Sopenharmony_ci	expected_flags = STATX_INO | STATX_SIZE | STATX_MODE | STATX_MTIME;
9262306a36Sopenharmony_ci	if ((getattr_ret->stat.result_mask & expected_flags) !=
9362306a36Sopenharmony_ci	    expected_flags) {
9462306a36Sopenharmony_ci		hmdfs_debug("remote getattr failed with flag %x",
9562306a36Sopenharmony_ci			    getattr_ret->stat.result_mask);
9662306a36Sopenharmony_ci		kfree(lookup_ret);
9762306a36Sopenharmony_ci		kfree(getattr_ret);
9862306a36Sopenharmony_ci		return NULL;
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	lookup_ret->i_mode = getattr_ret->stat.mode;
10262306a36Sopenharmony_ci	lookup_ret->i_size = getattr_ret->stat.size;
10362306a36Sopenharmony_ci	lookup_ret->i_mtime = getattr_ret->stat.mtime.tv_sec;
10462306a36Sopenharmony_ci	lookup_ret->i_mtime_nsec = getattr_ret->stat.mtime.tv_nsec;
10562306a36Sopenharmony_ci	lookup_ret->i_ino = getattr_ret->stat.ino;
10662306a36Sopenharmony_ci	kfree(getattr_ret);
10762306a36Sopenharmony_ci	return lookup_ret;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic void hmdfs_remote_readdir_work(struct work_struct *work)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct hmdfs_readdir_work *rw =
11362306a36Sopenharmony_ci		container_of(to_delayed_work(work), struct hmdfs_readdir_work,
11462306a36Sopenharmony_ci			     dwork);
11562306a36Sopenharmony_ci	struct dentry *dentry = rw->dentry;
11662306a36Sopenharmony_ci	struct hmdfs_peer *con = rw->con;
11762306a36Sopenharmony_ci	const struct cred *old_cred = hmdfs_override_creds(con->sbi->cred);
11862306a36Sopenharmony_ci	bool empty = false;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	get_remote_dentry_file(dentry, con);
12162306a36Sopenharmony_ci	hmdfs_d(dentry)->async_readdir_in_progress = 0;
12262306a36Sopenharmony_ci	hmdfs_revert_creds(old_cred);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	spin_lock(&con->sbi->async_readdir_work_lock);
12562306a36Sopenharmony_ci	list_del(&rw->head);
12662306a36Sopenharmony_ci	empty = list_empty(&con->sbi->async_readdir_work_list);
12762306a36Sopenharmony_ci	spin_unlock(&con->sbi->async_readdir_work_lock);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	dput(dentry);
13062306a36Sopenharmony_ci	peer_put(con);
13162306a36Sopenharmony_ci	kfree(rw);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (empty)
13462306a36Sopenharmony_ci		wake_up_interruptible(&con->sbi->async_readdir_wq);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void get_remote_dentry_file_in_wq(struct dentry *dentry,
13862306a36Sopenharmony_ci					 struct hmdfs_peer *con)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct hmdfs_readdir_work *rw = NULL;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* do nothing if async readdir is already in progress */
14362306a36Sopenharmony_ci	if (cmpxchg_relaxed(&hmdfs_d(dentry)->async_readdir_in_progress, 0,
14462306a36Sopenharmony_ci			     1))
14562306a36Sopenharmony_ci		return;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	rw = kmalloc(sizeof(*rw), GFP_KERNEL);
14862306a36Sopenharmony_ci	if (!rw) {
14962306a36Sopenharmony_ci		hmdfs_d(dentry)->async_readdir_in_progress = 0;
15062306a36Sopenharmony_ci		return;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	dget(dentry);
15462306a36Sopenharmony_ci	peer_get(con);
15562306a36Sopenharmony_ci	rw->dentry = dentry;
15662306a36Sopenharmony_ci	rw->con = con;
15762306a36Sopenharmony_ci	spin_lock(&con->sbi->async_readdir_work_lock);
15862306a36Sopenharmony_ci	INIT_DELAYED_WORK(&rw->dwork, hmdfs_remote_readdir_work);
15962306a36Sopenharmony_ci	list_add(&rw->head, &con->sbi->async_readdir_work_list);
16062306a36Sopenharmony_ci	spin_unlock(&con->sbi->async_readdir_work_lock);
16162306a36Sopenharmony_ci	queue_delayed_work(con->dentry_wq, &rw->dwork, 0);
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_civoid get_remote_dentry_file_sync(struct dentry *dentry, struct hmdfs_peer *con)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	get_remote_dentry_file_in_wq(dentry, con);
16762306a36Sopenharmony_ci	flush_workqueue(con->dentry_wq);
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistruct hmdfs_lookup_ret *hmdfs_lookup_by_con(struct hmdfs_peer *con,
17162306a36Sopenharmony_ci					     struct dentry *dentry,
17262306a36Sopenharmony_ci					     struct qstr *qstr,
17362306a36Sopenharmony_ci					     unsigned int flags,
17462306a36Sopenharmony_ci					     const char *relative_path)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct hmdfs_lookup_ret *result = NULL;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/*
17962306a36Sopenharmony_ci		* LOOKUP_REVAL means we found stale info from dentry file, thus
18062306a36Sopenharmony_ci		* we need to use remote getattr.
18162306a36Sopenharmony_ci		*/
18262306a36Sopenharmony_ci	if (flags & LOOKUP_REVAL) {
18362306a36Sopenharmony_ci		/*
18462306a36Sopenharmony_ci			* HMDFS_LOOKUP_REVAL means we need to skip dentry cache
18562306a36Sopenharmony_ci			* in lookup, because dentry cache in server might have
18662306a36Sopenharmony_ci			* stale data.
18762306a36Sopenharmony_ci			*/
18862306a36Sopenharmony_ci		result = get_remote_inode_info(con, dentry,
18962306a36Sopenharmony_ci						HMDFS_LOOKUP_REVAL);
19062306a36Sopenharmony_ci		get_remote_dentry_file_in_wq(dentry->d_parent, con);
19162306a36Sopenharmony_ci		return result;
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	/* If cache file is still valid */
19562306a36Sopenharmony_ci	if (hmdfs_cache_revalidate(READ_ONCE(con->conn_time),
19662306a36Sopenharmony_ci					con->device_id, dentry->d_parent)) {
19762306a36Sopenharmony_ci		result = lookup_remote_dentry(dentry, qstr,
19862306a36Sopenharmony_ci						con->device_id);
19962306a36Sopenharmony_ci		/*
20062306a36Sopenharmony_ci			* If lookup from cache file failed, use getattr to see
20162306a36Sopenharmony_ci			* if remote have created the file.
20262306a36Sopenharmony_ci			*/
20362306a36Sopenharmony_ci		if (!(flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) &&
20462306a36Sopenharmony_ci			!result)
20562306a36Sopenharmony_ci			result = get_remote_inode_info(con, dentry, 0);
20662306a36Sopenharmony_ci		/* If cache file expired, use getattr directly
20762306a36Sopenharmony_ci			* except create and rename opt
20862306a36Sopenharmony_ci			*/
20962306a36Sopenharmony_ci	} else {
21062306a36Sopenharmony_ci		result = get_remote_inode_info(con, dentry, 0);
21162306a36Sopenharmony_ci		get_remote_dentry_file_in_wq(dentry->d_parent, con);
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	return result;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/*
21862306a36Sopenharmony_ci * hmdfs_update_inode_size - update inode size when finding aready existed
21962306a36Sopenharmony_ci * inode.
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci * First of all, if the file is opened for writing, we don't update inode size
22262306a36Sopenharmony_ci * here, because inode size is about to be changed after writing.
22362306a36Sopenharmony_ci *
22462306a36Sopenharmony_ci * If the file is not opened, simply update getattr_isize(not actual inode size,
22562306a36Sopenharmony_ci * just a value showed to user). This is safe because inode size will be
22662306a36Sopenharmony_ci * up-to-date after open.
22762306a36Sopenharmony_ci *
22862306a36Sopenharmony_ci * If the file is opened for read:
22962306a36Sopenharmony_ci * a. getattr_isize == HMDFS_STALE_REMOTE_ISIZE
23062306a36Sopenharmony_ci *   1) i_size == new_size, nothing need to be done.
23162306a36Sopenharmony_ci *   2) i_size > new_size, we keep the i_size and set getattr_isize to new_size,
23262306a36Sopenharmony_ci *      stale data might be readed in this case, which is fine because file is
23362306a36Sopenharmony_ci *      opened before remote truncate the file.
23462306a36Sopenharmony_ci *   3) i_size < new_size, we drop the last page of the file if i_size is not
23562306a36Sopenharmony_ci *      aligned to PAGE_SIZE, clear getattr_isize, and update i_size to
23662306a36Sopenharmony_ci *      new_size.
23762306a36Sopenharmony_ci * b. getattr_isize != HMDFS_STALE_REMOTE_ISIZE, getattr_isize will only be set
23862306a36Sopenharmony_ci *    after 2).
23962306a36Sopenharmony_ci *   4) getattr_isize > i_size, this situation is impossible.
24062306a36Sopenharmony_ci *   5) i_size >= new_size, this case is the same as 2).
24162306a36Sopenharmony_ci *   6) i_size < new_size, this case is the same as 3).
24262306a36Sopenharmony_ci */
24362306a36Sopenharmony_cistatic void hmdfs_update_inode_size(struct inode *inode, uint64_t new_size)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
24662306a36Sopenharmony_ci	int writecount;
24762306a36Sopenharmony_ci	uint64_t size;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	inode_lock(inode);
25062306a36Sopenharmony_ci	size = info->getattr_isize;
25162306a36Sopenharmony_ci	if (size == HMDFS_STALE_REMOTE_ISIZE)
25262306a36Sopenharmony_ci		size = i_size_read(inode);
25362306a36Sopenharmony_ci	if (size == new_size) {
25462306a36Sopenharmony_ci		inode_unlock(inode);
25562306a36Sopenharmony_ci		return;
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	writecount = atomic_read(&inode->i_writecount);
25962306a36Sopenharmony_ci	/* check if writing is in progress */
26062306a36Sopenharmony_ci	if (writecount > 0) {
26162306a36Sopenharmony_ci		info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE;
26262306a36Sopenharmony_ci		inode_unlock(inode);
26362306a36Sopenharmony_ci		return;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/* check if there is no one who opens the file */
26762306a36Sopenharmony_ci	if (kref_read(&info->ref) == 0)
26862306a36Sopenharmony_ci		goto update_info;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/* check if there is someone who opens the file for read */
27162306a36Sopenharmony_ci	if (writecount == 0) {
27262306a36Sopenharmony_ci		uint64_t aligned_size;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci		/* use inode size here instead of getattr_isize */
27562306a36Sopenharmony_ci		size = i_size_read(inode);
27662306a36Sopenharmony_ci		if (new_size <= size)
27762306a36Sopenharmony_ci			goto update_info;
27862306a36Sopenharmony_ci		/*
27962306a36Sopenharmony_ci		 * if the old inode size is not aligned to HMDFS_PAGE_SIZE, we
28062306a36Sopenharmony_ci		 * need to drop the last page of the inode, otherwise zero will
28162306a36Sopenharmony_ci		 * be returned while reading the new range in the page after
28262306a36Sopenharmony_ci		 * chaning inode size.
28362306a36Sopenharmony_ci		 */
28462306a36Sopenharmony_ci		aligned_size = round_down(size, HMDFS_PAGE_SIZE);
28562306a36Sopenharmony_ci		if (aligned_size != size)
28662306a36Sopenharmony_ci			truncate_inode_pages(inode->i_mapping, aligned_size);
28762306a36Sopenharmony_ci		i_size_write(inode, new_size);
28862306a36Sopenharmony_ci		info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE;
28962306a36Sopenharmony_ci		inode_unlock(inode);
29062306a36Sopenharmony_ci		return;
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ciupdate_info:
29462306a36Sopenharmony_ci	info->getattr_isize = new_size;
29562306a36Sopenharmony_ci	inode_unlock(inode);
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic void hmdfs_update_inode(struct inode *inode,
29962306a36Sopenharmony_ci			       struct hmdfs_lookup_ret *lookup_result)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct hmdfs_time_t remote_mtime = {
30262306a36Sopenharmony_ci		.tv_sec = lookup_result->i_mtime,
30362306a36Sopenharmony_ci		.tv_nsec = lookup_result->i_mtime_nsec,
30462306a36Sopenharmony_ci	};
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/*
30762306a36Sopenharmony_ci	 * We only update mtime if the file is not opened for writing. If we do
30862306a36Sopenharmony_ci	 * update it before writing is about to start, user might see the mtime
30962306a36Sopenharmony_ci	 * up-and-down if system time in server and client do not match. However
31062306a36Sopenharmony_ci	 * mtime in client will eventually match server after timeout without
31162306a36Sopenharmony_ci	 * writing.
31262306a36Sopenharmony_ci	 */
31362306a36Sopenharmony_ci	if (!inode_is_open_for_write(inode))
31462306a36Sopenharmony_ci		inode->i_mtime = remote_mtime;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/*
31762306a36Sopenharmony_ci	 * We don't care i_size of dir, and lock inode for dir
31862306a36Sopenharmony_ci	 * might cause deadlock.
31962306a36Sopenharmony_ci	 */
32062306a36Sopenharmony_ci	if (S_ISREG(inode->i_mode))
32162306a36Sopenharmony_ci		hmdfs_update_inode_size(inode, lookup_result->i_size);
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic void hmdfs_fill_inode_remote(struct inode *inode, struct inode *dir,
32562306a36Sopenharmony_ci				     umode_t mode)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci#ifdef CONFIG_HMDFS_FS_PERMISSION
32862306a36Sopenharmony_ci	inode->i_uid = dir->i_uid;
32962306a36Sopenharmony_ci	inode->i_gid = dir->i_gid;
33062306a36Sopenharmony_ci#endif
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistruct inode *fill_inode_remote(struct super_block *sb, struct hmdfs_peer *con,
33462306a36Sopenharmony_ci				struct hmdfs_lookup_ret *res, struct inode *dir)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	int ret = 0;
33762306a36Sopenharmony_ci	struct inode *inode = NULL;
33862306a36Sopenharmony_ci	struct hmdfs_inode_info *info;
33962306a36Sopenharmony_ci	umode_t mode = res->i_mode;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	inode = hmdfs_iget5_locked_remote(sb, con, res->i_ino);
34262306a36Sopenharmony_ci	if (!inode)
34362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	info = hmdfs_i(inode);
34662306a36Sopenharmony_ci	info->inode_type = HMDFS_LAYER_OTHER_REMOTE;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* the inode was found in cache */
34962306a36Sopenharmony_ci	if (!(inode->i_state & I_NEW)) {
35062306a36Sopenharmony_ci		hmdfs_fill_inode_remote(inode, dir, mode);
35162306a36Sopenharmony_ci		hmdfs_update_inode(inode, res);
35262306a36Sopenharmony_ci		return inode;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	hmdfs_remote_init_stash_status(con, inode, mode);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	inode->__i_ctime.tv_sec = 0;
35862306a36Sopenharmony_ci	inode->__i_ctime.tv_nsec = 0;
35962306a36Sopenharmony_ci	inode->i_mtime.tv_sec = res->i_mtime;
36062306a36Sopenharmony_ci	inode->i_mtime.tv_nsec = res->i_mtime_nsec;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	inode->i_uid = KUIDT_INIT((uid_t)1000);
36362306a36Sopenharmony_ci	inode->i_gid = KGIDT_INIT((gid_t)1000);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (S_ISDIR(mode))
36662306a36Sopenharmony_ci		inode->i_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IXOTH;
36762306a36Sopenharmony_ci	else if (S_ISREG(mode))
36862306a36Sopenharmony_ci		inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
36962306a36Sopenharmony_ci	else if (S_ISLNK(mode))
37062306a36Sopenharmony_ci		inode->i_mode = S_IFREG | S_IRWXU | S_IRWXG;
37162306a36Sopenharmony_ci	else {
37262306a36Sopenharmony_ci		ret = -EIO;
37362306a36Sopenharmony_ci		goto bad_inode;
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (S_ISREG(mode) || S_ISLNK(mode)) {
37762306a36Sopenharmony_ci		inode->i_op = &hmdfs_dev_file_iops_remote;
37862306a36Sopenharmony_ci		inode->i_fop = &hmdfs_dev_file_fops_remote;
37962306a36Sopenharmony_ci		inode->i_size = res->i_size;
38062306a36Sopenharmony_ci		set_nlink(inode, 1);
38162306a36Sopenharmony_ci	} else if (S_ISDIR(mode)) {
38262306a36Sopenharmony_ci		inode->i_op = &hmdfs_dev_dir_inode_ops_remote;
38362306a36Sopenharmony_ci		inode->i_fop = &hmdfs_dev_dir_ops_remote;
38462306a36Sopenharmony_ci		set_nlink(inode, 2);
38562306a36Sopenharmony_ci	} else {
38662306a36Sopenharmony_ci		ret = -EIO;
38762306a36Sopenharmony_ci		goto bad_inode;
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	inode->i_mapping->a_ops = &hmdfs_dev_file_aops_remote;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	hmdfs_fill_inode_remote(inode, dir, mode);
39362306a36Sopenharmony_ci	unlock_new_inode(inode);
39462306a36Sopenharmony_ci	return inode;
39562306a36Sopenharmony_cibad_inode:
39662306a36Sopenharmony_ci	iget_failed(inode);
39762306a36Sopenharmony_ci	return ERR_PTR(ret);
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic struct dentry *hmdfs_lookup_remote_dentry(struct inode *parent_inode,
40162306a36Sopenharmony_ci						 struct dentry *child_dentry,
40262306a36Sopenharmony_ci						 int flags)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct dentry *ret = NULL;
40562306a36Sopenharmony_ci	struct inode *inode = NULL;
40662306a36Sopenharmony_ci	struct super_block *sb = parent_inode->i_sb;
40762306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = sb->s_fs_info;
40862306a36Sopenharmony_ci	struct hmdfs_lookup_ret *lookup_result = NULL;
40962306a36Sopenharmony_ci	struct hmdfs_peer *con = NULL;
41062306a36Sopenharmony_ci	char *file_name = NULL;
41162306a36Sopenharmony_ci	int file_name_len = child_dentry->d_name.len;
41262306a36Sopenharmony_ci	struct qstr qstr;
41362306a36Sopenharmony_ci	struct hmdfs_dentry_info *gdi = hmdfs_d(child_dentry);
41462306a36Sopenharmony_ci	uint64_t device_id = 0;
41562306a36Sopenharmony_ci	char *relative_path = NULL;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	file_name = kzalloc(NAME_MAX + 1, GFP_KERNEL);
41862306a36Sopenharmony_ci	if (!file_name)
41962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
42062306a36Sopenharmony_ci	strncpy(file_name, child_dentry->d_name.name, file_name_len);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	qstr.name = file_name;
42362306a36Sopenharmony_ci	qstr.len = strlen(file_name);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	device_id = gdi->device_id;
42662306a36Sopenharmony_ci	con = hmdfs_lookup_from_devid(sbi, device_id);
42762306a36Sopenharmony_ci	if (!con) {
42862306a36Sopenharmony_ci		ret = ERR_PTR(-ESHUTDOWN);
42962306a36Sopenharmony_ci		goto done;
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	relative_path = hmdfs_get_dentry_relative_path(child_dentry->d_parent);
43362306a36Sopenharmony_ci	if (unlikely(!relative_path)) {
43462306a36Sopenharmony_ci		ret = ERR_PTR(-ENOMEM);
43562306a36Sopenharmony_ci		hmdfs_err("get relative path failed %d", -ENOMEM);
43662306a36Sopenharmony_ci		goto done;
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	lookup_result = hmdfs_lookup_by_con(con, child_dentry, &qstr, flags,
44062306a36Sopenharmony_ci					    relative_path);
44162306a36Sopenharmony_ci	if (lookup_result != NULL) {
44262306a36Sopenharmony_ci		if (S_ISLNK(lookup_result->i_mode))
44362306a36Sopenharmony_ci			gdi->file_type = HM_SYMLINK;
44462306a36Sopenharmony_ci		else if (in_share_dir(child_dentry))
44562306a36Sopenharmony_ci			gdi->file_type = HM_SHARE;
44662306a36Sopenharmony_ci		inode = fill_inode_remote(sb, con, lookup_result, parent_inode);
44762306a36Sopenharmony_ci		check_and_fixup_ownership_remote(parent_inode,
44862306a36Sopenharmony_ci						 inode,
44962306a36Sopenharmony_ci						 child_dentry);
45062306a36Sopenharmony_ci		ret = d_splice_alias(inode, child_dentry);
45162306a36Sopenharmony_ci		if (!IS_ERR_OR_NULL(ret))
45262306a36Sopenharmony_ci			child_dentry = ret;
45362306a36Sopenharmony_ci	} else {
45462306a36Sopenharmony_ci		ret = ERR_PTR(-ENOENT);
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cidone:
45862306a36Sopenharmony_ci	if (con)
45962306a36Sopenharmony_ci		peer_put(con);
46062306a36Sopenharmony_ci	kfree(relative_path);
46162306a36Sopenharmony_ci	kfree(lookup_result);
46262306a36Sopenharmony_ci	kfree(file_name);
46362306a36Sopenharmony_ci	return ret;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistruct dentry *hmdfs_lookup_remote(struct inode *parent_inode,
46762306a36Sopenharmony_ci				   struct dentry *child_dentry,
46862306a36Sopenharmony_ci				   unsigned int flags)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	int err = 0;
47162306a36Sopenharmony_ci	struct dentry *ret = NULL;
47262306a36Sopenharmony_ci	struct hmdfs_dentry_info *gdi = NULL;
47362306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	trace_hmdfs_lookup_remote(parent_inode, child_dentry, flags);
47662306a36Sopenharmony_ci	if (child_dentry->d_name.len > NAME_MAX) {
47762306a36Sopenharmony_ci		err = -ENAMETOOLONG;
47862306a36Sopenharmony_ci		ret = ERR_PTR(-ENAMETOOLONG);
47962306a36Sopenharmony_ci		goto out;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	err = init_hmdfs_dentry_info(sbi, child_dentry,
48362306a36Sopenharmony_ci				     HMDFS_LAYER_OTHER_REMOTE);
48462306a36Sopenharmony_ci	if (err) {
48562306a36Sopenharmony_ci		ret = ERR_PTR(err);
48662306a36Sopenharmony_ci		goto out;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci	gdi = hmdfs_d(child_dentry);
48962306a36Sopenharmony_ci	gdi->device_id = hmdfs_d(child_dentry->d_parent)->device_id;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (is_current_hmdfs_server_ctx())
49262306a36Sopenharmony_ci		goto out;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	ret = hmdfs_lookup_remote_dentry(parent_inode, child_dentry, flags);
49562306a36Sopenharmony_ci	/*
49662306a36Sopenharmony_ci	 * don't return error if inode do not exist, so that vfs can continue
49762306a36Sopenharmony_ci	 * to create it.
49862306a36Sopenharmony_ci	 */
49962306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(ret)) {
50062306a36Sopenharmony_ci		err = PTR_ERR(ret);
50162306a36Sopenharmony_ci		if (err == -ENOENT)
50262306a36Sopenharmony_ci			ret = NULL;
50362306a36Sopenharmony_ci	} else {
50462306a36Sopenharmony_ci		child_dentry = ret;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ciout:
50862306a36Sopenharmony_ci	if (!err)
50962306a36Sopenharmony_ci		hmdfs_set_time(child_dentry, jiffies);
51062306a36Sopenharmony_ci	trace_hmdfs_lookup_remote_end(parent_inode, child_dentry, err);
51162306a36Sopenharmony_ci	return ret;
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci/* delete dentry in cache file */
51562306a36Sopenharmony_civoid delete_in_cache_file(uint64_t dev_id, struct dentry *dentry)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	struct clearcache_item *item = NULL;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	item = hmdfs_find_cache_item(dev_id, dentry->d_parent);
52062306a36Sopenharmony_ci	if (item) {
52162306a36Sopenharmony_ci		hmdfs_delete_dentry(dentry, item->filp);
52262306a36Sopenharmony_ci		kref_put(&item->ref, release_cache_item);
52362306a36Sopenharmony_ci	} else {
52462306a36Sopenharmony_ci		hmdfs_info("find cache item failed, con:%llu", dev_id);
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ciint hmdfs_mkdir_remote_dentry(struct hmdfs_peer *conn, struct dentry *dentry,
52962306a36Sopenharmony_ci			      umode_t mode)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	int err = 0;
53262306a36Sopenharmony_ci	char *dir_path = NULL;
53362306a36Sopenharmony_ci	struct dentry *parent_dentry = dentry->d_parent;
53462306a36Sopenharmony_ci	struct inode *parent_inode = d_inode(parent_dentry);
53562306a36Sopenharmony_ci	struct super_block *sb = parent_inode->i_sb;
53662306a36Sopenharmony_ci	const unsigned char *d_name = dentry->d_name.name;
53762306a36Sopenharmony_ci	struct hmdfs_lookup_ret *mkdir_ret = NULL;
53862306a36Sopenharmony_ci	struct inode *inode = NULL;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	mkdir_ret = kmalloc(sizeof(*mkdir_ret), GFP_KERNEL);
54162306a36Sopenharmony_ci	if (!mkdir_ret) {
54262306a36Sopenharmony_ci		err = -ENOMEM;
54362306a36Sopenharmony_ci		return err;
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci	dir_path = hmdfs_get_dentry_relative_path(parent_dentry);
54662306a36Sopenharmony_ci	if (!dir_path) {
54762306a36Sopenharmony_ci		err = -EACCES;
54862306a36Sopenharmony_ci		goto mkdir_out;
54962306a36Sopenharmony_ci	}
55062306a36Sopenharmony_ci	err = hmdfs_client_start_mkdir(conn, dir_path, d_name, mode, mkdir_ret);
55162306a36Sopenharmony_ci	if (err) {
55262306a36Sopenharmony_ci		hmdfs_err("hmdfs_client_start_mkdir failed err = %d", err);
55362306a36Sopenharmony_ci		goto mkdir_out;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci	if (mkdir_ret) {
55662306a36Sopenharmony_ci		inode = fill_inode_remote(sb, conn, mkdir_ret, parent_inode);
55762306a36Sopenharmony_ci		check_and_fixup_ownership_remote(parent_inode,
55862306a36Sopenharmony_ci						 inode,
55962306a36Sopenharmony_ci						 dentry);
56062306a36Sopenharmony_ci		if (!IS_ERR(inode))
56162306a36Sopenharmony_ci			d_add(dentry, inode);
56262306a36Sopenharmony_ci		else
56362306a36Sopenharmony_ci			err = PTR_ERR(inode);
56462306a36Sopenharmony_ci	} else {
56562306a36Sopenharmony_ci		err = -ENOENT;
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cimkdir_out:
56962306a36Sopenharmony_ci	kfree(dir_path);
57062306a36Sopenharmony_ci	kfree(mkdir_ret);
57162306a36Sopenharmony_ci	return err;
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ciint hmdfs_mkdir_remote(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	int err = 0;
57762306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(dir);
57862306a36Sopenharmony_ci	struct hmdfs_peer *con = info->conn;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	if (!con) {
58162306a36Sopenharmony_ci		hmdfs_warning("qpb_debug: con is null!");
58262306a36Sopenharmony_ci		goto out;
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	err = hmdfs_mkdir_remote_dentry(con, dentry, mode);
58662306a36Sopenharmony_ci	if (!err)
58762306a36Sopenharmony_ci		create_in_cache_file(con->device_id, dentry);
58862306a36Sopenharmony_ci	else
58962306a36Sopenharmony_ci		hmdfs_err("remote mkdir failed err = %d", err);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ciout:
59262306a36Sopenharmony_ci	trace_hmdfs_mkdir_remote(dir, dentry, err);
59362306a36Sopenharmony_ci	return err;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ciint hmdfs_create_remote_dentry(struct hmdfs_peer *conn, struct dentry *dentry,
59762306a36Sopenharmony_ci			       umode_t mode, bool want_excl)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	int err = 0;
60062306a36Sopenharmony_ci	char *dir_path = NULL;
60162306a36Sopenharmony_ci	struct dentry *parent_dentry = dentry->d_parent;
60262306a36Sopenharmony_ci	struct inode *parent_inode = d_inode(parent_dentry);
60362306a36Sopenharmony_ci	struct super_block *sb = parent_inode->i_sb;
60462306a36Sopenharmony_ci	const unsigned char *d_name = dentry->d_name.name;
60562306a36Sopenharmony_ci	struct hmdfs_lookup_ret *create_ret = NULL;
60662306a36Sopenharmony_ci	struct inode *inode = NULL;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	create_ret = kmalloc(sizeof(*create_ret), GFP_KERNEL);
60962306a36Sopenharmony_ci	if (!create_ret) {
61062306a36Sopenharmony_ci		err = -ENOMEM;
61162306a36Sopenharmony_ci		return err;
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci	dir_path = hmdfs_get_dentry_relative_path(parent_dentry);
61462306a36Sopenharmony_ci	if (!dir_path) {
61562306a36Sopenharmony_ci		err = -EACCES;
61662306a36Sopenharmony_ci		goto create_out;
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci	err = hmdfs_client_start_create(conn, dir_path, d_name, mode,
61962306a36Sopenharmony_ci					want_excl, create_ret);
62062306a36Sopenharmony_ci	if (err) {
62162306a36Sopenharmony_ci		hmdfs_err("hmdfs_client_start_create failed err = %d", err);
62262306a36Sopenharmony_ci		goto create_out;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci	if (create_ret) {
62562306a36Sopenharmony_ci		inode = fill_inode_remote(sb, conn, create_ret, parent_inode);
62662306a36Sopenharmony_ci		check_and_fixup_ownership_remote(parent_inode,
62762306a36Sopenharmony_ci						 inode,
62862306a36Sopenharmony_ci						 dentry);
62962306a36Sopenharmony_ci		if (!IS_ERR(inode))
63062306a36Sopenharmony_ci			d_add(dentry, inode);
63162306a36Sopenharmony_ci		else
63262306a36Sopenharmony_ci			err = PTR_ERR(inode);
63362306a36Sopenharmony_ci	} else {
63462306a36Sopenharmony_ci		err = -ENOENT;
63562306a36Sopenharmony_ci		hmdfs_err("get remote inode info failed err = %d", err);
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cicreate_out:
63962306a36Sopenharmony_ci	kfree(dir_path);
64062306a36Sopenharmony_ci	kfree(create_ret);
64162306a36Sopenharmony_ci	return err;
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ciint hmdfs_create_remote(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode,
64562306a36Sopenharmony_ci			bool want_excl)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	int err = 0;
64862306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(dir);
64962306a36Sopenharmony_ci	struct hmdfs_peer *con = info->conn;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	if (!con) {
65262306a36Sopenharmony_ci		hmdfs_warning("qpb_debug: con is null!");
65362306a36Sopenharmony_ci		goto out;
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	err = hmdfs_create_remote_dentry(con, dentry, mode, want_excl);
65762306a36Sopenharmony_ci	if (!err)
65862306a36Sopenharmony_ci		create_in_cache_file(con->device_id, dentry);
65962306a36Sopenharmony_ci	else
66062306a36Sopenharmony_ci		hmdfs_err("remote create failed err = %d", err);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ciout:
66362306a36Sopenharmony_ci	trace_hmdfs_create_remote(dir, dentry, err);
66462306a36Sopenharmony_ci	return err;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ciint hmdfs_rmdir_remote_dentry(struct hmdfs_peer *conn, struct dentry *dentry)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	int error = 0;
67062306a36Sopenharmony_ci	char *dir_path = NULL;
67162306a36Sopenharmony_ci	const char *dentry_name = dentry->d_name.name;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	dir_path = hmdfs_get_dentry_relative_path(dentry->d_parent);
67462306a36Sopenharmony_ci	if (!dir_path) {
67562306a36Sopenharmony_ci		error = -EACCES;
67662306a36Sopenharmony_ci		goto rmdir_out;
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	error = hmdfs_client_start_rmdir(conn, dir_path, dentry_name);
68062306a36Sopenharmony_ci	if (!error)
68162306a36Sopenharmony_ci		delete_in_cache_file(conn->device_id, dentry);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_cirmdir_out:
68462306a36Sopenharmony_ci	kfree(dir_path);
68562306a36Sopenharmony_ci	return error;
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ciint hmdfs_rmdir_remote(struct inode *dir, struct dentry *dentry)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	int err = 0;
69162306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(dentry->d_inode);
69262306a36Sopenharmony_ci	struct hmdfs_peer *con = info->conn;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	if (!con)
69562306a36Sopenharmony_ci		goto out;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) {
69862306a36Sopenharmony_ci		err = -EACCES;
69962306a36Sopenharmony_ci		goto out;
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	err = hmdfs_rmdir_remote_dentry(con, dentry);
70362306a36Sopenharmony_ci	/* drop dentry even remote failed
70462306a36Sopenharmony_ci	 * it maybe cause that one remote devices disconnect
70562306a36Sopenharmony_ci	 * when doing remote rmdir
70662306a36Sopenharmony_ci	 */
70762306a36Sopenharmony_ci	d_drop(dentry);
70862306a36Sopenharmony_ciout:
70962306a36Sopenharmony_ci	/* return connect device's errcode */
71062306a36Sopenharmony_ci	trace_hmdfs_rmdir_remote(dir, dentry, err);
71162306a36Sopenharmony_ci	return err;
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ciint hmdfs_dev_unlink_from_con(struct hmdfs_peer *conn, struct dentry *dentry)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	int error = 0;
71762306a36Sopenharmony_ci	char *dir_path = NULL;
71862306a36Sopenharmony_ci	const char *dentry_name = dentry->d_name.name;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	dir_path = hmdfs_get_dentry_relative_path(dentry->d_parent);
72162306a36Sopenharmony_ci	if (!dir_path) {
72262306a36Sopenharmony_ci		error = -EACCES;
72362306a36Sopenharmony_ci		goto unlink_out;
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci	error = hmdfs_client_start_unlink(conn, dir_path, dentry_name);
72662306a36Sopenharmony_ci	if (!error) {
72762306a36Sopenharmony_ci		delete_in_cache_file(conn->device_id, dentry);
72862306a36Sopenharmony_ci		drop_nlink(d_inode(dentry));
72962306a36Sopenharmony_ci		d_drop(dentry);
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ciunlink_out:
73262306a36Sopenharmony_ci	kfree(dir_path);
73362306a36Sopenharmony_ci	return error;
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ciint hmdfs_unlink_remote(struct inode *dir, struct dentry *dentry)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(dentry->d_inode);
73962306a36Sopenharmony_ci	struct hmdfs_peer *conn = info->conn;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON)
74262306a36Sopenharmony_ci		return -EACCES;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	if (!conn)
74562306a36Sopenharmony_ci		return 0;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (conn->status != NODE_STAT_ONLINE)
74862306a36Sopenharmony_ci		return 0;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	return hmdfs_dev_unlink_from_con(conn, dentry);
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci/* rename dentry in cache file */
75462306a36Sopenharmony_cistatic void rename_in_cache_file(uint64_t dev_id, struct dentry *old_dentry,
75562306a36Sopenharmony_ci				 struct dentry *new_dentry)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	struct clearcache_item *old_item = NULL;
75862306a36Sopenharmony_ci	struct clearcache_item *new_item = NULL;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	old_item = hmdfs_find_cache_item(dev_id, old_dentry->d_parent);
76162306a36Sopenharmony_ci	new_item = hmdfs_find_cache_item(dev_id, new_dentry->d_parent);
76262306a36Sopenharmony_ci	if (old_item != NULL && new_item != NULL) {
76362306a36Sopenharmony_ci		hmdfs_rename_dentry(old_dentry, new_dentry, old_item->filp,
76462306a36Sopenharmony_ci				    new_item->filp);
76562306a36Sopenharmony_ci	} else if (old_item != NULL) {
76662306a36Sopenharmony_ci		hmdfs_err("new cache item find failed!");
76762306a36Sopenharmony_ci	} else if (new_item != NULL) {
76862306a36Sopenharmony_ci		hmdfs_err("old cache item find failed!");
76962306a36Sopenharmony_ci	} else {
77062306a36Sopenharmony_ci		hmdfs_err("both cache item find failed!");
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	if (old_item)
77462306a36Sopenharmony_ci		kref_put(&old_item->ref, release_cache_item);
77562306a36Sopenharmony_ci	if (new_item)
77662306a36Sopenharmony_ci		kref_put(&new_item->ref, release_cache_item);
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ciint hmdfs_rename_remote(struct mnt_idmap *idmap, struct inode *old_dir, struct dentry *old_dentry,
78062306a36Sopenharmony_ci			struct inode *new_dir, struct dentry *new_dentry,
78162306a36Sopenharmony_ci			unsigned int flags)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	int err = 0;
78462306a36Sopenharmony_ci	int ret = 0;
78562306a36Sopenharmony_ci	const char *old_dentry_d_name = old_dentry->d_name.name;
78662306a36Sopenharmony_ci	char *relative_old_dir_path = 0;
78762306a36Sopenharmony_ci	const char *new_dentry_d_name = new_dentry->d_name.name;
78862306a36Sopenharmony_ci	char *relative_new_dir_path = 0;
78962306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(old_dentry->d_inode);
79062306a36Sopenharmony_ci	struct hmdfs_peer *con = info->conn;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	trace_hmdfs_rename_remote(old_dir, old_dentry, new_dir, new_dentry,
79362306a36Sopenharmony_ci				  flags);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	if (flags & ~RENAME_NOREPLACE)
79662306a36Sopenharmony_ci		return -EINVAL;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	if (hmdfs_file_type(old_dentry->d_name.name) != HMDFS_TYPE_COMMON ||
79962306a36Sopenharmony_ci	    hmdfs_file_type(new_dentry->d_name.name) != HMDFS_TYPE_COMMON) {
80062306a36Sopenharmony_ci		return -EACCES;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	if (hmdfs_i(old_dir)->inode_type != hmdfs_i(new_dir)->inode_type) {
80462306a36Sopenharmony_ci		hmdfs_err("in different view");
80562306a36Sopenharmony_ci		return -EPERM;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (hmdfs_d(old_dentry)->device_id != hmdfs_d(new_dentry)->device_id)
80962306a36Sopenharmony_ci		return -EXDEV;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	relative_old_dir_path =
81262306a36Sopenharmony_ci		hmdfs_get_dentry_relative_path(old_dentry->d_parent);
81362306a36Sopenharmony_ci	relative_new_dir_path =
81462306a36Sopenharmony_ci		hmdfs_get_dentry_relative_path(new_dentry->d_parent);
81562306a36Sopenharmony_ci	if (!relative_old_dir_path || !relative_new_dir_path) {
81662306a36Sopenharmony_ci		err = -EACCES;
81762306a36Sopenharmony_ci		goto rename_out;
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci	if (S_ISREG(old_dentry->d_inode->i_mode)) {
82062306a36Sopenharmony_ci		hmdfs_debug("send MSG to remote devID %llu",
82162306a36Sopenharmony_ci				con->device_id);
82262306a36Sopenharmony_ci		err = hmdfs_client_start_rename(
82362306a36Sopenharmony_ci			con, relative_old_dir_path, old_dentry_d_name,
82462306a36Sopenharmony_ci			relative_new_dir_path, new_dentry_d_name,
82562306a36Sopenharmony_ci			flags);
82662306a36Sopenharmony_ci		if (!err)
82762306a36Sopenharmony_ci			rename_in_cache_file(con->device_id, old_dentry,
82862306a36Sopenharmony_ci						new_dentry);
82962306a36Sopenharmony_ci	} else if (S_ISDIR(old_dentry->d_inode->i_mode)) {
83062306a36Sopenharmony_ci		if (con->status == NODE_STAT_ONLINE) {
83162306a36Sopenharmony_ci			ret = hmdfs_client_start_rename(
83262306a36Sopenharmony_ci				con, relative_old_dir_path, old_dentry_d_name,
83362306a36Sopenharmony_ci				relative_new_dir_path, new_dentry_d_name,
83462306a36Sopenharmony_ci				flags);
83562306a36Sopenharmony_ci			if (!ret)
83662306a36Sopenharmony_ci				rename_in_cache_file(con->device_id, old_dentry,
83762306a36Sopenharmony_ci						     new_dentry);
83862306a36Sopenharmony_ci			else
83962306a36Sopenharmony_ci				err = ret;
84062306a36Sopenharmony_ci		}
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci	if (!err)
84362306a36Sopenharmony_ci		d_invalidate(old_dentry);
84462306a36Sopenharmony_cirename_out:
84562306a36Sopenharmony_ci	kfree(relative_old_dir_path);
84662306a36Sopenharmony_ci	kfree(relative_new_dir_path);
84762306a36Sopenharmony_ci	return err;
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_cistatic int hmdfs_dir_setattr_remote(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *ia)
85162306a36Sopenharmony_ci{
85262306a36Sopenharmony_ci	// Do not support dir setattr
85362306a36Sopenharmony_ci	return 0;
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ciconst struct inode_operations hmdfs_dev_dir_inode_ops_remote = {
85762306a36Sopenharmony_ci	.lookup = hmdfs_lookup_remote,
85862306a36Sopenharmony_ci	.mkdir = hmdfs_mkdir_remote,
85962306a36Sopenharmony_ci	.create = hmdfs_create_remote,
86062306a36Sopenharmony_ci	.rmdir = hmdfs_rmdir_remote,
86162306a36Sopenharmony_ci	.unlink = hmdfs_unlink_remote,
86262306a36Sopenharmony_ci	.rename = hmdfs_rename_remote,
86362306a36Sopenharmony_ci	.setattr = hmdfs_dir_setattr_remote,
86462306a36Sopenharmony_ci	.permission = hmdfs_permission,
86562306a36Sopenharmony_ci};
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic int hmdfs_setattr_remote(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *ia)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(d_inode(dentry));
87062306a36Sopenharmony_ci	struct hmdfs_peer *conn = info->conn;
87162306a36Sopenharmony_ci	struct inode *inode = d_inode(dentry);
87262306a36Sopenharmony_ci	char *send_buf = NULL;
87362306a36Sopenharmony_ci	int err = 0;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	if (hmdfs_inode_is_stashing(info))
87662306a36Sopenharmony_ci		return -EAGAIN;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	send_buf = hmdfs_get_dentry_relative_path(dentry);
87962306a36Sopenharmony_ci	if (!send_buf) {
88062306a36Sopenharmony_ci		err = -ENOMEM;
88162306a36Sopenharmony_ci		goto out_free;
88262306a36Sopenharmony_ci	}
88362306a36Sopenharmony_ci	if (ia->ia_valid & ATTR_SIZE) {
88462306a36Sopenharmony_ci		err = inode_newsize_ok(inode, ia->ia_size);
88562306a36Sopenharmony_ci		if (err)
88662306a36Sopenharmony_ci			goto out_free;
88762306a36Sopenharmony_ci		truncate_setsize(inode, ia->ia_size);
88862306a36Sopenharmony_ci		info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE;
88962306a36Sopenharmony_ci	}
89062306a36Sopenharmony_ci	if (ia->ia_valid & ATTR_MTIME)
89162306a36Sopenharmony_ci		inode->i_mtime = ia->ia_mtime;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	if ((ia->ia_valid & ATTR_SIZE) || (ia->ia_valid & ATTR_MTIME)) {
89462306a36Sopenharmony_ci		struct setattr_info send_setattr_info = {
89562306a36Sopenharmony_ci			.size = cpu_to_le64(ia->ia_size),
89662306a36Sopenharmony_ci			.valid = cpu_to_le32(ia->ia_valid),
89762306a36Sopenharmony_ci			.mtime = cpu_to_le64(ia->ia_mtime.tv_sec),
89862306a36Sopenharmony_ci			.mtime_nsec = cpu_to_le32(ia->ia_mtime.tv_nsec),
89962306a36Sopenharmony_ci		};
90062306a36Sopenharmony_ci		err = hmdfs_send_setattr(conn, send_buf, &send_setattr_info);
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ciout_free:
90362306a36Sopenharmony_ci	kfree(send_buf);
90462306a36Sopenharmony_ci	return err;
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ciint hmdfs_remote_getattr(struct hmdfs_peer *conn, struct dentry *dentry,
90862306a36Sopenharmony_ci			 unsigned int lookup_flags,
90962306a36Sopenharmony_ci			 struct hmdfs_getattr_ret **result)
91062306a36Sopenharmony_ci{
91162306a36Sopenharmony_ci	char *send_buf = NULL;
91262306a36Sopenharmony_ci	struct hmdfs_getattr_ret *attr = NULL;
91362306a36Sopenharmony_ci	int err = 0;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (dentry->d_sb != conn->sbi->sb || !result)
91662306a36Sopenharmony_ci		return -EINVAL;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
91962306a36Sopenharmony_ci	if (!attr)
92062306a36Sopenharmony_ci		return -ENOMEM;
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	send_buf = hmdfs_get_dentry_relative_path(dentry);
92362306a36Sopenharmony_ci	if (!send_buf) {
92462306a36Sopenharmony_ci		kfree(attr);
92562306a36Sopenharmony_ci		return -ENOMEM;
92662306a36Sopenharmony_ci	}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	err = hmdfs_send_getattr(conn, send_buf, lookup_flags, attr);
92962306a36Sopenharmony_ci	kfree(send_buf);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	if (err) {
93262306a36Sopenharmony_ci		kfree(attr);
93362306a36Sopenharmony_ci		return err;
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	*result = attr;
93762306a36Sopenharmony_ci	return 0;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic int hmdfs_get_cached_attr_remote(struct mnt_idmap *idmap, const struct path *path,
94162306a36Sopenharmony_ci					struct kstat *stat, u32 request_mask,
94262306a36Sopenharmony_ci					unsigned int flags)
94362306a36Sopenharmony_ci{
94462306a36Sopenharmony_ci	struct inode *inode = d_inode(path->dentry);
94562306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
94662306a36Sopenharmony_ci	uint64_t size = info->getattr_isize;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	stat->ino = inode->i_ino;
94962306a36Sopenharmony_ci	stat->mtime = inode->i_mtime;
95062306a36Sopenharmony_ci	stat->mode = inode->i_mode;
95162306a36Sopenharmony_ci	stat->uid.val = inode->i_uid.val;
95262306a36Sopenharmony_ci	stat->gid.val = inode->i_gid.val;
95362306a36Sopenharmony_ci	if (size == HMDFS_STALE_REMOTE_ISIZE)
95462306a36Sopenharmony_ci		size = i_size_read(inode);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	stat->size = size;
95762306a36Sopenharmony_ci	return 0;
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_cissize_t hmdfs_remote_listxattr(struct dentry *dentry, char *list, size_t size)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	struct inode *inode = d_inode(dentry);
96362306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
96462306a36Sopenharmony_ci	struct hmdfs_peer *conn = info->conn;
96562306a36Sopenharmony_ci	char *send_buf = NULL;
96662306a36Sopenharmony_ci	ssize_t res = 0;
96762306a36Sopenharmony_ci	size_t r_size = size;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	if (!hmdfs_support_xattr(dentry))
97062306a36Sopenharmony_ci		return -EOPNOTSUPP;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	if (size > HMDFS_LISTXATTR_SIZE_MAX)
97362306a36Sopenharmony_ci		r_size = HMDFS_LISTXATTR_SIZE_MAX;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	send_buf = hmdfs_get_dentry_relative_path(dentry);
97662306a36Sopenharmony_ci	if (!send_buf)
97762306a36Sopenharmony_ci		return -ENOMEM;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	res = hmdfs_send_listxattr(conn, send_buf, list, r_size);
98062306a36Sopenharmony_ci	kfree(send_buf);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	if (res == -ERANGE && r_size != size) {
98362306a36Sopenharmony_ci		hmdfs_info("no support listxattr size over than %d",
98462306a36Sopenharmony_ci			   HMDFS_LISTXATTR_SIZE_MAX);
98562306a36Sopenharmony_ci		res = -E2BIG;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	return res;
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ciconst struct inode_operations hmdfs_dev_file_iops_remote = {
99262306a36Sopenharmony_ci	.setattr = hmdfs_setattr_remote,
99362306a36Sopenharmony_ci	.permission = hmdfs_permission,
99462306a36Sopenharmony_ci	.getattr = hmdfs_get_cached_attr_remote,
99562306a36Sopenharmony_ci	.listxattr = hmdfs_remote_listxattr,
99662306a36Sopenharmony_ci};
997