162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * fs/hmdfs/inode.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "hmdfs_device_view.h"
962306a36Sopenharmony_ci#include "inode.h"
1062306a36Sopenharmony_ci#include "comm/connection.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/**
1362306a36Sopenharmony_ci * Rules to generate inode numbers:
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * "/", "/device_view", "/merge_view", "/device_view/local", "/device_view/cid"
1662306a36Sopenharmony_ci * = DOMAIN {3} : dev_id {29} : HMDFS_ROOT {32}
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * "/device_view/cid/xxx"
1962306a36Sopenharmony_ci * = DOMAIN {3} : dev_id {29} : hash(remote_ino){32}
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * "/merge_view/xxx"
2262306a36Sopenharmony_ci * = DOMAIN {3} : lower's dev_id {29} : lower's ino_raw {32}
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define BIT_WIDE_TOTAL 64
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define BIT_WIDE_DOMAIN 3
2862306a36Sopenharmony_ci#define BIT_WIDE_DEVID 29
2962306a36Sopenharmony_ci#define BIT_WIDE_INO_RAW 32
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cienum DOMAIN {
3262306a36Sopenharmony_ci	DOMAIN_ROOT,
3362306a36Sopenharmony_ci	DOMAIN_DEVICE_LOCAL,
3462306a36Sopenharmony_ci	DOMAIN_DEVICE_REMOTE,
3562306a36Sopenharmony_ci	DOMAIN_DEVICE_CLOUD,
3662306a36Sopenharmony_ci	DOMAIN_MERGE_VIEW,
3762306a36Sopenharmony_ci	DOMAIN_CLOUD_MERGE_VIEW,
3862306a36Sopenharmony_ci	DOMAIN_INVALID,
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciunion hmdfs_ino {
4262306a36Sopenharmony_ci	const uint64_t ino_output;
4362306a36Sopenharmony_ci	struct {
4462306a36Sopenharmony_ci		uint64_t ino_raw : BIT_WIDE_INO_RAW;
4562306a36Sopenharmony_ci		uint64_t dev_id : BIT_WIDE_DEVID;
4662306a36Sopenharmony_ci		uint8_t domain : BIT_WIDE_DOMAIN;
4762306a36Sopenharmony_ci	};
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic uint8_t read_ino_domain(uint64_t ino)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	union hmdfs_ino _ino = {
5362306a36Sopenharmony_ci		.ino_output = ino,
5462306a36Sopenharmony_ci	};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	return _ino.domain;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistruct iget_args {
6062306a36Sopenharmony_ci	/* The lower inode of local/merge/root(part) inode */
6162306a36Sopenharmony_ci	struct inode *lo_i;
6262306a36Sopenharmony_ci	/* The peer of remote inode */
6362306a36Sopenharmony_ci	struct hmdfs_peer *peer;
6462306a36Sopenharmony_ci	/* The ino of remote inode */
6562306a36Sopenharmony_ci	uint64_t remote_ino;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/* The recordId of cloud inode */
6862306a36Sopenharmony_ci	uint8_t *cloud_record_id;
6962306a36Sopenharmony_ci	uint8_t *reserved;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/* Returned inode's ino */
7262306a36Sopenharmony_ci	union hmdfs_ino ino;
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/**
7662306a36Sopenharmony_ci * iget_test - whether or not the inode with matched hashval is the one we are
7762306a36Sopenharmony_ci * looking for
7862306a36Sopenharmony_ci *
7962306a36Sopenharmony_ci * @inode: the local inode we found in inode cache with matched hashval
8062306a36Sopenharmony_ci * @data: struct iget_args
8162306a36Sopenharmony_ci */
8262306a36Sopenharmony_cistatic int iget_test(struct inode *inode, void *data)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct hmdfs_inode_info *hii = hmdfs_i(inode);
8562306a36Sopenharmony_ci	struct iget_args *ia = data;
8662306a36Sopenharmony_ci	int res = 0;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	WARN_ON(ia->ino.domain < DOMAIN_ROOT ||
8962306a36Sopenharmony_ci		ia->ino.domain >= DOMAIN_INVALID);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (read_ino_domain(inode->i_ino) == DOMAIN_ROOT)
9262306a36Sopenharmony_ci		return 1;
9362306a36Sopenharmony_ci	if (read_ino_domain(inode->i_ino) != ia->ino.domain)
9462306a36Sopenharmony_ci		return 0;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	switch (ia->ino.domain) {
9762306a36Sopenharmony_ci	case DOMAIN_MERGE_VIEW:
9862306a36Sopenharmony_ci	case DOMAIN_CLOUD_MERGE_VIEW:
9962306a36Sopenharmony_ci		res = (ia->lo_i == hii->lower_inode);
10062306a36Sopenharmony_ci		break;
10162306a36Sopenharmony_ci	case DOMAIN_DEVICE_LOCAL:
10262306a36Sopenharmony_ci		res = (ia->lo_i == hii->lower_inode);
10362306a36Sopenharmony_ci		break;
10462306a36Sopenharmony_ci	case DOMAIN_DEVICE_REMOTE:
10562306a36Sopenharmony_ci		res = (ia->peer == hii->conn &&
10662306a36Sopenharmony_ci		       ia->remote_ino == hii->remote_ino);
10762306a36Sopenharmony_ci		break;
10862306a36Sopenharmony_ci	case DOMAIN_DEVICE_CLOUD:
10962306a36Sopenharmony_ci		res = (ia->cloud_record_id &&
11062306a36Sopenharmony_ci		       (memcmp(ia->cloud_record_id, hii->cloud_record_id,
11162306a36Sopenharmony_ci			       CLOUD_RECORD_ID_LEN) == 0) &&
11262306a36Sopenharmony_ci		       (ia->reserved[0] == hii->reserved[0]));
11362306a36Sopenharmony_ci		break;
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return res;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/**
12062306a36Sopenharmony_ci * iget_set - initialize a inode with iget_args
12162306a36Sopenharmony_ci *
12262306a36Sopenharmony_ci * @sb: the superblock of current hmdfs instance
12362306a36Sopenharmony_ci * @data: struct iget_args
12462306a36Sopenharmony_ci */
12562306a36Sopenharmony_cistatic int iget_set(struct inode *inode, void *data)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct hmdfs_inode_info *hii = hmdfs_i(inode);
12862306a36Sopenharmony_ci	struct iget_args *ia = (struct iget_args *)data;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	inode->i_ino = ia->ino.ino_output;
13162306a36Sopenharmony_ci	inode_inc_iversion(inode);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	hii->conn = ia->peer;
13462306a36Sopenharmony_ci	hii->remote_ino = ia->remote_ino;
13562306a36Sopenharmony_ci	hii->lower_inode = ia->lo_i;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (ia->cloud_record_id) {
13862306a36Sopenharmony_ci		memcpy(hii->cloud_record_id, ia->cloud_record_id, CLOUD_RECORD_ID_LEN);
13962306a36Sopenharmony_ci		memcpy(hii->reserved, ia->reserved, CLOUD_DENTRY_RESERVED_LENGTH);
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	return 0;
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic uint64_t make_ino_raw_dev_local(uint64_t lo_ino)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	if (!(lo_ino >> BIT_WIDE_INO_RAW))
14862306a36Sopenharmony_ci		return lo_ino;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return lo_ino * GOLDEN_RATIO_64 >> BIT_WIDE_INO_RAW;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic uint64_t make_ino_raw_dev_remote(uint64_t remote_ino)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	return hash_long(remote_ino, BIT_WIDE_INO_RAW);
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/**
15962306a36Sopenharmony_ci * hmdfs_iget5_locked_merge - obtain an inode for the merge-view
16062306a36Sopenharmony_ci *
16162306a36Sopenharmony_ci * @sb: superblock of current instance
16262306a36Sopenharmony_ci * @fst_lo_i: the lower inode of it's first comrade
16362306a36Sopenharmony_ci *
16462306a36Sopenharmony_ci * Simply replace the lower's domain for a new ino.
16562306a36Sopenharmony_ci */
16662306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_merge(struct super_block *sb,
16762306a36Sopenharmony_ci				       struct dentry *fst_lo_d)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct iget_args ia = {
17062306a36Sopenharmony_ci		.lo_i = d_inode(fst_lo_d),
17162306a36Sopenharmony_ci		.peer = NULL,
17262306a36Sopenharmony_ci		.remote_ino = 0,
17362306a36Sopenharmony_ci		.cloud_record_id = NULL,
17462306a36Sopenharmony_ci		.ino.ino_output = 0,
17562306a36Sopenharmony_ci	};
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	if (unlikely(!d_inode(fst_lo_d))) {
17862306a36Sopenharmony_ci		hmdfs_err("Received a invalid lower inode");
17962306a36Sopenharmony_ci		return NULL;
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci	if (unlikely(!hmdfs_d(fst_lo_d))) {
18262306a36Sopenharmony_ci		hmdfs_err("Received a invalid fsdata");
18362306a36Sopenharmony_ci		return NULL;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	ia.ino.ino_raw = d_inode(fst_lo_d)->i_ino;
18762306a36Sopenharmony_ci	ia.ino.dev_id = hmdfs_d(fst_lo_d)->device_id;
18862306a36Sopenharmony_ci	ia.ino.domain = DOMAIN_MERGE_VIEW;
18962306a36Sopenharmony_ci	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_cloud_merge(struct super_block *sb,
19362306a36Sopenharmony_ci					     struct dentry *fst_lo_d)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	struct iget_args ia = {
19662306a36Sopenharmony_ci		.lo_i = d_inode(fst_lo_d),
19762306a36Sopenharmony_ci		.peer = NULL,
19862306a36Sopenharmony_ci		.remote_ino = 0,
19962306a36Sopenharmony_ci		.cloud_record_id = NULL,
20062306a36Sopenharmony_ci		.ino.ino_output = 0,
20162306a36Sopenharmony_ci	};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (unlikely(!d_inode(fst_lo_d))) {
20462306a36Sopenharmony_ci		hmdfs_err("Received a invalid lower inode");
20562306a36Sopenharmony_ci		return NULL;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci	if (unlikely(!hmdfs_d(fst_lo_d))) {
20862306a36Sopenharmony_ci		hmdfs_err("Received a invalid fsdata");
20962306a36Sopenharmony_ci		return NULL;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	ia.ino.ino_raw = d_inode(fst_lo_d)->i_ino;
21362306a36Sopenharmony_ci	ia.ino.dev_id = hmdfs_d(fst_lo_d)->device_id;
21462306a36Sopenharmony_ci	ia.ino.domain = DOMAIN_CLOUD_MERGE_VIEW;
21562306a36Sopenharmony_ci	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/**
21962306a36Sopenharmony_ci * hmdfs_iget5_locked_local - obtain an inode for the local-dev-view
22062306a36Sopenharmony_ci *
22162306a36Sopenharmony_ci * @sb: superblock of current instance
22262306a36Sopenharmony_ci * @lo_i: the lower inode from local filesystem
22362306a36Sopenharmony_ci *
22462306a36Sopenharmony_ci * Hashing local inode's ino to generate our ino. We continue to compare the
22562306a36Sopenharmony_ci * address of the lower_inode for uniqueness when collisions occurred.
22662306a36Sopenharmony_ci */
22762306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_local(struct super_block *sb,
22862306a36Sopenharmony_ci				       struct inode *lo_i)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct iget_args ia = {
23162306a36Sopenharmony_ci		.lo_i = lo_i,
23262306a36Sopenharmony_ci		.peer = NULL,
23362306a36Sopenharmony_ci		.remote_ino = 0,
23462306a36Sopenharmony_ci		.cloud_record_id = NULL,
23562306a36Sopenharmony_ci		.ino.ino_output = 0,
23662306a36Sopenharmony_ci	};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if (unlikely(!lo_i)) {
23962306a36Sopenharmony_ci		hmdfs_err("Received a invalid lower inode");
24062306a36Sopenharmony_ci		return NULL;
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci	ia.ino.ino_raw = make_ino_raw_dev_local(lo_i->i_ino);
24362306a36Sopenharmony_ci	ia.ino.dev_id = 0;
24462306a36Sopenharmony_ci	ia.ino.domain = DOMAIN_DEVICE_LOCAL;
24562306a36Sopenharmony_ci	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci/**
24962306a36Sopenharmony_ci * hmdfs_iget5_locked_remote - obtain an inode for the remote-dev-view
25062306a36Sopenharmony_ci *
25162306a36Sopenharmony_ci * @sb: superblock of current instance
25262306a36Sopenharmony_ci * @peer: corresponding device node
25362306a36Sopenharmony_ci * @remote_ino: remote inode's ino
25462306a36Sopenharmony_ci *
25562306a36Sopenharmony_ci * Hash remote ino for ino's 32bit~1bit.
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci * Note that currenly implementation assume the each remote inode has unique
25862306a36Sopenharmony_ci * ino. Thus the combination of the peer's unique dev_id and the remote_ino
25962306a36Sopenharmony_ci * is enough to determine a unique remote inode.
26062306a36Sopenharmony_ci */
26162306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_remote(struct super_block *sb,
26262306a36Sopenharmony_ci					struct hmdfs_peer *peer,
26362306a36Sopenharmony_ci					uint64_t remote_ino)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct iget_args ia = {
26662306a36Sopenharmony_ci		.lo_i = NULL,
26762306a36Sopenharmony_ci		.peer = peer,
26862306a36Sopenharmony_ci		.remote_ino = remote_ino,
26962306a36Sopenharmony_ci		.cloud_record_id = NULL,
27062306a36Sopenharmony_ci		.ino.ino_output = 0,
27162306a36Sopenharmony_ci	};
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (unlikely(!peer)) {
27462306a36Sopenharmony_ci		hmdfs_err("Received a invalid peer");
27562306a36Sopenharmony_ci		return NULL;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	ia.ino.ino_raw = make_ino_raw_dev_remote(remote_ino);
27962306a36Sopenharmony_ci	ia.ino.dev_id = peer->device_id;
28062306a36Sopenharmony_ci	ia.ino.domain = DOMAIN_DEVICE_REMOTE;
28162306a36Sopenharmony_ci	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/**
28562306a36Sopenharmony_ci * hmdfs_iget5_locked_cloud - obtain an inode for the cloud-dev-view
28662306a36Sopenharmony_ci *
28762306a36Sopenharmony_ci * @sb: superblock of current instance
28862306a36Sopenharmony_ci * @peer: corresponding device node
28962306a36Sopenharmony_ci * @cloud_id: cloud file record id
29062306a36Sopenharmony_ci *
29162306a36Sopenharmony_ci * Hash remote ino for ino's 32bit~1bit.
29262306a36Sopenharmony_ci *
29362306a36Sopenharmony_ci * Note that currenly implementation assume the each remote inode has unique
29462306a36Sopenharmony_ci * ino. Thus the combination of the peer's unique dev_id and the remote_ino
29562306a36Sopenharmony_ci * is enough to determine a unique remote inode.
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_cloud(struct super_block *sb,
29862306a36Sopenharmony_ci				       struct hmdfs_peer *peer,
29962306a36Sopenharmony_ci				       struct hmdfs_lookup_cloud_ret *res)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct iget_args ia = {
30262306a36Sopenharmony_ci		.lo_i = NULL,
30362306a36Sopenharmony_ci		.peer = peer,
30462306a36Sopenharmony_ci		.remote_ino = 0,
30562306a36Sopenharmony_ci		.cloud_record_id = res->record_id,
30662306a36Sopenharmony_ci		.reserved = res->reserved,
30762306a36Sopenharmony_ci		.ino.ino_output = 0,
30862306a36Sopenharmony_ci	};
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	if (unlikely(!peer)) {
31162306a36Sopenharmony_ci		hmdfs_err("Received a invalid peer");
31262306a36Sopenharmony_ci		return NULL;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	ia.ino.ino_raw = make_ino_raw_cloud(res->record_id) + res->reserved[0];
31662306a36Sopenharmony_ci	ia.ino.dev_id = peer->device_id;
31762306a36Sopenharmony_ci	ia.ino.domain = DOMAIN_DEVICE_CLOUD;
31862306a36Sopenharmony_ci	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistruct inode *hmdfs_iget_locked_root(struct super_block *sb, uint64_t root_ino,
32262306a36Sopenharmony_ci				     struct inode *lo_i,
32362306a36Sopenharmony_ci				     struct hmdfs_peer *peer)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct iget_args ia = {
32662306a36Sopenharmony_ci		.lo_i = lo_i,
32762306a36Sopenharmony_ci		.peer = peer,
32862306a36Sopenharmony_ci		.remote_ino = 0,
32962306a36Sopenharmony_ci		.cloud_record_id = NULL,
33062306a36Sopenharmony_ci		.ino.ino_raw = root_ino,
33162306a36Sopenharmony_ci		.ino.dev_id = peer ? peer->device_id : 0,
33262306a36Sopenharmony_ci		.ino.domain = DOMAIN_ROOT,
33362306a36Sopenharmony_ci	};
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (unlikely(root_ino < 0 || root_ino >= HMDFS_ROOT_INVALID)) {
33662306a36Sopenharmony_ci		hmdfs_err("Root %llu is invalid", root_ino);
33762306a36Sopenharmony_ci		return NULL;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci	if (unlikely(root_ino == HMDFS_ROOT_DEV_REMOTE && !peer)) {
34062306a36Sopenharmony_ci		hmdfs_err("Root %llu received a invalid peer", root_ino);
34162306a36Sopenharmony_ci		return NULL;
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_civoid hmdfs_update_upper_file(struct file *upper_file, struct file *lower_file)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	loff_t upper_size = i_size_read(upper_file->f_inode);
35162306a36Sopenharmony_ci	loff_t lower_size = i_size_read(lower_file->f_inode);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (upper_file->f_inode->i_mapping && upper_size != lower_size) {
35462306a36Sopenharmony_ci		i_size_write(upper_file->f_inode, lower_size);
35562306a36Sopenharmony_ci		truncate_inode_pages(upper_file->f_inode->i_mapping, 0);
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci}