162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * fs/hmdfs/file_merge.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "hmdfs_merge_view.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/file.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "hmdfs.h"
1362306a36Sopenharmony_ci#include "hmdfs_trace.h"
1462306a36Sopenharmony_ci#include "authority/authentication.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct hmdfs_iterate_callback_merge {
1762306a36Sopenharmony_ci	struct dir_context ctx;
1862306a36Sopenharmony_ci	struct dir_context *caller;
1962306a36Sopenharmony_ci	/*
2062306a36Sopenharmony_ci	 * Record the return value of 'caller->actor':
2162306a36Sopenharmony_ci	 *
2262306a36Sopenharmony_ci	 * false, buffer is exhausted
2362306a36Sopenharmony_ci	 * false, current task is pending
2462306a36Sopenharmony_ci	 * false, something is wrong
2562306a36Sopenharmony_ci	 * true, success and can do more
2662306a36Sopenharmony_ci	 */
2762306a36Sopenharmony_ci	bool result ;
2862306a36Sopenharmony_ci	struct rb_root *root;
2962306a36Sopenharmony_ci	uint64_t dev_id;
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct hmdfs_cache_entry {
3362306a36Sopenharmony_ci	struct rb_node rb_node;
3462306a36Sopenharmony_ci	int name_len;
3562306a36Sopenharmony_ci	char *name;
3662306a36Sopenharmony_ci	int file_type;
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct hmdfs_user_info {
4062306a36Sopenharmony_ci	char *local_path;
4162306a36Sopenharmony_ci	char *distributed_path;
4262306a36Sopenharmony_ci	char *bundle_name;
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistruct hmdfs_cache_entry *allocate_entry(const char *name, int namelen,
4662306a36Sopenharmony_ci					 int d_type)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	struct hmdfs_cache_entry *data;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	data = kmalloc(sizeof(*data), GFP_KERNEL);
5162306a36Sopenharmony_ci	if (!data)
5262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	data->name = kstrndup(name, namelen, GFP_KERNEL);
5562306a36Sopenharmony_ci	if (!data->name) {
5662306a36Sopenharmony_ci		kfree(data);
5762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	data->name_len = namelen;
6162306a36Sopenharmony_ci	data->file_type = d_type;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return data;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ciint insert_filename(struct rb_root *root, struct hmdfs_cache_entry **new_entry)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct rb_node *parent = NULL;
6962306a36Sopenharmony_ci	struct rb_node **new_node = &(root->rb_node);
7062306a36Sopenharmony_ci	int cmp_res = 0;
7162306a36Sopenharmony_ci	struct hmdfs_cache_entry *data = *new_entry;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	while (*new_node) {
7462306a36Sopenharmony_ci		struct hmdfs_cache_entry *entry = container_of(
7562306a36Sopenharmony_ci			*new_node, struct hmdfs_cache_entry, rb_node);
7662306a36Sopenharmony_ci		parent = *new_node;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		if (data->name_len < entry->name_len)
7962306a36Sopenharmony_ci			cmp_res = -1;
8062306a36Sopenharmony_ci		else if (data->name_len > entry->name_len)
8162306a36Sopenharmony_ci			cmp_res = 1;
8262306a36Sopenharmony_ci		else
8362306a36Sopenharmony_ci			cmp_res = strncmp(data->name, entry->name,
8462306a36Sopenharmony_ci					  data->name_len);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		if (!cmp_res) {
8762306a36Sopenharmony_ci			kfree(data->name);
8862306a36Sopenharmony_ci			kfree(data);
8962306a36Sopenharmony_ci			*new_entry = entry;
9062306a36Sopenharmony_ci			return entry->file_type;
9162306a36Sopenharmony_ci		}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		if (cmp_res < 0)
9462306a36Sopenharmony_ci			new_node = &((*new_node)->rb_left);
9562306a36Sopenharmony_ci		else if (cmp_res > 0)
9662306a36Sopenharmony_ci			new_node = &((*new_node)->rb_right);
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	rb_link_node(&data->rb_node, parent, new_node);
10062306a36Sopenharmony_ci	rb_insert_color(&data->rb_node, root);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	return 0;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic void recursive_delete(struct rb_node *node)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	struct hmdfs_cache_entry *entry = NULL;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (!node)
11062306a36Sopenharmony_ci		return;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	recursive_delete(node->rb_left);
11362306a36Sopenharmony_ci	recursive_delete(node->rb_right);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	entry = container_of(node, struct hmdfs_cache_entry, rb_node);
11662306a36Sopenharmony_ci	kfree(entry->name);
11762306a36Sopenharmony_ci	kfree(entry);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic void destroy_tree(struct rb_root *root)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	if (!root)
12362306a36Sopenharmony_ci		return;
12462306a36Sopenharmony_ci	recursive_delete(root->rb_node);
12562306a36Sopenharmony_ci	root->rb_node = NULL;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic void delete_filename(struct rb_root *root,
12962306a36Sopenharmony_ci			    struct hmdfs_cache_entry *data)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct rb_node **node = &(root->rb_node);
13262306a36Sopenharmony_ci	struct hmdfs_cache_entry *entry = NULL;
13362306a36Sopenharmony_ci	int cmp_res = 0;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	while (*node) {
13662306a36Sopenharmony_ci		entry = container_of(*node, struct hmdfs_cache_entry, rb_node);
13762306a36Sopenharmony_ci		if (data->name_len < entry->name_len)
13862306a36Sopenharmony_ci			cmp_res = -1;
13962306a36Sopenharmony_ci		else if (data->name_len > entry->name_len)
14062306a36Sopenharmony_ci			cmp_res = 1;
14162306a36Sopenharmony_ci		else
14262306a36Sopenharmony_ci			cmp_res = strncmp(data->name, entry->name,
14362306a36Sopenharmony_ci					  data->name_len);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci		if (!cmp_res)
14662306a36Sopenharmony_ci			goto found;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		if (cmp_res < 0)
14962306a36Sopenharmony_ci			node = &((*node)->rb_left);
15062306a36Sopenharmony_ci		else if (cmp_res > 0)
15162306a36Sopenharmony_ci			node = &((*node)->rb_right);
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci	return;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cifound:
15662306a36Sopenharmony_ci	rb_erase(*node, root);
15762306a36Sopenharmony_ci	kfree(entry->name);
15862306a36Sopenharmony_ci	kfree(entry);
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic void rename_conflicting_file(char *dentry_name, int *len,
16262306a36Sopenharmony_ci				    unsigned int dev_id)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	int i = *len - 1;
16562306a36Sopenharmony_ci	int dot_pos = -1;
16662306a36Sopenharmony_ci	char *buffer;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	buffer = kzalloc(DENTRY_NAME_MAX_LEN, GFP_KERNEL);
16962306a36Sopenharmony_ci	if (!buffer)
17062306a36Sopenharmony_ci		return;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	while (i >= 0) {
17362306a36Sopenharmony_ci		if (dentry_name[i] == '/')
17462306a36Sopenharmony_ci			break;
17562306a36Sopenharmony_ci		if (dentry_name[i] == '.') {
17662306a36Sopenharmony_ci			// TODO: 这个修改同步到 CT01
17762306a36Sopenharmony_ci			dot_pos = i;
17862306a36Sopenharmony_ci			break;
17962306a36Sopenharmony_ci		}
18062306a36Sopenharmony_ci		i--;
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (dot_pos == -1) {
18462306a36Sopenharmony_ci		snprintf(dentry_name + *len, DENTRY_NAME_MAX_LEN - *len,
18562306a36Sopenharmony_ci			 CONFLICTING_FILE_SUFFIX, dev_id);
18662306a36Sopenharmony_ci		goto done;
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	for (i = 0; i < *len - dot_pos; i++)
19062306a36Sopenharmony_ci		buffer[i] = dentry_name[i + dot_pos];
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	buffer[i] = '\0';
19362306a36Sopenharmony_ci	snprintf(dentry_name + dot_pos, DENTRY_NAME_MAX_LEN - dot_pos,
19462306a36Sopenharmony_ci		 CONFLICTING_FILE_SUFFIX, dev_id);
19562306a36Sopenharmony_ci	strcat(dentry_name, buffer);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cidone:
19862306a36Sopenharmony_ci	*len = strlen(dentry_name);
19962306a36Sopenharmony_ci	kfree(buffer);
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic void rename_conflicting_directory(char *dentry_name, int *len)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	snprintf(dentry_name + *len, DENTRY_NAME_MAX_LEN - *len,
20562306a36Sopenharmony_ci		 CONFLICTING_DIR_SUFFIX);
20662306a36Sopenharmony_ci	*len += strlen(CONFLICTING_DIR_SUFFIX);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic bool hmdfs_actor_merge(struct dir_context *ctx, const char *name,
21062306a36Sopenharmony_ci			     int namelen, long long offset, unsigned long long ino,
21162306a36Sopenharmony_ci			     unsigned int d_type)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	bool ret = true;
21462306a36Sopenharmony_ci	int insert_res = 0;
21562306a36Sopenharmony_ci	int max_devid_len = 2;
21662306a36Sopenharmony_ci	char *dentry_name = NULL;
21762306a36Sopenharmony_ci	int dentry_len = namelen;
21862306a36Sopenharmony_ci	struct hmdfs_cache_entry *cache_entry = NULL;
21962306a36Sopenharmony_ci	struct hmdfs_iterate_callback_merge *iterate_callback_merge = NULL;
22062306a36Sopenharmony_ci	struct dir_context *org_ctx = NULL;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (hmdfs_file_type(name) != HMDFS_TYPE_COMMON) {
22362306a36Sopenharmony_ci		/*
22462306a36Sopenharmony_ci		* return true here, so that the caller can continue to next
22562306a36Sopenharmony_ci		* dentry even if failed on this dentry somehow.
22662306a36Sopenharmony_ci		*/
22762306a36Sopenharmony_ci		return true;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (namelen > NAME_MAX)
23262306a36Sopenharmony_ci		return false;
23362306a36Sopenharmony_ci	dentry_name = kzalloc(NAME_MAX + 1, GFP_KERNEL);
23462306a36Sopenharmony_ci	if (!dentry_name)
23562306a36Sopenharmony_ci		return false;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	strncpy(dentry_name, name, dentry_len);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	cache_entry = allocate_entry(dentry_name, dentry_len, d_type);
24062306a36Sopenharmony_ci	if (IS_ERR(cache_entry)) {
24162306a36Sopenharmony_ci		ret = PTR_ERR(cache_entry);
24262306a36Sopenharmony_ci		goto done;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	iterate_callback_merge =
24662306a36Sopenharmony_ci		container_of(ctx, struct hmdfs_iterate_callback_merge, ctx);
24762306a36Sopenharmony_ci	insert_res =
24862306a36Sopenharmony_ci		insert_filename(iterate_callback_merge->root, &cache_entry);
24962306a36Sopenharmony_ci	if (d_type == DT_DIR && insert_res == DT_DIR) {
25062306a36Sopenharmony_ci		goto done;
25162306a36Sopenharmony_ci	} else if (d_type == DT_DIR &&
25262306a36Sopenharmony_ci		  (insert_res == DT_REG || insert_res == DT_LNK)) {
25362306a36Sopenharmony_ci		if (strlen(CONFLICTING_DIR_SUFFIX) > NAME_MAX - dentry_len) {
25462306a36Sopenharmony_ci			ret = false;
25562306a36Sopenharmony_ci			goto delete;
25662306a36Sopenharmony_ci		}
25762306a36Sopenharmony_ci		rename_conflicting_directory(dentry_name, &dentry_len);
25862306a36Sopenharmony_ci		cache_entry->file_type = DT_DIR;
25962306a36Sopenharmony_ci	} else if ((d_type == DT_REG || d_type == DT_LNK) && insert_res > 0) {
26062306a36Sopenharmony_ci		if (strlen(CONFLICTING_FILE_SUFFIX) + max_devid_len >
26162306a36Sopenharmony_ci		    NAME_MAX - dentry_len) {
26262306a36Sopenharmony_ci			ret = false;
26362306a36Sopenharmony_ci			goto delete;
26462306a36Sopenharmony_ci		}
26562306a36Sopenharmony_ci		rename_conflicting_file(dentry_name, &dentry_len,
26662306a36Sopenharmony_ci					iterate_callback_merge->dev_id);
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	org_ctx = iterate_callback_merge->caller;
27062306a36Sopenharmony_ci	ret = org_ctx->actor(org_ctx, dentry_name, dentry_len, org_ctx->pos,
27162306a36Sopenharmony_ci			     ino, d_type);
27262306a36Sopenharmony_ci	/*
27362306a36Sopenharmony_ci	 * Record original return value, so that the caller can be aware of
27462306a36Sopenharmony_ci	 * different situations.
27562306a36Sopenharmony_ci	 */
27662306a36Sopenharmony_ci	iterate_callback_merge->result = ret;
27762306a36Sopenharmony_ci	if (!ret && d_type == DT_DIR && cache_entry->file_type == DT_DIR &&
27862306a36Sopenharmony_ci	   (insert_res == DT_REG || insert_res == DT_LNK))
27962306a36Sopenharmony_ci		cache_entry->file_type = DT_REG;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cidelete:
28262306a36Sopenharmony_ci	if (!ret && !insert_res)
28362306a36Sopenharmony_ci		delete_filename(iterate_callback_merge->root, cache_entry);
28462306a36Sopenharmony_cidone:
28562306a36Sopenharmony_ci	kfree(dentry_name);
28662306a36Sopenharmony_ci	return ret;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistruct hmdfs_file_info *
29062306a36Sopenharmony_ciget_next_hmdfs_file_info(struct hmdfs_file_info *fi_head, int device_id)
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	struct hmdfs_file_info *fi_iter = NULL;
29362306a36Sopenharmony_ci	struct hmdfs_file_info *fi_result = NULL;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	mutex_lock(&fi_head->comrade_list_lock);
29662306a36Sopenharmony_ci	list_for_each_entry_safe(fi_iter, fi_result, &(fi_head->comrade_list),
29762306a36Sopenharmony_ci				  comrade_list) {
29862306a36Sopenharmony_ci		if (fi_iter->device_id == device_id)
29962306a36Sopenharmony_ci			break;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci	mutex_unlock(&fi_head->comrade_list_lock);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	return fi_result != fi_head ? fi_result : NULL;
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistruct hmdfs_file_info *get_hmdfs_file_info(struct hmdfs_file_info *fi_head,
30762306a36Sopenharmony_ci					    int device_id)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	struct hmdfs_file_info *fi_iter = NULL;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	mutex_lock(&fi_head->comrade_list_lock);
31262306a36Sopenharmony_ci	list_for_each_entry(fi_iter, &(fi_head->comrade_list), comrade_list) {
31362306a36Sopenharmony_ci		if (fi_iter->device_id == device_id) {
31462306a36Sopenharmony_ci			mutex_unlock(&fi_head->comrade_list_lock);
31562306a36Sopenharmony_ci			return fi_iter;
31662306a36Sopenharmony_ci		}
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci	mutex_unlock(&fi_head->comrade_list_lock);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return NULL;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ciint hmdfs_iterate_merge(struct file *file, struct dir_context *ctx)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	int err = 0;
32662306a36Sopenharmony_ci	struct hmdfs_file_info *fi_head = hmdfs_f(file);
32762306a36Sopenharmony_ci	struct hmdfs_file_info *fi_iter = NULL;
32862306a36Sopenharmony_ci	struct file *lower_file_iter = NULL;
32962306a36Sopenharmony_ci	loff_t start_pos = ctx->pos;
33062306a36Sopenharmony_ci	unsigned long device_id = (unsigned long)((ctx->pos) << 1 >>
33162306a36Sopenharmony_ci				  (POS_BIT_NUM - DEV_ID_BIT_NUM));
33262306a36Sopenharmony_ci	struct hmdfs_iterate_callback_merge ctx_merge = {
33362306a36Sopenharmony_ci		.ctx.actor = hmdfs_actor_merge,
33462306a36Sopenharmony_ci		.caller = ctx,
33562306a36Sopenharmony_ci		.root = &fi_head->root,
33662306a36Sopenharmony_ci		.dev_id = device_id
33762306a36Sopenharmony_ci	};
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/* pos = -1 indicates that all devices have been traversed
34062306a36Sopenharmony_ci	 * or an error has occurred.
34162306a36Sopenharmony_ci	 */
34262306a36Sopenharmony_ci	if (ctx->pos == -1)
34362306a36Sopenharmony_ci		return 0;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	fi_iter = get_hmdfs_file_info(fi_head, device_id);
34662306a36Sopenharmony_ci	if (!fi_iter) {
34762306a36Sopenharmony_ci		fi_iter = get_next_hmdfs_file_info(fi_head, device_id);
34862306a36Sopenharmony_ci		// dev_id is changed, parameter is set 0 to get next file info
34962306a36Sopenharmony_ci		if (fi_iter)
35062306a36Sopenharmony_ci			ctx_merge.ctx.pos =
35162306a36Sopenharmony_ci				hmdfs_set_pos(fi_iter->device_id, 0, 0);
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci	while (fi_iter) {
35462306a36Sopenharmony_ci		ctx_merge.dev_id = fi_iter->device_id;
35562306a36Sopenharmony_ci		device_id = ctx_merge.dev_id;
35662306a36Sopenharmony_ci		lower_file_iter = fi_iter->lower_file;
35762306a36Sopenharmony_ci		lower_file_iter->f_pos = file->f_pos;
35862306a36Sopenharmony_ci		err = iterate_dir(lower_file_iter, &ctx_merge.ctx);
35962306a36Sopenharmony_ci		file->f_pos = lower_file_iter->f_pos;
36062306a36Sopenharmony_ci		ctx->pos = file->f_pos;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci		if (err)
36362306a36Sopenharmony_ci			goto done;
36462306a36Sopenharmony_ci		/*
36562306a36Sopenharmony_ci		 * ctx->actor return nonzero means buffer is exhausted or
36662306a36Sopenharmony_ci		 * something is wrong, thus we should not continue.
36762306a36Sopenharmony_ci		 */
36862306a36Sopenharmony_ci		if (ctx_merge.result)
36962306a36Sopenharmony_ci			goto done;
37062306a36Sopenharmony_ci		fi_iter = get_next_hmdfs_file_info(fi_head, device_id);
37162306a36Sopenharmony_ci		if (fi_iter) {
37262306a36Sopenharmony_ci			file->f_pos = hmdfs_set_pos(fi_iter->device_id, 0, 0);
37362306a36Sopenharmony_ci			ctx->pos = file->f_pos;
37462306a36Sopenharmony_ci		}
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_cidone:
37762306a36Sopenharmony_ci	trace_hmdfs_iterate_merge(file->f_path.dentry, start_pos, ctx->pos,
37862306a36Sopenharmony_ci				  err);
37962306a36Sopenharmony_ci	return err;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ciint do_dir_open_merge(struct file *file, const struct cred *cred,
38362306a36Sopenharmony_ci		      struct hmdfs_file_info *fi_head)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	int ret = -EINVAL;
38662306a36Sopenharmony_ci	struct hmdfs_dentry_info_merge *dim = hmdfs_dm(file->f_path.dentry);
38762306a36Sopenharmony_ci	struct hmdfs_dentry_comrade *comrade = NULL;
38862306a36Sopenharmony_ci	struct hmdfs_file_info *fi = NULL;
38962306a36Sopenharmony_ci	struct path lo_p = { .mnt = file->f_path.mnt };
39062306a36Sopenharmony_ci	struct file *lower_file = NULL;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(cred))
39362306a36Sopenharmony_ci		return ret;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	wait_event(dim->wait_queue, !has_merge_lookup_work(dim));
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	mutex_lock(&dim->comrade_list_lock);
39862306a36Sopenharmony_ci	list_for_each_entry(comrade, &(dim->comrade_list), list) {
39962306a36Sopenharmony_ci		fi = kzalloc(sizeof(*fi), GFP_KERNEL);
40062306a36Sopenharmony_ci		if (!fi) {
40162306a36Sopenharmony_ci			ret = ret ? -ENOMEM : 0;
40262306a36Sopenharmony_ci			continue; // allow some dir to fail to open
40362306a36Sopenharmony_ci		}
40462306a36Sopenharmony_ci		lo_p.dentry = comrade->lo_d;
40562306a36Sopenharmony_ci		// make sure that dentry will not be dentry_kill before open
40662306a36Sopenharmony_ci		dget(lo_p.dentry);
40762306a36Sopenharmony_ci		if (unlikely(d_is_negative(lo_p.dentry))) {
40862306a36Sopenharmony_ci			hmdfs_info("dentry is negative, try again");
40962306a36Sopenharmony_ci			kfree(fi);
41062306a36Sopenharmony_ci			dput(lo_p.dentry);
41162306a36Sopenharmony_ci			continue;  // skip this device
41262306a36Sopenharmony_ci		}
41362306a36Sopenharmony_ci		lower_file = dentry_open(&lo_p, file->f_flags, cred);
41462306a36Sopenharmony_ci		dput(lo_p.dentry);
41562306a36Sopenharmony_ci		if (IS_ERR(lower_file)) {
41662306a36Sopenharmony_ci			kfree(fi);
41762306a36Sopenharmony_ci			continue;
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci		ret = 0;
42062306a36Sopenharmony_ci		fi->device_id = comrade->dev_id;
42162306a36Sopenharmony_ci		fi->lower_file = lower_file;
42262306a36Sopenharmony_ci		mutex_lock(&fi_head->comrade_list_lock);
42362306a36Sopenharmony_ci		list_add_tail(&fi->comrade_list, &fi_head->comrade_list);
42462306a36Sopenharmony_ci		mutex_unlock(&fi_head->comrade_list_lock);
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci	mutex_unlock(&dim->comrade_list_lock);
42762306a36Sopenharmony_ci	return ret;
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ciint hmdfs_dir_open_merge(struct inode *inode, struct file *file)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	int ret = 0;
43362306a36Sopenharmony_ci	struct hmdfs_file_info *fi = NULL;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	fi = kzalloc(sizeof(*fi), GFP_KERNEL);
43662306a36Sopenharmony_ci	if (!fi)
43762306a36Sopenharmony_ci		return -ENOMEM;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	file->private_data = fi;
44062306a36Sopenharmony_ci	fi->root = RB_ROOT;
44162306a36Sopenharmony_ci	mutex_init(&fi->comrade_list_lock);
44262306a36Sopenharmony_ci	INIT_LIST_HEAD(&fi->comrade_list);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	ret = do_dir_open_merge(file, hmdfs_sb(inode->i_sb)->cred, fi);
44562306a36Sopenharmony_ci	if (ret)
44662306a36Sopenharmony_ci		kfree(fi);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	return ret;
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ciint hmdfs_dir_release_merge(struct inode *inode, struct file *file)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct hmdfs_file_info *fi_head = hmdfs_f(file);
45462306a36Sopenharmony_ci	struct hmdfs_file_info *fi_iter = NULL;
45562306a36Sopenharmony_ci	struct hmdfs_file_info *fi_temp = NULL;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	mutex_lock(&fi_head->comrade_list_lock);
45862306a36Sopenharmony_ci	list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
45962306a36Sopenharmony_ci				  comrade_list) {
46062306a36Sopenharmony_ci		list_del_init(&(fi_iter->comrade_list));
46162306a36Sopenharmony_ci		fput(fi_iter->lower_file);
46262306a36Sopenharmony_ci		kfree(fi_iter);
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci	mutex_unlock(&fi_head->comrade_list_lock);
46562306a36Sopenharmony_ci	destroy_tree(&fi_head->root);
46662306a36Sopenharmony_ci	file->private_data = NULL;
46762306a36Sopenharmony_ci	kfree(fi_head);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	return 0;
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_cistatic long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cilong hmdfs_dir_unlocked_ioctl_merge(struct file *file, unsigned int cmd,
47562306a36Sopenharmony_ci							unsigned long arg)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	struct hmdfs_file_info *fi_head = hmdfs_f(file);
47862306a36Sopenharmony_ci	struct hmdfs_file_info *fi_iter = NULL;
47962306a36Sopenharmony_ci	struct hmdfs_file_info *fi_temp = NULL;
48062306a36Sopenharmony_ci	struct file *lower_file = NULL;
48162306a36Sopenharmony_ci	int error = -ENOTTY;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (cmd == HMDFS_IOC_GET_DST_PATH)
48462306a36Sopenharmony_ci		return hmdfs_ioc_get_dst_path(file, arg);
48562306a36Sopenharmony_ci	mutex_lock(&fi_head->comrade_list_lock);
48662306a36Sopenharmony_ci	list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
48762306a36Sopenharmony_ci				  comrade_list) {
48862306a36Sopenharmony_ci		if (fi_iter->device_id == 0) {
48962306a36Sopenharmony_ci			lower_file = fi_iter->lower_file;
49062306a36Sopenharmony_ci			if (lower_file->f_op->unlocked_ioctl)
49162306a36Sopenharmony_ci				error = lower_file->f_op->unlocked_ioctl(
49262306a36Sopenharmony_ci					lower_file, cmd, arg);
49362306a36Sopenharmony_ci			break;
49462306a36Sopenharmony_ci		}
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci	mutex_unlock(&fi_head->comrade_list_lock);
49762306a36Sopenharmony_ci	return error;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cilong hmdfs_dir_compat_ioctl_merge(struct file *file, unsigned int cmd,
50162306a36Sopenharmony_ci							unsigned long arg)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct hmdfs_file_info *fi_head = hmdfs_f(file);
50462306a36Sopenharmony_ci	struct hmdfs_file_info *fi_iter = NULL;
50562306a36Sopenharmony_ci	struct hmdfs_file_info *fi_temp = NULL;
50662306a36Sopenharmony_ci	struct file *lower_file = NULL;
50762306a36Sopenharmony_ci	int error = -ENOTTY;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (cmd == HMDFS_IOC_GET_DST_PATH)
51062306a36Sopenharmony_ci		return hmdfs_ioc_get_dst_path(file, arg);
51162306a36Sopenharmony_ci	mutex_lock(&fi_head->comrade_list_lock);
51262306a36Sopenharmony_ci	list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
51362306a36Sopenharmony_ci				  comrade_list) {
51462306a36Sopenharmony_ci		if (fi_iter->device_id == 0) {
51562306a36Sopenharmony_ci			lower_file = fi_iter->lower_file;
51662306a36Sopenharmony_ci			if (lower_file->f_op->compat_ioctl)
51762306a36Sopenharmony_ci				error = lower_file->f_op->compat_ioctl(
51862306a36Sopenharmony_ci					lower_file, cmd, arg);
51962306a36Sopenharmony_ci			break;
52062306a36Sopenharmony_ci		}
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci	mutex_unlock(&fi_head->comrade_list_lock);
52362306a36Sopenharmony_ci	return error;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ciconst struct file_operations hmdfs_dir_fops_merge = {
52762306a36Sopenharmony_ci	.owner = THIS_MODULE,
52862306a36Sopenharmony_ci	.iterate_shared = hmdfs_iterate_merge,
52962306a36Sopenharmony_ci	.open = hmdfs_dir_open_merge,
53062306a36Sopenharmony_ci	.release = hmdfs_dir_release_merge,
53162306a36Sopenharmony_ci	.unlocked_ioctl = hmdfs_dir_unlocked_ioctl_merge,
53262306a36Sopenharmony_ci	.compat_ioctl = hmdfs_dir_compat_ioctl_merge,
53362306a36Sopenharmony_ci};
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic ssize_t hmdfs_merge_read_iter(struct kiocb *iocb, struct iov_iter *iter)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	return hmdfs_do_read_iter(iocb->ki_filp, iter, &iocb->ki_pos);
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cissize_t hmdfs_merge_write_iter(struct kiocb *iocb, struct iov_iter *iter)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	return hmdfs_do_write_iter(iocb->ki_filp, iter, &iocb->ki_pos);
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ciint hmdfs_file_open_merge(struct inode *inode, struct file *file)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	int err = 0;
54862306a36Sopenharmony_ci	struct file *lower_file = NULL;
54962306a36Sopenharmony_ci	struct path lo_p = { .mnt = file->f_path.mnt };
55062306a36Sopenharmony_ci	struct super_block *sb = inode->i_sb;
55162306a36Sopenharmony_ci	const struct cred *cred = hmdfs_sb(sb)->cred;
55262306a36Sopenharmony_ci	struct hmdfs_file_info *gfi = NULL;
55362306a36Sopenharmony_ci	struct dentry *parent = NULL;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	lo_p.dentry = hmdfs_get_fst_lo_d(file->f_path.dentry);
55662306a36Sopenharmony_ci	if (!lo_p.dentry) {
55762306a36Sopenharmony_ci		err = -EINVAL;
55862306a36Sopenharmony_ci		goto out_err;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	gfi = kzalloc(sizeof(*gfi), GFP_KERNEL);
56262306a36Sopenharmony_ci	if (!gfi) {
56362306a36Sopenharmony_ci		err = -ENOMEM;
56462306a36Sopenharmony_ci		goto out_err;
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	parent = dget_parent(file->f_path.dentry);
56862306a36Sopenharmony_ci	lower_file = dentry_open(&lo_p, file->f_flags, cred);
56962306a36Sopenharmony_ci	if (IS_ERR(lower_file)) {
57062306a36Sopenharmony_ci		err = PTR_ERR(lower_file);
57162306a36Sopenharmony_ci		kfree(gfi);
57262306a36Sopenharmony_ci	} else {
57362306a36Sopenharmony_ci		gfi->lower_file = lower_file;
57462306a36Sopenharmony_ci		file->private_data = gfi;
57562306a36Sopenharmony_ci		hmdfs_update_upper_file(file, lower_file);
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci	dput(parent);
57862306a36Sopenharmony_ciout_err:
57962306a36Sopenharmony_ci	dput(lo_p.dentry);
58062306a36Sopenharmony_ci	return err;
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ciint hmdfs_file_flush_merge(struct file *file, fl_owner_t id)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct hmdfs_file_info *gfi = hmdfs_f(file);
58662306a36Sopenharmony_ci	struct file *lower_file = gfi->lower_file;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (lower_file->f_op->flush)
58962306a36Sopenharmony_ci		return lower_file->f_op->flush(lower_file, id);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	return 0;
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic long hmdfs_ioc_get_writeopen_cnt(struct file *filp, unsigned long arg)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct hmdfs_file_info *gfi = hmdfs_f(filp);
59762306a36Sopenharmony_ci	struct file *lower_file = gfi->lower_file;
59862306a36Sopenharmony_ci	struct inode *lower_inode = file_inode(lower_file);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	u32 wo_cnt = atomic_read(&(hmdfs_i(lower_inode))->write_opened);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	return put_user(wo_cnt, (int __user *)arg);
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic int copy_string_from_user(unsigned long pos, unsigned long len,
60662306a36Sopenharmony_ci				char **data)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	char *tmp_data;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	if (len >= PATH_MAX)
61162306a36Sopenharmony_ci		return -EINVAL;
61262306a36Sopenharmony_ci	if (!access_ok((char __user *)pos, len))
61362306a36Sopenharmony_ci		return -EFAULT;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	tmp_data = kzalloc(len + 1, GFP_KERNEL);
61662306a36Sopenharmony_ci	if (!tmp_data)
61762306a36Sopenharmony_ci		return -ENOMEM;
61862306a36Sopenharmony_ci	*data = tmp_data;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if (copy_from_user(tmp_data, (char __user *)pos, len))
62162306a36Sopenharmony_ci		return -EFAULT;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	return 0;
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic int hmdfs_get_info_from_user(unsigned long pos,
62762306a36Sopenharmony_ci		struct hmdfs_dst_info *hdi, struct hmdfs_user_info *data)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	int ret = 0;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (!access_ok((struct hmdfs_dst_info __user *)pos,
63262306a36Sopenharmony_ci			sizeof(struct hmdfs_dst_info)))
63362306a36Sopenharmony_ci		return -ENOMEM;
63462306a36Sopenharmony_ci	if (copy_from_user(hdi, (struct hmdfs_dst_info __user *)pos,
63562306a36Sopenharmony_ci			sizeof(struct hmdfs_dst_info)))
63662306a36Sopenharmony_ci		return -EFAULT;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	ret = copy_string_from_user(hdi->local_path_pos, hdi->local_path_len,
63962306a36Sopenharmony_ci				    &data->local_path);
64062306a36Sopenharmony_ci	if (ret != 0)
64162306a36Sopenharmony_ci		return ret;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	ret = copy_string_from_user(hdi->distributed_path_pos,
64462306a36Sopenharmony_ci				    hdi->distributed_path_len,
64562306a36Sopenharmony_ci				    &data->distributed_path);
64662306a36Sopenharmony_ci	if (ret != 0)
64762306a36Sopenharmony_ci		return ret;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	ret = copy_string_from_user(hdi->bundle_name_pos, hdi->bundle_name_len,
65062306a36Sopenharmony_ci				    &data->bundle_name);
65162306a36Sopenharmony_ci	if (ret != 0)
65262306a36Sopenharmony_ci		return ret;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	return 0;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic const struct cred *change_cred(struct dentry *dentry,
65862306a36Sopenharmony_ci				      const char *bundle_name)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	int bid;
66162306a36Sopenharmony_ci	struct cred *cred = NULL;
66262306a36Sopenharmony_ci	const struct cred *old_cred = NULL;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	cred = prepare_creds();
66562306a36Sopenharmony_ci	if (!cred) {
66662306a36Sopenharmony_ci		return NULL;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci	bid = get_bundle_uid(hmdfs_sb(dentry->d_sb), bundle_name);
66962306a36Sopenharmony_ci	if (bid != 0) {
67062306a36Sopenharmony_ci		cred->fsuid = KUIDT_INIT(bid);
67162306a36Sopenharmony_ci		cred->fsgid = KGIDT_INIT(bid);
67262306a36Sopenharmony_ci		old_cred = override_creds(cred);
67362306a36Sopenharmony_ci	}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	return old_cred;
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic int get_file_size(const char *path_value, uint64_t pos)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	int ret;
68162306a36Sopenharmony_ci	uint64_t size;
68262306a36Sopenharmony_ci	struct path path;
68362306a36Sopenharmony_ci	struct kstat buf;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	ret = kern_path(path_value, 0, &path);
68662306a36Sopenharmony_ci	if (ret)
68762306a36Sopenharmony_ci		return ret;
68862306a36Sopenharmony_ci	ret = vfs_getattr(&path, &buf, STATX_BASIC_STATS | STATX_BTIME, 0);
68962306a36Sopenharmony_ci	path_put(&path);
69062306a36Sopenharmony_ci	if (ret) {
69162306a36Sopenharmony_ci		hmdfs_err("call vfs_getattr failed, err %d", ret);
69262306a36Sopenharmony_ci		return ret;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	size = buf.size;
69662306a36Sopenharmony_ci	ret = copy_to_user((uint64_t __user *)pos, &size, sizeof(uint64_t));
69762306a36Sopenharmony_ci	return ret;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic int create_link_file(struct hmdfs_user_info *data)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	int ret;
70362306a36Sopenharmony_ci	struct dentry *dentry;
70462306a36Sopenharmony_ci	struct path path;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	ret = kern_path(data->distributed_path, 0, &path);
70762306a36Sopenharmony_ci	if (ret == 0){
70862306a36Sopenharmony_ci		path_put(&path);
70962306a36Sopenharmony_ci		return ret;
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	dentry = kern_path_create(AT_FDCWD, data->distributed_path, &path, 0);
71362306a36Sopenharmony_ci	if (IS_ERR(dentry))
71462306a36Sopenharmony_ci		return PTR_ERR(dentry);
71562306a36Sopenharmony_ci	ret = vfs_symlink(&nop_mnt_idmap, path.dentry->d_inode, dentry, data->local_path);
71662306a36Sopenharmony_ci	done_path_create(&path, dentry);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	return ret;
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cistatic int create_dir(const char *path_value, mode_t mode)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	int err = 0;
72462306a36Sopenharmony_ci	struct path path;
72562306a36Sopenharmony_ci	struct dentry *dentry;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	dentry = kern_path_create(AT_FDCWD, path_value, &path, LOOKUP_DIRECTORY);
72862306a36Sopenharmony_ci	if(PTR_ERR(dentry) == -EEXIST)
72962306a36Sopenharmony_ci		return 0;
73062306a36Sopenharmony_ci	if (IS_ERR(dentry))
73162306a36Sopenharmony_ci		return PTR_ERR(dentry);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	err = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode);
73462306a36Sopenharmony_ci	if (err && err != -EEXIST)
73562306a36Sopenharmony_ci		hmdfs_err("vfs_mkdir failed, err = %d", err);
73662306a36Sopenharmony_ci	done_path_create(&path, dentry);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	return err;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic int create_dir_recursive(const char *path_value, mode_t mode)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	int err = 0;
74462306a36Sopenharmony_ci	char *tmp_path = kstrdup(path_value, GFP_KERNEL);
74562306a36Sopenharmony_ci	char *p = tmp_path;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (!tmp_path)
74862306a36Sopenharmony_ci		return -ENOMEM;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	if (*p == '/')
75162306a36Sopenharmony_ci		p++;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	while (*p) {
75462306a36Sopenharmony_ci		if (*p == '/') {
75562306a36Sopenharmony_ci			*p = '\0';
75662306a36Sopenharmony_ci			err = create_dir(tmp_path, mode);
75762306a36Sopenharmony_ci			if (err != 0)
75862306a36Sopenharmony_ci				break;
75962306a36Sopenharmony_ci			*p = '/';
76062306a36Sopenharmony_ci		}
76162306a36Sopenharmony_ci		p++;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	kfree(tmp_path);
76562306a36Sopenharmony_ci	return err;
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	int ret = 0;
77162306a36Sopenharmony_ci	const struct cred *old_cred;
77262306a36Sopenharmony_ci	struct hmdfs_dst_info hdi;
77362306a36Sopenharmony_ci	struct hmdfs_user_info *data;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	data = kzalloc(sizeof(*data), GFP_KERNEL);
77662306a36Sopenharmony_ci	if (!data) {
77762306a36Sopenharmony_ci		ret = -ENOMEM;
77862306a36Sopenharmony_ci		goto err_free_data;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	ret = hmdfs_get_info_from_user(arg, &hdi, data);
78262306a36Sopenharmony_ci	if (ret != 0)
78362306a36Sopenharmony_ci		goto err_free_all;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	old_cred = change_cred(filp->f_path.dentry, data->bundle_name);
78662306a36Sopenharmony_ci	if (!old_cred) {
78762306a36Sopenharmony_ci		ret = -EACCES;
78862306a36Sopenharmony_ci		goto err_free_all;
78962306a36Sopenharmony_ci	}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	ret = create_dir_recursive(data->distributed_path, DIR_MODE);
79262306a36Sopenharmony_ci	if (ret != 0)
79362306a36Sopenharmony_ci		goto err_revert;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	ret = create_link_file(data);
79662306a36Sopenharmony_ci	if (ret != 0 && ret != -EEXIST)
79762306a36Sopenharmony_ci		goto err_revert;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	ret = get_file_size(data->local_path, hdi.size);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cierr_revert:
80262306a36Sopenharmony_ci	revert_creds(old_cred);
80362306a36Sopenharmony_cierr_free_all:
80462306a36Sopenharmony_ci	kfree(data->local_path);
80562306a36Sopenharmony_ci	kfree(data->distributed_path);
80662306a36Sopenharmony_ci	kfree(data->bundle_name);
80762306a36Sopenharmony_cierr_free_data:
80862306a36Sopenharmony_ci	kfree(data);
80962306a36Sopenharmony_ci	return ret;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic long hmdfs_file_ioctl_merge(struct file *filp, unsigned int cmd, unsigned long arg)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	switch (cmd) {
81562306a36Sopenharmony_ci	case HMDFS_IOC_GET_WRITEOPEN_CNT:
81662306a36Sopenharmony_ci		return hmdfs_ioc_get_writeopen_cnt(filp, arg);
81762306a36Sopenharmony_ci	case HMDFS_IOC_GET_DST_PATH:
81862306a36Sopenharmony_ci		return hmdfs_ioc_get_dst_path(filp, arg);
81962306a36Sopenharmony_ci	default:
82062306a36Sopenharmony_ci		return -ENOTTY;
82162306a36Sopenharmony_ci	}
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci/* Transparent transmission of parameters to device_view level,
82562306a36Sopenharmony_ci * so file operations are same as device_view local operations.
82662306a36Sopenharmony_ci */
82762306a36Sopenharmony_ciconst struct file_operations hmdfs_file_fops_merge = {
82862306a36Sopenharmony_ci	.owner = THIS_MODULE,
82962306a36Sopenharmony_ci	.llseek = hmdfs_file_llseek_local,
83062306a36Sopenharmony_ci	.read_iter = hmdfs_merge_read_iter,
83162306a36Sopenharmony_ci	.write_iter = hmdfs_merge_write_iter,
83262306a36Sopenharmony_ci	.mmap = hmdfs_file_mmap_local,
83362306a36Sopenharmony_ci	.open = hmdfs_file_open_merge,
83462306a36Sopenharmony_ci	.flush = hmdfs_file_flush_merge,
83562306a36Sopenharmony_ci	.release = hmdfs_file_release_local,
83662306a36Sopenharmony_ci	.fsync = hmdfs_fsync_local,
83762306a36Sopenharmony_ci	.unlocked_ioctl	= hmdfs_file_ioctl_merge,
83862306a36Sopenharmony_ci	.compat_ioctl = hmdfs_file_ioctl_merge,
83962306a36Sopenharmony_ci	.splice_read = copy_splice_read,
84062306a36Sopenharmony_ci	.splice_write = iter_file_splice_write,
84162306a36Sopenharmony_ci};
842