18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * fs/hmdfs/file_remote.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/backing-dev.h>
98c2ecf20Sopenharmony_ci#include <linux/file.h>
108c2ecf20Sopenharmony_ci#include <linux/fs.h>
118c2ecf20Sopenharmony_ci#include <linux/namei.h>
128c2ecf20Sopenharmony_ci#include <linux/page-flags.h>
138c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
148c2ecf20Sopenharmony_ci#include <linux/pagevec.h>
158c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <linux/wait.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "file_remote.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "comm/socket_adapter.h"
228c2ecf20Sopenharmony_ci#include "hmdfs.h"
238c2ecf20Sopenharmony_ci#include "hmdfs_client.h"
248c2ecf20Sopenharmony_ci#include "hmdfs_dentryfile.h"
258c2ecf20Sopenharmony_ci#include "hmdfs_trace.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic inline bool hmdfs_remote_write_cache_expired(
288c2ecf20Sopenharmony_ci		struct hmdfs_inode_info *info)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	return time_after(jiffies, info->writecache_expire);
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cienum expire_reason {
348c2ecf20Sopenharmony_ci	ALL_GOOD = 0,
358c2ecf20Sopenharmony_ci	INO_DISMATCH = 1,
368c2ecf20Sopenharmony_ci	SIZE_OR_CTIME_DISMATCH = 2,
378c2ecf20Sopenharmony_ci	TIMER_EXPIRE = 3,
388c2ecf20Sopenharmony_ci	TIMER_WORKING = 4,
398c2ecf20Sopenharmony_ci	STABLE_CTIME_DISMATCH = 5,
408c2ecf20Sopenharmony_ci	KEEP_CACHE = 6,
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci * hmdfs_open_final_remote - Do final steps of opening a remote file, update
458c2ecf20Sopenharmony_ci * local inode cache and decide whether of not to truncate inode pages.
468c2ecf20Sopenharmony_ci *
478c2ecf20Sopenharmony_ci * @info: hmdfs inode info
488c2ecf20Sopenharmony_ci * @open_ret: values returned from remote when opening a remote file
498c2ecf20Sopenharmony_ci * @keep_cache: keep local cache & i_size
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_cistatic int hmdfs_open_final_remote(struct hmdfs_inode_info *info,
528c2ecf20Sopenharmony_ci				   struct hmdfs_open_ret *open_ret,
538c2ecf20Sopenharmony_ci				   struct file *file, bool keep_cache)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	struct inode *inode = &info->vfs_inode;
568c2ecf20Sopenharmony_ci	bool truncate = false;
578c2ecf20Sopenharmony_ci	enum expire_reason reason = ALL_GOOD;
588c2ecf20Sopenharmony_ci	int ret = 0;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	/*
618c2ecf20Sopenharmony_ci	 * if remote inode number changed and lookup stale data, we'll return
628c2ecf20Sopenharmony_ci	 * -ESTALE, and reopen the file with metedate from remote getattr.
638c2ecf20Sopenharmony_ci	 */
648c2ecf20Sopenharmony_ci	if (info->remote_ino != open_ret->ino) {
658c2ecf20Sopenharmony_ci		hmdfs_debug(
668c2ecf20Sopenharmony_ci			"got stale local inode, ino in local %llu, ino from open %llu",
678c2ecf20Sopenharmony_ci			info->remote_ino, open_ret->ino);
688c2ecf20Sopenharmony_ci		hmdfs_send_close(info->conn, &open_ret->fid);
698c2ecf20Sopenharmony_ci		reason = INO_DISMATCH;
708c2ecf20Sopenharmony_ci		ret = -ESTALE;
718c2ecf20Sopenharmony_ci		goto out;
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (keep_cache) {
758c2ecf20Sopenharmony_ci		reason = KEEP_CACHE;
768c2ecf20Sopenharmony_ci		trace_hmdfs_open_final_remote(info, open_ret, file, reason);
778c2ecf20Sopenharmony_ci		goto set_fid_out;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/*
818c2ecf20Sopenharmony_ci	 * if remote size do not match local inode, or remote ctime do not match
828c2ecf20Sopenharmony_ci	 * the last time same file was opened.
838c2ecf20Sopenharmony_ci	 */
848c2ecf20Sopenharmony_ci	if (inode->i_size != open_ret->file_size ||
858c2ecf20Sopenharmony_ci	    hmdfs_time_compare(&info->remote_ctime, &open_ret->remote_ctime)) {
868c2ecf20Sopenharmony_ci		truncate = true;
878c2ecf20Sopenharmony_ci		reason = SIZE_OR_CTIME_DISMATCH;
888c2ecf20Sopenharmony_ci		goto out;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/*
928c2ecf20Sopenharmony_ci	 * If 'writecache_expire' is set, check if it expires. And skip the
938c2ecf20Sopenharmony_ci	 * checking of stable_ctime.
948c2ecf20Sopenharmony_ci	 */
958c2ecf20Sopenharmony_ci	if (info->writecache_expire) {
968c2ecf20Sopenharmony_ci		truncate = hmdfs_remote_write_cache_expired(info);
978c2ecf20Sopenharmony_ci		if (truncate)
988c2ecf20Sopenharmony_ci			reason = TIMER_EXPIRE;
998c2ecf20Sopenharmony_ci		else
1008c2ecf20Sopenharmony_ci			reason = TIMER_WORKING;
1018c2ecf20Sopenharmony_ci		goto out;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	/* the first time, or remote ctime is ahead of remote time */
1058c2ecf20Sopenharmony_ci	if (info->stable_ctime.tv_sec == 0 && info->stable_ctime.tv_nsec == 0) {
1068c2ecf20Sopenharmony_ci		truncate = true;
1078c2ecf20Sopenharmony_ci		reason = STABLE_CTIME_DISMATCH;
1088c2ecf20Sopenharmony_ci		goto out;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/*
1128c2ecf20Sopenharmony_ci	 * - if last stable_ctime == stable_ctime, we do nothing.
1138c2ecf20Sopenharmony_ci	 *   a. if ctime < stable_ctime, data is ensured to be uptodate,
1148c2ecf20Sopenharmony_ci	 *   b. if ctime == stable_ctime, stale data might be accessed. This is
1158c2ecf20Sopenharmony_ci	 *      acceptable since pagecache will be dropped later.
1168c2ecf20Sopenharmony_ci	 *   c. ctime > stable_ctime is impossible.
1178c2ecf20Sopenharmony_ci	 * - if last stable_ctime < stable_ctime, we clear the cache.
1188c2ecf20Sopenharmony_ci	 *   d. ctime != last stable_ctime is impossible
1198c2ecf20Sopenharmony_ci	 *   e. ctime == last stable_ctime, this is possible to read again from
1208c2ecf20Sopenharmony_ci	 *      b, thus we need to drop the cache.
1218c2ecf20Sopenharmony_ci	 * - if last stable_ctime > stable_ctime, we clear the cache.
1228c2ecf20Sopenharmony_ci	 *   stable_ctime must be zero in this case, this is possible because
1238c2ecf20Sopenharmony_ci	 *   system time might be changed.
1248c2ecf20Sopenharmony_ci	 */
1258c2ecf20Sopenharmony_ci	if (hmdfs_time_compare(&info->stable_ctime, &open_ret->stable_ctime)) {
1268c2ecf20Sopenharmony_ci		truncate = true;
1278c2ecf20Sopenharmony_ci		reason = STABLE_CTIME_DISMATCH;
1288c2ecf20Sopenharmony_ci		goto out;
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ciout:
1328c2ecf20Sopenharmony_ci	trace_hmdfs_open_final_remote(info, open_ret, file, reason);
1338c2ecf20Sopenharmony_ci	if (ret)
1348c2ecf20Sopenharmony_ci		return ret;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (reason == SIZE_OR_CTIME_DISMATCH) {
1378c2ecf20Sopenharmony_ci		inode->i_ctime = open_ret->remote_ctime;
1388c2ecf20Sopenharmony_ci		info->remote_ctime = open_ret->remote_ctime;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (truncate) {
1428c2ecf20Sopenharmony_ci		info->writecache_expire = 0;
1438c2ecf20Sopenharmony_ci		truncate_inode_pages(inode->i_mapping, 0);
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	atomic64_set(&info->write_counter, 0);
1478c2ecf20Sopenharmony_ci	info->stable_ctime = open_ret->stable_ctime;
1488c2ecf20Sopenharmony_ci	i_size_write(inode, open_ret->file_size);
1498c2ecf20Sopenharmony_ci	info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE;
1508c2ecf20Sopenharmony_ciset_fid_out:
1518c2ecf20Sopenharmony_ci	spin_lock(&info->fid_lock);
1528c2ecf20Sopenharmony_ci	info->fid = open_ret->fid;
1538c2ecf20Sopenharmony_ci	spin_unlock(&info->fid_lock);
1548c2ecf20Sopenharmony_ci	return 0;
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ciint hmdfs_do_open_remote(struct file *file, bool keep_cache)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(file_inode(file));
1608c2ecf20Sopenharmony_ci	struct hmdfs_peer *conn = info->conn;
1618c2ecf20Sopenharmony_ci	struct hmdfs_open_ret open_ret;
1628c2ecf20Sopenharmony_ci	__u8 file_type = hmdfs_d(file->f_path.dentry)->file_type;
1638c2ecf20Sopenharmony_ci	char *send_buf;
1648c2ecf20Sopenharmony_ci	int err = 0;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	send_buf = hmdfs_get_dentry_relative_path(file->f_path.dentry);
1678c2ecf20Sopenharmony_ci	if (!send_buf) {
1688c2ecf20Sopenharmony_ci		err = -ENOMEM;
1698c2ecf20Sopenharmony_ci		goto out_free;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci	err = hmdfs_send_open(conn, send_buf, file_type, &open_ret);
1728c2ecf20Sopenharmony_ci	if (err) {
1738c2ecf20Sopenharmony_ci		hmdfs_err("hmdfs_send_open return failed with %d", err);
1748c2ecf20Sopenharmony_ci		goto out_free;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	err = hmdfs_open_final_remote(info, &open_ret, file, keep_cache);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ciout_free:
1808c2ecf20Sopenharmony_ci	kfree(send_buf);
1818c2ecf20Sopenharmony_ci	return err;
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic inline bool hmdfs_remote_need_reopen(struct hmdfs_inode_info *info)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	return test_bit(HMDFS_FID_NEED_OPEN, &info->fid_flags);
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic inline bool hmdfs_remote_is_opening_file(struct hmdfs_inode_info *info)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	return test_bit(HMDFS_FID_OPENING, &info->fid_flags);
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int hmdfs_remote_wait_opening_file(struct hmdfs_inode_info *info)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	int err;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (!hmdfs_remote_is_opening_file(info))
1998c2ecf20Sopenharmony_ci		return 0;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	err = ___wait_event(info->fid_wq, hmdfs_remote_is_opening_file(info),
2028c2ecf20Sopenharmony_ci			    TASK_INTERRUPTIBLE, 0, 0,
2038c2ecf20Sopenharmony_ci			    spin_unlock(&info->fid_lock);
2048c2ecf20Sopenharmony_ci			    schedule();
2058c2ecf20Sopenharmony_ci			    spin_lock(&info->fid_lock));
2068c2ecf20Sopenharmony_ci	if (err)
2078c2ecf20Sopenharmony_ci		err = -EINTR;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	return err;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic int hmdfs_remote_file_reopen(struct hmdfs_inode_info *info,
2138c2ecf20Sopenharmony_ci				    struct file *filp)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	int err = 0;
2168c2ecf20Sopenharmony_ci	struct hmdfs_peer *conn = info->conn;
2178c2ecf20Sopenharmony_ci	struct inode *inode = NULL;
2188c2ecf20Sopenharmony_ci	struct hmdfs_fid fid;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (conn->status == NODE_STAT_OFFLINE)
2218c2ecf20Sopenharmony_ci		return -EAGAIN;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	spin_lock(&info->fid_lock);
2248c2ecf20Sopenharmony_ci	err = hmdfs_remote_wait_opening_file(info);
2258c2ecf20Sopenharmony_ci	if (err || !hmdfs_remote_need_reopen(info)) {
2268c2ecf20Sopenharmony_ci		spin_unlock(&info->fid_lock);
2278c2ecf20Sopenharmony_ci		goto out;
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	set_bit(HMDFS_FID_OPENING, &info->fid_flags);
2318c2ecf20Sopenharmony_ci	fid = info->fid;
2328c2ecf20Sopenharmony_ci	spin_unlock(&info->fid_lock);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	inode = &info->vfs_inode;
2358c2ecf20Sopenharmony_ci	inode_lock(inode);
2368c2ecf20Sopenharmony_ci	/*
2378c2ecf20Sopenharmony_ci	 * Most closing cases are meaningless, except for one:
2388c2ecf20Sopenharmony_ci	 *        read process A         read process B
2398c2ecf20Sopenharmony_ci	 *    err = -EBADF              err = -EBADF       (caused by re-online)
2408c2ecf20Sopenharmony_ci	 *    set_need_reopen
2418c2ecf20Sopenharmony_ci	 *    do reopen
2428c2ecf20Sopenharmony_ci	 *    fid = new fid_1 [server hold fid_1]
2438c2ecf20Sopenharmony_ci	 *                              set need_reopen
2448c2ecf20Sopenharmony_ci	 *                              do reopen
2458c2ecf20Sopenharmony_ci	 *                                send close (fid_1) // In case of leak
2468c2ecf20Sopenharmony_ci	 *                              fid = new fid_2
2478c2ecf20Sopenharmony_ci	 */
2488c2ecf20Sopenharmony_ci	if (fid.id != HMDFS_INODE_INVALID_FILE_ID)
2498c2ecf20Sopenharmony_ci		hmdfs_send_close(conn, &fid);
2508c2ecf20Sopenharmony_ci	err = hmdfs_do_open_remote(filp, true);
2518c2ecf20Sopenharmony_ci	inode_unlock(inode);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	spin_lock(&info->fid_lock);
2548c2ecf20Sopenharmony_ci	/*
2558c2ecf20Sopenharmony_ci	 * May make the bit set in offline handler lost, but server
2568c2ecf20Sopenharmony_ci	 * will tell us whether or not the newly-opened file id is
2578c2ecf20Sopenharmony_ci	 * generated before offline, if it is opened before offline,
2588c2ecf20Sopenharmony_ci	 * the operation on the file id will return -EBADF and
2598c2ecf20Sopenharmony_ci	 * HMDFS_FID_NEED_OPEN bit will be set again.
2608c2ecf20Sopenharmony_ci	 */
2618c2ecf20Sopenharmony_ci	if (!err)
2628c2ecf20Sopenharmony_ci		clear_bit(HMDFS_FID_NEED_OPEN, &info->fid_flags);
2638c2ecf20Sopenharmony_ci	clear_bit(HMDFS_FID_OPENING, &info->fid_flags);
2648c2ecf20Sopenharmony_ci	spin_unlock(&info->fid_lock);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	wake_up_interruptible_all(&info->fid_wq);
2678c2ecf20Sopenharmony_ciout:
2688c2ecf20Sopenharmony_ci	return err;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic int hmdfs_remote_check_and_reopen(struct hmdfs_inode_info *info,
2728c2ecf20Sopenharmony_ci					 struct file *filp)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	if (!hmdfs_remote_need_reopen(info))
2758c2ecf20Sopenharmony_ci		return 0;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	return hmdfs_remote_file_reopen(info, filp);
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_civoid hmdfs_do_close_remote(struct kref *kref)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	struct hmdfs_inode_info *info =
2838c2ecf20Sopenharmony_ci		container_of(kref, struct hmdfs_inode_info, ref);
2848c2ecf20Sopenharmony_ci	struct hmdfs_fid fid;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	hmdfs_remote_fetch_fid(info, &fid);
2878c2ecf20Sopenharmony_ci	/* This function can return asynchronously */
2888c2ecf20Sopenharmony_ci	hmdfs_send_close(info->conn, &fid);
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic inline bool hmdfs_remote_need_track_file(const struct hmdfs_sb_info *sbi,
2928c2ecf20Sopenharmony_ci						fmode_t mode)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	return (hmdfs_is_stash_enabled(sbi) && (mode & FMODE_WRITE));
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic void
2988c2ecf20Sopenharmony_cihmdfs_remote_del_wr_opened_inode_nolock(struct hmdfs_inode_info *info)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	WARN_ON(list_empty(&info->wr_opened_node));
3018c2ecf20Sopenharmony_ci	if (atomic_dec_and_test(&info->wr_opened_cnt))
3028c2ecf20Sopenharmony_ci		list_del_init(&info->wr_opened_node);
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_civoid hmdfs_remote_del_wr_opened_inode(struct hmdfs_peer *conn,
3068c2ecf20Sopenharmony_ci				      struct hmdfs_inode_info *info)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	spin_lock(&conn->wr_opened_inode_lock);
3098c2ecf20Sopenharmony_ci	hmdfs_remote_del_wr_opened_inode_nolock(info);
3108c2ecf20Sopenharmony_ci	spin_unlock(&conn->wr_opened_inode_lock);
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_civoid hmdfs_remote_add_wr_opened_inode_nolock(struct hmdfs_peer *conn,
3148c2ecf20Sopenharmony_ci					     struct hmdfs_inode_info *info)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	if (list_empty(&info->wr_opened_node)) {
3178c2ecf20Sopenharmony_ci		atomic_set(&info->wr_opened_cnt, 1);
3188c2ecf20Sopenharmony_ci		list_add_tail(&info->wr_opened_node,
3198c2ecf20Sopenharmony_ci			      &conn->wr_opened_inode_list);
3208c2ecf20Sopenharmony_ci	} else {
3218c2ecf20Sopenharmony_ci		atomic_inc(&info->wr_opened_cnt);
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic void hmdfs_remote_add_wr_opened_inode(struct hmdfs_peer *conn,
3268c2ecf20Sopenharmony_ci					     struct hmdfs_inode_info *info)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	spin_lock(&conn->wr_opened_inode_lock);
3298c2ecf20Sopenharmony_ci	hmdfs_remote_add_wr_opened_inode_nolock(conn, info);
3308c2ecf20Sopenharmony_ci	spin_unlock(&conn->wr_opened_inode_lock);
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ciint hmdfs_file_open_remote(struct inode *inode, struct file *file)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
3368c2ecf20Sopenharmony_ci	struct kref *ref = &(info->ref);
3378c2ecf20Sopenharmony_ci	int err = 0;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	inode_lock(inode);
3408c2ecf20Sopenharmony_ci	if (kref_read(ref) == 0) {
3418c2ecf20Sopenharmony_ci		err = hmdfs_do_open_remote(file, false);
3428c2ecf20Sopenharmony_ci		if (err == 0)
3438c2ecf20Sopenharmony_ci			kref_init(ref);
3448c2ecf20Sopenharmony_ci	} else {
3458c2ecf20Sopenharmony_ci		kref_get(ref);
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci	inode_unlock(inode);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (!err && hmdfs_remote_need_track_file(hmdfs_sb(inode->i_sb),
3508c2ecf20Sopenharmony_ci						 file->f_mode))
3518c2ecf20Sopenharmony_ci		hmdfs_remote_add_wr_opened_inode(info->conn, info);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	return err;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic void hmdfs_set_writecache_expire(struct hmdfs_inode_info *info,
3578c2ecf20Sopenharmony_ci					unsigned int seconds)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	unsigned long new_expire = jiffies + (unsigned long)seconds * HZ;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	/*
3628c2ecf20Sopenharmony_ci	 * When file has been written before closing, set pagecache expire
3638c2ecf20Sopenharmony_ci	 * if it has not been set yet. This is necessary because ctime might
3648c2ecf20Sopenharmony_ci	 * stay the same after overwrite.
3658c2ecf20Sopenharmony_ci	 */
3668c2ecf20Sopenharmony_ci	if (info->writecache_expire &&
3678c2ecf20Sopenharmony_ci	    time_after(new_expire, info->writecache_expire))
3688c2ecf20Sopenharmony_ci		return;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	info->writecache_expire = new_expire;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic void hmdfs_remote_keep_writecache(struct inode *inode, struct file *file)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	struct hmdfs_inode_info *info = NULL;
3768c2ecf20Sopenharmony_ci	struct kref *ref = NULL;
3778c2ecf20Sopenharmony_ci	struct hmdfs_getattr_ret *getattr_ret = NULL;
3788c2ecf20Sopenharmony_ci	unsigned int write_cache_timeout =
3798c2ecf20Sopenharmony_ci		hmdfs_sb(inode->i_sb)->write_cache_timeout;
3808c2ecf20Sopenharmony_ci	int err;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (!write_cache_timeout)
3838c2ecf20Sopenharmony_ci		return;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	info = hmdfs_i(inode);
3868c2ecf20Sopenharmony_ci	ref = &(info->ref);
3878c2ecf20Sopenharmony_ci	/*
3888c2ecf20Sopenharmony_ci	 * don't do anything if file is still opening or file hasn't been
3898c2ecf20Sopenharmony_ci	 * written.
3908c2ecf20Sopenharmony_ci	 */
3918c2ecf20Sopenharmony_ci	if (kref_read(ref) > 0 || !atomic64_read(&info->write_counter))
3928c2ecf20Sopenharmony_ci		return;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	/*
3958c2ecf20Sopenharmony_ci	 * If remote getattr failed, and we don't update ctime,
3968c2ecf20Sopenharmony_ci	 * pagecache will be truncated the next time file is opened.
3978c2ecf20Sopenharmony_ci	 */
3988c2ecf20Sopenharmony_ci	err = hmdfs_remote_getattr(info->conn, file_dentry(file), 0,
3998c2ecf20Sopenharmony_ci				   &getattr_ret);
4008c2ecf20Sopenharmony_ci	if (err) {
4018c2ecf20Sopenharmony_ci		hmdfs_err("remote getattr failed with err %d", err);
4028c2ecf20Sopenharmony_ci		return;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	if (!(getattr_ret->stat.result_mask & STATX_CTIME)) {
4068c2ecf20Sopenharmony_ci		hmdfs_err("get remote ctime failed with mask 0x%x",
4078c2ecf20Sopenharmony_ci			  getattr_ret->stat.result_mask);
4088c2ecf20Sopenharmony_ci		kfree(getattr_ret);
4098c2ecf20Sopenharmony_ci		return;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci	/*
4128c2ecf20Sopenharmony_ci	 * update ctime from remote, in case that pagecahe will be
4138c2ecf20Sopenharmony_ci	 * truncated in next open.
4148c2ecf20Sopenharmony_ci	 */
4158c2ecf20Sopenharmony_ci	inode->i_ctime = getattr_ret->stat.ctime;
4168c2ecf20Sopenharmony_ci	info->remote_ctime = getattr_ret->stat.ctime;
4178c2ecf20Sopenharmony_ci	hmdfs_set_writecache_expire(info, write_cache_timeout);
4188c2ecf20Sopenharmony_ci	kfree(getattr_ret);
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ciint hmdfs_file_release_remote(struct inode *inode, struct file *file)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (hmdfs_remote_need_track_file(hmdfs_sb(inode->i_sb), file->f_mode))
4268c2ecf20Sopenharmony_ci		hmdfs_remote_del_wr_opened_inode(info->conn, info);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	inode_lock(inode);
4298c2ecf20Sopenharmony_ci	kref_put(&info->ref, hmdfs_do_close_remote);
4308c2ecf20Sopenharmony_ci	hmdfs_remote_keep_writecache(inode, file);
4318c2ecf20Sopenharmony_ci	inode_unlock(inode);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return 0;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic int hmdfs_file_flush(struct file *file, fl_owner_t id)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	int err = 0;
4398c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	if (!(file->f_mode & FMODE_WRITE))
4428c2ecf20Sopenharmony_ci		return 0;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/*
4458c2ecf20Sopenharmony_ci	 * Continue regardless of whether file reopen fails or not,
4468c2ecf20Sopenharmony_ci	 * because there may be no dirty page.
4478c2ecf20Sopenharmony_ci	 */
4488c2ecf20Sopenharmony_ci	hmdfs_remote_check_and_reopen(hmdfs_i(inode), file);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	/*
4518c2ecf20Sopenharmony_ci	 * Wait for wsem here would impact the performance greatly, so we
4528c2ecf20Sopenharmony_ci	 * overlap the time to issue as many wbs as we can, expecting async
4538c2ecf20Sopenharmony_ci	 * wbs are eliminated afterwards.
4548c2ecf20Sopenharmony_ci	 */
4558c2ecf20Sopenharmony_ci	filemap_fdatawrite(inode->i_mapping);
4568c2ecf20Sopenharmony_ci	down_write(&hmdfs_i(inode)->wpage_sem);
4578c2ecf20Sopenharmony_ci	err = filemap_write_and_wait(inode->i_mapping);
4588c2ecf20Sopenharmony_ci	up_write(&hmdfs_i(inode)->wpage_sem);
4598c2ecf20Sopenharmony_ci	return err;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic ssize_t hmdfs_file_read_iter_remote(struct kiocb *iocb,
4638c2ecf20Sopenharmony_ci					   struct iov_iter *iter)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	struct file *filp = iocb->ki_filp;
4668c2ecf20Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(file_inode(filp));
4678c2ecf20Sopenharmony_ci	struct file_ra_state *ra = NULL;
4688c2ecf20Sopenharmony_ci	unsigned int rtt;
4698c2ecf20Sopenharmony_ci	int err;
4708c2ecf20Sopenharmony_ci	bool tried = false;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ciretry:
4738c2ecf20Sopenharmony_ci	err = hmdfs_remote_check_and_reopen(info, filp);
4748c2ecf20Sopenharmony_ci	if (err)
4758c2ecf20Sopenharmony_ci		return err;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	ra = &filp->f_ra;
4788c2ecf20Sopenharmony_ci	/* rtt is measured in 10 msecs */
4798c2ecf20Sopenharmony_ci	rtt = hmdfs_tcpi_rtt(info->conn) / 10000;
4808c2ecf20Sopenharmony_ci	switch (rtt) {
4818c2ecf20Sopenharmony_ci	case 0:
4828c2ecf20Sopenharmony_ci		break;
4838c2ecf20Sopenharmony_ci	case 1:
4848c2ecf20Sopenharmony_ci		ra->ra_pages = 256;
4858c2ecf20Sopenharmony_ci		break;
4868c2ecf20Sopenharmony_ci	case 2:
4878c2ecf20Sopenharmony_ci		ra->ra_pages = 512;
4888c2ecf20Sopenharmony_ci		break;
4898c2ecf20Sopenharmony_ci	default:
4908c2ecf20Sopenharmony_ci		ra->ra_pages = 1024;
4918c2ecf20Sopenharmony_ci		break;
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	err = generic_file_read_iter(iocb, iter);
4958c2ecf20Sopenharmony_ci	if (err < 0 && !tried && hmdfs_remote_need_reopen(info)) {
4968c2ecf20Sopenharmony_ci		/* Read from a stale fid, try read again once. */
4978c2ecf20Sopenharmony_ci		tried = true;
4988c2ecf20Sopenharmony_ci		goto retry;
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	return err;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic inline bool hmdfs_is_file_unwritable(const struct hmdfs_inode_info *info,
5058c2ecf20Sopenharmony_ci					    bool check_stash)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	return (check_stash && hmdfs_inode_is_stashing(info)) ||
5088c2ecf20Sopenharmony_ci	       !hmdfs_is_node_online(info->conn);
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cistatic ssize_t __hmdfs_file_write_iter_remote(struct kiocb *iocb,
5128c2ecf20Sopenharmony_ci					      struct iov_iter *iter,
5138c2ecf20Sopenharmony_ci					      bool check_stash)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	struct file *filp = iocb->ki_filp;
5168c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(filp);
5178c2ecf20Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
5188c2ecf20Sopenharmony_ci	ssize_t ret;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	if (hmdfs_is_file_unwritable(info, check_stash))
5218c2ecf20Sopenharmony_ci		return -EAGAIN;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	ret = hmdfs_remote_check_and_reopen(info, filp);
5248c2ecf20Sopenharmony_ci	if (ret)
5258c2ecf20Sopenharmony_ci		return ret;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	inode_lock(inode);
5288c2ecf20Sopenharmony_ci	if (hmdfs_is_file_unwritable(info, check_stash)) {
5298c2ecf20Sopenharmony_ci		ret = -EAGAIN;
5308c2ecf20Sopenharmony_ci		goto out;
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci	ret = generic_write_checks(iocb, iter);
5338c2ecf20Sopenharmony_ci	if (ret > 0)
5348c2ecf20Sopenharmony_ci		ret = __generic_file_write_iter(iocb, iter);
5358c2ecf20Sopenharmony_ciout:
5368c2ecf20Sopenharmony_ci	inode_unlock(inode);
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (ret > 0)
5398c2ecf20Sopenharmony_ci		ret = generic_write_sync(iocb, ret);
5408c2ecf20Sopenharmony_ci	return ret;
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cissize_t hmdfs_file_write_iter_remote_nocheck(struct kiocb *iocb,
5448c2ecf20Sopenharmony_ci					     struct iov_iter *iter)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	return __hmdfs_file_write_iter_remote(iocb, iter, false);
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic ssize_t hmdfs_file_write_iter_remote(struct kiocb *iocb,
5508c2ecf20Sopenharmony_ci					    struct iov_iter *iter)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	return __hmdfs_file_write_iter_remote(iocb, iter, true);
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci/* hmdfs not support mmap write remote file */
5568c2ecf20Sopenharmony_cistatic vm_fault_t hmdfs_page_mkwrite(struct vm_fault *vmf)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	return VM_FAULT_SIGBUS;
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cistatic const struct vm_operations_struct hmdfs_file_vm_ops = {
5628c2ecf20Sopenharmony_ci	.fault = filemap_fault,
5638c2ecf20Sopenharmony_ci	.map_pages = filemap_map_pages,
5648c2ecf20Sopenharmony_ci	.page_mkwrite = hmdfs_page_mkwrite,
5658c2ecf20Sopenharmony_ci};
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic int hmdfs_file_mmap_remote(struct file *file, struct vm_area_struct *vma)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	vma->vm_ops = &hmdfs_file_vm_ops;
5708c2ecf20Sopenharmony_ci	file_accessed(file);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	return 0;
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_cistatic int hmdfs_file_fsync_remote(struct file *file, loff_t start, loff_t end,
5768c2ecf20Sopenharmony_ci				   int datasync)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(file_inode(file));
5798c2ecf20Sopenharmony_ci	struct hmdfs_peer *conn = info->conn;
5808c2ecf20Sopenharmony_ci	struct hmdfs_fid fid;
5818c2ecf20Sopenharmony_ci	int err;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	trace_hmdfs_fsync_enter_remote(conn->sbi, conn->device_id,
5848c2ecf20Sopenharmony_ci				       info->remote_ino, datasync);
5858c2ecf20Sopenharmony_ci	/*
5868c2ecf20Sopenharmony_ci	 * Continue regardless of whether file reopen fails or not,
5878c2ecf20Sopenharmony_ci	 * because there may be no dirty page.
5888c2ecf20Sopenharmony_ci	 */
5898c2ecf20Sopenharmony_ci	hmdfs_remote_check_and_reopen(info, file);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	filemap_fdatawrite(file->f_mapping);
5928c2ecf20Sopenharmony_ci	down_write(&info->wpage_sem);
5938c2ecf20Sopenharmony_ci	err = file_write_and_wait_range(file, start, end);
5948c2ecf20Sopenharmony_ci	up_write(&info->wpage_sem);
5958c2ecf20Sopenharmony_ci	if (err) {
5968c2ecf20Sopenharmony_ci		hmdfs_err("local fsync fail with %d", err);
5978c2ecf20Sopenharmony_ci		goto out;
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	hmdfs_remote_fetch_fid(info, &fid);
6018c2ecf20Sopenharmony_ci	err = hmdfs_send_fsync(conn, &fid, start, end, datasync);
6028c2ecf20Sopenharmony_ci	if (err)
6038c2ecf20Sopenharmony_ci		hmdfs_err("send fsync fail with %d", err);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ciout:
6068c2ecf20Sopenharmony_ci	trace_hmdfs_fsync_exit_remote(conn->sbi, conn->device_id,
6078c2ecf20Sopenharmony_ci				      info->remote_ino,
6088c2ecf20Sopenharmony_ci				      get_cmd_timeout(conn->sbi, F_FSYNC), err);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	/* Compatible with POSIX retcode */
6118c2ecf20Sopenharmony_ci	if (err == -ETIME)
6128c2ecf20Sopenharmony_ci		err = -EIO;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	return err;
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ciconst struct file_operations hmdfs_dev_file_fops_remote = {
6188c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
6198c2ecf20Sopenharmony_ci	.llseek = generic_file_llseek,
6208c2ecf20Sopenharmony_ci	.read_iter = hmdfs_file_read_iter_remote,
6218c2ecf20Sopenharmony_ci	.write_iter = hmdfs_file_write_iter_remote,
6228c2ecf20Sopenharmony_ci	.mmap = hmdfs_file_mmap_remote,
6238c2ecf20Sopenharmony_ci	.open = hmdfs_file_open_remote,
6248c2ecf20Sopenharmony_ci	.release = hmdfs_file_release_remote,
6258c2ecf20Sopenharmony_ci	.flush = hmdfs_file_flush,
6268c2ecf20Sopenharmony_ci	.fsync = hmdfs_file_fsync_remote,
6278c2ecf20Sopenharmony_ci	.splice_read = generic_file_splice_read,
6288c2ecf20Sopenharmony_ci	.splice_write = iter_file_splice_write,
6298c2ecf20Sopenharmony_ci};
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic void hmdfs_fill_page_zero(struct page *page)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	void *addr = NULL;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	addr = kmap(page);
6368c2ecf20Sopenharmony_ci	memset(addr, 0, PAGE_SIZE);
6378c2ecf20Sopenharmony_ci	kunmap(page);
6388c2ecf20Sopenharmony_ci	SetPageUptodate(page);
6398c2ecf20Sopenharmony_ci	unlock_page(page);
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic int hmdfs_readpage_remote(struct file *file, struct page *page)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
6458c2ecf20Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
6468c2ecf20Sopenharmony_ci	loff_t isize = i_size_read(inode);
6478c2ecf20Sopenharmony_ci	pgoff_t end_index = (isize - 1) >> PAGE_SHIFT;
6488c2ecf20Sopenharmony_ci	struct hmdfs_fid fid;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (!isize || page->index > end_index) {
6518c2ecf20Sopenharmony_ci		hmdfs_fill_page_zero(page);
6528c2ecf20Sopenharmony_ci		return 0;
6538c2ecf20Sopenharmony_ci	}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	if (!isize || page->index > end_index) {
6568c2ecf20Sopenharmony_ci		hmdfs_fill_page_zero(page);
6578c2ecf20Sopenharmony_ci		return 0;
6588c2ecf20Sopenharmony_ci	}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	hmdfs_remote_fetch_fid(info, &fid);
6618c2ecf20Sopenharmony_ci	return hmdfs_client_readpage(info->conn, &fid, page);
6628c2ecf20Sopenharmony_ci}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ciuint32_t hmdfs_get_writecount(struct page *page)
6658c2ecf20Sopenharmony_ci{
6668c2ecf20Sopenharmony_ci	uint32_t count = 0;
6678c2ecf20Sopenharmony_ci	loff_t pos = (loff_t)page->index << HMDFS_PAGE_OFFSET;
6688c2ecf20Sopenharmony_ci	struct inode *inode = page->mapping->host;
6698c2ecf20Sopenharmony_ci	loff_t size = i_size_read(inode);
6708c2ecf20Sopenharmony_ci	/*
6718c2ecf20Sopenharmony_ci	 * If page offset is greater than i_size, this is possible when
6728c2ecf20Sopenharmony_ci	 * writepage concurrent with truncate. In this case, we don't need to
6738c2ecf20Sopenharmony_ci	 * do remote writepage since it'll be truncated after the page is
6748c2ecf20Sopenharmony_ci	 * unlocked.
6758c2ecf20Sopenharmony_ci	 */
6768c2ecf20Sopenharmony_ci	if (pos >= size)
6778c2ecf20Sopenharmony_ci		count = 0;
6788c2ecf20Sopenharmony_ci	/*
6798c2ecf20Sopenharmony_ci	 * If the page about to write is beyond i_size, we can't write beyond
6808c2ecf20Sopenharmony_ci	 * i_size because remote file size will be wrong.
6818c2ecf20Sopenharmony_ci	 */
6828c2ecf20Sopenharmony_ci	else if (size < pos + HMDFS_PAGE_SIZE)
6838c2ecf20Sopenharmony_ci		count = size - pos;
6848c2ecf20Sopenharmony_ci	/* It's safe to write the whole page */
6858c2ecf20Sopenharmony_ci	else
6868c2ecf20Sopenharmony_ci		count = HMDFS_PAGE_SIZE;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	return count;
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_cistatic bool allow_cur_thread_wpage(struct hmdfs_inode_info *info,
6928c2ecf20Sopenharmony_ci				   bool *rsem_held, bool sync_all)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	WARN_ON(!rsem_held);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	if (sync_all) {
6978c2ecf20Sopenharmony_ci		*rsem_held = false;
6988c2ecf20Sopenharmony_ci		return true;
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci	*rsem_held = down_read_trylock(&info->wpage_sem);
7018c2ecf20Sopenharmony_ci	return *rsem_held;
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci/**
7058c2ecf20Sopenharmony_ci * hmdfs_writepage_remote - writeback a dirty page to remote
7068c2ecf20Sopenharmony_ci *
7078c2ecf20Sopenharmony_ci * INFO:
7088c2ecf20Sopenharmony_ci * When asked to WB_SYNC_ALL, this function should leave with both the page and
7098c2ecf20Sopenharmony_ci * the radix tree node clean to achieve close-to-open consitency. Moreover,
7108c2ecf20Sopenharmony_ci * this shall never return -EIO to help filemap to iterate all dirty pages.
7118c2ecf20Sopenharmony_ci *
7128c2ecf20Sopenharmony_ci * INFO:
7138c2ecf20Sopenharmony_ci * When asked to WB_SYNC_NONE, this function should be mercy if faults(oom or
7148c2ecf20Sopenharmony_ci * bad pipe) happended to enable subsequent r/w & wb.
7158c2ecf20Sopenharmony_ci */
7168c2ecf20Sopenharmony_cistatic int hmdfs_writepage_remote(struct page *page,
7178c2ecf20Sopenharmony_ci				  struct writeback_control *wbc)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	struct inode *inode = page->mapping->host;
7208c2ecf20Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
7218c2ecf20Sopenharmony_ci	struct hmdfs_sb_info *sbi = hmdfs_sb(inode->i_sb);
7228c2ecf20Sopenharmony_ci	int ret = 0;
7238c2ecf20Sopenharmony_ci	bool rsem_held = false;
7248c2ecf20Sopenharmony_ci	bool sync = wbc->sync_mode == WB_SYNC_ALL;
7258c2ecf20Sopenharmony_ci	struct hmdfs_writepage_context *param = NULL;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	if (!allow_cur_thread_wpage(info, &rsem_held, sync))
7288c2ecf20Sopenharmony_ci		goto out_unlock;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	set_page_writeback(page);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	param = kzalloc(sizeof(*param), GFP_NOFS);
7338c2ecf20Sopenharmony_ci	if (!param) {
7348c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7358c2ecf20Sopenharmony_ci		goto out_endwb;
7368c2ecf20Sopenharmony_ci	}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	if (sync && hmdfs_usr_sig_pending(current)) {
7398c2ecf20Sopenharmony_ci		ClearPageUptodate(page);
7408c2ecf20Sopenharmony_ci		goto out_free;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci	param->count = hmdfs_get_writecount(page);
7438c2ecf20Sopenharmony_ci	if (!param->count)
7448c2ecf20Sopenharmony_ci		goto out_free;
7458c2ecf20Sopenharmony_ci	param->rsem_held = rsem_held;
7468c2ecf20Sopenharmony_ci	hmdfs_remote_fetch_fid(info, &param->fid);
7478c2ecf20Sopenharmony_ci	param->sync_all = sync;
7488c2ecf20Sopenharmony_ci	param->caller = current;
7498c2ecf20Sopenharmony_ci	get_task_struct(current);
7508c2ecf20Sopenharmony_ci	param->page = page;
7518c2ecf20Sopenharmony_ci	param->timeout = jiffies + msecs_to_jiffies(sbi->wb_timeout_ms);
7528c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&param->retry_dwork, hmdfs_remote_writepage_retry);
7538c2ecf20Sopenharmony_ci	ret = hmdfs_remote_do_writepage(info->conn, param);
7548c2ecf20Sopenharmony_ci	if (likely(!ret))
7558c2ecf20Sopenharmony_ci		return 0;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	put_task_struct(current);
7588c2ecf20Sopenharmony_ciout_free:
7598c2ecf20Sopenharmony_ci	kfree(param);
7608c2ecf20Sopenharmony_ciout_endwb:
7618c2ecf20Sopenharmony_ci	end_page_writeback(page);
7628c2ecf20Sopenharmony_ci	if (rsem_held)
7638c2ecf20Sopenharmony_ci		up_read(&info->wpage_sem);
7648c2ecf20Sopenharmony_ciout_unlock:
7658c2ecf20Sopenharmony_ci	if (sync || !hmdfs_need_redirty_page(info, ret)) {
7668c2ecf20Sopenharmony_ci		SetPageError(page);
7678c2ecf20Sopenharmony_ci		mapping_set_error(page->mapping, ret);
7688c2ecf20Sopenharmony_ci	} else {
7698c2ecf20Sopenharmony_ci		redirty_page_for_writepage(wbc, page);
7708c2ecf20Sopenharmony_ci	}
7718c2ecf20Sopenharmony_ci	unlock_page(page);
7728c2ecf20Sopenharmony_ci	return ret;
7738c2ecf20Sopenharmony_ci}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic void hmdfs_account_dirty_pages(struct address_space *mapping)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	struct hmdfs_sb_info *sbi = mapping->host->i_sb->s_fs_info;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (!sbi->h_wb->dirty_writeback_control)
7808c2ecf20Sopenharmony_ci		return;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	this_cpu_inc(*sbi->h_wb->bdp_ratelimits);
7838c2ecf20Sopenharmony_ci}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_cistatic int hmdfs_write_begin_remote(struct file *file,
7868c2ecf20Sopenharmony_ci				    struct address_space *mapping, loff_t pos,
7878c2ecf20Sopenharmony_ci				    unsigned int len, unsigned int flags,
7888c2ecf20Sopenharmony_ci				    struct page **pagep, void **fsdata)
7898c2ecf20Sopenharmony_ci{
7908c2ecf20Sopenharmony_ci	pgoff_t index = ((unsigned long long)pos) >> PAGE_SHIFT;
7918c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
7928c2ecf20Sopenharmony_ci	struct page *page = NULL;
7938c2ecf20Sopenharmony_ci	int ret = 0;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_cistart:
7968c2ecf20Sopenharmony_ci	page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
7978c2ecf20Sopenharmony_ci	if (!page)
7988c2ecf20Sopenharmony_ci		return -ENOMEM;
7998c2ecf20Sopenharmony_ci	*pagep = page;
8008c2ecf20Sopenharmony_ci	wait_on_page_writeback(page);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	// If this page will be covered completely.
8038c2ecf20Sopenharmony_ci	if (len == HMDFS_PAGE_SIZE || PageUptodate(page))
8048c2ecf20Sopenharmony_ci		return 0;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	/*
8078c2ecf20Sopenharmony_ci	 * If data existed in this page will covered,
8088c2ecf20Sopenharmony_ci	 * we just need to clear this page.
8098c2ecf20Sopenharmony_ci	 */
8108c2ecf20Sopenharmony_ci	if (!((unsigned long long)pos & (HMDFS_PAGE_SIZE - 1)) &&
8118c2ecf20Sopenharmony_ci	    (pos + len) >= i_size_read(inode)) {
8128c2ecf20Sopenharmony_ci		zero_user_segment(page, len, HMDFS_PAGE_SIZE);
8138c2ecf20Sopenharmony_ci		return 0;
8148c2ecf20Sopenharmony_ci	}
8158c2ecf20Sopenharmony_ci	/*
8168c2ecf20Sopenharmony_ci	 * We need readpage before write date to this page.
8178c2ecf20Sopenharmony_ci	 */
8188c2ecf20Sopenharmony_ci	ret = hmdfs_readpage_remote(file, page);
8198c2ecf20Sopenharmony_ci	if (!ret) {
8208c2ecf20Sopenharmony_ci		if (PageLocked(page)) {
8218c2ecf20Sopenharmony_ci			ret = __lock_page_killable(page);
8228c2ecf20Sopenharmony_ci			if (!ret)
8238c2ecf20Sopenharmony_ci				unlock_page(page);
8248c2ecf20Sopenharmony_ci		}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci		if (!ret && PageUptodate(page)) {
8278c2ecf20Sopenharmony_ci			put_page(page);
8288c2ecf20Sopenharmony_ci			goto start;
8298c2ecf20Sopenharmony_ci		}
8308c2ecf20Sopenharmony_ci		if (!ret)
8318c2ecf20Sopenharmony_ci			ret = -EIO;
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci	put_page(page);
8348c2ecf20Sopenharmony_ci	return ret;
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_cistatic int hmdfs_write_end_remote(struct file *file,
8388c2ecf20Sopenharmony_ci				  struct address_space *mapping, loff_t pos,
8398c2ecf20Sopenharmony_ci				  unsigned int len, unsigned int copied,
8408c2ecf20Sopenharmony_ci				  struct page *page, void *fsdata)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	struct inode *inode = page->mapping->host;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	if (!PageUptodate(page)) {
8458c2ecf20Sopenharmony_ci		if (unlikely(copied != len))
8468c2ecf20Sopenharmony_ci			copied = 0;
8478c2ecf20Sopenharmony_ci		else
8488c2ecf20Sopenharmony_ci			SetPageUptodate(page);
8498c2ecf20Sopenharmony_ci	}
8508c2ecf20Sopenharmony_ci	if (!copied)
8518c2ecf20Sopenharmony_ci		goto unlock_out;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	if (!PageDirty(page)) {
8548c2ecf20Sopenharmony_ci		hmdfs_account_dirty_pages(mapping);
8558c2ecf20Sopenharmony_ci		set_page_dirty(page);
8568c2ecf20Sopenharmony_ci	}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	if (pos + copied > i_size_read(inode)) {
8598c2ecf20Sopenharmony_ci		i_size_write(inode, pos + copied);
8608c2ecf20Sopenharmony_ci		hmdfs_i(inode)->getattr_isize = HMDFS_STALE_REMOTE_ISIZE;
8618c2ecf20Sopenharmony_ci	}
8628c2ecf20Sopenharmony_ciunlock_out:
8638c2ecf20Sopenharmony_ci	unlock_page(page);
8648c2ecf20Sopenharmony_ci	put_page(page);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	/* hmdfs private writeback control */
8678c2ecf20Sopenharmony_ci	hmdfs_balance_dirty_pages_ratelimited(mapping);
8688c2ecf20Sopenharmony_ci	return copied;
8698c2ecf20Sopenharmony_ci}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ciconst struct address_space_operations hmdfs_dev_file_aops_remote = {
8728c2ecf20Sopenharmony_ci	.readpage = hmdfs_readpage_remote,
8738c2ecf20Sopenharmony_ci	.write_begin = hmdfs_write_begin_remote,
8748c2ecf20Sopenharmony_ci	.write_end = hmdfs_write_end_remote,
8758c2ecf20Sopenharmony_ci	.writepage = hmdfs_writepage_remote,
8768c2ecf20Sopenharmony_ci	.set_page_dirty = __set_page_dirty_nobuffers,
8778c2ecf20Sopenharmony_ci};
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ciloff_t hmdfs_set_pos(unsigned long dev_id, unsigned long group_id,
8808c2ecf20Sopenharmony_ci			    unsigned long offset)
8818c2ecf20Sopenharmony_ci{
8828c2ecf20Sopenharmony_ci	loff_t pos;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	pos = ((loff_t)dev_id << (POS_BIT_NUM - 1 - DEV_ID_BIT_NUM)) +
8858c2ecf20Sopenharmony_ci	      ((loff_t)group_id << OFFSET_BIT_NUM) + offset;
8868c2ecf20Sopenharmony_ci	if (dev_id)
8878c2ecf20Sopenharmony_ci		pos |= ((loff_t)1 << (POS_BIT_NUM - 1));
8888c2ecf20Sopenharmony_ci	return pos;
8898c2ecf20Sopenharmony_ci}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ciint analysis_dentry_file_from_con(struct hmdfs_sb_info *sbi,
8928c2ecf20Sopenharmony_ci					 struct file *file,
8938c2ecf20Sopenharmony_ci					 struct file *handler,
8948c2ecf20Sopenharmony_ci					 struct dir_context *ctx)
8958c2ecf20Sopenharmony_ci{
8968c2ecf20Sopenharmony_ci	struct hmdfs_dentry_group *dentry_group = NULL;
8978c2ecf20Sopenharmony_ci	loff_t pos = ctx->pos;
8988c2ecf20Sopenharmony_ci	unsigned long dev_id = (unsigned long)((pos << 1) >> (POS_BIT_NUM - DEV_ID_BIT_NUM));
8998c2ecf20Sopenharmony_ci	unsigned long group_id = (unsigned long)((pos << (1 + DEV_ID_BIT_NUM)) >>
9008c2ecf20Sopenharmony_ci				 (POS_BIT_NUM - GROUP_ID_BIT_NUM));
9018c2ecf20Sopenharmony_ci	loff_t offset = pos & OFFSET_BIT_MASK;
9028c2ecf20Sopenharmony_ci	int group_num = 0;
9038c2ecf20Sopenharmony_ci	char *dentry_name = NULL;
9048c2ecf20Sopenharmony_ci	int iterate_result = 0;
9058c2ecf20Sopenharmony_ci	int i, j;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	dentry_group = kzalloc(sizeof(*dentry_group), GFP_KERNEL);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	if (!dentry_group)
9108c2ecf20Sopenharmony_ci		return -ENOMEM;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(handler)) {
9138c2ecf20Sopenharmony_ci		kfree(dentry_group);
9148c2ecf20Sopenharmony_ci		return -ENOENT;
9158c2ecf20Sopenharmony_ci	}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	group_num = get_dentry_group_cnt(file_inode(handler));
9188c2ecf20Sopenharmony_ci	dentry_name = kzalloc(DENTRY_NAME_MAX_LEN, GFP_KERNEL);
9198c2ecf20Sopenharmony_ci	if (!dentry_name) {
9208c2ecf20Sopenharmony_ci		kfree(dentry_group);
9218c2ecf20Sopenharmony_ci		return -ENOMEM;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	for (i = group_id; i < group_num; i++) {
9258c2ecf20Sopenharmony_ci		int ret = hmdfs_metainfo_read(sbi, handler, dentry_group,
9268c2ecf20Sopenharmony_ci					      sizeof(struct hmdfs_dentry_group),
9278c2ecf20Sopenharmony_ci					      i);
9288c2ecf20Sopenharmony_ci		if (ret != sizeof(struct hmdfs_dentry_group)) {
9298c2ecf20Sopenharmony_ci			hmdfs_err("read dentry group failed ret:%d", ret);
9308c2ecf20Sopenharmony_ci			goto done;
9318c2ecf20Sopenharmony_ci		}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci		for (j = offset; j < DENTRY_PER_GROUP; j++) {
9348c2ecf20Sopenharmony_ci			int len;
9358c2ecf20Sopenharmony_ci			int file_type = DT_UNKNOWN;
9368c2ecf20Sopenharmony_ci			bool is_continue;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci			len = le16_to_cpu(dentry_group->nsl[j].namelen);
9398c2ecf20Sopenharmony_ci			if (!test_bit_le(j, dentry_group->bitmap) || len == 0)
9408c2ecf20Sopenharmony_ci				continue;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci			memset(dentry_name, 0, DENTRY_NAME_MAX_LEN);
9438c2ecf20Sopenharmony_ci			// TODO: Support more file_type
9448c2ecf20Sopenharmony_ci			if (S_ISDIR(le16_to_cpu(dentry_group->nsl[j].i_mode)))
9458c2ecf20Sopenharmony_ci				file_type = DT_DIR;
9468c2ecf20Sopenharmony_ci			else if (S_ISREG(le16_to_cpu(
9478c2ecf20Sopenharmony_ci					 dentry_group->nsl[j].i_mode)))
9488c2ecf20Sopenharmony_ci				file_type = DT_REG;
9498c2ecf20Sopenharmony_ci			else if (S_ISLNK(le16_to_cpu(
9508c2ecf20Sopenharmony_ci					 dentry_group->nsl[j].i_mode)))
9518c2ecf20Sopenharmony_ci				file_type = DT_LNK;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci			strncat(dentry_name, dentry_group->filename[j], len);
9548c2ecf20Sopenharmony_ci			pos = hmdfs_set_pos(dev_id, i, j);
9558c2ecf20Sopenharmony_ci			is_continue =
9568c2ecf20Sopenharmony_ci				dir_emit(ctx, dentry_name, len,
9578c2ecf20Sopenharmony_ci					 pos + INUNUMBER_START, file_type);
9588c2ecf20Sopenharmony_ci			if (!is_continue) {
9598c2ecf20Sopenharmony_ci				ctx->pos = pos;
9608c2ecf20Sopenharmony_ci				iterate_result = 1;
9618c2ecf20Sopenharmony_ci				goto done;
9628c2ecf20Sopenharmony_ci			}
9638c2ecf20Sopenharmony_ci		}
9648c2ecf20Sopenharmony_ci		offset = 0;
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_cidone:
9688c2ecf20Sopenharmony_ci	kfree(dentry_name);
9698c2ecf20Sopenharmony_ci	kfree(dentry_group);
9708c2ecf20Sopenharmony_ci	return iterate_result;
9718c2ecf20Sopenharmony_ci}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ciint hmdfs_dev_readdir_from_con(struct hmdfs_peer *con, struct file *file,
9748c2ecf20Sopenharmony_ci			       struct dir_context *ctx)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	int iterate_result = 0;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	iterate_result = analysis_dentry_file_from_con(
9798c2ecf20Sopenharmony_ci		con->sbi, file, file->private_data, ctx);
9808c2ecf20Sopenharmony_ci	return iterate_result;
9818c2ecf20Sopenharmony_ci}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_cistatic int hmdfs_iterate_remote(struct file *file, struct dir_context *ctx)
9848c2ecf20Sopenharmony_ci{
9858c2ecf20Sopenharmony_ci	int err = 0;
9868c2ecf20Sopenharmony_ci	loff_t start_pos = ctx->pos;
9878c2ecf20Sopenharmony_ci	struct hmdfs_peer *con = NULL;
9888c2ecf20Sopenharmony_ci	struct hmdfs_dentry_info *di = hmdfs_d(file->f_path.dentry);
9898c2ecf20Sopenharmony_ci	bool is_local = !((ctx->pos) >> (POS_BIT_NUM - 1));
9908c2ecf20Sopenharmony_ci	uint64_t dev_id = di->device_id;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	if (ctx->pos == -1)
9938c2ecf20Sopenharmony_ci		return 0;
9948c2ecf20Sopenharmony_ci	if (is_local)
9958c2ecf20Sopenharmony_ci		ctx->pos = hmdfs_set_pos(dev_id, 0, 0);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	con = hmdfs_lookup_from_devid(file->f_inode->i_sb->s_fs_info, dev_id);
9988c2ecf20Sopenharmony_ci	if (con) {
9998c2ecf20Sopenharmony_ci		// ctx->pos = 0;
10008c2ecf20Sopenharmony_ci		err = hmdfs_dev_readdir_from_con(con, file, ctx);
10018c2ecf20Sopenharmony_ci		if (unlikely(!con)) {
10028c2ecf20Sopenharmony_ci			hmdfs_err("con is null");
10038c2ecf20Sopenharmony_ci			goto done;
10048c2ecf20Sopenharmony_ci		}
10058c2ecf20Sopenharmony_ci		peer_put(con);
10068c2ecf20Sopenharmony_ci		if (err)
10078c2ecf20Sopenharmony_ci			goto done;
10088c2ecf20Sopenharmony_ci	}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_cidone:
10118c2ecf20Sopenharmony_ci	if (err <= 0)
10128c2ecf20Sopenharmony_ci		ctx->pos = -1;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	trace_hmdfs_iterate_remote(file->f_path.dentry, start_pos, ctx->pos,
10158c2ecf20Sopenharmony_ci				   err);
10168c2ecf20Sopenharmony_ci	return err;
10178c2ecf20Sopenharmony_ci}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ciint hmdfs_dir_open_remote(struct inode *inode, struct file *file)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
10228c2ecf20Sopenharmony_ci	struct clearcache_item *cache_item = NULL;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	if (info->conn) {
10258c2ecf20Sopenharmony_ci		if (!hmdfs_cache_revalidate(READ_ONCE(info->conn->conn_time),
10268c2ecf20Sopenharmony_ci					    info->conn->device_id,
10278c2ecf20Sopenharmony_ci					    file->f_path.dentry))
10288c2ecf20Sopenharmony_ci			get_remote_dentry_file_sync(file->f_path.dentry,
10298c2ecf20Sopenharmony_ci						    info->conn);
10308c2ecf20Sopenharmony_ci		cache_item = hmdfs_find_cache_item(info->conn->device_id,
10318c2ecf20Sopenharmony_ci						   file->f_path.dentry);
10328c2ecf20Sopenharmony_ci		if (cache_item) {
10338c2ecf20Sopenharmony_ci			file->private_data = cache_item->filp;
10348c2ecf20Sopenharmony_ci			get_file(file->private_data);
10358c2ecf20Sopenharmony_ci			kref_put(&cache_item->ref, release_cache_item);
10368c2ecf20Sopenharmony_ci			return 0;
10378c2ecf20Sopenharmony_ci		}
10388c2ecf20Sopenharmony_ci		return -ENOENT;
10398c2ecf20Sopenharmony_ci	}
10408c2ecf20Sopenharmony_ci	return -ENOENT;
10418c2ecf20Sopenharmony_ci}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_cistatic int hmdfs_dir_release_remote(struct inode *inode, struct file *file)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	if (file->private_data)
10468c2ecf20Sopenharmony_ci		fput(file->private_data);
10478c2ecf20Sopenharmony_ci	file->private_data = NULL;
10488c2ecf20Sopenharmony_ci	return 0;
10498c2ecf20Sopenharmony_ci}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ciconst struct file_operations hmdfs_dev_dir_ops_remote = {
10528c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
10538c2ecf20Sopenharmony_ci	.iterate = hmdfs_iterate_remote,
10548c2ecf20Sopenharmony_ci	.open = hmdfs_dir_open_remote,
10558c2ecf20Sopenharmony_ci	.release = hmdfs_dir_release_remote,
10568c2ecf20Sopenharmony_ci	.fsync = __generic_file_fsync,
10578c2ecf20Sopenharmony_ci};
1058