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, ¶m); 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