162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * fs/hmdfs/hmdfs_client.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "hmdfs_client.h"
962306a36Sopenharmony_ci#include "hmdfs_server.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/highmem.h>
1262306a36Sopenharmony_ci#include <linux/sched/signal.h>
1362306a36Sopenharmony_ci#include <linux/statfs.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "comm/socket_adapter.h"
1662306a36Sopenharmony_ci#include "hmdfs_dentryfile.h"
1762306a36Sopenharmony_ci#include "hmdfs_trace.h"
1862306a36Sopenharmony_ci#include "comm/node_cb.h"
1962306a36Sopenharmony_ci#include "stash.h"
2062306a36Sopenharmony_ci#include "authority/authentication.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define HMDFS_SYNC_WPAGE_RETRY_MS 2000
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic inline void free_sm_outbuf(struct hmdfs_send_command *sm)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	if (sm->out_buf && sm->out_len != 0)
2762306a36Sopenharmony_ci		kfree(sm->out_buf);
2862306a36Sopenharmony_ci	sm->out_len = 0;
2962306a36Sopenharmony_ci	sm->out_buf = NULL;
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ciint hmdfs_send_open(struct hmdfs_peer *con, const char *send_buf,
3362306a36Sopenharmony_ci		    __u8 file_type, struct hmdfs_open_ret *open_ret)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	int ret;
3662306a36Sopenharmony_ci	int path_len = strlen(send_buf);
3762306a36Sopenharmony_ci	size_t send_len = sizeof(struct open_request) + path_len + 1;
3862306a36Sopenharmony_ci	struct open_request *open_req = kzalloc(send_len, GFP_KERNEL);
3962306a36Sopenharmony_ci	struct open_response *resp;
4062306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
4162306a36Sopenharmony_ci		.data = open_req,
4262306a36Sopenharmony_ci		.len = send_len,
4362306a36Sopenharmony_ci		.out_buf = NULL,
4462306a36Sopenharmony_ci		.local_filp = NULL,
4562306a36Sopenharmony_ci	};
4662306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_OPEN);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	if (!open_req) {
4962306a36Sopenharmony_ci		ret = -ENOMEM;
5062306a36Sopenharmony_ci		goto out;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci	open_req->file_type = file_type;
5362306a36Sopenharmony_ci	open_req->path_len = cpu_to_le32(path_len);
5462306a36Sopenharmony_ci	strcpy(open_req->buf, send_buf);
5562306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
5662306a36Sopenharmony_ci	kfree(open_req);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (!ret && (sm.out_len == 0 || !sm.out_buf))
5962306a36Sopenharmony_ci		ret = -ENOENT;
6062306a36Sopenharmony_ci	if (ret)
6162306a36Sopenharmony_ci		goto out;
6262306a36Sopenharmony_ci	resp = sm.out_buf;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	open_ret->ino = le64_to_cpu(resp->ino);
6562306a36Sopenharmony_ci	open_ret->fid.ver = le64_to_cpu(resp->file_ver);
6662306a36Sopenharmony_ci	open_ret->fid.id = le32_to_cpu(resp->file_id);
6762306a36Sopenharmony_ci	open_ret->file_size = le64_to_cpu(resp->file_size);
6862306a36Sopenharmony_ci	open_ret->remote_ctime.tv_sec = le64_to_cpu(resp->ctime);
6962306a36Sopenharmony_ci	open_ret->remote_ctime.tv_nsec = le32_to_cpu(resp->ctime_nsec);
7062306a36Sopenharmony_ci	open_ret->stable_ctime.tv_sec = le64_to_cpu(resp->stable_ctime);
7162306a36Sopenharmony_ci	open_ret->stable_ctime.tv_nsec = le32_to_cpu(resp->stable_ctime_nsec);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciout:
7462306a36Sopenharmony_ci	free_sm_outbuf(&sm);
7562306a36Sopenharmony_ci	return ret;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_civoid hmdfs_send_close(struct hmdfs_peer *con, const struct hmdfs_fid *fid)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	size_t send_len = sizeof(struct release_request);
8162306a36Sopenharmony_ci	struct release_request *release_req = kzalloc(send_len, GFP_KERNEL);
8262306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
8362306a36Sopenharmony_ci		.data = release_req,
8462306a36Sopenharmony_ci		.len = send_len,
8562306a36Sopenharmony_ci		.local_filp = NULL,
8662306a36Sopenharmony_ci	};
8762306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_RELEASE);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (!release_req)
9062306a36Sopenharmony_ci		return;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	release_req->file_ver = cpu_to_le64(fid->ver);
9362306a36Sopenharmony_ci	release_req->file_id = cpu_to_le32(fid->id);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	hmdfs_sendmessage_request(con, &sm);
9662306a36Sopenharmony_ci	kfree(release_req);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciint hmdfs_send_fsync(struct hmdfs_peer *con, const struct hmdfs_fid *fid,
10062306a36Sopenharmony_ci		     __s64 start, __s64 end, __s32 datasync)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	int ret;
10362306a36Sopenharmony_ci	struct fsync_request *fsync_req =
10462306a36Sopenharmony_ci		kzalloc(sizeof(struct fsync_request), GFP_KERNEL);
10562306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
10662306a36Sopenharmony_ci		.data = fsync_req,
10762306a36Sopenharmony_ci		.len = sizeof(struct fsync_request),
10862306a36Sopenharmony_ci		.out_buf = NULL,
10962306a36Sopenharmony_ci		.local_filp = NULL,
11062306a36Sopenharmony_ci	};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_FSYNC);
11362306a36Sopenharmony_ci	if (!fsync_req)
11462306a36Sopenharmony_ci		return -ENOMEM;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	fsync_req->file_ver = cpu_to_le64(fid->ver);
11762306a36Sopenharmony_ci	fsync_req->file_id = cpu_to_le32(fid->id);
11862306a36Sopenharmony_ci	fsync_req->datasync = cpu_to_le32(datasync);
11962306a36Sopenharmony_ci	fsync_req->start = cpu_to_le64(start);
12062306a36Sopenharmony_ci	fsync_req->end = cpu_to_le64(end);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	free_sm_outbuf(&sm);
12562306a36Sopenharmony_ci	kfree(fsync_req);
12662306a36Sopenharmony_ci	return ret;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ciint hmdfs_client_readpage(struct hmdfs_peer *con, const struct hmdfs_fid *fid,
13062306a36Sopenharmony_ci			  struct page *page)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	int ret;
13362306a36Sopenharmony_ci	size_t send_len = sizeof(struct readpage_request);
13462306a36Sopenharmony_ci	struct readpage_request *read_data = kzalloc(send_len, GFP_KERNEL);
13562306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
13662306a36Sopenharmony_ci		.data = read_data,
13762306a36Sopenharmony_ci		.len = send_len,
13862306a36Sopenharmony_ci		.local_filp = NULL,
13962306a36Sopenharmony_ci	};
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_READPAGE);
14262306a36Sopenharmony_ci	if (!read_data) {
14362306a36Sopenharmony_ci		unlock_page(page);
14462306a36Sopenharmony_ci		return -ENOMEM;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	sm.out_buf = page;
14862306a36Sopenharmony_ci	read_data->file_ver = cpu_to_le64(fid->ver);
14962306a36Sopenharmony_ci	read_data->file_id = cpu_to_le32(fid->id);
15062306a36Sopenharmony_ci	read_data->size = cpu_to_le32(HMDFS_PAGE_SIZE);
15162306a36Sopenharmony_ci	read_data->index = cpu_to_le64(page->index);
15262306a36Sopenharmony_ci	ret = hmdfs_sendpage_request(con, &sm);
15362306a36Sopenharmony_ci	kfree(read_data);
15462306a36Sopenharmony_ci	return ret;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cibool hmdfs_usr_sig_pending(struct task_struct *p)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	sigset_t *sig = &p->pending.signal;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (likely(!signal_pending(p)))
16262306a36Sopenharmony_ci		return false;
16362306a36Sopenharmony_ci	return sigismember(sig, SIGINT) || sigismember(sig, SIGTERM) ||
16462306a36Sopenharmony_ci	       sigismember(sig, SIGKILL);
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_civoid hmdfs_client_writepage_done(struct hmdfs_inode_info *info,
16862306a36Sopenharmony_ci				 struct hmdfs_writepage_context *ctx)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	struct page *page = ctx->page;
17162306a36Sopenharmony_ci	bool unlock = ctx->rsem_held;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	SetPageUptodate(page);
17462306a36Sopenharmony_ci	end_page_writeback(page);
17562306a36Sopenharmony_ci	if (unlock)
17662306a36Sopenharmony_ci		up_read(&info->wpage_sem);
17762306a36Sopenharmony_ci	unlock_page(page);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic void hmdfs_client_writepage_err(struct hmdfs_peer *peer,
18162306a36Sopenharmony_ci				       struct hmdfs_inode_info *info,
18262306a36Sopenharmony_ci				       struct hmdfs_writepage_context *ctx,
18362306a36Sopenharmony_ci				       int err)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct page *page = ctx->page;
18662306a36Sopenharmony_ci	bool unlock = ctx->rsem_held;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (err == -ENOMEM || err == -EAGAIN || err == -ESHUTDOWN ||
18962306a36Sopenharmony_ci	    err == -ETIME)
19062306a36Sopenharmony_ci		SetPageUptodate(page);
19162306a36Sopenharmony_ci	else
19262306a36Sopenharmony_ci		hmdfs_info("Page %ld of file %u writeback err %d devid %llu",
19362306a36Sopenharmony_ci			   page->index, ctx->fid.id, err, peer->device_id);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/*
19662306a36Sopenharmony_ci	 * Current and subsequent writebacks have been canceled by the
19762306a36Sopenharmony_ci	 * user, leaving these pages' states in chaos. Read pages in
19862306a36Sopenharmony_ci	 * the future to update these pages.
19962306a36Sopenharmony_ci	 */
20062306a36Sopenharmony_ci	if (ctx->sync_all && hmdfs_usr_sig_pending(ctx->caller))
20162306a36Sopenharmony_ci		ClearPageUptodate(page);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (ctx->sync_all || !time_is_after_eq_jiffies(ctx->timeout) ||
20462306a36Sopenharmony_ci	    !(err == -ETIME || hmdfs_need_redirty_page(info, err))) {
20562306a36Sopenharmony_ci		SetPageError(page);
20662306a36Sopenharmony_ci		mapping_set_error(page->mapping, -EIO);
20762306a36Sopenharmony_ci	} else {
20862306a36Sopenharmony_ci		__set_page_dirty_nobuffers(page);
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	end_page_writeback(page);
21262306a36Sopenharmony_ci	if (unlock)
21362306a36Sopenharmony_ci		up_read(&info->wpage_sem);
21462306a36Sopenharmony_ci	unlock_page(page);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic inline bool
21862306a36Sopenharmony_cihmdfs_no_timedout_sync_write(struct hmdfs_writepage_context *ctx)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	return ctx->sync_all && time_is_after_eq_jiffies(ctx->timeout);
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic inline bool
22462306a36Sopenharmony_cihmdfs_client_rewrite_for_timeout(struct hmdfs_writepage_context *ctx, int err)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	return (err == -ETIME && hmdfs_no_timedout_sync_write(ctx) &&
22762306a36Sopenharmony_ci		!hmdfs_usr_sig_pending(ctx->caller));
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic inline bool
23162306a36Sopenharmony_cihmdfs_client_rewrite_for_offline(struct hmdfs_sb_info *sbi,
23262306a36Sopenharmony_ci				 struct hmdfs_writepage_context *ctx, int err)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(ctx->page->mapping->host);
23562306a36Sopenharmony_ci	unsigned int status = READ_ONCE(info->stash_status);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/*
23862306a36Sopenharmony_ci	 * No retry if offline occurs during inode restoration.
23962306a36Sopenharmony_ci	 *
24062306a36Sopenharmony_ci	 * Do retry if local file cache is ready even it is not
24162306a36Sopenharmony_ci	 * a WB_SYNC_ALL write, else no-sync_all writeback will
24262306a36Sopenharmony_ci	 * return -EIO, mapping_set_error(mapping, -EIO) will be
24362306a36Sopenharmony_ci	 * called and it will make the concurrent calling of
24462306a36Sopenharmony_ci	 * filemap_write_and_wait() in hmdfs_flush_stash_file_data()
24562306a36Sopenharmony_ci	 * return -EIO.
24662306a36Sopenharmony_ci	 */
24762306a36Sopenharmony_ci	return (hmdfs_is_stash_enabled(sbi) &&
24862306a36Sopenharmony_ci		status != HMDFS_REMOTE_INODE_RESTORING &&
24962306a36Sopenharmony_ci		(hmdfs_no_timedout_sync_write(ctx) ||
25062306a36Sopenharmony_ci		 status == HMDFS_REMOTE_INODE_STASHING) &&
25162306a36Sopenharmony_ci		hmdfs_is_offline_or_timeout_err(err));
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic inline bool
25562306a36Sopenharmony_cihmdfs_client_redo_writepage(struct hmdfs_sb_info *sbi,
25662306a36Sopenharmony_ci			    struct hmdfs_writepage_context *ctx, int err)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	return hmdfs_client_rewrite_for_timeout(ctx, err) ||
25962306a36Sopenharmony_ci	       hmdfs_client_rewrite_for_offline(sbi, ctx, err);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic bool hmdfs_remote_write_to_remote(struct hmdfs_inode_info *info)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	unsigned int status = READ_ONCE(info->stash_status);
26562306a36Sopenharmony_ci	bool stashing;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (status != HMDFS_REMOTE_INODE_STASHING)
26862306a36Sopenharmony_ci		return true;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/* Ensure it's OK to use info->cache afterwards */
27162306a36Sopenharmony_ci	spin_lock(&info->stash_lock);
27262306a36Sopenharmony_ci	stashing = (info->stash_status == HMDFS_REMOTE_INODE_STASHING);
27362306a36Sopenharmony_ci	spin_unlock(&info->stash_lock);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return !stashing;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciint hmdfs_remote_do_writepage(struct hmdfs_peer *con,
27962306a36Sopenharmony_ci			      struct hmdfs_writepage_context *ctx)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(ctx->page->mapping->host);
28262306a36Sopenharmony_ci	bool to_remote = false;
28362306a36Sopenharmony_ci	int err = 0;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	to_remote = hmdfs_remote_write_to_remote(info);
28662306a36Sopenharmony_ci	if (to_remote)
28762306a36Sopenharmony_ci		err = hmdfs_client_writepage(info->conn, ctx);
28862306a36Sopenharmony_ci	else
28962306a36Sopenharmony_ci		err = hmdfs_stash_writepage(info->conn, ctx);
29062306a36Sopenharmony_ci	if (!err)
29162306a36Sopenharmony_ci		return 0;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	if (!(to_remote &&
29462306a36Sopenharmony_ci	      hmdfs_client_rewrite_for_offline(con->sbi, ctx, err)))
29562306a36Sopenharmony_ci		return err;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	queue_delayed_work(con->retry_wb_wq, &ctx->retry_dwork,
29862306a36Sopenharmony_ci			   msecs_to_jiffies(HMDFS_SYNC_WPAGE_RETRY_MS));
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	return 0;
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_civoid hmdfs_remote_writepage_retry(struct work_struct *work)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct hmdfs_writepage_context *ctx =
30662306a36Sopenharmony_ci		container_of(work, struct hmdfs_writepage_context,
30762306a36Sopenharmony_ci			     retry_dwork.work);
30862306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(ctx->page->mapping->host);
30962306a36Sopenharmony_ci	struct hmdfs_peer *peer = info->conn;
31062306a36Sopenharmony_ci	const struct cred *old_cred = NULL;
31162306a36Sopenharmony_ci	int err;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	old_cred = hmdfs_override_creds(peer->sbi->cred);
31462306a36Sopenharmony_ci	err = hmdfs_remote_do_writepage(peer, ctx);
31562306a36Sopenharmony_ci	hmdfs_revert_creds(old_cred);
31662306a36Sopenharmony_ci	if (err) {
31762306a36Sopenharmony_ci		hmdfs_client_writepage_err(peer, info, ctx, err);
31862306a36Sopenharmony_ci		put_task_struct(ctx->caller);
31962306a36Sopenharmony_ci		kfree(ctx);
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_civoid hmdfs_writepage_cb(struct hmdfs_peer *peer, const struct hmdfs_req *req,
32462306a36Sopenharmony_ci			const struct hmdfs_resp *resp)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct hmdfs_writepage_context *ctx = req->private;
32762306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(ctx->page->mapping->host);
32862306a36Sopenharmony_ci	int ret = resp->ret_code;
32962306a36Sopenharmony_ci	unsigned long page_index = ctx->page->index;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	trace_hmdfs_writepage_cb_enter(peer, info->remote_ino, page_index, ret);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (!ret) {
33462306a36Sopenharmony_ci		hmdfs_client_writepage_done(info, ctx);
33562306a36Sopenharmony_ci		atomic64_inc(&info->write_counter);
33662306a36Sopenharmony_ci		goto cleanup_all;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (hmdfs_client_redo_writepage(peer->sbi, ctx, ret)) {
34062306a36Sopenharmony_ci		ret = hmdfs_remote_do_writepage(peer, ctx);
34162306a36Sopenharmony_ci		if (!ret)
34262306a36Sopenharmony_ci			goto cleanup_req;
34362306a36Sopenharmony_ci		WARN_ON(ret == -ETIME);
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	hmdfs_client_writepage_err(peer, info, ctx, ret);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cicleanup_all:
34962306a36Sopenharmony_ci	put_task_struct(ctx->caller);
35062306a36Sopenharmony_ci	kfree(ctx);
35162306a36Sopenharmony_cicleanup_req:
35262306a36Sopenharmony_ci	kfree(req->data);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	trace_hmdfs_writepage_cb_exit(peer, info->remote_ino, page_index, ret);
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ciint hmdfs_client_writepage(struct hmdfs_peer *con,
35862306a36Sopenharmony_ci			   struct hmdfs_writepage_context *param)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	int ret = 0;
36162306a36Sopenharmony_ci	size_t send_len = sizeof(struct writepage_request) + HMDFS_PAGE_SIZE;
36262306a36Sopenharmony_ci	struct writepage_request *write_data = kzalloc(send_len, GFP_NOFS);
36362306a36Sopenharmony_ci	struct hmdfs_req req;
36462306a36Sopenharmony_ci	char *data = NULL;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (unlikely(!write_data))
36762306a36Sopenharmony_ci		return -ENOMEM;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	WARN_ON(!PageLocked(param->page)); // VFS
37062306a36Sopenharmony_ci	WARN_ON(PageDirty(param->page)); // VFS
37162306a36Sopenharmony_ci	WARN_ON(!PageWriteback(param->page)); // hmdfs
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	write_data->file_ver = cpu_to_le64(param->fid.ver);
37462306a36Sopenharmony_ci	write_data->file_id = cpu_to_le32(param->fid.id);
37562306a36Sopenharmony_ci	write_data->index = cpu_to_le64(param->page->index);
37662306a36Sopenharmony_ci	write_data->count = cpu_to_le32(param->count);
37762306a36Sopenharmony_ci	data = kmap(param->page);
37862306a36Sopenharmony_ci	memcpy((char *)write_data->buf, data, HMDFS_PAGE_SIZE);
37962306a36Sopenharmony_ci	kunmap(param->page);
38062306a36Sopenharmony_ci	req.data = write_data;
38162306a36Sopenharmony_ci	req.data_len = send_len;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	req.private = param;
38462306a36Sopenharmony_ci	req.private_len = sizeof(*param);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	req.timeout = TIMEOUT_CONFIG;
38762306a36Sopenharmony_ci	hmdfs_init_cmd(&req.operations, F_WRITEPAGE);
38862306a36Sopenharmony_ci	ret = hmdfs_send_async_request(con, &req);
38962306a36Sopenharmony_ci	if (unlikely(ret))
39062306a36Sopenharmony_ci		kfree(write_data);
39162306a36Sopenharmony_ci	return ret;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_civoid hmdfs_client_recv_readpage(struct hmdfs_head_cmd *head, int err,
39562306a36Sopenharmony_ci				struct hmdfs_async_work *async_work)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	struct page *page = async_work->page;
39862306a36Sopenharmony_ci	int ret = le32_to_cpu(head->ret_code);
39962306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(page->mapping->host);
40062306a36Sopenharmony_ci	unsigned long page_index = page->index;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (!err)
40362306a36Sopenharmony_ci		SetPageUptodate(page);
40462306a36Sopenharmony_ci	else if (err == -EBADF)
40562306a36Sopenharmony_ci		/* There may be a stale fd caused by fid version, need reopen */
40662306a36Sopenharmony_ci		set_bit(HMDFS_FID_NEED_OPEN, &info->fid_flags);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	hmdfs_client_resp_statis(async_work->head.peer->sbi, F_READPAGE,
40962306a36Sopenharmony_ci				 HMDFS_RESP_NORMAL, async_work->start, jiffies);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	trace_hmdfs_client_recv_readpage(async_work->head.peer,
41262306a36Sopenharmony_ci					 info->remote_ino, page_index, ret);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	asw_done(async_work);
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci/* read cache dentry file at path and write them into filp */
41862306a36Sopenharmony_ciint hmdfs_client_start_readdir(struct hmdfs_peer *con, struct file *filp,
41962306a36Sopenharmony_ci			       const char *path, int path_len,
42062306a36Sopenharmony_ci			       struct hmdfs_dcache_header *header)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	int ret;
42362306a36Sopenharmony_ci	size_t send_len = sizeof(struct readdir_request) + path_len + 1;
42462306a36Sopenharmony_ci	struct readdir_request *req = kzalloc(send_len, GFP_KERNEL);
42562306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
42662306a36Sopenharmony_ci		.data = req,
42762306a36Sopenharmony_ci		.len = send_len,
42862306a36Sopenharmony_ci		.local_filp = filp,
42962306a36Sopenharmony_ci	};
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_ITERATE);
43262306a36Sopenharmony_ci	if (!req)
43362306a36Sopenharmony_ci		return -ENOMEM;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* add ref or it will be release at msg put */
43662306a36Sopenharmony_ci	get_file(sm.local_filp);
43762306a36Sopenharmony_ci	req->path_len = cpu_to_le32(path_len);
43862306a36Sopenharmony_ci	strncpy(req->path, path, path_len);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	/*
44162306a36Sopenharmony_ci	 * Is we already have a cache file, verify it. If it is
44262306a36Sopenharmony_ci	 * uptodate, then we don't have to transfer a new one
44362306a36Sopenharmony_ci	 */
44462306a36Sopenharmony_ci	if (header) {
44562306a36Sopenharmony_ci		req->dcache_crtime = header->dcache_crtime;
44662306a36Sopenharmony_ci		req->dcache_crtime_nsec = header->dcache_crtime_nsec;
44762306a36Sopenharmony_ci		req->dentry_ctime = header->dentry_ctime;
44862306a36Sopenharmony_ci		req->dentry_ctime_nsec = header->dentry_ctime_nsec;
44962306a36Sopenharmony_ci		req->num = header->num;
45062306a36Sopenharmony_ci		req->verify_cache = cpu_to_le32(1);
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
45462306a36Sopenharmony_ci	kfree(req);
45562306a36Sopenharmony_ci	return ret;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ciint hmdfs_client_start_mkdir(struct hmdfs_peer *con,
45962306a36Sopenharmony_ci			     const char *path, const char *name,
46062306a36Sopenharmony_ci			     umode_t mode, struct hmdfs_lookup_ret *mkdir_ret)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	int ret = 0;
46362306a36Sopenharmony_ci	int path_len = strlen(path);
46462306a36Sopenharmony_ci	int name_len = strlen(name);
46562306a36Sopenharmony_ci	size_t send_len = sizeof(struct mkdir_request) + path_len + 1 +
46662306a36Sopenharmony_ci			  name_len + 1;
46762306a36Sopenharmony_ci	struct mkdir_request *mkdir_req = kzalloc(send_len, GFP_KERNEL);
46862306a36Sopenharmony_ci	struct hmdfs_inodeinfo_response *resp = NULL;
46962306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
47062306a36Sopenharmony_ci		.data = mkdir_req,
47162306a36Sopenharmony_ci		.len = send_len,
47262306a36Sopenharmony_ci		.out_buf = NULL,
47362306a36Sopenharmony_ci		.local_filp = NULL,
47462306a36Sopenharmony_ci	};
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_MKDIR);
47762306a36Sopenharmony_ci	if (!mkdir_req)
47862306a36Sopenharmony_ci		return -ENOMEM;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	mkdir_req->path_len = cpu_to_le32(path_len);
48162306a36Sopenharmony_ci	mkdir_req->name_len = cpu_to_le32(name_len);
48262306a36Sopenharmony_ci	mkdir_req->mode = cpu_to_le16(mode);
48362306a36Sopenharmony_ci	strncpy(mkdir_req->path, path, path_len);
48462306a36Sopenharmony_ci	strncpy(mkdir_req->path + path_len + 1, name, name_len);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
48762306a36Sopenharmony_ci	if (ret == -ENOENT || ret == -ETIME || ret == -EOPNOTSUPP)
48862306a36Sopenharmony_ci		goto out;
48962306a36Sopenharmony_ci	if (!sm.out_buf) {
49062306a36Sopenharmony_ci		ret = -ENOENT;
49162306a36Sopenharmony_ci		goto out;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci	resp = sm.out_buf;
49462306a36Sopenharmony_ci	mkdir_ret->i_mode = le16_to_cpu(resp->i_mode);
49562306a36Sopenharmony_ci	mkdir_ret->i_size = le64_to_cpu(resp->i_size);
49662306a36Sopenharmony_ci	mkdir_ret->i_mtime = le64_to_cpu(resp->i_mtime);
49762306a36Sopenharmony_ci	mkdir_ret->i_mtime_nsec = le32_to_cpu(resp->i_mtime_nsec);
49862306a36Sopenharmony_ci	mkdir_ret->i_ino = le64_to_cpu(resp->i_ino);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ciout:
50162306a36Sopenharmony_ci	free_sm_outbuf(&sm);
50262306a36Sopenharmony_ci	kfree(mkdir_req);
50362306a36Sopenharmony_ci	return ret;
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ciint hmdfs_client_start_create(struct hmdfs_peer *con,
50762306a36Sopenharmony_ci			      const char *path, const char *name,
50862306a36Sopenharmony_ci			      umode_t mode, bool want_excl,
50962306a36Sopenharmony_ci			      struct hmdfs_lookup_ret *create_ret)
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	int ret = 0;
51262306a36Sopenharmony_ci	int path_len = strlen(path);
51362306a36Sopenharmony_ci	int name_len = strlen(name);
51462306a36Sopenharmony_ci	size_t send_len = sizeof(struct create_request) + path_len + 1 +
51562306a36Sopenharmony_ci			  name_len + 1;
51662306a36Sopenharmony_ci	struct create_request *create_req = kzalloc(send_len, GFP_KERNEL);
51762306a36Sopenharmony_ci	struct hmdfs_inodeinfo_response *resp = NULL;
51862306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
51962306a36Sopenharmony_ci		.data = create_req,
52062306a36Sopenharmony_ci		.len = send_len,
52162306a36Sopenharmony_ci		.out_buf = NULL,
52262306a36Sopenharmony_ci		.local_filp = NULL,
52362306a36Sopenharmony_ci	};
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_CREATE);
52662306a36Sopenharmony_ci	if (!create_req)
52762306a36Sopenharmony_ci		return -ENOMEM;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	create_req->path_len = cpu_to_le32(path_len);
53062306a36Sopenharmony_ci	create_req->name_len = cpu_to_le32(name_len);
53162306a36Sopenharmony_ci	create_req->mode = cpu_to_le16(mode);
53262306a36Sopenharmony_ci	create_req->want_excl = want_excl;
53362306a36Sopenharmony_ci	strncpy(create_req->path, path, path_len);
53462306a36Sopenharmony_ci	strncpy(create_req->path + path_len + 1, name, name_len);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
53762306a36Sopenharmony_ci	if (ret == -ENOENT || ret == -ETIME || ret == -EOPNOTSUPP)
53862306a36Sopenharmony_ci		goto out;
53962306a36Sopenharmony_ci	if (!sm.out_buf) {
54062306a36Sopenharmony_ci		ret = -ENOENT;
54162306a36Sopenharmony_ci		goto out;
54262306a36Sopenharmony_ci	}
54362306a36Sopenharmony_ci	resp = sm.out_buf;
54462306a36Sopenharmony_ci	create_ret->i_mode = le16_to_cpu(resp->i_mode);
54562306a36Sopenharmony_ci	create_ret->i_size = le64_to_cpu(resp->i_size);
54662306a36Sopenharmony_ci	create_ret->i_mtime = le64_to_cpu(resp->i_mtime);
54762306a36Sopenharmony_ci	create_ret->i_mtime_nsec = le32_to_cpu(resp->i_mtime_nsec);
54862306a36Sopenharmony_ci	create_ret->i_ino = le64_to_cpu(resp->i_ino);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ciout:
55162306a36Sopenharmony_ci	free_sm_outbuf(&sm);
55262306a36Sopenharmony_ci	kfree(create_req);
55362306a36Sopenharmony_ci	return ret;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ciint hmdfs_client_start_rmdir(struct hmdfs_peer *con, const char *path,
55762306a36Sopenharmony_ci			     const char *name)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	int ret;
56062306a36Sopenharmony_ci	int path_len = strlen(path);
56162306a36Sopenharmony_ci	int name_len = strlen(name);
56262306a36Sopenharmony_ci	size_t send_len = sizeof(struct rmdir_request) + path_len + 1 +
56362306a36Sopenharmony_ci			  name_len + 1;
56462306a36Sopenharmony_ci	struct rmdir_request *rmdir_req = kzalloc(send_len, GFP_KERNEL);
56562306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
56662306a36Sopenharmony_ci		.data = rmdir_req,
56762306a36Sopenharmony_ci		.len = send_len,
56862306a36Sopenharmony_ci		.out_buf = NULL,
56962306a36Sopenharmony_ci		.local_filp = NULL,
57062306a36Sopenharmony_ci	};
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_RMDIR);
57362306a36Sopenharmony_ci	if (!rmdir_req)
57462306a36Sopenharmony_ci		return -ENOMEM;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	rmdir_req->path_len = cpu_to_le32(path_len);
57762306a36Sopenharmony_ci	rmdir_req->name_len = cpu_to_le32(name_len);
57862306a36Sopenharmony_ci	strncpy(rmdir_req->path, path, path_len);
57962306a36Sopenharmony_ci	strncpy(rmdir_req->path + path_len + 1, name, name_len);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
58262306a36Sopenharmony_ci	free_sm_outbuf(&sm);
58362306a36Sopenharmony_ci	kfree(rmdir_req);
58462306a36Sopenharmony_ci	return ret;
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ciint hmdfs_client_start_unlink(struct hmdfs_peer *con, const char *path,
58862306a36Sopenharmony_ci			      const char *name)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	int ret;
59162306a36Sopenharmony_ci	int path_len = strlen(path);
59262306a36Sopenharmony_ci	int name_len = strlen(name);
59362306a36Sopenharmony_ci	size_t send_len = sizeof(struct unlink_request) + path_len + 1 +
59462306a36Sopenharmony_ci			  name_len + 1;
59562306a36Sopenharmony_ci	struct unlink_request *unlink_req = kzalloc(send_len, GFP_KERNEL);
59662306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
59762306a36Sopenharmony_ci		.data = unlink_req,
59862306a36Sopenharmony_ci		.len = send_len,
59962306a36Sopenharmony_ci		.out_buf = NULL,
60062306a36Sopenharmony_ci		.local_filp = NULL,
60162306a36Sopenharmony_ci	};
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_UNLINK);
60462306a36Sopenharmony_ci	if (!unlink_req)
60562306a36Sopenharmony_ci		return -ENOMEM;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	unlink_req->path_len = cpu_to_le32(path_len);
60862306a36Sopenharmony_ci	unlink_req->name_len = cpu_to_le32(name_len);
60962306a36Sopenharmony_ci	strncpy(unlink_req->path, path, path_len);
61062306a36Sopenharmony_ci	strncpy(unlink_req->path + path_len + 1, name, name_len);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
61362306a36Sopenharmony_ci	kfree(unlink_req);
61462306a36Sopenharmony_ci	free_sm_outbuf(&sm);
61562306a36Sopenharmony_ci	return ret;
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ciint hmdfs_client_start_rename(struct hmdfs_peer *con, const char *old_path,
61962306a36Sopenharmony_ci			      const char *old_name, const char *new_path,
62062306a36Sopenharmony_ci			      const char *new_name, unsigned int flags)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	int ret;
62362306a36Sopenharmony_ci	int old_path_len = strlen(old_path);
62462306a36Sopenharmony_ci	int new_path_len = strlen(new_path);
62562306a36Sopenharmony_ci	int old_name_len = strlen(old_name);
62662306a36Sopenharmony_ci	int new_name_len = strlen(new_name);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	size_t send_len = sizeof(struct rename_request) + old_path_len + 1 +
62962306a36Sopenharmony_ci			  new_path_len + 1 + old_name_len + 1 + new_name_len +
63062306a36Sopenharmony_ci			  1;
63162306a36Sopenharmony_ci	struct rename_request *rename_req = kzalloc(send_len, GFP_KERNEL);
63262306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
63362306a36Sopenharmony_ci		.data = rename_req,
63462306a36Sopenharmony_ci		.len = send_len,
63562306a36Sopenharmony_ci		.out_buf = NULL,
63662306a36Sopenharmony_ci		.local_filp = NULL,
63762306a36Sopenharmony_ci	};
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_RENAME);
64062306a36Sopenharmony_ci	if (!rename_req)
64162306a36Sopenharmony_ci		return -ENOMEM;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	rename_req->old_path_len = cpu_to_le32(old_path_len);
64462306a36Sopenharmony_ci	rename_req->new_path_len = cpu_to_le32(new_path_len);
64562306a36Sopenharmony_ci	rename_req->old_name_len = cpu_to_le32(old_name_len);
64662306a36Sopenharmony_ci	rename_req->new_name_len = cpu_to_le32(new_name_len);
64762306a36Sopenharmony_ci	rename_req->flags = cpu_to_le32(flags);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	strncpy(rename_req->path, old_path, old_path_len);
65062306a36Sopenharmony_ci	strncpy(rename_req->path + old_path_len + 1, new_path, new_path_len);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	strncpy(rename_req->path + old_path_len + 1 + new_path_len + 1,
65362306a36Sopenharmony_ci		old_name, old_name_len);
65462306a36Sopenharmony_ci	strncpy(rename_req->path + old_path_len + 1 + new_path_len + 1 +
65562306a36Sopenharmony_ci			old_name_len + 1,
65662306a36Sopenharmony_ci		new_name, new_name_len);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
65962306a36Sopenharmony_ci	free_sm_outbuf(&sm);
66062306a36Sopenharmony_ci	kfree(rename_req);
66162306a36Sopenharmony_ci	return ret;
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ciint hmdfs_send_setattr(struct hmdfs_peer *con, const char *send_buf,
66562306a36Sopenharmony_ci		       struct setattr_info *attr_info)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	int ret;
66862306a36Sopenharmony_ci	int path_len = strlen(send_buf);
66962306a36Sopenharmony_ci	size_t send_len = path_len + 1 + sizeof(struct setattr_request);
67062306a36Sopenharmony_ci	struct setattr_request *setattr_req = kzalloc(send_len, GFP_KERNEL);
67162306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
67262306a36Sopenharmony_ci		.data = setattr_req,
67362306a36Sopenharmony_ci		.len = send_len,
67462306a36Sopenharmony_ci		.local_filp = NULL,
67562306a36Sopenharmony_ci	};
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_SETATTR);
67862306a36Sopenharmony_ci	if (!setattr_req)
67962306a36Sopenharmony_ci		return -ENOMEM;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	strcpy(setattr_req->buf, send_buf);
68262306a36Sopenharmony_ci	setattr_req->path_len = cpu_to_le32(path_len);
68362306a36Sopenharmony_ci	setattr_req->valid = cpu_to_le32(attr_info->valid);
68462306a36Sopenharmony_ci	setattr_req->size = cpu_to_le64(attr_info->size);
68562306a36Sopenharmony_ci	setattr_req->mtime = cpu_to_le64(attr_info->mtime);
68662306a36Sopenharmony_ci	setattr_req->mtime_nsec = cpu_to_le32(attr_info->mtime_nsec);
68762306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
68862306a36Sopenharmony_ci	kfree(setattr_req);
68962306a36Sopenharmony_ci	return ret;
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic void hmdfs_update_getattr_ret(struct getattr_response *resp,
69362306a36Sopenharmony_ci				     struct hmdfs_getattr_ret *result)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	struct kstat *stat = &result->stat;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	stat->result_mask = le32_to_cpu(resp->result_mask);
69862306a36Sopenharmony_ci	if (stat->result_mask == 0)
69962306a36Sopenharmony_ci		return;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	stat->ino = le64_to_cpu(resp->ino);
70262306a36Sopenharmony_ci	stat->mode = le16_to_cpu(resp->mode);
70362306a36Sopenharmony_ci	stat->nlink = le32_to_cpu(resp->nlink);
70462306a36Sopenharmony_ci	stat->uid.val = le32_to_cpu(resp->uid);
70562306a36Sopenharmony_ci	stat->gid.val = le32_to_cpu(resp->gid);
70662306a36Sopenharmony_ci	stat->size = le64_to_cpu(resp->size);
70762306a36Sopenharmony_ci	stat->blocks = le64_to_cpu(resp->blocks);
70862306a36Sopenharmony_ci	stat->blksize = le32_to_cpu(resp->blksize);
70962306a36Sopenharmony_ci	stat->atime.tv_sec = le64_to_cpu(resp->atime);
71062306a36Sopenharmony_ci	stat->atime.tv_nsec = le32_to_cpu(resp->atime_nsec);
71162306a36Sopenharmony_ci	stat->mtime.tv_sec = le64_to_cpu(resp->mtime);
71262306a36Sopenharmony_ci	stat->mtime.tv_nsec = le32_to_cpu(resp->mtime_nsec);
71362306a36Sopenharmony_ci	stat->ctime.tv_sec = le64_to_cpu(resp->ctime);
71462306a36Sopenharmony_ci	stat->ctime.tv_nsec = le32_to_cpu(resp->ctime_nsec);
71562306a36Sopenharmony_ci	stat->btime.tv_sec = le64_to_cpu(resp->crtime);
71662306a36Sopenharmony_ci	stat->btime.tv_nsec = le32_to_cpu(resp->crtime_nsec);
71762306a36Sopenharmony_ci	result->fsid = le64_to_cpu(resp->fsid);
71862306a36Sopenharmony_ci	/* currently not used */
71962306a36Sopenharmony_ci	result->i_flags = 0;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ciint hmdfs_send_getattr(struct hmdfs_peer *con, const char *send_buf,
72362306a36Sopenharmony_ci		       unsigned int lookup_flags,
72462306a36Sopenharmony_ci		       struct hmdfs_getattr_ret *result)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	int path_len = strlen(send_buf);
72762306a36Sopenharmony_ci	size_t send_len = path_len + 1 + sizeof(struct getattr_request);
72862306a36Sopenharmony_ci	int ret = 0;
72962306a36Sopenharmony_ci	struct getattr_request *req = kzalloc(send_len, GFP_KERNEL);
73062306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
73162306a36Sopenharmony_ci		.data = req,
73262306a36Sopenharmony_ci		.len = send_len,
73362306a36Sopenharmony_ci		.out_buf = NULL,
73462306a36Sopenharmony_ci		.local_filp = NULL,
73562306a36Sopenharmony_ci	};
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_GETATTR);
73862306a36Sopenharmony_ci	if (!req)
73962306a36Sopenharmony_ci		return -ENOMEM;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	req->path_len = cpu_to_le32(path_len);
74262306a36Sopenharmony_ci	req->lookup_flags = cpu_to_le32(lookup_flags);
74362306a36Sopenharmony_ci	strncpy(req->buf, send_buf, path_len);
74462306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
74562306a36Sopenharmony_ci	if (!ret && (sm.out_len == 0 || !sm.out_buf))
74662306a36Sopenharmony_ci		ret = -ENOENT;
74762306a36Sopenharmony_ci	if (ret)
74862306a36Sopenharmony_ci		goto out;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	hmdfs_update_getattr_ret(sm.out_buf, result);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ciout:
75362306a36Sopenharmony_ci	kfree(req);
75462306a36Sopenharmony_ci	free_sm_outbuf(&sm);
75562306a36Sopenharmony_ci	return ret;
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic void hmdfs_update_statfs_ret(struct statfs_response *resp,
75962306a36Sopenharmony_ci				    struct kstatfs *buf)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	buf->f_type = le64_to_cpu(resp->f_type);
76262306a36Sopenharmony_ci	buf->f_bsize = le64_to_cpu(resp->f_bsize);
76362306a36Sopenharmony_ci	buf->f_blocks = le64_to_cpu(resp->f_blocks);
76462306a36Sopenharmony_ci	buf->f_bfree = le64_to_cpu(resp->f_bfree);
76562306a36Sopenharmony_ci	buf->f_bavail = le64_to_cpu(resp->f_bavail);
76662306a36Sopenharmony_ci	buf->f_files = le64_to_cpu(resp->f_files);
76762306a36Sopenharmony_ci	buf->f_ffree = le64_to_cpu(resp->f_ffree);
76862306a36Sopenharmony_ci	buf->f_fsid.val[0] = le32_to_cpu(resp->f_fsid_0);
76962306a36Sopenharmony_ci	buf->f_fsid.val[1] = le32_to_cpu(resp->f_fsid_1);
77062306a36Sopenharmony_ci	buf->f_namelen = le64_to_cpu(resp->f_namelen);
77162306a36Sopenharmony_ci	buf->f_frsize = le64_to_cpu(resp->f_frsize);
77262306a36Sopenharmony_ci	buf->f_flags = le64_to_cpu(resp->f_flags);
77362306a36Sopenharmony_ci	buf->f_spare[0] = le64_to_cpu(resp->f_spare_0);
77462306a36Sopenharmony_ci	buf->f_spare[1] = le64_to_cpu(resp->f_spare_1);
77562306a36Sopenharmony_ci	buf->f_spare[2] = le64_to_cpu(resp->f_spare_2);
77662306a36Sopenharmony_ci	buf->f_spare[3] = le64_to_cpu(resp->f_spare_3);
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ciint hmdfs_send_statfs(struct hmdfs_peer *con, const char *path,
78062306a36Sopenharmony_ci		      struct kstatfs *buf)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	int ret;
78362306a36Sopenharmony_ci	int path_len = strlen(path);
78462306a36Sopenharmony_ci	size_t send_len = sizeof(struct statfs_request) + path_len + 1;
78562306a36Sopenharmony_ci	struct statfs_request *req = kzalloc(send_len, GFP_KERNEL);
78662306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
78762306a36Sopenharmony_ci		.data = req,
78862306a36Sopenharmony_ci		.len = send_len,
78962306a36Sopenharmony_ci		.out_buf = NULL,
79062306a36Sopenharmony_ci		.local_filp = NULL,
79162306a36Sopenharmony_ci	};
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_STATFS);
79462306a36Sopenharmony_ci	if (!req)
79562306a36Sopenharmony_ci		return -ENOMEM;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	req->path_len = cpu_to_le32(path_len);
79862306a36Sopenharmony_ci	strncpy(req->path, path, path_len);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	if (ret == -ETIME)
80362306a36Sopenharmony_ci		ret = -EIO;
80462306a36Sopenharmony_ci	if (!ret && (sm.out_len == 0 || !sm.out_buf))
80562306a36Sopenharmony_ci		ret = -ENOENT;
80662306a36Sopenharmony_ci	if (ret)
80762306a36Sopenharmony_ci		goto out;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	hmdfs_update_statfs_ret(sm.out_buf, buf);
81062306a36Sopenharmony_ciout:
81162306a36Sopenharmony_ci	kfree(req);
81262306a36Sopenharmony_ci	free_sm_outbuf(&sm);
81362306a36Sopenharmony_ci	return ret;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ciint hmdfs_send_syncfs(struct hmdfs_peer *con, int syncfs_timeout)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	int ret;
81962306a36Sopenharmony_ci	struct hmdfs_req req;
82062306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = con->sbi;
82162306a36Sopenharmony_ci	struct syncfs_request *syncfs_req =
82262306a36Sopenharmony_ci		kzalloc(sizeof(struct syncfs_request), GFP_KERNEL);
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	if (!syncfs_req) {
82562306a36Sopenharmony_ci		hmdfs_err("cannot allocate syncfs_request");
82662306a36Sopenharmony_ci		return -ENOMEM;
82762306a36Sopenharmony_ci	}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	hmdfs_init_cmd(&req.operations, F_SYNCFS);
83062306a36Sopenharmony_ci	req.timeout = syncfs_timeout;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	syncfs_req->version = cpu_to_le64(sbi->hsi.version);
83362306a36Sopenharmony_ci	req.data = syncfs_req;
83462306a36Sopenharmony_ci	req.data_len = sizeof(*syncfs_req);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	ret = hmdfs_send_async_request(con, &req);
83762306a36Sopenharmony_ci	if (ret) {
83862306a36Sopenharmony_ci		kfree(syncfs_req);
83962306a36Sopenharmony_ci		hmdfs_err("ret fail with %d", ret);
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	return ret;
84362306a36Sopenharmony_ci}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic void hmdfs_update_getxattr_ret(struct getxattr_response *resp,
84662306a36Sopenharmony_ci				     void *value, size_t o_size, int *ret)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	ssize_t size = le32_to_cpu(resp->size);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	if (o_size && o_size < size) {
85162306a36Sopenharmony_ci		*ret = -ERANGE;
85262306a36Sopenharmony_ci		return;
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	if (o_size)
85662306a36Sopenharmony_ci		memcpy(value, resp->value, size);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	*ret = size;
85962306a36Sopenharmony_ci}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ciint hmdfs_send_getxattr(struct hmdfs_peer *con, const char *send_buf,
86262306a36Sopenharmony_ci			const char *name, void *value, size_t size)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	size_t path_len = strlen(send_buf);
86562306a36Sopenharmony_ci	size_t name_len = strlen(name);
86662306a36Sopenharmony_ci	size_t send_len = path_len + name_len +
86762306a36Sopenharmony_ci			  sizeof(struct getxattr_request) + 2;
86862306a36Sopenharmony_ci	int ret = 0;
86962306a36Sopenharmony_ci	struct getxattr_request *req = kzalloc(send_len, GFP_KERNEL);
87062306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
87162306a36Sopenharmony_ci		.data = req,
87262306a36Sopenharmony_ci		.len = send_len,
87362306a36Sopenharmony_ci		.out_buf = NULL,
87462306a36Sopenharmony_ci		.local_filp = NULL,
87562306a36Sopenharmony_ci	};
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_GETXATTR);
87862306a36Sopenharmony_ci	if (!req)
87962306a36Sopenharmony_ci		return -ENOMEM;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	req->path_len = cpu_to_le32(path_len);
88262306a36Sopenharmony_ci	req->name_len = cpu_to_le32(name_len);
88362306a36Sopenharmony_ci	req->size = cpu_to_le32(size);
88462306a36Sopenharmony_ci	strncpy(req->buf, send_buf, path_len);
88562306a36Sopenharmony_ci	strncpy(req->buf + path_len + 1, name, name_len);
88662306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
88762306a36Sopenharmony_ci	if (!ret && (sm.out_len == 0 || !sm.out_buf))
88862306a36Sopenharmony_ci		ret = -ENOENT;
88962306a36Sopenharmony_ci	if (ret)
89062306a36Sopenharmony_ci		goto out;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	hmdfs_update_getxattr_ret(sm.out_buf, value, size, &ret);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ciout:
89562306a36Sopenharmony_ci	kfree(req);
89662306a36Sopenharmony_ci	free_sm_outbuf(&sm);
89762306a36Sopenharmony_ci	return ret;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ciint hmdfs_send_setxattr(struct hmdfs_peer *con, const char *send_buf,
90162306a36Sopenharmony_ci			const char *name, const void *value,
90262306a36Sopenharmony_ci			size_t size, int flags)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	size_t path_len = strlen(send_buf);
90562306a36Sopenharmony_ci	size_t name_len = strlen(name);
90662306a36Sopenharmony_ci	size_t send_len = path_len + name_len + size + 2 +
90762306a36Sopenharmony_ci			  sizeof(struct setxattr_request);
90862306a36Sopenharmony_ci	int ret = 0;
90962306a36Sopenharmony_ci	struct setxattr_request *req = kzalloc(send_len, GFP_KERNEL);
91062306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
91162306a36Sopenharmony_ci		.data = req,
91262306a36Sopenharmony_ci		.len = send_len,
91362306a36Sopenharmony_ci		.local_filp = NULL,
91462306a36Sopenharmony_ci	};
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_SETXATTR);
91762306a36Sopenharmony_ci	if (!req)
91862306a36Sopenharmony_ci		return -ENOMEM;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	req->path_len = cpu_to_le32(path_len);
92162306a36Sopenharmony_ci	req->name_len = cpu_to_le32(name_len);
92262306a36Sopenharmony_ci	req->size = cpu_to_le32(size);
92362306a36Sopenharmony_ci	req->flags = cpu_to_le32(flags);
92462306a36Sopenharmony_ci	strncpy(req->buf, send_buf, path_len);
92562306a36Sopenharmony_ci	strncpy(req->buf + path_len + 1, name, name_len);
92662306a36Sopenharmony_ci	if (!value)
92762306a36Sopenharmony_ci		req->del = true;
92862306a36Sopenharmony_ci	else
92962306a36Sopenharmony_ci		memcpy(req->buf + path_len + name_len + 2, value, size);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
93262306a36Sopenharmony_ci	kfree(req);
93362306a36Sopenharmony_ci	return ret;
93462306a36Sopenharmony_ci}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_cistatic void hmdfs_update_listxattr_ret(struct listxattr_response *resp,
93762306a36Sopenharmony_ci				       char *list, size_t o_size, ssize_t *ret)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	ssize_t size = le32_to_cpu(resp->size);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (o_size && o_size < size) {
94262306a36Sopenharmony_ci		*ret = -ERANGE;
94362306a36Sopenharmony_ci		return;
94462306a36Sopenharmony_ci	}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	/* multi name split with '\0', use memcpy */
94762306a36Sopenharmony_ci	if (o_size)
94862306a36Sopenharmony_ci		memcpy(list, resp->list, size);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	*ret = size;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_cissize_t hmdfs_send_listxattr(struct hmdfs_peer *con, const char *send_buf,
95462306a36Sopenharmony_ci			     char *list, size_t size)
95562306a36Sopenharmony_ci{
95662306a36Sopenharmony_ci	size_t path_len = strlen(send_buf);
95762306a36Sopenharmony_ci	size_t send_len = path_len + 1 + sizeof(struct listxattr_request);
95862306a36Sopenharmony_ci	ssize_t ret = 0;
95962306a36Sopenharmony_ci	struct listxattr_request *req = kzalloc(send_len, GFP_KERNEL);
96062306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
96162306a36Sopenharmony_ci		.data = req,
96262306a36Sopenharmony_ci		.len = send_len,
96362306a36Sopenharmony_ci		.out_buf = NULL,
96462306a36Sopenharmony_ci		.local_filp = NULL,
96562306a36Sopenharmony_ci	};
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_LISTXATTR);
96862306a36Sopenharmony_ci	if (!req)
96962306a36Sopenharmony_ci		return -ENOMEM;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	req->path_len = cpu_to_le32(path_len);
97262306a36Sopenharmony_ci	req->size = cpu_to_le32(size);
97362306a36Sopenharmony_ci	strncpy(req->buf, send_buf, path_len);
97462306a36Sopenharmony_ci	ret = hmdfs_sendmessage_request(con, &sm);
97562306a36Sopenharmony_ci	if (!ret && (sm.out_len == 0 || !sm.out_buf))
97662306a36Sopenharmony_ci		ret = -ENOENT;
97762306a36Sopenharmony_ci	if (ret)
97862306a36Sopenharmony_ci		goto out;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	hmdfs_update_listxattr_ret(sm.out_buf, list, size, &ret);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ciout:
98362306a36Sopenharmony_ci	kfree(req);
98462306a36Sopenharmony_ci	free_sm_outbuf(&sm);
98562306a36Sopenharmony_ci	return ret;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_civoid hmdfs_recv_syncfs_cb(struct hmdfs_peer *peer, const struct hmdfs_req *req,
98962306a36Sopenharmony_ci			  const struct hmdfs_resp *resp)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = peer->sbi;
99262306a36Sopenharmony_ci	struct syncfs_request *syncfs_req = (struct syncfs_request *)req->data;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	WARN_ON(!syncfs_req);
99562306a36Sopenharmony_ci	spin_lock(&sbi->hsi.v_lock);
99662306a36Sopenharmony_ci	if (le64_to_cpu(syncfs_req->version) != sbi->hsi.version) {
99762306a36Sopenharmony_ci		hmdfs_info(
99862306a36Sopenharmony_ci			"Recv stale syncfs resp[ver: %llu] from device %llu, current ver %llu",
99962306a36Sopenharmony_ci			le64_to_cpu(syncfs_req->version), peer->device_id,
100062306a36Sopenharmony_ci			sbi->hsi.version);
100162306a36Sopenharmony_ci		spin_unlock(&sbi->hsi.v_lock);
100262306a36Sopenharmony_ci		goto out;
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	if (!sbi->hsi.remote_ret)
100662306a36Sopenharmony_ci		sbi->hsi.remote_ret = resp->ret_code;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (resp->ret_code) {
100962306a36Sopenharmony_ci		hmdfs_err("Recv syncfs error code %d from device %llu",
101062306a36Sopenharmony_ci			  resp->ret_code, peer->device_id);
101162306a36Sopenharmony_ci	} else {
101262306a36Sopenharmony_ci		/*
101362306a36Sopenharmony_ci		 * Set @sb_dirty_count to zero if no one else produce
101462306a36Sopenharmony_ci		 * dirty data on remote server during remote sync.
101562306a36Sopenharmony_ci		 */
101662306a36Sopenharmony_ci		atomic64_cmpxchg(&peer->sb_dirty_count,
101762306a36Sopenharmony_ci				 peer->old_sb_dirty_count, 0);
101862306a36Sopenharmony_ci	}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	atomic_dec(&sbi->hsi.wait_count);
102162306a36Sopenharmony_ci	spin_unlock(&sbi->hsi.v_lock);
102262306a36Sopenharmony_ci	wake_up_interruptible(&sbi->hsi.wq);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ciout:
102562306a36Sopenharmony_ci	kfree(syncfs_req);
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_civoid hmdfs_send_drop_push(struct hmdfs_peer *con, const char *path)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci	int path_len = strlen(path);
103162306a36Sopenharmony_ci	size_t send_len = sizeof(struct drop_push_request) + path_len + 1;
103262306a36Sopenharmony_ci	struct drop_push_request *dp_req = kzalloc(send_len, GFP_KERNEL);
103362306a36Sopenharmony_ci	struct hmdfs_send_command sm = {
103462306a36Sopenharmony_ci		.data = dp_req,
103562306a36Sopenharmony_ci		.len = send_len,
103662306a36Sopenharmony_ci		.local_filp = NULL,
103762306a36Sopenharmony_ci	};
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	hmdfs_init_cmd(&sm.operations, F_DROP_PUSH);
104062306a36Sopenharmony_ci	if (!dp_req)
104162306a36Sopenharmony_ci		return;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	dp_req->path_len = cpu_to_le32(path_len);
104462306a36Sopenharmony_ci	strncpy(dp_req->path, path, path_len);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	hmdfs_sendmessage_request(con, &sm);
104762306a36Sopenharmony_ci	kfree(dp_req);
104862306a36Sopenharmony_ci}
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_cistatic void *hmdfs_get_msg_next(struct hmdfs_peer *peer, int *id)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	struct hmdfs_msg_idr_head *head = NULL;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	spin_lock(&peer->idr_lock);
105562306a36Sopenharmony_ci	head = idr_get_next(&peer->msg_idr, id);
105662306a36Sopenharmony_ci	if (head && head->type < MSG_IDR_MAX && head->type >= 0)
105762306a36Sopenharmony_ci		kref_get(&head->ref);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	spin_unlock(&peer->idr_lock);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	return head;
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_civoid hmdfs_client_offline_notify(struct hmdfs_peer *conn, int evt,
106562306a36Sopenharmony_ci				 unsigned int seq)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	int id;
106862306a36Sopenharmony_ci	int count = 0;
106962306a36Sopenharmony_ci	struct hmdfs_msg_idr_head *head = NULL;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	for (id = 0; (head = hmdfs_get_msg_next(conn, &id)) != NULL; ++id) {
107262306a36Sopenharmony_ci		switch (head->type) {
107362306a36Sopenharmony_ci		case MSG_IDR_1_0_NONE:
107462306a36Sopenharmony_ci			head_put(head);
107562306a36Sopenharmony_ci			head_put(head);
107662306a36Sopenharmony_ci			break;
107762306a36Sopenharmony_ci		case MSG_IDR_MESSAGE_SYNC:
107862306a36Sopenharmony_ci		case MSG_IDR_1_0_MESSAGE_SYNC:
107962306a36Sopenharmony_ci			hmdfs_response_wakeup((struct sendmsg_wait_queue *)head,
108062306a36Sopenharmony_ci					      -ETIME, 0, NULL);
108162306a36Sopenharmony_ci			hmdfs_debug("wakeup id=%d", head->msg_id);
108262306a36Sopenharmony_ci			msg_put((struct sendmsg_wait_queue *)head);
108362306a36Sopenharmony_ci			break;
108462306a36Sopenharmony_ci		case MSG_IDR_MESSAGE_ASYNC:
108562306a36Sopenharmony_ci			hmdfs_wakeup_parasite(
108662306a36Sopenharmony_ci				(struct hmdfs_msg_parasite *)head);
108762306a36Sopenharmony_ci			hmdfs_debug("wakeup parasite id=%d", head->msg_id);
108862306a36Sopenharmony_ci			mp_put((struct hmdfs_msg_parasite *)head);
108962306a36Sopenharmony_ci			break;
109062306a36Sopenharmony_ci		case MSG_IDR_PAGE:
109162306a36Sopenharmony_ci		case MSG_IDR_1_0_PAGE:
109262306a36Sopenharmony_ci			hmdfs_wakeup_async_work(
109362306a36Sopenharmony_ci				(struct hmdfs_async_work *)head);
109462306a36Sopenharmony_ci			hmdfs_debug("wakeup async work id=%d", head->msg_id);
109562306a36Sopenharmony_ci			asw_put((struct hmdfs_async_work *)head);
109662306a36Sopenharmony_ci			break;
109762306a36Sopenharmony_ci		default:
109862306a36Sopenharmony_ci			hmdfs_err("Bad type=%d id=%d", head->type,
109962306a36Sopenharmony_ci				  head->msg_id);
110062306a36Sopenharmony_ci			break;
110162306a36Sopenharmony_ci		}
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci		count++;
110462306a36Sopenharmony_ci		/* If there are too many idr to process, avoid to soft lockup,
110562306a36Sopenharmony_ci		 * process every 512 message we resched
110662306a36Sopenharmony_ci		 */
110762306a36Sopenharmony_ci		if (count % HMDFS_IDR_RESCHED_COUNT == 0)
110862306a36Sopenharmony_ci			cond_resched();
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_cistatic struct hmdfs_node_cb_desc client_cb[] = {
111362306a36Sopenharmony_ci	{
111462306a36Sopenharmony_ci		.evt = NODE_EVT_OFFLINE,
111562306a36Sopenharmony_ci		.sync = true,
111662306a36Sopenharmony_ci		.fn = hmdfs_client_offline_notify,
111762306a36Sopenharmony_ci	},
111862306a36Sopenharmony_ci};
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_civoid __init hmdfs_client_add_node_evt_cb(void)
112162306a36Sopenharmony_ci{
112262306a36Sopenharmony_ci	hmdfs_node_add_evt_cb(client_cb, ARRAY_SIZE(client_cb));
112362306a36Sopenharmony_ci}
1124