18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * fs/hmdfs/comm/socket_adapter.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "socket_adapter.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/file.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/namei.h>
138c2ecf20Sopenharmony_ci#include <linux/net.h>
148c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
158c2ecf20Sopenharmony_ci#include <net/sock.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "authority/authentication.h"
188c2ecf20Sopenharmony_ci#include "comm/device_node.h"
198c2ecf20Sopenharmony_ci#include "hmdfs_client.h"
208c2ecf20Sopenharmony_ci#include "hmdfs_server.h"
218c2ecf20Sopenharmony_ci#include "hmdfs_trace.h"
228c2ecf20Sopenharmony_ci#include "message_verify.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define ACQUIRE_WFIRED_INTVAL_USEC_MIN 10
258c2ecf20Sopenharmony_ci#define ACQUIRE_WFIRED_INTVAL_USEC_MAX 30
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_citypedef void (*request_callback)(struct hmdfs_peer *, struct hmdfs_head_cmd *,
288c2ecf20Sopenharmony_ci				 void *);
298c2ecf20Sopenharmony_citypedef void (*response_callback)(struct hmdfs_peer *,
308c2ecf20Sopenharmony_ci				  struct sendmsg_wait_queue *, void *, size_t);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic const request_callback s_recv_callbacks[F_SIZE] = {
338c2ecf20Sopenharmony_ci	[F_OPEN] = hmdfs_server_open,
348c2ecf20Sopenharmony_ci	[F_READPAGE] = hmdfs_server_readpage,
358c2ecf20Sopenharmony_ci	[F_RELEASE] = hmdfs_server_release,
368c2ecf20Sopenharmony_ci	[F_WRITEPAGE] = hmdfs_server_writepage,
378c2ecf20Sopenharmony_ci	[F_ITERATE] = hmdfs_server_readdir,
388c2ecf20Sopenharmony_ci	[F_MKDIR] = hmdfs_server_mkdir,
398c2ecf20Sopenharmony_ci	[F_CREATE] = hmdfs_server_create,
408c2ecf20Sopenharmony_ci	[F_RMDIR] = hmdfs_server_rmdir,
418c2ecf20Sopenharmony_ci	[F_UNLINK] = hmdfs_server_unlink,
428c2ecf20Sopenharmony_ci	[F_RENAME] = hmdfs_server_rename,
438c2ecf20Sopenharmony_ci	[F_SETATTR] = hmdfs_server_setattr,
448c2ecf20Sopenharmony_ci	[F_STATFS] = hmdfs_server_statfs,
458c2ecf20Sopenharmony_ci	[F_DROP_PUSH] = hmdfs_server_get_drop_push,
468c2ecf20Sopenharmony_ci	[F_GETATTR] = hmdfs_server_getattr,
478c2ecf20Sopenharmony_ci	[F_FSYNC] = hmdfs_server_fsync,
488c2ecf20Sopenharmony_ci	[F_SYNCFS] = hmdfs_server_syncfs,
498c2ecf20Sopenharmony_ci	[F_GETXATTR] = hmdfs_server_getxattr,
508c2ecf20Sopenharmony_ci	[F_SETXATTR] = hmdfs_server_setxattr,
518c2ecf20Sopenharmony_ci	[F_LISTXATTR] = hmdfs_server_listxattr,
528c2ecf20Sopenharmony_ci	[F_ATOMIC_OPEN] = hmdfs_server_atomic_open,
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_citypedef void (*file_request_callback)(struct hmdfs_peer *,
568c2ecf20Sopenharmony_ci				      struct hmdfs_send_command *);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistruct async_req_callbacks {
598c2ecf20Sopenharmony_ci	void (*on_wakeup)(struct hmdfs_peer *peer, const struct hmdfs_req *req,
608c2ecf20Sopenharmony_ci			  const struct hmdfs_resp *resp);
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic const struct async_req_callbacks g_async_req_callbacks[F_SIZE] = {
648c2ecf20Sopenharmony_ci	[F_SYNCFS] = { .on_wakeup = hmdfs_recv_syncfs_cb },
658c2ecf20Sopenharmony_ci	[F_WRITEPAGE] = { .on_wakeup = hmdfs_writepage_cb },
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic void msg_release(struct kref *kref)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct sendmsg_wait_queue *msg_wq;
718c2ecf20Sopenharmony_ci	struct hmdfs_peer *con;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	msg_wq = (struct sendmsg_wait_queue *)container_of(kref,
748c2ecf20Sopenharmony_ci			struct hmdfs_msg_idr_head, ref);
758c2ecf20Sopenharmony_ci	con = msg_wq->head.peer;
768c2ecf20Sopenharmony_ci	idr_remove(&con->msg_idr, msg_wq->head.msg_id);
778c2ecf20Sopenharmony_ci	spin_unlock(&con->idr_lock);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	kfree(msg_wq->buf);
808c2ecf20Sopenharmony_ci	if (msg_wq->recv_info.local_filp)
818c2ecf20Sopenharmony_ci		fput(msg_wq->recv_info.local_filp);
828c2ecf20Sopenharmony_ci	kfree(msg_wq);
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci// Always remember to find before put, and make sure con is avilable
868c2ecf20Sopenharmony_civoid msg_put(struct sendmsg_wait_queue *msg_wq)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	kref_put_lock(&msg_wq->head.ref, msg_release,
898c2ecf20Sopenharmony_ci		      &msg_wq->head.peer->idr_lock);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic void recv_info_init(struct file_recv_info *recv_info)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	memset(recv_info, 0, sizeof(struct file_recv_info));
958c2ecf20Sopenharmony_ci	atomic_set(&recv_info->local_fslices, 0);
968c2ecf20Sopenharmony_ci	atomic_set(&recv_info->state, FILE_RECV_PROCESS);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic int msg_init(struct hmdfs_peer *con, struct sendmsg_wait_queue *msg_wq,
1008c2ecf20Sopenharmony_ci		    struct hmdfs_cmd operations)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	int ret = 0;
1038c2ecf20Sopenharmony_ci	struct file_recv_info *recv_info = &msg_wq->recv_info;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	ret = hmdfs_alloc_msg_idr(con, MSG_IDR_MESSAGE_SYNC, msg_wq, operations);
1068c2ecf20Sopenharmony_ci	if (unlikely(ret))
1078c2ecf20Sopenharmony_ci		return ret;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	atomic_set(&msg_wq->valid, MSG_Q_SEND);
1108c2ecf20Sopenharmony_ci	init_waitqueue_head(&msg_wq->response_q);
1118c2ecf20Sopenharmony_ci	recv_info_init(recv_info);
1128c2ecf20Sopenharmony_ci	msg_wq->start = jiffies;
1138c2ecf20Sopenharmony_ci	return 0;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic inline void statistic_con_sb_dirty(struct hmdfs_peer *con,
1178c2ecf20Sopenharmony_ci					  const struct hmdfs_cmd *op)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	if (op->command == F_WRITEPAGE && op->cmd_flag == C_REQUEST)
1208c2ecf20Sopenharmony_ci		atomic64_inc(&con->sb_dirty_count);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ciint hmdfs_sendmessage(struct hmdfs_peer *node, struct hmdfs_send_data *msg)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	int ret = 0;
1268c2ecf20Sopenharmony_ci	struct connection *connect = NULL;
1278c2ecf20Sopenharmony_ci	struct tcp_handle *tcp = NULL;
1288c2ecf20Sopenharmony_ci	struct hmdfs_head_cmd *head = msg->head;
1298c2ecf20Sopenharmony_ci	const struct cred *old_cred;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (!node) {
1328c2ecf20Sopenharmony_ci		hmdfs_err("node NULL when send cmd %d",
1338c2ecf20Sopenharmony_ci			  head->operations.command);
1348c2ecf20Sopenharmony_ci		ret = -EAGAIN;
1358c2ecf20Sopenharmony_ci		goto out_err;
1368c2ecf20Sopenharmony_ci	} else if (node->status != NODE_STAT_ONLINE) {
1378c2ecf20Sopenharmony_ci		hmdfs_err("device %llu OFFLINE %d when send cmd %d",
1388c2ecf20Sopenharmony_ci			  node->device_id, node->status,
1398c2ecf20Sopenharmony_ci			  head->operations.command);
1408c2ecf20Sopenharmony_ci		ret = -EAGAIN;
1418c2ecf20Sopenharmony_ci		goto out;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	old_cred = hmdfs_override_creds(node->sbi->system_cred);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	do {
1478c2ecf20Sopenharmony_ci		connect = get_conn_impl(node, CONNECT_TYPE_TCP);
1488c2ecf20Sopenharmony_ci		if (!connect) {
1498c2ecf20Sopenharmony_ci			hmdfs_info_ratelimited(
1508c2ecf20Sopenharmony_ci				"device %llu no connection available when send cmd %d, get new session",
1518c2ecf20Sopenharmony_ci				node->device_id, head->operations.command);
1528c2ecf20Sopenharmony_ci			if (node->status != NODE_STAT_OFFLINE) {
1538c2ecf20Sopenharmony_ci				struct notify_param param;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci				memcpy(param.remote_cid, node->cid,
1568c2ecf20Sopenharmony_ci				       HMDFS_CID_SIZE);
1578c2ecf20Sopenharmony_ci				param.notify = NOTIFY_OFFLINE;
1588c2ecf20Sopenharmony_ci				param.fd = INVALID_SOCKET_FD;
1598c2ecf20Sopenharmony_ci				notify(node, &param);
1608c2ecf20Sopenharmony_ci			}
1618c2ecf20Sopenharmony_ci			ret = -EAGAIN;
1628c2ecf20Sopenharmony_ci			goto revert_cred;
1638c2ecf20Sopenharmony_ci		}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		ret = connect->send_message(connect, msg);
1668c2ecf20Sopenharmony_ci		if (ret == -ESHUTDOWN) {
1678c2ecf20Sopenharmony_ci			hmdfs_info("device %llu send cmd %d message fail, connection stop",
1688c2ecf20Sopenharmony_ci				   node->device_id, head->operations.command);
1698c2ecf20Sopenharmony_ci			connect->status = CONNECT_STAT_STOP;
1708c2ecf20Sopenharmony_ci			tcp = connect->connect_handle;
1718c2ecf20Sopenharmony_ci			if (node->status != NODE_STAT_OFFLINE) {
1728c2ecf20Sopenharmony_ci				connection_get(connect);
1738c2ecf20Sopenharmony_ci				if (!queue_work(node->reget_conn_wq,
1748c2ecf20Sopenharmony_ci						&connect->reget_work))
1758c2ecf20Sopenharmony_ci					connection_put(connect);
1768c2ecf20Sopenharmony_ci			}
1778c2ecf20Sopenharmony_ci			connection_put(connect);
1788c2ecf20Sopenharmony_ci			/*
1798c2ecf20Sopenharmony_ci			 * node->status is OFFLINE can not ensure
1808c2ecf20Sopenharmony_ci			 * node_seq will be increased before
1818c2ecf20Sopenharmony_ci			 * hmdfs_sendmessage() returns.
1828c2ecf20Sopenharmony_ci			 */
1838c2ecf20Sopenharmony_ci			hmdfs_node_inc_evt_seq(node);
1848c2ecf20Sopenharmony_ci		} else {
1858c2ecf20Sopenharmony_ci			connection_put(connect);
1868c2ecf20Sopenharmony_ci			goto revert_cred;
1878c2ecf20Sopenharmony_ci		}
1888c2ecf20Sopenharmony_ci	} while (node->status != NODE_STAT_OFFLINE);
1898c2ecf20Sopenharmony_cirevert_cred:
1908c2ecf20Sopenharmony_ci	hmdfs_revert_creds(old_cred);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (!ret)
1938c2ecf20Sopenharmony_ci		statistic_con_sb_dirty(node, &head->operations);
1948c2ecf20Sopenharmony_ciout:
1958c2ecf20Sopenharmony_ci	if (head->operations.cmd_flag == C_REQUEST)
1968c2ecf20Sopenharmony_ci		hmdfs_client_snd_statis(node->sbi,
1978c2ecf20Sopenharmony_ci					head->operations.command, ret);
1988c2ecf20Sopenharmony_ci	else if (head->operations.cmd_flag == C_RESPONSE)
1998c2ecf20Sopenharmony_ci		hmdfs_server_snd_statis(node->sbi,
2008c2ecf20Sopenharmony_ci					head->operations.command, ret);
2018c2ecf20Sopenharmony_ciout_err:
2028c2ecf20Sopenharmony_ci	return ret;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ciint hmdfs_sendmessage_response(struct hmdfs_peer *con,
2068c2ecf20Sopenharmony_ci			       struct hmdfs_head_cmd *cmd, __u32 data_len,
2078c2ecf20Sopenharmony_ci			       void *buf, __u32 ret_code)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	int ret;
2108c2ecf20Sopenharmony_ci	struct hmdfs_send_data msg;
2118c2ecf20Sopenharmony_ci	struct hmdfs_head_cmd head;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	head.magic = HMDFS_MSG_MAGIC;
2148c2ecf20Sopenharmony_ci	head.version = HMDFS_VERSION;
2158c2ecf20Sopenharmony_ci	head.operations = cmd->operations;
2168c2ecf20Sopenharmony_ci	head.operations.cmd_flag = C_RESPONSE;
2178c2ecf20Sopenharmony_ci	head.data_len = cpu_to_le32(data_len + sizeof(struct hmdfs_head_cmd));
2188c2ecf20Sopenharmony_ci	head.ret_code = cpu_to_le32(ret_code);
2198c2ecf20Sopenharmony_ci	head.msg_id = cmd->msg_id;
2208c2ecf20Sopenharmony_ci	head.reserved = cmd->reserved;
2218c2ecf20Sopenharmony_ci	head.reserved1 = cmd->reserved1;
2228c2ecf20Sopenharmony_ci	msg.head = &head;
2238c2ecf20Sopenharmony_ci	msg.head_len = sizeof(struct hmdfs_head_cmd);
2248c2ecf20Sopenharmony_ci	msg.data = buf;
2258c2ecf20Sopenharmony_ci	msg.len = data_len;
2268c2ecf20Sopenharmony_ci	msg.sdesc = NULL;
2278c2ecf20Sopenharmony_ci	msg.sdesc_len = 0;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	ret = hmdfs_sendmessage(con, &msg);
2308c2ecf20Sopenharmony_ci	return ret;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic void mp_release(struct kref *kref)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct hmdfs_msg_parasite *mp = NULL;
2368c2ecf20Sopenharmony_ci	struct hmdfs_peer *peer = NULL;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	mp = (struct hmdfs_msg_parasite *)container_of(kref,
2398c2ecf20Sopenharmony_ci			struct hmdfs_msg_idr_head, ref);
2408c2ecf20Sopenharmony_ci	peer = mp->head.peer;
2418c2ecf20Sopenharmony_ci	idr_remove(&peer->msg_idr, mp->head.msg_id);
2428c2ecf20Sopenharmony_ci	spin_unlock(&peer->idr_lock);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	peer_put(peer);
2458c2ecf20Sopenharmony_ci	kfree(mp->resp.out_buf);
2468c2ecf20Sopenharmony_ci	kfree(mp);
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_civoid mp_put(struct hmdfs_msg_parasite *mp)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	kref_put_lock(&mp->head.ref, mp_release, &mp->head.peer->idr_lock);
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic void async_request_cb_on_wakeup_fn(struct work_struct *w)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	struct hmdfs_msg_parasite *mp =
2578c2ecf20Sopenharmony_ci		container_of(w, struct hmdfs_msg_parasite, d_work.work);
2588c2ecf20Sopenharmony_ci	struct async_req_callbacks cbs;
2598c2ecf20Sopenharmony_ci	const struct cred *old_cred =
2608c2ecf20Sopenharmony_ci		hmdfs_override_creds(mp->head.peer->sbi->cred);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (mp->resp.ret_code == -ETIME)
2638c2ecf20Sopenharmony_ci		hmdfs_client_resp_statis(mp->head.peer->sbi,
2648c2ecf20Sopenharmony_ci					 mp->req.operations.command,
2658c2ecf20Sopenharmony_ci					 HMDFS_RESP_TIMEOUT, 0, 0);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	cbs = g_async_req_callbacks[mp->req.operations.command];
2688c2ecf20Sopenharmony_ci	if (cbs.on_wakeup)
2698c2ecf20Sopenharmony_ci		(*cbs.on_wakeup)(mp->head.peer, &mp->req, &mp->resp);
2708c2ecf20Sopenharmony_ci	mp_put(mp);
2718c2ecf20Sopenharmony_ci	hmdfs_revert_creds(old_cred);
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic struct hmdfs_msg_parasite *mp_alloc(struct hmdfs_peer *peer,
2758c2ecf20Sopenharmony_ci					   const struct hmdfs_req *req)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	struct hmdfs_msg_parasite *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
2788c2ecf20Sopenharmony_ci	int ret;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	if (unlikely(!mp))
2818c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	ret = hmdfs_alloc_msg_idr(peer, MSG_IDR_MESSAGE_ASYNC, mp,
2848c2ecf20Sopenharmony_ci				  mp->head.send_cmd_operations);
2858c2ecf20Sopenharmony_ci	if (unlikely(ret)) {
2868c2ecf20Sopenharmony_ci		kfree(mp);
2878c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	mp->start = jiffies;
2918c2ecf20Sopenharmony_ci	peer_get(mp->head.peer);
2928c2ecf20Sopenharmony_ci	mp->resp.ret_code = -ETIME;
2938c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&mp->d_work, async_request_cb_on_wakeup_fn);
2948c2ecf20Sopenharmony_ci	mp->wfired = false;
2958c2ecf20Sopenharmony_ci	mp->req = *req;
2968c2ecf20Sopenharmony_ci	return mp;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci/**
3008c2ecf20Sopenharmony_ci * hmdfs_send_async_request - sendout a async request
3018c2ecf20Sopenharmony_ci * @peer: target device node
3028c2ecf20Sopenharmony_ci * @req: request descriptor + necessary contexts
3038c2ecf20Sopenharmony_ci *
3048c2ecf20Sopenharmony_ci * Sendout a request synchronously and wait for its response asynchronously
3058c2ecf20Sopenharmony_ci * Return -ESHUTDOWN when the device node is unachievable
3068c2ecf20Sopenharmony_ci * Return -EAGAIN if the network is recovering
3078c2ecf20Sopenharmony_ci * Return -ENOMEM if out of memory
3088c2ecf20Sopenharmony_ci *
3098c2ecf20Sopenharmony_ci * Register g_async_req_callbacks to recv the response
3108c2ecf20Sopenharmony_ci */
3118c2ecf20Sopenharmony_ciint hmdfs_send_async_request(struct hmdfs_peer *peer,
3128c2ecf20Sopenharmony_ci			     const struct hmdfs_req *req)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	int ret = 0;
3158c2ecf20Sopenharmony_ci	struct hmdfs_send_data msg;
3168c2ecf20Sopenharmony_ci	struct hmdfs_head_cmd head;
3178c2ecf20Sopenharmony_ci	struct hmdfs_msg_parasite *mp = NULL;
3188c2ecf20Sopenharmony_ci	size_t msg_len = req->data_len + sizeof(struct hmdfs_head_cmd);
3198c2ecf20Sopenharmony_ci	unsigned int timeout;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (req->timeout == TIMEOUT_CONFIG)
3228c2ecf20Sopenharmony_ci		timeout = get_cmd_timeout(peer->sbi, req->operations.command);
3238c2ecf20Sopenharmony_ci	else
3248c2ecf20Sopenharmony_ci		timeout = req->timeout;
3258c2ecf20Sopenharmony_ci	if (timeout == TIMEOUT_UNINIT || timeout == TIMEOUT_NONE) {
3268c2ecf20Sopenharmony_ci		hmdfs_err("send msg %d with uninitialized/invalid timeout",
3278c2ecf20Sopenharmony_ci			  req->operations.command);
3288c2ecf20Sopenharmony_ci		return -EINVAL;
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	if (!hmdfs_is_node_online(peer))
3328c2ecf20Sopenharmony_ci		return -EAGAIN;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	mp = mp_alloc(peer, req);
3358c2ecf20Sopenharmony_ci	if (IS_ERR(mp))
3368c2ecf20Sopenharmony_ci		return PTR_ERR(mp);
3378c2ecf20Sopenharmony_ci	head.magic = HMDFS_MSG_MAGIC;
3388c2ecf20Sopenharmony_ci	head.version = HMDFS_VERSION;
3398c2ecf20Sopenharmony_ci	head.data_len = cpu_to_le32(msg_len);
3408c2ecf20Sopenharmony_ci	head.operations = mp->req.operations;
3418c2ecf20Sopenharmony_ci	head.msg_id = cpu_to_le32(mp->head.msg_id);
3428c2ecf20Sopenharmony_ci	head.reserved = 0;
3438c2ecf20Sopenharmony_ci	head.reserved1 = 0;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	msg.head = &head;
3468c2ecf20Sopenharmony_ci	msg.head_len = sizeof(head);
3478c2ecf20Sopenharmony_ci	msg.data = mp->req.data;
3488c2ecf20Sopenharmony_ci	msg.len = mp->req.data_len;
3498c2ecf20Sopenharmony_ci	msg.sdesc_len = 0;
3508c2ecf20Sopenharmony_ci	msg.sdesc = NULL;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	ret = hmdfs_sendmessage(peer, &msg);
3538c2ecf20Sopenharmony_ci	if (unlikely(ret)) {
3548c2ecf20Sopenharmony_ci		mp_put(mp);
3558c2ecf20Sopenharmony_ci		goto out;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	queue_delayed_work(peer->async_wq, &mp->d_work, timeout * HZ);
3598c2ecf20Sopenharmony_ci	/*
3608c2ecf20Sopenharmony_ci	 * The work may havn't been queued upon the arriving of it's response,
3618c2ecf20Sopenharmony_ci	 * resulting in meaningless waiting. So we use the membar to tell the
3628c2ecf20Sopenharmony_ci	 * recv thread if the work has been queued
3638c2ecf20Sopenharmony_ci	 */
3648c2ecf20Sopenharmony_ci	smp_store_release(&mp->wfired, true);
3658c2ecf20Sopenharmony_ciout:
3668c2ecf20Sopenharmony_ci	hmdfs_dec_msg_idr_process(peer);
3678c2ecf20Sopenharmony_ci	return ret;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int hmdfs_record_async_readdir(struct hmdfs_peer *con,
3718c2ecf20Sopenharmony_ci				      struct sendmsg_wait_queue *msg_wq)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct hmdfs_sb_info *sbi = con->sbi;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	spin_lock(&sbi->async_readdir_msg_lock);
3768c2ecf20Sopenharmony_ci	if (sbi->async_readdir_prohibit) {
3778c2ecf20Sopenharmony_ci		spin_unlock(&sbi->async_readdir_msg_lock);
3788c2ecf20Sopenharmony_ci		return -EINTR;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	list_add(&msg_wq->async_msg, &sbi->async_readdir_msg_list);
3828c2ecf20Sopenharmony_ci	spin_unlock(&sbi->async_readdir_msg_lock);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return 0;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic void hmdfs_untrack_async_readdir(struct hmdfs_peer *con,
3888c2ecf20Sopenharmony_ci					struct sendmsg_wait_queue *msg_wq)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	struct hmdfs_sb_info *sbi = con->sbi;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	spin_lock(&sbi->async_readdir_msg_lock);
3938c2ecf20Sopenharmony_ci	list_del(&msg_wq->async_msg);
3948c2ecf20Sopenharmony_ci	spin_unlock(&sbi->async_readdir_msg_lock);
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ciint hmdfs_sendmessage_request(struct hmdfs_peer *con,
3988c2ecf20Sopenharmony_ci			      struct hmdfs_send_command *sm)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	int time_left;
4018c2ecf20Sopenharmony_ci	int ret = 0;
4028c2ecf20Sopenharmony_ci	struct sendmsg_wait_queue *msg_wq = NULL;
4038c2ecf20Sopenharmony_ci	struct hmdfs_send_data msg;
4048c2ecf20Sopenharmony_ci	size_t outlen = sm->len + sizeof(struct hmdfs_head_cmd);
4058c2ecf20Sopenharmony_ci	unsigned int timeout =
4068c2ecf20Sopenharmony_ci		get_cmd_timeout(con->sbi, sm->operations.command);
4078c2ecf20Sopenharmony_ci	struct hmdfs_head_cmd *head = NULL;
4088c2ecf20Sopenharmony_ci	bool dec = false;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	if (!hmdfs_is_node_online(con)) {
4118c2ecf20Sopenharmony_ci		ret = -EAGAIN;
4128c2ecf20Sopenharmony_ci		goto free_filp;
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (timeout == TIMEOUT_UNINIT) {
4168c2ecf20Sopenharmony_ci		hmdfs_err_ratelimited("send msg %d with uninitialized timeout",
4178c2ecf20Sopenharmony_ci				      sm->operations.command);
4188c2ecf20Sopenharmony_ci		ret = -EINVAL;
4198c2ecf20Sopenharmony_ci		goto free_filp;
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	head = kzalloc(sizeof(struct hmdfs_head_cmd), GFP_KERNEL);
4238c2ecf20Sopenharmony_ci	if (!head) {
4248c2ecf20Sopenharmony_ci		ret = -ENOMEM;
4258c2ecf20Sopenharmony_ci		goto free_filp;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	sm->out_buf = NULL;
4298c2ecf20Sopenharmony_ci	head->magic = HMDFS_MSG_MAGIC;
4308c2ecf20Sopenharmony_ci	head->version = HMDFS_VERSION;
4318c2ecf20Sopenharmony_ci	head->operations = sm->operations;
4328c2ecf20Sopenharmony_ci	head->data_len = cpu_to_le32(outlen);
4338c2ecf20Sopenharmony_ci	head->ret_code = cpu_to_le32(sm->ret_code);
4348c2ecf20Sopenharmony_ci	head->reserved = 0;
4358c2ecf20Sopenharmony_ci	head->reserved1 = 0;
4368c2ecf20Sopenharmony_ci	if (timeout != TIMEOUT_NONE) {
4378c2ecf20Sopenharmony_ci		msg_wq = kzalloc(sizeof(*msg_wq), GFP_KERNEL);
4388c2ecf20Sopenharmony_ci		if (!msg_wq) {
4398c2ecf20Sopenharmony_ci			ret = -ENOMEM;
4408c2ecf20Sopenharmony_ci			goto free_filp;
4418c2ecf20Sopenharmony_ci		}
4428c2ecf20Sopenharmony_ci		ret = msg_init(con, msg_wq, sm->operations);
4438c2ecf20Sopenharmony_ci		if (ret) {
4448c2ecf20Sopenharmony_ci			kfree(msg_wq);
4458c2ecf20Sopenharmony_ci			msg_wq = NULL;
4468c2ecf20Sopenharmony_ci			goto free_filp;
4478c2ecf20Sopenharmony_ci		}
4488c2ecf20Sopenharmony_ci		dec = true;
4498c2ecf20Sopenharmony_ci		head->msg_id = cpu_to_le32(msg_wq->head.msg_id);
4508c2ecf20Sopenharmony_ci		if (sm->operations.command == F_ITERATE)
4518c2ecf20Sopenharmony_ci			msg_wq->recv_info.local_filp = sm->local_filp;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci	msg.head = head;
4548c2ecf20Sopenharmony_ci	msg.head_len = sizeof(struct hmdfs_head_cmd);
4558c2ecf20Sopenharmony_ci	msg.data = sm->data;
4568c2ecf20Sopenharmony_ci	msg.len = sm->len;
4578c2ecf20Sopenharmony_ci	msg.sdesc_len = 0;
4588c2ecf20Sopenharmony_ci	msg.sdesc = NULL;
4598c2ecf20Sopenharmony_ci	ret = hmdfs_sendmessage(con, &msg);
4608c2ecf20Sopenharmony_ci	if (ret) {
4618c2ecf20Sopenharmony_ci		hmdfs_err_ratelimited("send err sm->device_id, %lld, msg_id %u",
4628c2ecf20Sopenharmony_ci				      con->device_id, head->msg_id);
4638c2ecf20Sopenharmony_ci		goto free;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	if (timeout == TIMEOUT_NONE)
4678c2ecf20Sopenharmony_ci		goto free;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	hmdfs_dec_msg_idr_process(con);
4708c2ecf20Sopenharmony_ci	dec = false;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	if (sm->operations.command == F_ITERATE) {
4738c2ecf20Sopenharmony_ci		ret = hmdfs_record_async_readdir(con, msg_wq);
4748c2ecf20Sopenharmony_ci		if (ret) {
4758c2ecf20Sopenharmony_ci			atomic_set(&msg_wq->recv_info.state, FILE_RECV_ERR_SPC);
4768c2ecf20Sopenharmony_ci			goto free;
4778c2ecf20Sopenharmony_ci		}
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	time_left = wait_event_interruptible_timeout(
4818c2ecf20Sopenharmony_ci		msg_wq->response_q,
4828c2ecf20Sopenharmony_ci		(atomic_read(&msg_wq->valid) == MSG_Q_END_RECV), timeout * HZ);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	if (sm->operations.command == F_ITERATE)
4858c2ecf20Sopenharmony_ci		hmdfs_untrack_async_readdir(con, msg_wq);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	if (time_left == -ERESTARTSYS || time_left == 0) {
4888c2ecf20Sopenharmony_ci		hmdfs_err("timeout err sm->device_id %lld,  msg_id %d cmd %d",
4898c2ecf20Sopenharmony_ci			  con->device_id, head->msg_id,
4908c2ecf20Sopenharmony_ci			  head->operations.command);
4918c2ecf20Sopenharmony_ci		if (sm->operations.command == F_ITERATE)
4928c2ecf20Sopenharmony_ci			atomic_set(&msg_wq->recv_info.state, FILE_RECV_ERR_NET);
4938c2ecf20Sopenharmony_ci		ret = -ETIME;
4948c2ecf20Sopenharmony_ci		hmdfs_client_resp_statis(con->sbi, sm->operations.command,
4958c2ecf20Sopenharmony_ci					 HMDFS_RESP_TIMEOUT, 0, 0);
4968c2ecf20Sopenharmony_ci		goto free;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci	sm->out_buf = msg_wq->buf;
4998c2ecf20Sopenharmony_ci	msg_wq->buf = NULL;
5008c2ecf20Sopenharmony_ci	sm->out_len = msg_wq->size - sizeof(struct hmdfs_head_cmd);
5018c2ecf20Sopenharmony_ci	ret = msg_wq->ret;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cifree:
5048c2ecf20Sopenharmony_ci	if (msg_wq)
5058c2ecf20Sopenharmony_ci		msg_put(msg_wq);
5068c2ecf20Sopenharmony_ci	if (dec)
5078c2ecf20Sopenharmony_ci		hmdfs_dec_msg_idr_process(con);
5088c2ecf20Sopenharmony_ci	kfree(head);
5098c2ecf20Sopenharmony_ci	return ret;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cifree_filp:
5128c2ecf20Sopenharmony_ci	if (sm->local_filp)
5138c2ecf20Sopenharmony_ci		fput(sm->local_filp);
5148c2ecf20Sopenharmony_ci	kfree(head);
5158c2ecf20Sopenharmony_ci	return ret;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic int hmdfs_send_slice(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd,
5198c2ecf20Sopenharmony_ci			    struct slice_descriptor *sdesc, void *slice_buf)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	int ret;
5228c2ecf20Sopenharmony_ci	struct hmdfs_send_data msg;
5238c2ecf20Sopenharmony_ci	struct hmdfs_head_cmd head;
5248c2ecf20Sopenharmony_ci	int content_size = le32_to_cpu(sdesc->content_size);
5258c2ecf20Sopenharmony_ci	int msg_len = sizeof(struct hmdfs_head_cmd) + content_size +
5268c2ecf20Sopenharmony_ci		      sizeof(struct slice_descriptor);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	head.magic = HMDFS_MSG_MAGIC;
5298c2ecf20Sopenharmony_ci	head.version = HMDFS_VERSION;
5308c2ecf20Sopenharmony_ci	head.operations = cmd->operations;
5318c2ecf20Sopenharmony_ci	head.operations.cmd_flag = C_RESPONSE;
5328c2ecf20Sopenharmony_ci	head.data_len = cpu_to_le32(msg_len);
5338c2ecf20Sopenharmony_ci	head.ret_code = cpu_to_le32(0);
5348c2ecf20Sopenharmony_ci	head.msg_id = cmd->msg_id;
5358c2ecf20Sopenharmony_ci	head.reserved = cmd->reserved;
5368c2ecf20Sopenharmony_ci	head.reserved1 = cmd->reserved1;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	msg.head = &head;
5398c2ecf20Sopenharmony_ci	msg.head_len = sizeof(struct hmdfs_head_cmd);
5408c2ecf20Sopenharmony_ci	msg.sdesc = sdesc;
5418c2ecf20Sopenharmony_ci	msg.sdesc_len = le32_to_cpu(sizeof(struct slice_descriptor));
5428c2ecf20Sopenharmony_ci	msg.data = slice_buf;
5438c2ecf20Sopenharmony_ci	msg.len = content_size;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	ret = hmdfs_sendmessage(con, &msg);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	return ret;
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ciint hmdfs_readfile_response(struct hmdfs_peer *con, struct hmdfs_head_cmd *head,
5518c2ecf20Sopenharmony_ci			    struct file *filp)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	int ret;
5548c2ecf20Sopenharmony_ci	const unsigned int slice_size = PAGE_SIZE;
5558c2ecf20Sopenharmony_ci	char *slice_buf = NULL;
5568c2ecf20Sopenharmony_ci	loff_t file_offset = 0, file_size;
5578c2ecf20Sopenharmony_ci	ssize_t size;
5588c2ecf20Sopenharmony_ci	struct slice_descriptor sdesc;
5598c2ecf20Sopenharmony_ci	unsigned int slice_sn = 0;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	if (!filp)
5628c2ecf20Sopenharmony_ci		return hmdfs_sendmessage_response(con, head, 0, NULL, 0);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	sdesc.slice_size = cpu_to_le32(slice_size);
5658c2ecf20Sopenharmony_ci	file_size = i_size_read(file_inode(filp));
5668c2ecf20Sopenharmony_ci	file_size = round_up(file_size, slice_size);
5678c2ecf20Sopenharmony_ci	sdesc.num_slices = cpu_to_le32(file_size / slice_size);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	slice_buf = kmalloc(slice_size, GFP_KERNEL);
5708c2ecf20Sopenharmony_ci	if (!slice_buf) {
5718c2ecf20Sopenharmony_ci		ret = -ENOMEM;
5728c2ecf20Sopenharmony_ci		goto out;
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	while (1) {
5768c2ecf20Sopenharmony_ci		sdesc.slice_sn = cpu_to_le32(slice_sn++);
5778c2ecf20Sopenharmony_ci		size = kernel_read(filp, slice_buf, (size_t)slice_size,
5788c2ecf20Sopenharmony_ci				   &file_offset);
5798c2ecf20Sopenharmony_ci		if (IS_ERR_VALUE(size)) {
5808c2ecf20Sopenharmony_ci			ret = (int)size;
5818c2ecf20Sopenharmony_ci			goto out;
5828c2ecf20Sopenharmony_ci		}
5838c2ecf20Sopenharmony_ci		sdesc.content_size = cpu_to_le32(size);
5848c2ecf20Sopenharmony_ci		ret = hmdfs_send_slice(con, head, &sdesc, slice_buf);
5858c2ecf20Sopenharmony_ci		if (ret) {
5868c2ecf20Sopenharmony_ci			hmdfs_info("Cannot send file slice %d ",
5878c2ecf20Sopenharmony_ci				   le32_to_cpu(sdesc.slice_sn));
5888c2ecf20Sopenharmony_ci			break;
5898c2ecf20Sopenharmony_ci		}
5908c2ecf20Sopenharmony_ci		if (file_offset >= i_size_read(file_inode(filp)))
5918c2ecf20Sopenharmony_ci			break;
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ciout:
5958c2ecf20Sopenharmony_ci	kfree(slice_buf);
5968c2ecf20Sopenharmony_ci	if (ret)
5978c2ecf20Sopenharmony_ci		hmdfs_sendmessage_response(con, head, 0, NULL, ret);
5988c2ecf20Sopenharmony_ci	return ret;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic void asw_release(struct kref *kref)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	struct hmdfs_async_work *asw = NULL;
6048c2ecf20Sopenharmony_ci	struct hmdfs_peer *peer = NULL;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	asw = (struct hmdfs_async_work *)container_of(kref,
6078c2ecf20Sopenharmony_ci			struct hmdfs_msg_idr_head, ref);
6088c2ecf20Sopenharmony_ci	peer = asw->head.peer;
6098c2ecf20Sopenharmony_ci	idr_remove(&peer->msg_idr, asw->head.msg_id);
6108c2ecf20Sopenharmony_ci	spin_unlock(&peer->idr_lock);
6118c2ecf20Sopenharmony_ci	kfree(asw);
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_civoid asw_put(struct hmdfs_async_work *asw)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	kref_put_lock(&asw->head.ref, asw_release, &asw->head.peer->idr_lock);
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_civoid hmdfs_recv_page_work_fn(struct work_struct *ptr)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct hmdfs_async_work *async_work =
6228c2ecf20Sopenharmony_ci		container_of(ptr, struct hmdfs_async_work, d_work.work);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	hmdfs_client_resp_statis(async_work->head.peer->sbi,
6258c2ecf20Sopenharmony_ci					F_READPAGE, HMDFS_RESP_TIMEOUT, 0, 0);
6268c2ecf20Sopenharmony_ci	hmdfs_err_ratelimited("timeout and release page, msg_id:%u",
6278c2ecf20Sopenharmony_ci			      async_work->head.msg_id);
6288c2ecf20Sopenharmony_ci	asw_done(async_work);
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ciint hmdfs_sendpage_request(struct hmdfs_peer *con,
6328c2ecf20Sopenharmony_ci			   struct hmdfs_send_command *sm)
6338c2ecf20Sopenharmony_ci{
6348c2ecf20Sopenharmony_ci	int ret = 0;
6358c2ecf20Sopenharmony_ci	struct hmdfs_send_data msg;
6368c2ecf20Sopenharmony_ci	struct hmdfs_async_work *async_work = NULL;
6378c2ecf20Sopenharmony_ci	size_t outlen = sm->len + sizeof(struct hmdfs_head_cmd);
6388c2ecf20Sopenharmony_ci	struct hmdfs_head_cmd head;
6398c2ecf20Sopenharmony_ci	unsigned int timeout;
6408c2ecf20Sopenharmony_ci	unsigned long start = jiffies;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	WARN_ON(!sm->out_buf);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	timeout = get_cmd_timeout(con->sbi, sm->operations.command);
6458c2ecf20Sopenharmony_ci	if (timeout == TIMEOUT_UNINIT) {
6468c2ecf20Sopenharmony_ci		hmdfs_err("send msg %d with uninitialized timeout",
6478c2ecf20Sopenharmony_ci			  sm->operations.command);
6488c2ecf20Sopenharmony_ci		ret = -EINVAL;
6498c2ecf20Sopenharmony_ci		goto unlock;
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	if (!hmdfs_is_node_online(con)) {
6538c2ecf20Sopenharmony_ci		ret = -EAGAIN;
6548c2ecf20Sopenharmony_ci		goto unlock;
6558c2ecf20Sopenharmony_ci	}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	memset(&head, 0, sizeof(head));
6588c2ecf20Sopenharmony_ci	head.magic = HMDFS_MSG_MAGIC;
6598c2ecf20Sopenharmony_ci	head.version = HMDFS_VERSION;
6608c2ecf20Sopenharmony_ci	head.operations = sm->operations;
6618c2ecf20Sopenharmony_ci	head.data_len = cpu_to_le32(outlen);
6628c2ecf20Sopenharmony_ci	head.ret_code = cpu_to_le32(sm->ret_code);
6638c2ecf20Sopenharmony_ci	head.reserved = 0;
6648c2ecf20Sopenharmony_ci	head.reserved1 = 0;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	msg.head = &head;
6678c2ecf20Sopenharmony_ci	msg.head_len = sizeof(struct hmdfs_head_cmd);
6688c2ecf20Sopenharmony_ci	msg.data = sm->data;
6698c2ecf20Sopenharmony_ci	msg.len = sm->len;
6708c2ecf20Sopenharmony_ci	msg.sdesc_len = 0;
6718c2ecf20Sopenharmony_ci	msg.sdesc = NULL;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	async_work = kzalloc(sizeof(*async_work), GFP_KERNEL);
6748c2ecf20Sopenharmony_ci	if (!async_work) {
6758c2ecf20Sopenharmony_ci		ret = -ENOMEM;
6768c2ecf20Sopenharmony_ci		goto unlock;
6778c2ecf20Sopenharmony_ci	}
6788c2ecf20Sopenharmony_ci	async_work->start = start;
6798c2ecf20Sopenharmony_ci	ret = hmdfs_alloc_msg_idr(con, MSG_IDR_PAGE, async_work, sm->operations);
6808c2ecf20Sopenharmony_ci	if (ret) {
6818c2ecf20Sopenharmony_ci		hmdfs_err("alloc msg_id failed, err %d", ret);
6828c2ecf20Sopenharmony_ci		goto unlock;
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci	head.msg_id = cpu_to_le32(async_work->head.msg_id);
6858c2ecf20Sopenharmony_ci	async_work->page = sm->out_buf;
6868c2ecf20Sopenharmony_ci	asw_get(async_work);
6878c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&async_work->d_work, hmdfs_recv_page_work_fn);
6888c2ecf20Sopenharmony_ci	ret = queue_delayed_work(con->async_wq, &async_work->d_work,
6898c2ecf20Sopenharmony_ci				 timeout * HZ);
6908c2ecf20Sopenharmony_ci	if (!ret) {
6918c2ecf20Sopenharmony_ci		hmdfs_err("queue_delayed_work failed, msg_id %u", head.msg_id);
6928c2ecf20Sopenharmony_ci		goto fail_and_unlock_page;
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci	ret = hmdfs_sendmessage(con, &msg);
6958c2ecf20Sopenharmony_ci	if (ret) {
6968c2ecf20Sopenharmony_ci		hmdfs_err("send err sm->device_id, %lld, msg_id %u",
6978c2ecf20Sopenharmony_ci			  con->device_id, head.msg_id);
6988c2ecf20Sopenharmony_ci		if (!cancel_delayed_work(&async_work->d_work)) {
6998c2ecf20Sopenharmony_ci			hmdfs_err("cancel async work err");
7008c2ecf20Sopenharmony_ci			asw_put(async_work);
7018c2ecf20Sopenharmony_ci			hmdfs_dec_msg_idr_process(con);
7028c2ecf20Sopenharmony_ci			goto out;
7038c2ecf20Sopenharmony_ci		}
7048c2ecf20Sopenharmony_ci		goto fail_and_unlock_page;
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	asw_put(async_work);
7088c2ecf20Sopenharmony_ci	hmdfs_dec_msg_idr_process(con);
7098c2ecf20Sopenharmony_ci	return 0;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_cifail_and_unlock_page:
7128c2ecf20Sopenharmony_ci	asw_put(async_work);
7138c2ecf20Sopenharmony_ci	asw_done(async_work);
7148c2ecf20Sopenharmony_ci	hmdfs_dec_msg_idr_process(con);
7158c2ecf20Sopenharmony_ci	return ret;
7168c2ecf20Sopenharmony_ciunlock:
7178c2ecf20Sopenharmony_ci	kfree(async_work);
7188c2ecf20Sopenharmony_ci	unlock_page(sm->out_buf);
7198c2ecf20Sopenharmony_ciout:
7208c2ecf20Sopenharmony_ci	return ret;
7218c2ecf20Sopenharmony_ci}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_cistatic void hmdfs_request_handle_sync(struct hmdfs_peer *con,
7248c2ecf20Sopenharmony_ci				      struct hmdfs_head_cmd *head, void *buf)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	unsigned long start = jiffies;
7278c2ecf20Sopenharmony_ci	const struct cred *saved_cred = hmdfs_override_fsids(true);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	if (!saved_cred) {
7308c2ecf20Sopenharmony_ci		hmdfs_err("prepare cred failed!");
7318c2ecf20Sopenharmony_ci		kfree(buf);
7328c2ecf20Sopenharmony_ci		return;
7338c2ecf20Sopenharmony_ci	}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	s_recv_callbacks[head->operations.command](con, head, buf);
7368c2ecf20Sopenharmony_ci	hmdfs_statistic(con->sbi, head->operations.command, jiffies - start);
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	kfree(buf);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	hmdfs_revert_fsids(saved_cred);
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_cistatic void hmdfs_msg_handle_sync(struct hmdfs_peer *con,
7448c2ecf20Sopenharmony_ci				 struct hmdfs_head_cmd *head, void *buf)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	const struct cred *old_cred = hmdfs_override_creds(con->sbi->cred);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/*
7498c2ecf20Sopenharmony_ci	 * Reuse PF_NPROC_EXCEEDED as an indication of hmdfs server context:
7508c2ecf20Sopenharmony_ci	 * 1. PF_NPROC_EXCEEDED will set by setreuid()/setuid()/setresuid(),
7518c2ecf20Sopenharmony_ci	 *    we assume kwork will not call theses syscalls.
7528c2ecf20Sopenharmony_ci	 * 2. PF_NPROC_EXCEEDED will be cleared by execv(), and kworker
7538c2ecf20Sopenharmony_ci	 *    will not call it.
7548c2ecf20Sopenharmony_ci	 */
7558c2ecf20Sopenharmony_ci	current->flags |= PF_NPROC_EXCEEDED;
7568c2ecf20Sopenharmony_ci	hmdfs_request_handle_sync(con, head, buf);
7578c2ecf20Sopenharmony_ci	current->flags &= ~PF_NPROC_EXCEEDED;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	hmdfs_revert_creds(old_cred);
7608c2ecf20Sopenharmony_ci}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_cistatic void hmdfs_request_work_fn(struct work_struct *ptr)
7648c2ecf20Sopenharmony_ci{
7658c2ecf20Sopenharmony_ci	struct work_handler_desp *desp =
7668c2ecf20Sopenharmony_ci		container_of(ptr, struct work_handler_desp, work);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	hmdfs_msg_handle_sync(desp->peer, desp->head, desp->buf);
7698c2ecf20Sopenharmony_ci	peer_put(desp->peer);
7708c2ecf20Sopenharmony_ci	kfree(desp->head);
7718c2ecf20Sopenharmony_ci	kfree(desp);
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_cistatic int hmdfs_msg_handle_async(struct hmdfs_peer *con,
7758c2ecf20Sopenharmony_ci				  struct hmdfs_head_cmd *head, void *buf,
7768c2ecf20Sopenharmony_ci				  struct workqueue_struct *wq,
7778c2ecf20Sopenharmony_ci				  void (*work_fn)(struct work_struct *ptr))
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	struct work_handler_desp *desp = NULL;
7808c2ecf20Sopenharmony_ci	struct hmdfs_head_cmd *dup_head = NULL;
7818c2ecf20Sopenharmony_ci	int ret;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	desp = kzalloc(sizeof(*desp), GFP_KERNEL);
7848c2ecf20Sopenharmony_ci	if (!desp) {
7858c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7868c2ecf20Sopenharmony_ci		goto exit_desp;
7878c2ecf20Sopenharmony_ci	}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	dup_head = kzalloc(sizeof(*dup_head), GFP_KERNEL);
7908c2ecf20Sopenharmony_ci	if (!dup_head) {
7918c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7928c2ecf20Sopenharmony_ci		goto exit_desp;
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	*dup_head = *head;
7968c2ecf20Sopenharmony_ci	desp->peer = con;
7978c2ecf20Sopenharmony_ci	desp->head = dup_head;
7988c2ecf20Sopenharmony_ci	desp->buf = buf;
7998c2ecf20Sopenharmony_ci	INIT_WORK(&desp->work, work_fn);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	peer_get(con);
8028c2ecf20Sopenharmony_ci	queue_work(wq, &desp->work);
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	ret = 0;
8058c2ecf20Sopenharmony_ci	return ret;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ciexit_desp:
8088c2ecf20Sopenharmony_ci	kfree(desp);
8098c2ecf20Sopenharmony_ci	return ret;
8108c2ecf20Sopenharmony_ci}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_cistatic int hmdfs_request_recv(struct hmdfs_peer *con,
8138c2ecf20Sopenharmony_ci			      struct hmdfs_head_cmd *head, void *buf)
8148c2ecf20Sopenharmony_ci{
8158c2ecf20Sopenharmony_ci	int ret;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	if (head->operations.command >= F_SIZE ||
8188c2ecf20Sopenharmony_ci	    !s_recv_callbacks[head->operations.command]) {
8198c2ecf20Sopenharmony_ci		ret = -EINVAL;
8208c2ecf20Sopenharmony_ci		hmdfs_err("NULL callback, command %d",
8218c2ecf20Sopenharmony_ci			  head->operations.command);
8228c2ecf20Sopenharmony_ci		goto out;
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	switch (head->operations.command) {
8268c2ecf20Sopenharmony_ci	case F_OPEN:
8278c2ecf20Sopenharmony_ci	case F_RELEASE:
8288c2ecf20Sopenharmony_ci	case F_ITERATE:
8298c2ecf20Sopenharmony_ci	case F_MKDIR:
8308c2ecf20Sopenharmony_ci	case F_RMDIR:
8318c2ecf20Sopenharmony_ci	case F_CREATE:
8328c2ecf20Sopenharmony_ci	case F_UNLINK:
8338c2ecf20Sopenharmony_ci	case F_RENAME:
8348c2ecf20Sopenharmony_ci	case F_SETATTR:
8358c2ecf20Sopenharmony_ci	case F_STATFS:
8368c2ecf20Sopenharmony_ci	case F_CONNECT_REKEY:
8378c2ecf20Sopenharmony_ci	case F_DROP_PUSH:
8388c2ecf20Sopenharmony_ci	case F_GETATTR:
8398c2ecf20Sopenharmony_ci	case F_FSYNC:
8408c2ecf20Sopenharmony_ci	case F_SYNCFS:
8418c2ecf20Sopenharmony_ci	case F_GETXATTR:
8428c2ecf20Sopenharmony_ci	case F_SETXATTR:
8438c2ecf20Sopenharmony_ci	case F_LISTXATTR:
8448c2ecf20Sopenharmony_ci	case F_ATOMIC_OPEN:
8458c2ecf20Sopenharmony_ci		ret = hmdfs_msg_handle_async(con, head, buf, con->req_handle_wq,
8468c2ecf20Sopenharmony_ci					     hmdfs_request_work_fn);
8478c2ecf20Sopenharmony_ci		break;
8488c2ecf20Sopenharmony_ci	case F_WRITEPAGE:
8498c2ecf20Sopenharmony_ci	case F_READPAGE:
8508c2ecf20Sopenharmony_ci		hmdfs_msg_handle_sync(con, head, buf);
8518c2ecf20Sopenharmony_ci		ret = 0;
8528c2ecf20Sopenharmony_ci		break;
8538c2ecf20Sopenharmony_ci	default:
8548c2ecf20Sopenharmony_ci		hmdfs_err("Fatal! Unexpected request command %d",
8558c2ecf20Sopenharmony_ci			  head->operations.command);
8568c2ecf20Sopenharmony_ci		ret = -EINVAL;
8578c2ecf20Sopenharmony_ci	}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ciout:
8608c2ecf20Sopenharmony_ci	return ret;
8618c2ecf20Sopenharmony_ci}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_civoid hmdfs_response_wakeup(struct sendmsg_wait_queue *msg_info,
8648c2ecf20Sopenharmony_ci			   __u32 ret_code, __u32 data_len, void *buf)
8658c2ecf20Sopenharmony_ci{
8668c2ecf20Sopenharmony_ci	msg_info->ret = ret_code;
8678c2ecf20Sopenharmony_ci	msg_info->size = data_len;
8688c2ecf20Sopenharmony_ci	msg_info->buf = buf;
8698c2ecf20Sopenharmony_ci	atomic_set(&msg_info->valid, MSG_Q_END_RECV);
8708c2ecf20Sopenharmony_ci	wake_up_interruptible(&msg_info->response_q);
8718c2ecf20Sopenharmony_ci}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_cistatic int hmdfs_readfile_slice(struct sendmsg_wait_queue *msg_info,
8748c2ecf20Sopenharmony_ci				struct work_handler_desp *desp)
8758c2ecf20Sopenharmony_ci{
8768c2ecf20Sopenharmony_ci	struct slice_descriptor *sdesc = desp->buf;
8778c2ecf20Sopenharmony_ci	void *slice_buf = sdesc + 1;
8788c2ecf20Sopenharmony_ci	struct file_recv_info *recv_info = &msg_info->recv_info;
8798c2ecf20Sopenharmony_ci	struct file *filp = recv_info->local_filp;
8808c2ecf20Sopenharmony_ci	loff_t offset;
8818c2ecf20Sopenharmony_ci	ssize_t written_size;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	if (filp == NULL) {
8848c2ecf20Sopenharmony_ci		hmdfs_warning("recv_info filp is NULL \n");
8858c2ecf20Sopenharmony_ci		return -EINVAL;
8868c2ecf20Sopenharmony_ci	}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	if (atomic_read(&recv_info->state) != FILE_RECV_PROCESS)
8898c2ecf20Sopenharmony_ci		return -EBUSY;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	offset = le32_to_cpu(sdesc->slice_size) * le32_to_cpu(sdesc->slice_sn);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	written_size = kernel_write(filp, slice_buf,
8948c2ecf20Sopenharmony_ci				    le32_to_cpu(sdesc->content_size), &offset);
8958c2ecf20Sopenharmony_ci	if (IS_ERR_VALUE(written_size)) {
8968c2ecf20Sopenharmony_ci		atomic_set(&recv_info->state, FILE_RECV_ERR_SPC);
8978c2ecf20Sopenharmony_ci		hmdfs_info("Fatal! Cannot store a file slice %d/%d, ret = %d",
8988c2ecf20Sopenharmony_ci			   le32_to_cpu(sdesc->slice_sn),
8998c2ecf20Sopenharmony_ci			   le32_to_cpu(sdesc->num_slices), (int)written_size);
9008c2ecf20Sopenharmony_ci		return (int)written_size;
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	if (atomic_inc_return(&recv_info->local_fslices) >=
9048c2ecf20Sopenharmony_ci	    le32_to_cpu(sdesc->num_slices))
9058c2ecf20Sopenharmony_ci		atomic_set(&recv_info->state, FILE_RECV_SUCC);
9068c2ecf20Sopenharmony_ci	return 0;
9078c2ecf20Sopenharmony_ci}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_cistatic void hmdfs_file_response_work_fn(struct work_struct *ptr)
9108c2ecf20Sopenharmony_ci{
9118c2ecf20Sopenharmony_ci	struct work_handler_desp *desp =
9128c2ecf20Sopenharmony_ci		container_of(ptr, struct work_handler_desp, work);
9138c2ecf20Sopenharmony_ci	struct sendmsg_wait_queue *msg_info = NULL;
9148c2ecf20Sopenharmony_ci	int ret;
9158c2ecf20Sopenharmony_ci	atomic_t *pstate = NULL;
9168c2ecf20Sopenharmony_ci	u8 cmd = desp->head->operations.command;
9178c2ecf20Sopenharmony_ci	const struct cred *old_cred =
9188c2ecf20Sopenharmony_ci		hmdfs_override_creds(desp->peer->sbi->cred);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	msg_info = (struct sendmsg_wait_queue *)hmdfs_find_msg_head(desp->peer,
9218c2ecf20Sopenharmony_ci		le32_to_cpu(desp->head->msg_id), desp->head->operations);
9228c2ecf20Sopenharmony_ci	if (!msg_info || atomic_read(&msg_info->valid) != MSG_Q_SEND) {
9238c2ecf20Sopenharmony_ci		hmdfs_client_resp_statis(desp->peer->sbi, cmd, HMDFS_RESP_DELAY,
9248c2ecf20Sopenharmony_ci					 0, 0);
9258c2ecf20Sopenharmony_ci		hmdfs_info("cannot find msg(id %d)",
9268c2ecf20Sopenharmony_ci			   le32_to_cpu(desp->head->msg_id));
9278c2ecf20Sopenharmony_ci		goto free;
9288c2ecf20Sopenharmony_ci	}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	ret = le32_to_cpu(desp->head->ret_code);
9318c2ecf20Sopenharmony_ci	if (ret || le32_to_cpu(desp->head->data_len) == sizeof(*desp->head))
9328c2ecf20Sopenharmony_ci		goto wakeup;
9338c2ecf20Sopenharmony_ci	ret = hmdfs_readfile_slice(msg_info, desp);
9348c2ecf20Sopenharmony_ci	pstate = &msg_info->recv_info.state;
9358c2ecf20Sopenharmony_ci	if (ret || atomic_read(pstate) != FILE_RECV_PROCESS)
9368c2ecf20Sopenharmony_ci		goto wakeup;
9378c2ecf20Sopenharmony_ci	goto free;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ciwakeup:
9408c2ecf20Sopenharmony_ci	hmdfs_response_wakeup(msg_info, ret, sizeof(struct hmdfs_head_cmd),
9418c2ecf20Sopenharmony_ci			      NULL);
9428c2ecf20Sopenharmony_ci	hmdfs_client_resp_statis(desp->peer->sbi, cmd, HMDFS_RESP_NORMAL,
9438c2ecf20Sopenharmony_ci				 msg_info->start, jiffies);
9448c2ecf20Sopenharmony_cifree:
9458c2ecf20Sopenharmony_ci	if (msg_info)
9468c2ecf20Sopenharmony_ci		msg_put(msg_info);
9478c2ecf20Sopenharmony_ci	peer_put(desp->peer);
9488c2ecf20Sopenharmony_ci	hmdfs_revert_creds(old_cred);
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	kfree(desp->buf);
9518c2ecf20Sopenharmony_ci	kfree(desp->head);
9528c2ecf20Sopenharmony_ci	kfree(desp);
9538c2ecf20Sopenharmony_ci}
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_cistatic void hmdfs_wait_mp_wfired(struct hmdfs_msg_parasite *mp)
9568c2ecf20Sopenharmony_ci{
9578c2ecf20Sopenharmony_ci	/* We just cancel queued works */
9588c2ecf20Sopenharmony_ci	while (unlikely(!smp_load_acquire(&mp->wfired)))
9598c2ecf20Sopenharmony_ci		usleep_range(ACQUIRE_WFIRED_INTVAL_USEC_MIN,
9608c2ecf20Sopenharmony_ci			     ACQUIRE_WFIRED_INTVAL_USEC_MAX);
9618c2ecf20Sopenharmony_ci}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ciint hmdfs_response_handle_sync(struct hmdfs_peer *con,
9648c2ecf20Sopenharmony_ci			       struct hmdfs_head_cmd *head, void *buf)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	struct sendmsg_wait_queue *msg_info = NULL;
9678c2ecf20Sopenharmony_ci	struct hmdfs_msg_parasite *mp = NULL;
9688c2ecf20Sopenharmony_ci	struct hmdfs_msg_idr_head *msg_head = NULL;
9698c2ecf20Sopenharmony_ci	u32 msg_id = le32_to_cpu(head->msg_id);
9708c2ecf20Sopenharmony_ci	bool woke = false;
9718c2ecf20Sopenharmony_ci	u8 cmd = head->operations.command;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	msg_head = hmdfs_find_msg_head(con, msg_id, head->operations);
9748c2ecf20Sopenharmony_ci	if (!msg_head)
9758c2ecf20Sopenharmony_ci		goto out;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	switch (msg_head->type) {
9788c2ecf20Sopenharmony_ci	case MSG_IDR_MESSAGE_SYNC:
9798c2ecf20Sopenharmony_ci		msg_info = (struct sendmsg_wait_queue *)msg_head;
9808c2ecf20Sopenharmony_ci		if (atomic_read(&msg_info->valid) == MSG_Q_SEND) {
9818c2ecf20Sopenharmony_ci			hmdfs_response_wakeup(msg_info,
9828c2ecf20Sopenharmony_ci					      le32_to_cpu(head->ret_code),
9838c2ecf20Sopenharmony_ci					      le32_to_cpu(head->data_len), buf);
9848c2ecf20Sopenharmony_ci			hmdfs_client_resp_statis(con->sbi, cmd,
9858c2ecf20Sopenharmony_ci						 HMDFS_RESP_NORMAL,
9868c2ecf20Sopenharmony_ci						 msg_info->start, jiffies);
9878c2ecf20Sopenharmony_ci			woke = true;
9888c2ecf20Sopenharmony_ci		}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci		msg_put(msg_info);
9918c2ecf20Sopenharmony_ci		break;
9928c2ecf20Sopenharmony_ci	case MSG_IDR_MESSAGE_ASYNC:
9938c2ecf20Sopenharmony_ci		mp = (struct hmdfs_msg_parasite *)msg_head;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci		hmdfs_wait_mp_wfired(mp);
9968c2ecf20Sopenharmony_ci		if (cancel_delayed_work(&mp->d_work)) {
9978c2ecf20Sopenharmony_ci			mp->resp.out_buf = buf;
9988c2ecf20Sopenharmony_ci			mp->resp.out_len =
9998c2ecf20Sopenharmony_ci				le32_to_cpu(head->data_len) - sizeof(*head);
10008c2ecf20Sopenharmony_ci			mp->resp.ret_code = le32_to_cpu(head->ret_code);
10018c2ecf20Sopenharmony_ci			queue_delayed_work(con->async_wq, &mp->d_work, 0);
10028c2ecf20Sopenharmony_ci			hmdfs_client_resp_statis(con->sbi, cmd,
10038c2ecf20Sopenharmony_ci						 HMDFS_RESP_NORMAL, mp->start,
10048c2ecf20Sopenharmony_ci						 jiffies);
10058c2ecf20Sopenharmony_ci			woke = true;
10068c2ecf20Sopenharmony_ci		}
10078c2ecf20Sopenharmony_ci		mp_put(mp);
10088c2ecf20Sopenharmony_ci		break;
10098c2ecf20Sopenharmony_ci	default:
10108c2ecf20Sopenharmony_ci		hmdfs_err("receive incorrect msg type %d msg_id %d cmd %d",
10118c2ecf20Sopenharmony_ci			  msg_head->type, msg_id, cmd);
10128c2ecf20Sopenharmony_ci		break;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	if (likely(woke))
10168c2ecf20Sopenharmony_ci		return 0;
10178c2ecf20Sopenharmony_ciout:
10188c2ecf20Sopenharmony_ci	hmdfs_client_resp_statis(con->sbi, cmd, HMDFS_RESP_DELAY, 0, 0);
10198c2ecf20Sopenharmony_ci	hmdfs_info("cannot find msg_id %d cmd %d", msg_id, cmd);
10208c2ecf20Sopenharmony_ci	return -EINVAL;
10218c2ecf20Sopenharmony_ci}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_cistatic int hmdfs_response_recv(struct hmdfs_peer *con,
10248c2ecf20Sopenharmony_ci			       struct hmdfs_head_cmd *head, void *buf)
10258c2ecf20Sopenharmony_ci{
10268c2ecf20Sopenharmony_ci	__u16 command = head->operations.command;
10278c2ecf20Sopenharmony_ci	int ret;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	if (command >= F_SIZE) {
10308c2ecf20Sopenharmony_ci		ret = -EINVAL;
10318c2ecf20Sopenharmony_ci		return ret;
10328c2ecf20Sopenharmony_ci	}
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	switch (head->operations.command) {
10358c2ecf20Sopenharmony_ci	case F_OPEN:
10368c2ecf20Sopenharmony_ci	case F_RELEASE:
10378c2ecf20Sopenharmony_ci	case F_READPAGE:
10388c2ecf20Sopenharmony_ci	case F_WRITEPAGE:
10398c2ecf20Sopenharmony_ci	case F_MKDIR:
10408c2ecf20Sopenharmony_ci	case F_RMDIR:
10418c2ecf20Sopenharmony_ci	case F_CREATE:
10428c2ecf20Sopenharmony_ci	case F_UNLINK:
10438c2ecf20Sopenharmony_ci	case F_RENAME:
10448c2ecf20Sopenharmony_ci	case F_SETATTR:
10458c2ecf20Sopenharmony_ci	case F_STATFS:
10468c2ecf20Sopenharmony_ci	case F_CONNECT_REKEY:
10478c2ecf20Sopenharmony_ci	case F_DROP_PUSH:
10488c2ecf20Sopenharmony_ci	case F_GETATTR:
10498c2ecf20Sopenharmony_ci	case F_FSYNC:
10508c2ecf20Sopenharmony_ci	case F_SYNCFS:
10518c2ecf20Sopenharmony_ci	case F_GETXATTR:
10528c2ecf20Sopenharmony_ci	case F_SETXATTR:
10538c2ecf20Sopenharmony_ci	case F_LISTXATTR:
10548c2ecf20Sopenharmony_ci		ret = hmdfs_response_handle_sync(con, head, buf);
10558c2ecf20Sopenharmony_ci		return ret;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	case F_ITERATE:
10588c2ecf20Sopenharmony_ci		ret = hmdfs_msg_handle_async(con, head, buf, con->async_wq,
10598c2ecf20Sopenharmony_ci					     hmdfs_file_response_work_fn);
10608c2ecf20Sopenharmony_ci		return ret;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	default:
10638c2ecf20Sopenharmony_ci		hmdfs_err("Fatal! Unexpected response command %d",
10648c2ecf20Sopenharmony_ci			  head->operations.command);
10658c2ecf20Sopenharmony_ci		ret = -EINVAL;
10668c2ecf20Sopenharmony_ci		return ret;
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_civoid hmdfs_recv_mesg_callback(struct hmdfs_peer *con, void *head,
10718c2ecf20Sopenharmony_ci				     void *buf)
10728c2ecf20Sopenharmony_ci{
10738c2ecf20Sopenharmony_ci	struct hmdfs_head_cmd *hmdfs_head = (struct hmdfs_head_cmd *)head;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	trace_hmdfs_recv_mesg_callback(hmdfs_head);
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	if (hmdfs_message_verify(con, hmdfs_head, buf) < 0) {
10788c2ecf20Sopenharmony_ci		hmdfs_info("Message %d has been abandoned", hmdfs_head->msg_id);
10798c2ecf20Sopenharmony_ci		goto out_err;
10808c2ecf20Sopenharmony_ci	}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	switch (hmdfs_head->operations.cmd_flag) {
10838c2ecf20Sopenharmony_ci	case C_REQUEST:
10848c2ecf20Sopenharmony_ci		if (hmdfs_request_recv(con, hmdfs_head, buf) < 0)
10858c2ecf20Sopenharmony_ci			goto out_err;
10868c2ecf20Sopenharmony_ci		break;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	case C_RESPONSE:
10898c2ecf20Sopenharmony_ci		if (hmdfs_response_recv(con, hmdfs_head, buf) < 0)
10908c2ecf20Sopenharmony_ci			goto out_err;
10918c2ecf20Sopenharmony_ci		break;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	default:
10948c2ecf20Sopenharmony_ci		hmdfs_err("Fatal! Unexpected msg cmd %d",
10958c2ecf20Sopenharmony_ci			  hmdfs_head->operations.cmd_flag);
10968c2ecf20Sopenharmony_ci		goto out_err;
10978c2ecf20Sopenharmony_ci	}
10988c2ecf20Sopenharmony_ci	return;
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ciout_err:
11018c2ecf20Sopenharmony_ci	kfree(buf);
11028c2ecf20Sopenharmony_ci}
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_civoid hmdfs_wakeup_parasite(struct hmdfs_msg_parasite *mp)
11058c2ecf20Sopenharmony_ci{
11068c2ecf20Sopenharmony_ci	hmdfs_wait_mp_wfired(mp);
11078c2ecf20Sopenharmony_ci	if (!cancel_delayed_work(&mp->d_work))
11088c2ecf20Sopenharmony_ci		hmdfs_err("cancel parasite work err msg_id=%d cmd=%d",
11098c2ecf20Sopenharmony_ci			  mp->head.msg_id, mp->req.operations.command);
11108c2ecf20Sopenharmony_ci	else
11118c2ecf20Sopenharmony_ci		async_request_cb_on_wakeup_fn(&mp->d_work.work);
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_civoid hmdfs_wakeup_async_work(struct hmdfs_async_work *async_work)
11158c2ecf20Sopenharmony_ci{
11168c2ecf20Sopenharmony_ci	if (!cancel_delayed_work(&async_work->d_work))
11178c2ecf20Sopenharmony_ci		hmdfs_err("cancel async work err msg_id=%d",
11188c2ecf20Sopenharmony_ci			  async_work->head.msg_id);
11198c2ecf20Sopenharmony_ci	else
11208c2ecf20Sopenharmony_ci		hmdfs_recv_page_work_fn(&async_work->d_work.work);
11218c2ecf20Sopenharmony_ci}
1122