162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * fs/hmdfs/inode_cloud_merge.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "hmdfs_merge_view.h"
962306a36Sopenharmony_ci#include <linux/atomic.h>
1062306a36Sopenharmony_ci#include <linux/fs.h>
1162306a36Sopenharmony_ci#include <linux/fs_stack.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/list.h>
1462306a36Sopenharmony_ci#include <linux/mount.h>
1562306a36Sopenharmony_ci#include <linux/namei.h>
1662306a36Sopenharmony_ci#include <linux/rwsem.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/types.h>
1962306a36Sopenharmony_ci#include "authority/authentication.h"
2062306a36Sopenharmony_ci#include "hmdfs_trace.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic struct inode *fill_inode_merge(struct super_block *sb,
2362306a36Sopenharmony_ci				      struct inode *parent_inode,
2462306a36Sopenharmony_ci				      struct dentry *child_dentry,
2562306a36Sopenharmony_ci				      struct dentry *lo_d_dentry)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	int ret = 0;
2862306a36Sopenharmony_ci	struct dentry *fst_lo_d = NULL;
2962306a36Sopenharmony_ci	struct hmdfs_inode_info *info = NULL;
3062306a36Sopenharmony_ci	struct inode *inode = NULL;
3162306a36Sopenharmony_ci	umode_t mode;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	if (lo_d_dentry) {
3462306a36Sopenharmony_ci		fst_lo_d = lo_d_dentry;
3562306a36Sopenharmony_ci		dget(fst_lo_d);
3662306a36Sopenharmony_ci	} else {
3762306a36Sopenharmony_ci		fst_lo_d = hmdfs_get_fst_lo_d(child_dentry);
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci	if (!fst_lo_d) {
4062306a36Sopenharmony_ci		inode = ERR_PTR(-EINVAL);
4162306a36Sopenharmony_ci		goto out;
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci	if (hmdfs_i(parent_inode)->inode_type == HMDFS_LAYER_ZERO)
4462306a36Sopenharmony_ci		inode = hmdfs_iget_locked_root(sb, HMDFS_ROOT_MERGE_CLOUD, NULL,
4562306a36Sopenharmony_ci					       NULL);
4662306a36Sopenharmony_ci	else
4762306a36Sopenharmony_ci		inode = hmdfs_iget5_locked_cloud_merge(sb, fst_lo_d);
4862306a36Sopenharmony_ci	if (!inode) {
4962306a36Sopenharmony_ci		hmdfs_err("iget5_locked get inode NULL");
5062306a36Sopenharmony_ci		inode = ERR_PTR(-ENOMEM);
5162306a36Sopenharmony_ci		goto out;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci	if (!(inode->i_state & I_NEW))
5462306a36Sopenharmony_ci		goto out;
5562306a36Sopenharmony_ci	info = hmdfs_i(inode);
5662306a36Sopenharmony_ci	if (hmdfs_i(parent_inode)->inode_type == HMDFS_LAYER_ZERO)
5762306a36Sopenharmony_ci		info->inode_type = HMDFS_LAYER_FIRST_MERGE_CLOUD;
5862306a36Sopenharmony_ci	else
5962306a36Sopenharmony_ci		info->inode_type = HMDFS_LAYER_OTHER_MERGE_CLOUD;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	inode->i_uid = USER_DATA_RW_UID;
6262306a36Sopenharmony_ci	inode->i_gid = USER_DATA_RW_GID;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	update_inode_attr(inode, child_dentry);
6562306a36Sopenharmony_ci	mode = d_inode(fst_lo_d)->i_mode;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (S_ISREG(mode)) {
6862306a36Sopenharmony_ci		inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
6962306a36Sopenharmony_ci		inode->i_op = &hmdfs_file_iops_cloud_merge;
7062306a36Sopenharmony_ci		inode->i_fop = &hmdfs_file_fops_merge;
7162306a36Sopenharmony_ci		set_nlink(inode, 1);
7262306a36Sopenharmony_ci	} else if (S_ISDIR(mode)) {
7362306a36Sopenharmony_ci		inode->i_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IXOTH;
7462306a36Sopenharmony_ci		inode->i_op = &hmdfs_dir_iops_cloud_merge;
7562306a36Sopenharmony_ci		inode->i_fop = &hmdfs_dir_fops_merge;
7662306a36Sopenharmony_ci		set_nlink(inode, get_num_comrades(child_dentry) + 2);
7762306a36Sopenharmony_ci	} else {
7862306a36Sopenharmony_ci		ret = -EIO;
7962306a36Sopenharmony_ci		goto bad_inode;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	unlock_new_inode(inode);
8362306a36Sopenharmony_ciout:
8462306a36Sopenharmony_ci	dput(fst_lo_d);
8562306a36Sopenharmony_ci	return inode;
8662306a36Sopenharmony_cibad_inode:
8762306a36Sopenharmony_ci	iget_failed(inode);
8862306a36Sopenharmony_ci	return ERR_PTR(ret);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic struct hmdfs_dentry_comrade *
9262306a36Sopenharmony_cicloud_merge_lookup_comrade(struct hmdfs_sb_info *sbi,
9362306a36Sopenharmony_ci			   const char *name,
9462306a36Sopenharmony_ci			   int devid,
9562306a36Sopenharmony_ci			   unsigned int flags)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	int err;
9862306a36Sopenharmony_ci	struct path root, path;
9962306a36Sopenharmony_ci	struct hmdfs_dentry_comrade *comrade = NULL;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	err = kern_path(sbi->real_dst, LOOKUP_DIRECTORY, &root);
10262306a36Sopenharmony_ci	if (err) {
10362306a36Sopenharmony_ci		comrade = ERR_PTR(err);
10462306a36Sopenharmony_ci		goto out;
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	err = vfs_path_lookup(root.dentry, root.mnt, name, flags, &path);
10862306a36Sopenharmony_ci	if (err) {
10962306a36Sopenharmony_ci		comrade = ERR_PTR(err);
11062306a36Sopenharmony_ci		goto root_put;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	comrade = alloc_comrade(path.dentry, devid);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	path_put(&path);
11662306a36Sopenharmony_ciroot_put:
11762306a36Sopenharmony_ci	path_put(&root);
11862306a36Sopenharmony_ciout:
11962306a36Sopenharmony_ci	return comrade;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic void merge_lookup_sync(struct hmdfs_dentry_info_merge *mdi,
12362306a36Sopenharmony_ci			     struct hmdfs_sb_info *sbi,
12462306a36Sopenharmony_ci			     int devid,
12562306a36Sopenharmony_ci			     const char *name,
12662306a36Sopenharmony_ci			     unsigned int flags)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct hmdfs_dentry_comrade *comrade;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	comrade = cloud_merge_lookup_comrade(sbi, name, devid, flags);
13162306a36Sopenharmony_ci	if (IS_ERR(comrade))
13262306a36Sopenharmony_ci		return;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	mutex_lock(&mdi->comrade_list_lock);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (!is_valid_comrade(mdi, hmdfs_cm(comrade)))
13762306a36Sopenharmony_ci		destroy_comrade(comrade);
13862306a36Sopenharmony_ci	else
13962306a36Sopenharmony_ci		link_comrade(&mdi->comrade_list, comrade);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	mutex_unlock(&mdi->comrade_list_lock);
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int lookup_merge_normal(struct dentry *dentry, unsigned int flags)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	int ret = -ENOMEM;
14762306a36Sopenharmony_ci	int devid = -1;
14862306a36Sopenharmony_ci	struct dentry *pdentry = dget_parent(dentry);
14962306a36Sopenharmony_ci	struct hmdfs_dentry_info_merge *mdi = hmdfs_dm(dentry);
15062306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = hmdfs_sb(dentry->d_sb);
15162306a36Sopenharmony_ci	char *rname, *ppath, *cpath;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	rname = hmdfs_get_real_dname(dentry, &devid, &mdi->type);
15462306a36Sopenharmony_ci	if (unlikely(!rname)) {
15562306a36Sopenharmony_ci		goto out;
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	ppath = hmdfs_merge_get_dentry_relative_path(pdentry);
15962306a36Sopenharmony_ci	if (unlikely(!ppath)) {
16062306a36Sopenharmony_ci		hmdfs_err("failed to get parent relative path");
16162306a36Sopenharmony_ci		goto out_rname;
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	cpath = kzalloc(PATH_MAX, GFP_KERNEL);
16562306a36Sopenharmony_ci	if (unlikely(!cpath)) {
16662306a36Sopenharmony_ci		hmdfs_err("failed to get child device_view path");
16762306a36Sopenharmony_ci		goto out_ppath;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (mdi->type != DT_REG || devid == 0) {
17162306a36Sopenharmony_ci		snprintf(cpath, PATH_MAX, "device_view/local%s/%s", ppath,
17262306a36Sopenharmony_ci			rname);
17362306a36Sopenharmony_ci		merge_lookup_sync(mdi, sbi, 0, cpath, flags);
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci	if (mdi->type == DT_REG && !is_comrade_list_empty(mdi)) {
17662306a36Sopenharmony_ci		ret = 0;
17762306a36Sopenharmony_ci		goto found;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	snprintf(cpath, PATH_MAX, "device_view/%s%s/%s", CLOUD_CID,
18162306a36Sopenharmony_ci			ppath, rname);
18262306a36Sopenharmony_ci	merge_lookup_sync(mdi, sbi, CLOUD_DEVICE, cpath, flags);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	ret = -ENOENT;
18562306a36Sopenharmony_ci	if (!is_comrade_list_empty(mdi))
18662306a36Sopenharmony_ci		ret = 0;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cifound:
18962306a36Sopenharmony_ci	kfree(cpath);
19062306a36Sopenharmony_ciout_ppath:
19162306a36Sopenharmony_ci	kfree(ppath);
19262306a36Sopenharmony_ciout_rname:
19362306a36Sopenharmony_ci	kfree(rname);
19462306a36Sopenharmony_ciout:
19562306a36Sopenharmony_ci	dput(pdentry);
19662306a36Sopenharmony_ci	return ret;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/**
20062306a36Sopenharmony_ci * do_lookup_merge_root - lookup the root of the merge view(root/merge_view)
20162306a36Sopenharmony_ci *
20262306a36Sopenharmony_ci * It's common for a network filesystem to incur various of faults, so we
20362306a36Sopenharmony_ci * intent to show mercy for faults here, except faults reported by the local.
20462306a36Sopenharmony_ci */
20562306a36Sopenharmony_cistatic int do_lookup_cloud_merge_root(struct path path_dev,
20662306a36Sopenharmony_ci				struct dentry *child_dentry, unsigned int flags)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct hmdfs_dentry_comrade *comrade;
20962306a36Sopenharmony_ci	const int buf_len =
21062306a36Sopenharmony_ci		max((int)HMDFS_CID_SIZE + 1, (int)sizeof(DEVICE_VIEW_LOCAL));
21162306a36Sopenharmony_ci	char *buf = kzalloc(buf_len, GFP_KERNEL);
21262306a36Sopenharmony_ci	LIST_HEAD(head);
21362306a36Sopenharmony_ci	int ret;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	if (!buf)
21662306a36Sopenharmony_ci		return -ENOMEM;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	// lookup real_dst/device_view/local
21962306a36Sopenharmony_ci	memcpy(buf, DEVICE_VIEW_LOCAL, sizeof(DEVICE_VIEW_LOCAL));
22062306a36Sopenharmony_ci	comrade = lookup_comrade(path_dev, buf, HMDFS_DEVID_LOCAL, flags);
22162306a36Sopenharmony_ci	if (IS_ERR(comrade)) {
22262306a36Sopenharmony_ci		ret = PTR_ERR(comrade);
22362306a36Sopenharmony_ci		goto out;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci	link_comrade(&head, comrade);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	memcpy(buf, CLOUD_CID, 6);
22862306a36Sopenharmony_ci	buf[5] = '\0';
22962306a36Sopenharmony_ci	comrade = lookup_comrade(path_dev, buf, CLOUD_DEVICE, flags);
23062306a36Sopenharmony_ci	if (IS_ERR(comrade)) {
23162306a36Sopenharmony_ci		ret = 0;
23262306a36Sopenharmony_ci		goto out;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	link_comrade(&head, comrade);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	assign_comrades_unlocked(child_dentry, &head);
23862306a36Sopenharmony_ci	ret = 0;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ciout:
24162306a36Sopenharmony_ci	kfree(buf);
24262306a36Sopenharmony_ci	return ret;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic int lookup_cloud_merge_root(struct inode *root_inode,
24662306a36Sopenharmony_ci			     struct dentry *child_dentry, unsigned int flags)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
24962306a36Sopenharmony_ci	struct path path_dev;
25062306a36Sopenharmony_ci	int ret = -ENOENT;
25162306a36Sopenharmony_ci	int buf_len;
25262306a36Sopenharmony_ci	char *buf = NULL;
25362306a36Sopenharmony_ci	bool locked, down;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	// consider additional one slash and one '\0'
25662306a36Sopenharmony_ci	buf_len = strlen(sbi->real_dst) + 1 + sizeof(DEVICE_VIEW_ROOT);
25762306a36Sopenharmony_ci	if (buf_len > PATH_MAX)
25862306a36Sopenharmony_ci		return -ENAMETOOLONG;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	buf = kmalloc(buf_len, GFP_KERNEL);
26162306a36Sopenharmony_ci	if (unlikely(!buf))
26262306a36Sopenharmony_ci		return -ENOMEM;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	sprintf(buf, "%s/%s", sbi->real_dst, DEVICE_VIEW_ROOT);
26562306a36Sopenharmony_ci	lock_root_inode_shared(root_inode, &locked, &down);
26662306a36Sopenharmony_ci	ret = hmdfs_get_path_in_sb(child_dentry->d_sb, buf, LOOKUP_DIRECTORY,
26762306a36Sopenharmony_ci				   &path_dev);
26862306a36Sopenharmony_ci	if (ret)
26962306a36Sopenharmony_ci		goto free_buf;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	ret = do_lookup_cloud_merge_root(path_dev, child_dentry, flags);
27262306a36Sopenharmony_ci	path_put(&path_dev);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cifree_buf:
27562306a36Sopenharmony_ci	kfree(buf);
27662306a36Sopenharmony_ci	restore_root_inode_sem(root_inode, locked, down);
27762306a36Sopenharmony_ci	return ret;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci// do this in a map-reduce manner
28162306a36Sopenharmony_cistruct dentry *hmdfs_lookup_cloud_merge(struct inode *parent_inode,
28262306a36Sopenharmony_ci				  struct dentry *child_dentry,
28362306a36Sopenharmony_ci				  unsigned int flags)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	bool create = flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET);
28662306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
28762306a36Sopenharmony_ci	struct hmdfs_inode_info *pii = hmdfs_i(parent_inode);
28862306a36Sopenharmony_ci	struct inode *child_inode = NULL;
28962306a36Sopenharmony_ci	struct dentry *ret_dentry = NULL;
29062306a36Sopenharmony_ci	int err = 0;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	/*
29362306a36Sopenharmony_ci	 * Internal flags like LOOKUP_CREATE should not pass to device view.
29462306a36Sopenharmony_ci	 * LOOKUP_REVAL is needed because dentry cache in hmdfs might be stale
29562306a36Sopenharmony_ci	 * after rename in lower fs. LOOKUP_DIRECTORY is not needed because
29662306a36Sopenharmony_ci	 * merge_view can do the judgement that whether result is directory or
29762306a36Sopenharmony_ci	 * not.
29862306a36Sopenharmony_ci	 */
29962306a36Sopenharmony_ci	flags = flags & LOOKUP_REVAL;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	child_dentry->d_fsdata = NULL;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (child_dentry->d_name.len > NAME_MAX) {
30462306a36Sopenharmony_ci		err = -ENAMETOOLONG;
30562306a36Sopenharmony_ci		goto out;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	err = init_hmdfs_dentry_info_merge(sbi, child_dentry);
30962306a36Sopenharmony_ci	if (unlikely(err))
31062306a36Sopenharmony_ci		goto out;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	if (pii->inode_type == HMDFS_LAYER_ZERO) {
31362306a36Sopenharmony_ci		hmdfs_dm(child_dentry)->dentry_type = HMDFS_LAYER_FIRST_MERGE_CLOUD;
31462306a36Sopenharmony_ci		err = lookup_cloud_merge_root(parent_inode, child_dentry, flags);
31562306a36Sopenharmony_ci	} else {
31662306a36Sopenharmony_ci		hmdfs_dm(child_dentry)->dentry_type = HMDFS_LAYER_OTHER_MERGE_CLOUD;
31762306a36Sopenharmony_ci		err = lookup_merge_normal(child_dentry, flags);
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (!err) {
32162306a36Sopenharmony_ci		struct hmdfs_inode_info *info = NULL;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci		child_inode = fill_inode_merge(parent_inode->i_sb, parent_inode,
32462306a36Sopenharmony_ci					       child_dentry, NULL);
32562306a36Sopenharmony_ci		if (IS_ERR(child_inode)) {
32662306a36Sopenharmony_ci			err = PTR_ERR(child_inode);
32762306a36Sopenharmony_ci			goto out;
32862306a36Sopenharmony_ci		}
32962306a36Sopenharmony_ci		info = hmdfs_i(child_inode);
33062306a36Sopenharmony_ci		if (info->inode_type == HMDFS_LAYER_FIRST_MERGE)
33162306a36Sopenharmony_ci			hmdfs_root_inode_perm_init(child_inode);
33262306a36Sopenharmony_ci		else
33362306a36Sopenharmony_ci			check_and_fixup_ownership_remote(parent_inode,
33462306a36Sopenharmony_ci							 child_inode,
33562306a36Sopenharmony_ci							 child_dentry);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci		ret_dentry = d_splice_alias(child_inode, child_dentry);
33862306a36Sopenharmony_ci		if (IS_ERR(ret_dentry)) {
33962306a36Sopenharmony_ci			clear_comrades(child_dentry);
34062306a36Sopenharmony_ci			err = PTR_ERR(ret_dentry);
34162306a36Sopenharmony_ci			goto out;
34262306a36Sopenharmony_ci		}
34362306a36Sopenharmony_ci		if (ret_dentry)
34462306a36Sopenharmony_ci			child_dentry = ret_dentry;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		goto out;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if ((err == -ENOENT) && create)
35062306a36Sopenharmony_ci		err = 0;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ciout:
35362306a36Sopenharmony_ci	return err ? ERR_PTR(err) : ret_dentry;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ciconst struct inode_operations hmdfs_file_iops_cloud_merge = {
35762306a36Sopenharmony_ci	.getattr = hmdfs_getattr_merge,
35862306a36Sopenharmony_ci	.setattr = hmdfs_setattr_merge,
35962306a36Sopenharmony_ci	.permission = hmdfs_permission,
36062306a36Sopenharmony_ci};
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ciint do_mkdir_cloud_merge(struct inode *parent_inode, struct dentry *child_dentry,
36362306a36Sopenharmony_ci		   umode_t mode, struct inode *lo_i_parent,
36462306a36Sopenharmony_ci		   struct dentry *lo_d_child)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	int ret = 0;
36762306a36Sopenharmony_ci	struct super_block *sb = parent_inode->i_sb;
36862306a36Sopenharmony_ci	struct inode *child_inode = NULL;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	ret = vfs_mkdir(&nop_mnt_idmap, lo_i_parent, lo_d_child, mode);
37162306a36Sopenharmony_ci	if (ret)
37262306a36Sopenharmony_ci		goto out;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	child_inode =
37562306a36Sopenharmony_ci		fill_inode_merge(sb, parent_inode, child_dentry, lo_d_child);
37662306a36Sopenharmony_ci	if (IS_ERR(child_inode)) {
37762306a36Sopenharmony_ci		ret = PTR_ERR(child_inode);
37862306a36Sopenharmony_ci		goto out;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	d_add(child_dentry, child_inode);
38262306a36Sopenharmony_ci	/* nlink should be increased with the joining of children */
38362306a36Sopenharmony_ci	set_nlink(parent_inode, 2);
38462306a36Sopenharmony_ci	hmdfs_update_meta(parent_inode);
38562306a36Sopenharmony_ciout:
38662306a36Sopenharmony_ci	return ret;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ciint do_create_cloud_merge(struct inode *parent_inode, struct dentry *child_dentry,
39062306a36Sopenharmony_ci		    umode_t mode, bool want_excl, struct inode *lo_i_parent,
39162306a36Sopenharmony_ci		    struct dentry *lo_d_child)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	int ret = 0;
39462306a36Sopenharmony_ci	struct super_block *sb = parent_inode->i_sb;
39562306a36Sopenharmony_ci	struct inode *child_inode = NULL;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	ret = vfs_create(&nop_mnt_idmap, lo_i_parent, lo_d_child, mode, want_excl);
39862306a36Sopenharmony_ci	if (ret)
39962306a36Sopenharmony_ci		goto out;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	child_inode =
40262306a36Sopenharmony_ci		fill_inode_merge(sb, parent_inode, child_dentry, lo_d_child);
40362306a36Sopenharmony_ci	if (IS_ERR(child_inode)) {
40462306a36Sopenharmony_ci		ret = PTR_ERR(child_inode);
40562306a36Sopenharmony_ci		goto out;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	d_add(child_dentry, child_inode);
40962306a36Sopenharmony_ci	/* nlink should be increased with the joining of children */
41062306a36Sopenharmony_ci	set_nlink(parent_inode, 2);
41162306a36Sopenharmony_ci	hmdfs_update_meta(parent_inode);
41262306a36Sopenharmony_ciout:
41362306a36Sopenharmony_ci	return ret;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ciint hmdfs_do_ops_cloud_merge(struct inode *i_parent, struct dentry *d_child,
41762306a36Sopenharmony_ci		       struct dentry *lo_d_child, struct path path,
41862306a36Sopenharmony_ci		       struct hmdfs_recursive_para *rec_op_para)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	int ret = 0;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (rec_op_para->is_last) {
42362306a36Sopenharmony_ci		switch (rec_op_para->opcode) {
42462306a36Sopenharmony_ci		case F_MKDIR_MERGE:
42562306a36Sopenharmony_ci			ret = do_mkdir_cloud_merge(i_parent, d_child,
42662306a36Sopenharmony_ci					     rec_op_para->mode,
42762306a36Sopenharmony_ci					     d_inode(path.dentry), lo_d_child);
42862306a36Sopenharmony_ci			break;
42962306a36Sopenharmony_ci		case F_CREATE_MERGE:
43062306a36Sopenharmony_ci			ret = do_create_cloud_merge(i_parent, d_child,
43162306a36Sopenharmony_ci					      rec_op_para->mode,
43262306a36Sopenharmony_ci					      rec_op_para->want_excl,
43362306a36Sopenharmony_ci					      d_inode(path.dentry), lo_d_child);
43462306a36Sopenharmony_ci			break;
43562306a36Sopenharmony_ci		default:
43662306a36Sopenharmony_ci			ret = -EINVAL;
43762306a36Sopenharmony_ci			break;
43862306a36Sopenharmony_ci		}
43962306a36Sopenharmony_ci	} else {
44062306a36Sopenharmony_ci		ret = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), lo_d_child,
44162306a36Sopenharmony_ci				rec_op_para->mode);
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci	if (ret)
44462306a36Sopenharmony_ci		hmdfs_err("vfs_ops failed, ops %d, err = %d",
44562306a36Sopenharmony_ci			  rec_op_para->opcode, ret);
44662306a36Sopenharmony_ci	return ret;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ciint hmdfs_create_lower_cloud_dentry(struct inode *i_parent, struct dentry *d_child,
45062306a36Sopenharmony_ci			      struct dentry *lo_d_parent, bool is_dir,
45162306a36Sopenharmony_ci			      struct hmdfs_recursive_para *rec_op_para)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = i_parent->i_sb->s_fs_info;
45462306a36Sopenharmony_ci	struct hmdfs_dentry_comrade *new_comrade = NULL;
45562306a36Sopenharmony_ci	struct dentry *lo_d_child = NULL;
45662306a36Sopenharmony_ci	char *path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
45762306a36Sopenharmony_ci	char *absolute_path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
45862306a36Sopenharmony_ci	char *path_name = NULL;
45962306a36Sopenharmony_ci	struct path path = { .mnt = NULL, .dentry = NULL };
46062306a36Sopenharmony_ci	int ret = 0;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if (unlikely(!path_buf || !absolute_path_buf)) {
46362306a36Sopenharmony_ci		ret = -ENOMEM;
46462306a36Sopenharmony_ci		goto out;
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	path_name = dentry_path_raw(lo_d_parent, path_buf, PATH_MAX);
46862306a36Sopenharmony_ci	if (IS_ERR(path_name)) {
46962306a36Sopenharmony_ci		ret = PTR_ERR(path_name);
47062306a36Sopenharmony_ci		goto out;
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci	if ((strlen(sbi->real_dst) + strlen(path_name) +
47362306a36Sopenharmony_ci	     strlen(d_child->d_name.name) + 2) > PATH_MAX) {
47462306a36Sopenharmony_ci		ret = -ENAMETOOLONG;
47562306a36Sopenharmony_ci		goto out;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	sprintf(absolute_path_buf, "%s%s/%s", sbi->real_dst, path_name,
47962306a36Sopenharmony_ci		d_child->d_name.name);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (is_dir)
48262306a36Sopenharmony_ci		lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf,
48362306a36Sopenharmony_ci					      &path, LOOKUP_DIRECTORY);
48462306a36Sopenharmony_ci	else
48562306a36Sopenharmony_ci		lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf,
48662306a36Sopenharmony_ci					      &path, 0);
48762306a36Sopenharmony_ci	if (IS_ERR(lo_d_child)) {
48862306a36Sopenharmony_ci		ret = PTR_ERR(lo_d_child);
48962306a36Sopenharmony_ci		goto out;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci	// to ensure link_comrade after vfs_mkdir succeed
49262306a36Sopenharmony_ci	ret = hmdfs_do_ops_cloud_merge(i_parent, d_child, lo_d_child, path,
49362306a36Sopenharmony_ci				 rec_op_para);
49462306a36Sopenharmony_ci	if (ret)
49562306a36Sopenharmony_ci		goto out_put;
49662306a36Sopenharmony_ci	new_comrade = alloc_comrade(lo_d_child, HMDFS_DEVID_LOCAL);
49762306a36Sopenharmony_ci	if (IS_ERR(new_comrade)) {
49862306a36Sopenharmony_ci		ret = PTR_ERR(new_comrade);
49962306a36Sopenharmony_ci		goto out_put;
50062306a36Sopenharmony_ci	} else {
50162306a36Sopenharmony_ci		link_comrade_unlocked(d_child, new_comrade);
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	update_inode_attr(d_inode(d_child), d_child);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ciout_put:
50762306a36Sopenharmony_ci	done_path_create(&path, lo_d_child);
50862306a36Sopenharmony_ciout:
50962306a36Sopenharmony_ci	kfree(absolute_path_buf);
51062306a36Sopenharmony_ci	kfree(path_buf);
51162306a36Sopenharmony_ci	return ret;
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic int create_lo_d_parent_recur(struct dentry *d_parent,
51562306a36Sopenharmony_ci				    struct dentry *d_child, umode_t mode,
51662306a36Sopenharmony_ci				    struct hmdfs_recursive_para *rec_op_para)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct dentry *lo_d_parent, *d_pparent;
51962306a36Sopenharmony_ci	int ret = 0;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
52262306a36Sopenharmony_ci	if (!lo_d_parent) {
52362306a36Sopenharmony_ci		d_pparent = dget_parent(d_parent);
52462306a36Sopenharmony_ci		ret = create_lo_d_parent_recur(d_pparent, d_parent,
52562306a36Sopenharmony_ci					       d_inode(d_parent)->i_mode,
52662306a36Sopenharmony_ci					       rec_op_para);
52762306a36Sopenharmony_ci		dput(d_pparent);
52862306a36Sopenharmony_ci		if (ret)
52962306a36Sopenharmony_ci			goto out;
53062306a36Sopenharmony_ci		lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
53162306a36Sopenharmony_ci		if (!lo_d_parent) {
53262306a36Sopenharmony_ci			ret = -ENOENT;
53362306a36Sopenharmony_ci			goto out;
53462306a36Sopenharmony_ci		}
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci	rec_op_para->is_last = false;
53762306a36Sopenharmony_ci	rec_op_para->mode = mode;
53862306a36Sopenharmony_ci	ret = hmdfs_create_lower_cloud_dentry(d_inode(d_parent), d_child, lo_d_parent,
53962306a36Sopenharmony_ci					true, rec_op_para);
54062306a36Sopenharmony_ciout:
54162306a36Sopenharmony_ci	dput(lo_d_parent);
54262306a36Sopenharmony_ci	return ret;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ciint create_lo_d_cloud_child(struct inode *i_parent, struct dentry *d_child,
54662306a36Sopenharmony_ci		      bool is_dir, struct hmdfs_recursive_para *rec_op_para)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	struct dentry *d_pparent, *lo_d_parent, *lo_d_child;
54962306a36Sopenharmony_ci	struct dentry *d_parent = dget_parent(d_child);
55062306a36Sopenharmony_ci	int ret = 0;
55162306a36Sopenharmony_ci	mode_t d_child_mode = rec_op_para->mode;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
55462306a36Sopenharmony_ci	if (!lo_d_parent) {
55562306a36Sopenharmony_ci		d_pparent = dget_parent(d_parent);
55662306a36Sopenharmony_ci		ret = create_lo_d_parent_recur(d_pparent, d_parent,
55762306a36Sopenharmony_ci					       d_inode(d_parent)->i_mode,
55862306a36Sopenharmony_ci					       rec_op_para);
55962306a36Sopenharmony_ci		dput(d_pparent);
56062306a36Sopenharmony_ci		if (unlikely(ret)) {
56162306a36Sopenharmony_ci			lo_d_child = ERR_PTR(ret);
56262306a36Sopenharmony_ci			goto out;
56362306a36Sopenharmony_ci		}
56462306a36Sopenharmony_ci		lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
56562306a36Sopenharmony_ci		if (!lo_d_parent) {
56662306a36Sopenharmony_ci			lo_d_child = ERR_PTR(-ENOENT);
56762306a36Sopenharmony_ci			goto out;
56862306a36Sopenharmony_ci		}
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci	rec_op_para->is_last = true;
57162306a36Sopenharmony_ci	rec_op_para->mode = d_child_mode;
57262306a36Sopenharmony_ci	ret = hmdfs_create_lower_cloud_dentry(i_parent, d_child, lo_d_parent, is_dir,
57362306a36Sopenharmony_ci					rec_op_para);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ciout:
57662306a36Sopenharmony_ci	dput(d_parent);
57762306a36Sopenharmony_ci	dput(lo_d_parent);
57862306a36Sopenharmony_ci	return ret;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ciint hmdfs_mkdir_cloud_merge(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	int ret = 0;
58462306a36Sopenharmony_ci	struct hmdfs_recursive_para *rec_op_para = NULL;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	// confict_name  & file_type is checked by hmdfs_mkdir_local
58762306a36Sopenharmony_ci	if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) {
58862306a36Sopenharmony_ci		ret = -EACCES;
58962306a36Sopenharmony_ci		goto out;
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci	rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
59262306a36Sopenharmony_ci	if (!rec_op_para) {
59362306a36Sopenharmony_ci		ret = -ENOMEM;
59462306a36Sopenharmony_ci		goto out;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	hmdfs_init_recursive_para(rec_op_para, F_MKDIR_MERGE, mode, false,
59862306a36Sopenharmony_ci				  NULL);
59962306a36Sopenharmony_ci	ret = create_lo_d_cloud_child(dir, dentry, true, rec_op_para);
60062306a36Sopenharmony_ciout:
60162306a36Sopenharmony_ci	hmdfs_trace_merge(trace_hmdfs_mkdir_merge, dir, dentry, ret);
60262306a36Sopenharmony_ci	if (ret)
60362306a36Sopenharmony_ci		d_drop(dentry);
60462306a36Sopenharmony_ci	kfree(rec_op_para);
60562306a36Sopenharmony_ci	return ret;
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ciint hmdfs_create_cloud_merge(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode,
60962306a36Sopenharmony_ci		       bool want_excl)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	struct hmdfs_recursive_para *rec_op_para = NULL;
61262306a36Sopenharmony_ci	int ret = 0;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
61562306a36Sopenharmony_ci	if (!rec_op_para) {
61662306a36Sopenharmony_ci		ret = -ENOMEM;
61762306a36Sopenharmony_ci		goto out;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci	hmdfs_init_recursive_para(rec_op_para, F_CREATE_MERGE, mode, want_excl,
62062306a36Sopenharmony_ci				  NULL);
62162306a36Sopenharmony_ci	// confict_name  & file_type is checked by hmdfs_create_local
62262306a36Sopenharmony_ci	ret = create_lo_d_cloud_child(dir, dentry, false, rec_op_para);
62362306a36Sopenharmony_ciout:
62462306a36Sopenharmony_ci	hmdfs_trace_merge(trace_hmdfs_create_merge, dir, dentry, ret);
62562306a36Sopenharmony_ci	if (ret)
62662306a36Sopenharmony_ci		d_drop(dentry);
62762306a36Sopenharmony_ci	kfree(rec_op_para);
62862306a36Sopenharmony_ci	return ret;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic int rename_lo_d_cloud_child(struct hmdfs_rename_para *rename_para,
63262306a36Sopenharmony_ci				   struct hmdfs_recursive_para *rec_op_para)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	struct dentry *d_pparent, *lo_d_parent;
63562306a36Sopenharmony_ci	struct dentry *d_parent = dget_parent(rename_para->new_dentry);
63662306a36Sopenharmony_ci	int ret = 0;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
63962306a36Sopenharmony_ci	if (!lo_d_parent) {
64062306a36Sopenharmony_ci		d_pparent = dget_parent(d_parent);
64162306a36Sopenharmony_ci		ret = create_lo_d_parent_recur(d_pparent, d_parent,
64262306a36Sopenharmony_ci					       d_inode(d_parent)->i_mode,
64362306a36Sopenharmony_ci					       rec_op_para);
64462306a36Sopenharmony_ci		dput(d_pparent);
64562306a36Sopenharmony_ci		if (unlikely(ret))
64662306a36Sopenharmony_ci			goto out;
64762306a36Sopenharmony_ci		lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL);
64862306a36Sopenharmony_ci		if (!lo_d_parent) {
64962306a36Sopenharmony_ci			ret = -ENOENT;
65062306a36Sopenharmony_ci			goto out;
65162306a36Sopenharmony_ci		}
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci	ret = do_rename_merge(rename_para->old_dir, rename_para->old_dentry,
65462306a36Sopenharmony_ci			      rename_para->new_dir, rename_para->new_dentry,
65562306a36Sopenharmony_ci			      rename_para->flags);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ciout:
65862306a36Sopenharmony_ci	dput(d_parent);
65962306a36Sopenharmony_ci	dput(lo_d_parent);
66062306a36Sopenharmony_ci	return ret;
66162306a36Sopenharmony_ci}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_cistatic int hmdfs_rename_cloud_merge(struct mnt_idmap *idmap, struct inode *old_dir,
66462306a36Sopenharmony_ci				    struct dentry *old_dentry,
66562306a36Sopenharmony_ci				    struct inode *new_dir,
66662306a36Sopenharmony_ci				    struct dentry *new_dentry,
66762306a36Sopenharmony_ci				    unsigned int flags)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	struct hmdfs_recursive_para *rec_op_para = NULL;
67062306a36Sopenharmony_ci	struct hmdfs_rename_para rename_para = { old_dir, old_dentry, new_dir,
67162306a36Sopenharmony_ci						 new_dentry, flags };
67262306a36Sopenharmony_ci	int ret = 0;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (hmdfs_file_type(old_dentry->d_name.name) != HMDFS_TYPE_COMMON ||
67562306a36Sopenharmony_ci	    hmdfs_file_type(new_dentry->d_name.name) != HMDFS_TYPE_COMMON) {
67662306a36Sopenharmony_ci		ret = -EACCES;
67762306a36Sopenharmony_ci		goto rename_out;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (hmdfs_i(old_dir)->inode_type != hmdfs_i(new_dir)->inode_type) {
68162306a36Sopenharmony_ci		hmdfs_err("in different view");
68262306a36Sopenharmony_ci		ret = -EPERM;
68362306a36Sopenharmony_ci		goto rename_out;
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL);
68762306a36Sopenharmony_ci	if (!rec_op_para) {
68862306a36Sopenharmony_ci		ret = -ENOMEM;
68962306a36Sopenharmony_ci		goto rename_out;
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci	trace_hmdfs_rename_merge(old_dir, old_dentry, new_dir, new_dentry,
69262306a36Sopenharmony_ci				 flags);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	hmdfs_init_recursive_para(rec_op_para, F_MKDIR_MERGE, 0, 0, NULL);
69562306a36Sopenharmony_ci	ret = rename_lo_d_cloud_child(&rename_para, rec_op_para);
69662306a36Sopenharmony_ci	if (ret != 0) {
69762306a36Sopenharmony_ci		d_drop(new_dentry);
69862306a36Sopenharmony_ci	} else {
69962306a36Sopenharmony_ci		hmdfs_update_meta(old_dir);
70062306a36Sopenharmony_ci		if (old_dir != new_dir)
70162306a36Sopenharmony_ci			hmdfs_update_meta(new_dir);
70262306a36Sopenharmony_ci	}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (S_ISREG(old_dentry->d_inode->i_mode) && !ret)
70562306a36Sopenharmony_ci		d_invalidate(old_dentry);
70662306a36Sopenharmony_cirename_out:
70762306a36Sopenharmony_ci	kfree(rec_op_para);
70862306a36Sopenharmony_ci	return ret;
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_civoid hmdfs_update_meta(struct inode *dir)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	dir->__i_ctime = dir->i_mtime = current_time(dir);
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ciconst struct inode_operations hmdfs_dir_iops_cloud_merge = {
71762306a36Sopenharmony_ci	.lookup = hmdfs_lookup_cloud_merge,
71862306a36Sopenharmony_ci	.mkdir = hmdfs_mkdir_cloud_merge,
71962306a36Sopenharmony_ci	.create = hmdfs_create_cloud_merge,
72062306a36Sopenharmony_ci	.rmdir = hmdfs_rmdir_merge,
72162306a36Sopenharmony_ci	.unlink = hmdfs_unlink_merge,
72262306a36Sopenharmony_ci	.rename = hmdfs_rename_cloud_merge,
72362306a36Sopenharmony_ci	.permission = hmdfs_permission,
72462306a36Sopenharmony_ci};
725