162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * fs/hmdfs/inode_cloud.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2023-2023 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_dentryfile_cloud.h"
1862306a36Sopenharmony_ci#include "hmdfs_share.h"
1962306a36Sopenharmony_ci#include "hmdfs_trace.h"
2062306a36Sopenharmony_ci#include "authority/authentication.h"
2162306a36Sopenharmony_ci#include "stash.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ciuint32_t make_ino_raw_cloud(uint8_t *cloud_id)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct qstr str;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	str.len = CLOUD_RECORD_ID_LEN;
2862306a36Sopenharmony_ci	str.name = cloud_id;
2962306a36Sopenharmony_ci	return hmdfs_dentry_hash(&str, CLOUD_RECORD_ID_LEN);
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct hmdfs_lookup_cloud_ret *lookup_cloud_dentry(struct dentry *child_dentry,
3362306a36Sopenharmony_ci					      const struct qstr *qstr,
3462306a36Sopenharmony_ci					      uint64_t dev_id)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct hmdfs_lookup_cloud_ret *lookup_ret;
3762306a36Sopenharmony_ci	struct hmdfs_dentry_cloud *dentry = NULL;
3862306a36Sopenharmony_ci	struct clearcache_item *cache_item = NULL;
3962306a36Sopenharmony_ci	struct hmdfs_dcache_lookup_ctx_cloud ctx;
4062306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	get_cloud_cache_file(child_dentry->d_parent, sbi);
4362306a36Sopenharmony_ci	cache_item = hmdfs_find_cache_item(dev_id, child_dentry->d_parent);
4462306a36Sopenharmony_ci	if (!cache_item)
4562306a36Sopenharmony_ci		return NULL;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	lookup_ret = kmalloc(sizeof(*lookup_ret), GFP_KERNEL);
4862306a36Sopenharmony_ci	if (!lookup_ret)
4962306a36Sopenharmony_ci		goto out;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	hmdfs_init_dcache_lookup_ctx_cloud(&ctx, sbi, qstr, cache_item->filp);
5262306a36Sopenharmony_ci	dentry = hmdfs_find_dentry_cloud(child_dentry, &ctx);
5362306a36Sopenharmony_ci	if (!dentry) {
5462306a36Sopenharmony_ci		kfree(lookup_ret);
5562306a36Sopenharmony_ci		lookup_ret = NULL;
5662306a36Sopenharmony_ci		goto out;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	lookup_ret->i_mode = le16_to_cpu(dentry->i_mode);
6062306a36Sopenharmony_ci	lookup_ret->i_size = le64_to_cpu(dentry->i_size);
6162306a36Sopenharmony_ci	lookup_ret->i_mtime = le64_to_cpu(dentry->i_mtime);
6262306a36Sopenharmony_ci	memcpy(lookup_ret->record_id, dentry->record_id, CLOUD_RECORD_ID_LEN);
6362306a36Sopenharmony_ci	memcpy(lookup_ret->reserved, dentry->reserved, CLOUD_DENTRY_RESERVED_LENGTH);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	hmdfs_unlock_file(ctx.filp, get_dentry_group_pos(ctx.bidx),
6662306a36Sopenharmony_ci			  DENTRYGROUP_SIZE);
6762306a36Sopenharmony_ci	kfree(ctx.page);
6862306a36Sopenharmony_ciout:
6962306a36Sopenharmony_ci	kref_put(&cache_item->ref, release_cache_item);
7062306a36Sopenharmony_ci	return lookup_ret;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic struct hmdfs_lookup_cloud_ret *
7462306a36Sopenharmony_cihmdfs_lookup_by_cloud(struct dentry *dentry, unsigned int flags)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct hmdfs_lookup_cloud_ret *result = NULL;
7762306a36Sopenharmony_ci	char *file_name = NULL;
7862306a36Sopenharmony_ci	struct qstr qstr;
7962306a36Sopenharmony_ci	int file_name_len = dentry->d_name.len;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	file_name = kzalloc(NAME_MAX + 1, GFP_KERNEL);
8262306a36Sopenharmony_ci	if (!file_name)
8362306a36Sopenharmony_ci		return NULL;
8462306a36Sopenharmony_ci	strncpy(file_name, dentry->d_name.name, file_name_len);
8562306a36Sopenharmony_ci	qstr.name = file_name;
8662306a36Sopenharmony_ci	qstr.len = strlen(file_name);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	result = lookup_cloud_dentry(dentry, &qstr, CLOUD_DEVICE);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	kfree(file_name);
9162306a36Sopenharmony_ci	return result;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/*
9562306a36Sopenharmony_ci * hmdfs_update_inode_size - update inode size when finding aready existed
9662306a36Sopenharmony_ci * inode.
9762306a36Sopenharmony_ci *
9862306a36Sopenharmony_ci * First of all, if the file is opened for writing, we don't update inode size
9962306a36Sopenharmony_ci * here, because inode size is about to be changed after writing.
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci * If the file is not opened, simply update getattr_isize(not actual inode size,
10262306a36Sopenharmony_ci * just a value showed to user). This is safe because inode size will be
10362306a36Sopenharmony_ci * up-to-date after open.
10462306a36Sopenharmony_ci *
10562306a36Sopenharmony_ci * If the file is opened for read:
10662306a36Sopenharmony_ci * a. getattr_isize == HMDFS_STALE_REMOTE_ISIZE
10762306a36Sopenharmony_ci *   1) i_size == new_size, nothing need to be done.
10862306a36Sopenharmony_ci *   2) i_size > new_size, we keep the i_size and set getattr_isize to new_size,
10962306a36Sopenharmony_ci *      stale data might be readed in this case, which is fine because file is
11062306a36Sopenharmony_ci *      opened before remote truncate the file.
11162306a36Sopenharmony_ci *   3) i_size < new_size, we drop the last page of the file if i_size is not
11262306a36Sopenharmony_ci *      aligned to PAGE_SIZE, clear getattr_isize, and update i_size to
11362306a36Sopenharmony_ci *      new_size.
11462306a36Sopenharmony_ci * b. getattr_isize != HMDFS_STALE_REMOTE_ISIZE, getattr_isize will only be set
11562306a36Sopenharmony_ci *    after 2).
11662306a36Sopenharmony_ci *   4) getattr_isize > i_size, this situation is impossible.
11762306a36Sopenharmony_ci *   5) i_size >= new_size, this case is the same as 2).
11862306a36Sopenharmony_ci *   6) i_size < new_size, this case is the same as 3).
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_cistatic void hmdfs_update_inode_size(struct inode *inode, uint64_t new_size)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
12362306a36Sopenharmony_ci	int writecount;
12462306a36Sopenharmony_ci	uint64_t size;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	inode_lock(inode);
12762306a36Sopenharmony_ci	size = info->getattr_isize;
12862306a36Sopenharmony_ci	if (size == HMDFS_STALE_REMOTE_ISIZE)
12962306a36Sopenharmony_ci		size = i_size_read(inode);
13062306a36Sopenharmony_ci	if (size == new_size) {
13162306a36Sopenharmony_ci		inode_unlock(inode);
13262306a36Sopenharmony_ci		return;
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	writecount = atomic_read(&inode->i_writecount);
13662306a36Sopenharmony_ci	/* check if writing is in progress */
13762306a36Sopenharmony_ci	if (writecount > 0) {
13862306a36Sopenharmony_ci		info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE;
13962306a36Sopenharmony_ci		inode_unlock(inode);
14062306a36Sopenharmony_ci		return;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* check if there is no one who opens the file */
14462306a36Sopenharmony_ci	if (kref_read(&info->ref) == 0)
14562306a36Sopenharmony_ci		goto update_info;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	/* check if there is someone who opens the file for read */
14862306a36Sopenharmony_ci	if (writecount == 0) {
14962306a36Sopenharmony_ci		uint64_t aligned_size;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		/* use inode size here instead of getattr_isize */
15262306a36Sopenharmony_ci		size = i_size_read(inode);
15362306a36Sopenharmony_ci		if (new_size <= size)
15462306a36Sopenharmony_ci			goto update_info;
15562306a36Sopenharmony_ci		/*
15662306a36Sopenharmony_ci		 * if the old inode size is not aligned to HMDFS_PAGE_SIZE, we
15762306a36Sopenharmony_ci		 * need to drop the last page of the inode, otherwise zero will
15862306a36Sopenharmony_ci		 * be returned while reading the new range in the page after
15962306a36Sopenharmony_ci		 * chaning inode size.
16062306a36Sopenharmony_ci		 */
16162306a36Sopenharmony_ci		aligned_size = round_down(size, HMDFS_PAGE_SIZE);
16262306a36Sopenharmony_ci		if (aligned_size != size)
16362306a36Sopenharmony_ci			truncate_inode_pages(inode->i_mapping, aligned_size);
16462306a36Sopenharmony_ci		i_size_write(inode, new_size);
16562306a36Sopenharmony_ci		info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE;
16662306a36Sopenharmony_ci		inode_unlock(inode);
16762306a36Sopenharmony_ci		return;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ciupdate_info:
17162306a36Sopenharmony_ci	info->getattr_isize = new_size;
17262306a36Sopenharmony_ci	inode_unlock(inode);
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic void hmdfs_update_inode(struct inode *inode,
17662306a36Sopenharmony_ci			       struct hmdfs_lookup_cloud_ret *lookup_result)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	struct hmdfs_time_t remote_mtime = {
17962306a36Sopenharmony_ci		.tv_sec = lookup_result->i_mtime,
18062306a36Sopenharmony_ci		.tv_nsec = 0,
18162306a36Sopenharmony_ci	};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/*
18462306a36Sopenharmony_ci	 * We only update mtime if the file is not opened for writing. If we do
18562306a36Sopenharmony_ci	 * update it before writing is about to start, user might see the mtime
18662306a36Sopenharmony_ci	 * up-and-down if system time in server and client do not match. However
18762306a36Sopenharmony_ci	 * mtime in client will eventually match server after timeout without
18862306a36Sopenharmony_ci	 * writing.
18962306a36Sopenharmony_ci	 */
19062306a36Sopenharmony_ci	if (!inode_is_open_for_write(inode))
19162306a36Sopenharmony_ci		inode->i_mtime = remote_mtime;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/*
19462306a36Sopenharmony_ci	 * We don't care i_size of dir, and lock inode for dir
19562306a36Sopenharmony_ci	 * might cause deadlock.
19662306a36Sopenharmony_ci	 */
19762306a36Sopenharmony_ci	if (S_ISREG(inode->i_mode))
19862306a36Sopenharmony_ci		hmdfs_update_inode_size(inode, lookup_result->i_size);
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic void hmdfs_fill_inode_permission(struct inode *inode, struct inode *dir,
20262306a36Sopenharmony_ci				     umode_t mode)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci#ifdef CONFIG_HMDFS_FS_PERMISSION
20562306a36Sopenharmony_ci	inode->i_uid = dir->i_uid;
20662306a36Sopenharmony_ci	inode->i_gid = dir->i_gid;
20762306a36Sopenharmony_ci#endif
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistruct hmdfs_peer peer;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistruct inode *fill_inode_cloud(struct super_block *sb, struct hmdfs_lookup_cloud_ret *res, struct inode *dir)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	int ret = 0;
21562306a36Sopenharmony_ci	struct inode *inode = NULL;
21662306a36Sopenharmony_ci	struct hmdfs_inode_info *info;
21762306a36Sopenharmony_ci	umode_t mode = res->i_mode;
21862306a36Sopenharmony_ci	peer.device_id = CLOUD_DEVICE;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	inode = hmdfs_iget5_locked_cloud(sb, &peer, res);
22162306a36Sopenharmony_ci	if (!inode)
22262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	info = hmdfs_i(inode);
22562306a36Sopenharmony_ci	info->inode_type = HMDFS_LAYER_OTHER_CLOUD;
22662306a36Sopenharmony_ci	/* the inode was found in cache */
22762306a36Sopenharmony_ci	if (!(inode->i_state & I_NEW)) {
22862306a36Sopenharmony_ci		hmdfs_fill_inode_permission(inode, dir, mode);
22962306a36Sopenharmony_ci		hmdfs_update_inode(inode, res);
23062306a36Sopenharmony_ci		return inode;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	inode->__i_ctime.tv_sec = 0;
23462306a36Sopenharmony_ci	inode->__i_ctime.tv_nsec = 0;
23562306a36Sopenharmony_ci	inode->i_mtime.tv_sec = res->i_mtime;
23662306a36Sopenharmony_ci	inode->i_mtime.tv_nsec = 0;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	inode->i_uid = USER_DATA_RW_UID;
23962306a36Sopenharmony_ci	inode->i_gid = USER_DATA_RW_GID;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (S_ISDIR(mode))
24262306a36Sopenharmony_ci		inode->i_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IXOTH;
24362306a36Sopenharmony_ci	else if (S_ISREG(mode))
24462306a36Sopenharmony_ci		inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
24562306a36Sopenharmony_ci	else {
24662306a36Sopenharmony_ci		ret = -EIO;
24762306a36Sopenharmony_ci		goto bad_inode;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (S_ISREG(mode)) {
25162306a36Sopenharmony_ci		inode->i_op = &hmdfs_dev_file_iops_cloud;
25262306a36Sopenharmony_ci		inode->i_fop = &hmdfs_dev_file_fops_cloud;
25362306a36Sopenharmony_ci		inode->i_size = res->i_size;
25462306a36Sopenharmony_ci		set_nlink(inode, 1);
25562306a36Sopenharmony_ci	} else if (S_ISDIR(mode)) {
25662306a36Sopenharmony_ci		inode->i_op = &hmdfs_dev_dir_inode_ops_cloud;
25762306a36Sopenharmony_ci		inode->i_fop = &hmdfs_dev_dir_ops_cloud;
25862306a36Sopenharmony_ci		set_nlink(inode, 2);
25962306a36Sopenharmony_ci	} else {
26062306a36Sopenharmony_ci		ret = -EIO;
26162306a36Sopenharmony_ci		goto bad_inode;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	inode->i_mapping->a_ops = &hmdfs_dev_file_aops_cloud;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	hmdfs_fill_inode_permission(inode, dir, mode);
26762306a36Sopenharmony_ci	unlock_new_inode(inode);
26862306a36Sopenharmony_ci	return inode;
26962306a36Sopenharmony_cibad_inode:
27062306a36Sopenharmony_ci	iget_failed(inode);
27162306a36Sopenharmony_ci	return ERR_PTR(ret);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic struct dentry *hmdfs_lookup_cloud_dentry(struct inode *parent_inode,
27562306a36Sopenharmony_ci						 struct dentry *child_dentry,
27662306a36Sopenharmony_ci						 int flags)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct dentry *ret = NULL;
27962306a36Sopenharmony_ci	struct inode *inode = NULL;
28062306a36Sopenharmony_ci	struct super_block *sb = parent_inode->i_sb;
28162306a36Sopenharmony_ci	struct hmdfs_lookup_cloud_ret *lookup_result = NULL;
28262306a36Sopenharmony_ci	struct hmdfs_dentry_info *gdi = hmdfs_d(child_dentry);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	lookup_result = hmdfs_lookup_by_cloud(child_dentry, flags);
28562306a36Sopenharmony_ci	if (lookup_result != NULL) {
28662306a36Sopenharmony_ci		if (in_share_dir(child_dentry))
28762306a36Sopenharmony_ci			gdi->file_type = HM_SHARE;
28862306a36Sopenharmony_ci		inode = fill_inode_cloud(sb, lookup_result, parent_inode);
28962306a36Sopenharmony_ci		if (IS_ERR(inode)) {
29062306a36Sopenharmony_ci			ret = ERR_CAST(inode);
29162306a36Sopenharmony_ci			goto out;
29262306a36Sopenharmony_ci		}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		check_and_fixup_ownership_remote(parent_inode,
29562306a36Sopenharmony_ci						 inode,
29662306a36Sopenharmony_ci						 child_dentry);
29762306a36Sopenharmony_ci		ret = d_splice_alias(inode, child_dentry);
29862306a36Sopenharmony_ci		if (!IS_ERR_OR_NULL(ret))
29962306a36Sopenharmony_ci			child_dentry = ret;
30062306a36Sopenharmony_ci	} else {
30162306a36Sopenharmony_ci		ret = ERR_PTR(-ENOENT);
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ciout:
30462306a36Sopenharmony_ci	kfree(lookup_result);
30562306a36Sopenharmony_ci	return ret;
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistruct dentry *hmdfs_lookup_cloud(struct inode *parent_inode,
30962306a36Sopenharmony_ci				   struct dentry *child_dentry,
31062306a36Sopenharmony_ci				   unsigned int flags)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	int err = 0;
31362306a36Sopenharmony_ci	struct dentry *ret = NULL;
31462306a36Sopenharmony_ci	struct hmdfs_dentry_info *gdi = NULL;
31562306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	trace_hmdfs_lookup_remote(parent_inode, child_dentry, flags);
31862306a36Sopenharmony_ci	if (child_dentry->d_name.len > NAME_MAX) {
31962306a36Sopenharmony_ci		err = -ENAMETOOLONG;
32062306a36Sopenharmony_ci		ret = ERR_PTR(-ENAMETOOLONG);
32162306a36Sopenharmony_ci		goto out;
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	err = init_hmdfs_dentry_info(sbi, child_dentry,
32562306a36Sopenharmony_ci				     HMDFS_LAYER_OTHER_CLOUD);
32662306a36Sopenharmony_ci	if (err) {
32762306a36Sopenharmony_ci		ret = ERR_PTR(err);
32862306a36Sopenharmony_ci		goto out;
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci	gdi = hmdfs_d(child_dentry);
33162306a36Sopenharmony_ci	gdi->device_id = hmdfs_d(child_dentry->d_parent)->device_id;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	ret = hmdfs_lookup_cloud_dentry(parent_inode, child_dentry, flags);
33462306a36Sopenharmony_ci	/*
33562306a36Sopenharmony_ci	 * don't return error if inode do not exist, so that vfs can continue
33662306a36Sopenharmony_ci	 * to create it.
33762306a36Sopenharmony_ci	 */
33862306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(ret)) {
33962306a36Sopenharmony_ci		err = PTR_ERR(ret);
34062306a36Sopenharmony_ci		if (err == -ENOENT)
34162306a36Sopenharmony_ci			ret = NULL;
34262306a36Sopenharmony_ci	} else {
34362306a36Sopenharmony_ci		child_dentry = ret;
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ciout:
34762306a36Sopenharmony_ci	if (!err)
34862306a36Sopenharmony_ci		hmdfs_set_time(child_dentry, jiffies);
34962306a36Sopenharmony_ci	trace_hmdfs_lookup_remote_end(parent_inode, child_dentry, err);
35062306a36Sopenharmony_ci	return ret;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ciint hmdfs_mkdir_cloud(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	return -EPERM;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ciint hmdfs_create_cloud(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode,
35962306a36Sopenharmony_ci			bool want_excl)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	return -EPERM;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ciint hmdfs_rmdir_cloud(struct inode *dir, struct dentry *dentry)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	return -EPERM;
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ciint hmdfs_unlink_cloud(struct inode *dir, struct dentry *dentry)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	return 0;
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ciint hmdfs_rename_cloud(struct mnt_idmap *idmap, struct inode *old_dir, struct dentry *old_dentry,
37562306a36Sopenharmony_ci			struct inode *new_dir, struct dentry *new_dentry,
37662306a36Sopenharmony_ci			unsigned int flags)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	return -EPERM;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic int hmdfs_dir_setattr_cloud(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *ia)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	// Do not support dir setattr
38462306a36Sopenharmony_ci	return 0;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ciconst struct inode_operations hmdfs_dev_dir_inode_ops_cloud = {
38862306a36Sopenharmony_ci	.lookup = hmdfs_lookup_cloud,
38962306a36Sopenharmony_ci	.mkdir = hmdfs_mkdir_cloud,
39062306a36Sopenharmony_ci	.create = hmdfs_create_cloud,
39162306a36Sopenharmony_ci	.rmdir = hmdfs_rmdir_cloud,
39262306a36Sopenharmony_ci	.unlink = hmdfs_unlink_cloud,
39362306a36Sopenharmony_ci	.rename = hmdfs_rename_cloud,
39462306a36Sopenharmony_ci	.setattr = hmdfs_dir_setattr_cloud,
39562306a36Sopenharmony_ci	.permission = hmdfs_permission,
39662306a36Sopenharmony_ci};
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int hmdfs_setattr_cloud(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *ia)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(d_inode(dentry));
40162306a36Sopenharmony_ci	struct inode *inode = d_inode(dentry);
40262306a36Sopenharmony_ci	int err = 0;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (hmdfs_inode_is_stashing(info))
40562306a36Sopenharmony_ci		return -EAGAIN;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (ia->ia_valid & ATTR_SIZE) {
40862306a36Sopenharmony_ci		err = inode_newsize_ok(inode, ia->ia_size);
40962306a36Sopenharmony_ci		if (err)
41062306a36Sopenharmony_ci			return err;
41162306a36Sopenharmony_ci		truncate_setsize(inode, ia->ia_size);
41262306a36Sopenharmony_ci		info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE;
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci	if (ia->ia_valid & ATTR_MTIME)
41562306a36Sopenharmony_ci		inode->i_mtime = ia->ia_mtime;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	return err;
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic int hmdfs_get_cached_attr_cloud(struct mnt_idmap *idmap, const struct path *path,
42262306a36Sopenharmony_ci					struct kstat *stat, u32 request_mask,
42362306a36Sopenharmony_ci					unsigned int flags)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct inode *inode = d_inode(path->dentry);
42662306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
42762306a36Sopenharmony_ci	uint64_t size = info->getattr_isize;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	stat->ino = inode->i_ino;
43062306a36Sopenharmony_ci	stat->mtime = inode->i_mtime;
43162306a36Sopenharmony_ci	stat->mode = inode->i_mode;
43262306a36Sopenharmony_ci	stat->uid.val = inode->i_uid.val;
43362306a36Sopenharmony_ci	stat->gid.val = inode->i_gid.val;
43462306a36Sopenharmony_ci	if (size == HMDFS_STALE_REMOTE_ISIZE)
43562306a36Sopenharmony_ci		size = i_size_read(inode);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	stat->size = size;
43862306a36Sopenharmony_ci	return 0;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ciconst struct inode_operations hmdfs_dev_file_iops_cloud = {
44262306a36Sopenharmony_ci	.setattr = hmdfs_setattr_cloud,
44362306a36Sopenharmony_ci	.permission = hmdfs_permission,
44462306a36Sopenharmony_ci	.getattr = hmdfs_get_cached_attr_cloud,
44562306a36Sopenharmony_ci	.listxattr = NULL,
44662306a36Sopenharmony_ci};
447