xref: /kernel/linux/linux-6.6/fs/hmdfs/file_remote.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * fs/hmdfs/file_remote.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/backing-dev.h>
962306a36Sopenharmony_ci#include <linux/file.h>
1062306a36Sopenharmony_ci#include <linux/fs.h>
1162306a36Sopenharmony_ci#include <linux/namei.h>
1262306a36Sopenharmony_ci#include <linux/page-flags.h>
1362306a36Sopenharmony_ci#include <linux/pagemap.h>
1462306a36Sopenharmony_ci#include <linux/pagevec.h>
1562306a36Sopenharmony_ci#include <linux/sched/signal.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/wait.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "file_remote.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "comm/socket_adapter.h"
2262306a36Sopenharmony_ci#include "hmdfs.h"
2362306a36Sopenharmony_ci#include "hmdfs_client.h"
2462306a36Sopenharmony_ci#include "hmdfs_dentryfile.h"
2562306a36Sopenharmony_ci#include "hmdfs_trace.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic inline bool hmdfs_remote_write_cache_expired(
2862306a36Sopenharmony_ci		struct hmdfs_inode_info *info)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	return time_after(jiffies, info->writecache_expire);
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cienum expire_reason {
3462306a36Sopenharmony_ci	ALL_GOOD = 0,
3562306a36Sopenharmony_ci	INO_DISMATCH = 1,
3662306a36Sopenharmony_ci	SIZE_OR_CTIME_DISMATCH = 2,
3762306a36Sopenharmony_ci	TIMER_EXPIRE = 3,
3862306a36Sopenharmony_ci	TIMER_WORKING = 4,
3962306a36Sopenharmony_ci	STABLE_CTIME_DISMATCH = 5,
4062306a36Sopenharmony_ci	KEEP_CACHE = 6,
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/*
4462306a36Sopenharmony_ci * hmdfs_open_final_remote - Do final steps of opening a remote file, update
4562306a36Sopenharmony_ci * local inode cache and decide whether of not to truncate inode pages.
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * @info: hmdfs inode info
4862306a36Sopenharmony_ci * @open_ret: values returned from remote when opening a remote file
4962306a36Sopenharmony_ci * @keep_cache: keep local cache & i_size
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_cistatic int hmdfs_open_final_remote(struct hmdfs_inode_info *info,
5262306a36Sopenharmony_ci				   struct hmdfs_open_ret *open_ret,
5362306a36Sopenharmony_ci				   struct file *file, bool keep_cache)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct inode *inode = &info->vfs_inode;
5662306a36Sopenharmony_ci	bool truncate = false;
5762306a36Sopenharmony_ci	enum expire_reason reason = ALL_GOOD;
5862306a36Sopenharmony_ci	int ret = 0;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/*
6162306a36Sopenharmony_ci	 * if remote inode number changed and lookup stale data, we'll return
6262306a36Sopenharmony_ci	 * -ESTALE, and reopen the file with metedate from remote getattr.
6362306a36Sopenharmony_ci	 */
6462306a36Sopenharmony_ci	if (info->remote_ino != open_ret->ino) {
6562306a36Sopenharmony_ci		hmdfs_debug(
6662306a36Sopenharmony_ci			"got stale local inode, ino in local %llu, ino from open %llu",
6762306a36Sopenharmony_ci			info->remote_ino, open_ret->ino);
6862306a36Sopenharmony_ci		hmdfs_send_close(info->conn, &open_ret->fid);
6962306a36Sopenharmony_ci		reason = INO_DISMATCH;
7062306a36Sopenharmony_ci		ret = -ESTALE;
7162306a36Sopenharmony_ci		goto out;
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (keep_cache) {
7562306a36Sopenharmony_ci		reason = KEEP_CACHE;
7662306a36Sopenharmony_ci		trace_hmdfs_open_final_remote(info, open_ret, file, reason);
7762306a36Sopenharmony_ci		goto set_fid_out;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/*
8162306a36Sopenharmony_ci	 * if remote size do not match local inode, or remote ctime do not match
8262306a36Sopenharmony_ci	 * the last time same file was opened.
8362306a36Sopenharmony_ci	 */
8462306a36Sopenharmony_ci	if (inode->i_size != open_ret->file_size ||
8562306a36Sopenharmony_ci	    hmdfs_time_compare(&info->remote_ctime, &open_ret->remote_ctime)) {
8662306a36Sopenharmony_ci		truncate = true;
8762306a36Sopenharmony_ci		reason = SIZE_OR_CTIME_DISMATCH;
8862306a36Sopenharmony_ci		goto out;
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/*
9262306a36Sopenharmony_ci	 * If 'writecache_expire' is set, check if it expires. And skip the
9362306a36Sopenharmony_ci	 * checking of stable_ctime.
9462306a36Sopenharmony_ci	 */
9562306a36Sopenharmony_ci	if (info->writecache_expire) {
9662306a36Sopenharmony_ci		truncate = hmdfs_remote_write_cache_expired(info);
9762306a36Sopenharmony_ci		if (truncate)
9862306a36Sopenharmony_ci			reason = TIMER_EXPIRE;
9962306a36Sopenharmony_ci		else
10062306a36Sopenharmony_ci			reason = TIMER_WORKING;
10162306a36Sopenharmony_ci		goto out;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* the first time, or remote ctime is ahead of remote time */
10562306a36Sopenharmony_ci	if (info->stable_ctime.tv_sec == 0 && info->stable_ctime.tv_nsec == 0) {
10662306a36Sopenharmony_ci		truncate = true;
10762306a36Sopenharmony_ci		reason = STABLE_CTIME_DISMATCH;
10862306a36Sopenharmony_ci		goto out;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/*
11262306a36Sopenharmony_ci	 * - if last stable_ctime == stable_ctime, we do nothing.
11362306a36Sopenharmony_ci	 *   a. if ctime < stable_ctime, data is ensured to be uptodate,
11462306a36Sopenharmony_ci	 *   b. if ctime == stable_ctime, stale data might be accessed. This is
11562306a36Sopenharmony_ci	 *      acceptable since pagecache will be dropped later.
11662306a36Sopenharmony_ci	 *   c. ctime > stable_ctime is impossible.
11762306a36Sopenharmony_ci	 * - if last stable_ctime < stable_ctime, we clear the cache.
11862306a36Sopenharmony_ci	 *   d. ctime != last stable_ctime is impossible
11962306a36Sopenharmony_ci	 *   e. ctime == last stable_ctime, this is possible to read again from
12062306a36Sopenharmony_ci	 *      b, thus we need to drop the cache.
12162306a36Sopenharmony_ci	 * - if last stable_ctime > stable_ctime, we clear the cache.
12262306a36Sopenharmony_ci	 *   stable_ctime must be zero in this case, this is possible because
12362306a36Sopenharmony_ci	 *   system time might be changed.
12462306a36Sopenharmony_ci	 */
12562306a36Sopenharmony_ci	if (hmdfs_time_compare(&info->stable_ctime, &open_ret->stable_ctime)) {
12662306a36Sopenharmony_ci		truncate = true;
12762306a36Sopenharmony_ci		reason = STABLE_CTIME_DISMATCH;
12862306a36Sopenharmony_ci		goto out;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciout:
13262306a36Sopenharmony_ci	trace_hmdfs_open_final_remote(info, open_ret, file, reason);
13362306a36Sopenharmony_ci	if (ret)
13462306a36Sopenharmony_ci		return ret;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (reason == SIZE_OR_CTIME_DISMATCH) {
13762306a36Sopenharmony_ci		inode->__i_ctime = open_ret->remote_ctime;
13862306a36Sopenharmony_ci		info->remote_ctime = open_ret->remote_ctime;
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	if (truncate) {
14262306a36Sopenharmony_ci		info->writecache_expire = 0;
14362306a36Sopenharmony_ci		truncate_inode_pages(inode->i_mapping, 0);
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	atomic64_set(&info->write_counter, 0);
14762306a36Sopenharmony_ci	info->stable_ctime = open_ret->stable_ctime;
14862306a36Sopenharmony_ci	i_size_write(inode, open_ret->file_size);
14962306a36Sopenharmony_ci	info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE;
15062306a36Sopenharmony_ciset_fid_out:
15162306a36Sopenharmony_ci	spin_lock(&info->fid_lock);
15262306a36Sopenharmony_ci	info->fid = open_ret->fid;
15362306a36Sopenharmony_ci	spin_unlock(&info->fid_lock);
15462306a36Sopenharmony_ci	return 0;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ciint hmdfs_do_open_remote(struct file *file, bool keep_cache)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(file_inode(file));
16062306a36Sopenharmony_ci	struct hmdfs_peer *conn = info->conn;
16162306a36Sopenharmony_ci	struct hmdfs_open_ret open_ret;
16262306a36Sopenharmony_ci	__u8 file_type = hmdfs_d(file->f_path.dentry)->file_type;
16362306a36Sopenharmony_ci	char *send_buf;
16462306a36Sopenharmony_ci	int err = 0;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	send_buf = hmdfs_get_dentry_relative_path(file->f_path.dentry);
16762306a36Sopenharmony_ci	if (!send_buf) {
16862306a36Sopenharmony_ci		err = -ENOMEM;
16962306a36Sopenharmony_ci		goto out_free;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci	err = hmdfs_send_open(conn, send_buf, file_type, &open_ret);
17262306a36Sopenharmony_ci	if (err) {
17362306a36Sopenharmony_ci		hmdfs_err("hmdfs_send_open return failed with %d", err);
17462306a36Sopenharmony_ci		goto out_free;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	err = hmdfs_open_final_remote(info, &open_ret, file, keep_cache);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ciout_free:
18062306a36Sopenharmony_ci	kfree(send_buf);
18162306a36Sopenharmony_ci	return err;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic inline bool hmdfs_remote_need_reopen(struct hmdfs_inode_info *info)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	return test_bit(HMDFS_FID_NEED_OPEN, &info->fid_flags);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic inline bool hmdfs_remote_is_opening_file(struct hmdfs_inode_info *info)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	return test_bit(HMDFS_FID_OPENING, &info->fid_flags);
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic int hmdfs_remote_wait_opening_file(struct hmdfs_inode_info *info)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	int err;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (!hmdfs_remote_is_opening_file(info))
19962306a36Sopenharmony_ci		return 0;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	err = ___wait_event(info->fid_wq, hmdfs_remote_is_opening_file(info),
20262306a36Sopenharmony_ci			    TASK_INTERRUPTIBLE, 0, 0,
20362306a36Sopenharmony_ci			    spin_unlock(&info->fid_lock);
20462306a36Sopenharmony_ci			    schedule();
20562306a36Sopenharmony_ci			    spin_lock(&info->fid_lock));
20662306a36Sopenharmony_ci	if (err)
20762306a36Sopenharmony_ci		err = -EINTR;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	return err;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic int hmdfs_remote_file_reopen(struct hmdfs_inode_info *info,
21362306a36Sopenharmony_ci				    struct file *filp)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	int err = 0;
21662306a36Sopenharmony_ci	struct hmdfs_peer *conn = info->conn;
21762306a36Sopenharmony_ci	struct inode *inode = NULL;
21862306a36Sopenharmony_ci	struct hmdfs_fid fid;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (conn->status == NODE_STAT_OFFLINE)
22162306a36Sopenharmony_ci		return -EAGAIN;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	spin_lock(&info->fid_lock);
22462306a36Sopenharmony_ci	err = hmdfs_remote_wait_opening_file(info);
22562306a36Sopenharmony_ci	if (err || !hmdfs_remote_need_reopen(info)) {
22662306a36Sopenharmony_ci		spin_unlock(&info->fid_lock);
22762306a36Sopenharmony_ci		goto out;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	set_bit(HMDFS_FID_OPENING, &info->fid_flags);
23162306a36Sopenharmony_ci	fid = info->fid;
23262306a36Sopenharmony_ci	spin_unlock(&info->fid_lock);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	inode = &info->vfs_inode;
23562306a36Sopenharmony_ci	inode_lock(inode);
23662306a36Sopenharmony_ci	/*
23762306a36Sopenharmony_ci	 * Most closing cases are meaningless, except for one:
23862306a36Sopenharmony_ci	 *        read process A         read process B
23962306a36Sopenharmony_ci	 *    err = -EBADF              err = -EBADF       (caused by re-online)
24062306a36Sopenharmony_ci	 *    set_need_reopen
24162306a36Sopenharmony_ci	 *    do reopen
24262306a36Sopenharmony_ci	 *    fid = new fid_1 [server hold fid_1]
24362306a36Sopenharmony_ci	 *                              set need_reopen
24462306a36Sopenharmony_ci	 *                              do reopen
24562306a36Sopenharmony_ci	 *                                send close (fid_1) // In case of leak
24662306a36Sopenharmony_ci	 *                              fid = new fid_2
24762306a36Sopenharmony_ci	 */
24862306a36Sopenharmony_ci	if (fid.id != HMDFS_INODE_INVALID_FILE_ID)
24962306a36Sopenharmony_ci		hmdfs_send_close(conn, &fid);
25062306a36Sopenharmony_ci	err = hmdfs_do_open_remote(filp, true);
25162306a36Sopenharmony_ci	inode_unlock(inode);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	spin_lock(&info->fid_lock);
25462306a36Sopenharmony_ci	/*
25562306a36Sopenharmony_ci	 * May make the bit set in offline handler lost, but server
25662306a36Sopenharmony_ci	 * will tell us whether or not the newly-opened file id is
25762306a36Sopenharmony_ci	 * generated before offline, if it is opened before offline,
25862306a36Sopenharmony_ci	 * the operation on the file id will return -EBADF and
25962306a36Sopenharmony_ci	 * HMDFS_FID_NEED_OPEN bit will be set again.
26062306a36Sopenharmony_ci	 */
26162306a36Sopenharmony_ci	if (!err)
26262306a36Sopenharmony_ci		clear_bit(HMDFS_FID_NEED_OPEN, &info->fid_flags);
26362306a36Sopenharmony_ci	clear_bit(HMDFS_FID_OPENING, &info->fid_flags);
26462306a36Sopenharmony_ci	spin_unlock(&info->fid_lock);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	wake_up_interruptible_all(&info->fid_wq);
26762306a36Sopenharmony_ciout:
26862306a36Sopenharmony_ci	return err;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic int hmdfs_remote_check_and_reopen(struct hmdfs_inode_info *info,
27262306a36Sopenharmony_ci					 struct file *filp)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	if (!hmdfs_remote_need_reopen(info))
27562306a36Sopenharmony_ci		return 0;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	return hmdfs_remote_file_reopen(info, filp);
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_civoid hmdfs_do_close_remote(struct kref *kref)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct hmdfs_inode_info *info =
28362306a36Sopenharmony_ci		container_of(kref, struct hmdfs_inode_info, ref);
28462306a36Sopenharmony_ci	struct hmdfs_fid fid;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	hmdfs_remote_fetch_fid(info, &fid);
28762306a36Sopenharmony_ci	/* This function can return asynchronously */
28862306a36Sopenharmony_ci	hmdfs_send_close(info->conn, &fid);
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic inline bool hmdfs_remote_need_track_file(const struct hmdfs_sb_info *sbi,
29262306a36Sopenharmony_ci						fmode_t mode)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	return (hmdfs_is_stash_enabled(sbi) && (mode & FMODE_WRITE));
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic void
29862306a36Sopenharmony_cihmdfs_remote_del_wr_opened_inode_nolock(struct hmdfs_inode_info *info)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	WARN_ON(list_empty(&info->wr_opened_node));
30162306a36Sopenharmony_ci	if (atomic_dec_and_test(&info->wr_opened_cnt))
30262306a36Sopenharmony_ci		list_del_init(&info->wr_opened_node);
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_civoid hmdfs_remote_del_wr_opened_inode(struct hmdfs_peer *conn,
30662306a36Sopenharmony_ci				      struct hmdfs_inode_info *info)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	spin_lock(&conn->wr_opened_inode_lock);
30962306a36Sopenharmony_ci	hmdfs_remote_del_wr_opened_inode_nolock(info);
31062306a36Sopenharmony_ci	spin_unlock(&conn->wr_opened_inode_lock);
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_civoid hmdfs_remote_add_wr_opened_inode_nolock(struct hmdfs_peer *conn,
31462306a36Sopenharmony_ci					     struct hmdfs_inode_info *info)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	if (list_empty(&info->wr_opened_node)) {
31762306a36Sopenharmony_ci		atomic_set(&info->wr_opened_cnt, 1);
31862306a36Sopenharmony_ci		list_add_tail(&info->wr_opened_node,
31962306a36Sopenharmony_ci			      &conn->wr_opened_inode_list);
32062306a36Sopenharmony_ci	} else {
32162306a36Sopenharmony_ci		atomic_inc(&info->wr_opened_cnt);
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic void hmdfs_remote_add_wr_opened_inode(struct hmdfs_peer *conn,
32662306a36Sopenharmony_ci					     struct hmdfs_inode_info *info)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	spin_lock(&conn->wr_opened_inode_lock);
32962306a36Sopenharmony_ci	hmdfs_remote_add_wr_opened_inode_nolock(conn, info);
33062306a36Sopenharmony_ci	spin_unlock(&conn->wr_opened_inode_lock);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ciint hmdfs_file_open_remote(struct inode *inode, struct file *file)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
33662306a36Sopenharmony_ci	struct kref *ref = &(info->ref);
33762306a36Sopenharmony_ci	int err = 0;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	inode_lock(inode);
34062306a36Sopenharmony_ci	if (kref_read(ref) == 0) {
34162306a36Sopenharmony_ci		err = hmdfs_do_open_remote(file, false);
34262306a36Sopenharmony_ci		if (err == 0)
34362306a36Sopenharmony_ci			kref_init(ref);
34462306a36Sopenharmony_ci	} else {
34562306a36Sopenharmony_ci		kref_get(ref);
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci	inode_unlock(inode);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (!err && hmdfs_remote_need_track_file(hmdfs_sb(inode->i_sb),
35062306a36Sopenharmony_ci						 file->f_mode))
35162306a36Sopenharmony_ci		hmdfs_remote_add_wr_opened_inode(info->conn, info);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return err;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic void hmdfs_set_writecache_expire(struct hmdfs_inode_info *info,
35762306a36Sopenharmony_ci					unsigned int seconds)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	unsigned long new_expire = jiffies + (unsigned long)seconds * HZ;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/*
36262306a36Sopenharmony_ci	 * When file has been written before closing, set pagecache expire
36362306a36Sopenharmony_ci	 * if it has not been set yet. This is necessary because ctime might
36462306a36Sopenharmony_ci	 * stay the same after overwrite.
36562306a36Sopenharmony_ci	 */
36662306a36Sopenharmony_ci	if (info->writecache_expire &&
36762306a36Sopenharmony_ci	    time_after(new_expire, info->writecache_expire))
36862306a36Sopenharmony_ci		return;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	info->writecache_expire = new_expire;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic void hmdfs_remote_keep_writecache(struct inode *inode, struct file *file)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct hmdfs_inode_info *info = NULL;
37662306a36Sopenharmony_ci	struct kref *ref = NULL;
37762306a36Sopenharmony_ci	struct hmdfs_getattr_ret *getattr_ret = NULL;
37862306a36Sopenharmony_ci	unsigned int write_cache_timeout =
37962306a36Sopenharmony_ci		hmdfs_sb(inode->i_sb)->write_cache_timeout;
38062306a36Sopenharmony_ci	int err;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	if (!write_cache_timeout)
38362306a36Sopenharmony_ci		return;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	info = hmdfs_i(inode);
38662306a36Sopenharmony_ci	ref = &(info->ref);
38762306a36Sopenharmony_ci	/*
38862306a36Sopenharmony_ci	 * don't do anything if file is still opening or file hasn't been
38962306a36Sopenharmony_ci	 * written.
39062306a36Sopenharmony_ci	 */
39162306a36Sopenharmony_ci	if (kref_read(ref) > 0 || !atomic64_read(&info->write_counter))
39262306a36Sopenharmony_ci		return;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/*
39562306a36Sopenharmony_ci	 * If remote getattr failed, and we don't update ctime,
39662306a36Sopenharmony_ci	 * pagecache will be truncated the next time file is opened.
39762306a36Sopenharmony_ci	 */
39862306a36Sopenharmony_ci	err = hmdfs_remote_getattr(info->conn, file_dentry(file), 0,
39962306a36Sopenharmony_ci				   &getattr_ret);
40062306a36Sopenharmony_ci	if (err) {
40162306a36Sopenharmony_ci		hmdfs_err("remote getattr failed with err %d", err);
40262306a36Sopenharmony_ci		return;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (!(getattr_ret->stat.result_mask & STATX_CTIME)) {
40662306a36Sopenharmony_ci		hmdfs_err("get remote ctime failed with mask 0x%x",
40762306a36Sopenharmony_ci			  getattr_ret->stat.result_mask);
40862306a36Sopenharmony_ci		kfree(getattr_ret);
40962306a36Sopenharmony_ci		return;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci	/*
41262306a36Sopenharmony_ci	 * update ctime from remote, in case that pagecahe will be
41362306a36Sopenharmony_ci	 * truncated in next open.
41462306a36Sopenharmony_ci	 */
41562306a36Sopenharmony_ci	inode->__i_ctime = getattr_ret->stat.ctime;
41662306a36Sopenharmony_ci	info->remote_ctime = getattr_ret->stat.ctime;
41762306a36Sopenharmony_ci	hmdfs_set_writecache_expire(info, write_cache_timeout);
41862306a36Sopenharmony_ci	kfree(getattr_ret);
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ciint hmdfs_file_release_remote(struct inode *inode, struct file *file)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	if (hmdfs_remote_need_track_file(hmdfs_sb(inode->i_sb), file->f_mode))
42662306a36Sopenharmony_ci		hmdfs_remote_del_wr_opened_inode(info->conn, info);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	inode_lock(inode);
42962306a36Sopenharmony_ci	kref_put(&info->ref, hmdfs_do_close_remote);
43062306a36Sopenharmony_ci	hmdfs_remote_keep_writecache(inode, file);
43162306a36Sopenharmony_ci	inode_unlock(inode);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic int hmdfs_file_flush(struct file *file, fl_owner_t id)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	int err = 0;
43962306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	if (!(file->f_mode & FMODE_WRITE))
44262306a36Sopenharmony_ci		return 0;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	/*
44562306a36Sopenharmony_ci	 * Continue regardless of whether file reopen fails or not,
44662306a36Sopenharmony_ci	 * because there may be no dirty page.
44762306a36Sopenharmony_ci	 */
44862306a36Sopenharmony_ci	hmdfs_remote_check_and_reopen(hmdfs_i(inode), file);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/*
45162306a36Sopenharmony_ci	 * Wait for wsem here would impact the performance greatly, so we
45262306a36Sopenharmony_ci	 * overlap the time to issue as many wbs as we can, expecting async
45362306a36Sopenharmony_ci	 * wbs are eliminated afterwards.
45462306a36Sopenharmony_ci	 */
45562306a36Sopenharmony_ci	filemap_fdatawrite(inode->i_mapping);
45662306a36Sopenharmony_ci	down_write(&hmdfs_i(inode)->wpage_sem);
45762306a36Sopenharmony_ci	err = filemap_write_and_wait(inode->i_mapping);
45862306a36Sopenharmony_ci	up_write(&hmdfs_i(inode)->wpage_sem);
45962306a36Sopenharmony_ci	return err;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic ssize_t hmdfs_file_read_iter_remote(struct kiocb *iocb,
46362306a36Sopenharmony_ci					   struct iov_iter *iter)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct file *filp = iocb->ki_filp;
46662306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(file_inode(filp));
46762306a36Sopenharmony_ci	struct file_ra_state *ra = NULL;
46862306a36Sopenharmony_ci	unsigned int rtt;
46962306a36Sopenharmony_ci	int err;
47062306a36Sopenharmony_ci	bool tried = false;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ciretry:
47362306a36Sopenharmony_ci	err = hmdfs_remote_check_and_reopen(info, filp);
47462306a36Sopenharmony_ci	if (err)
47562306a36Sopenharmony_ci		return err;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	ra = &filp->f_ra;
47862306a36Sopenharmony_ci	/* rtt is measured in 10 msecs */
47962306a36Sopenharmony_ci	rtt = hmdfs_tcpi_rtt(info->conn) / 10000;
48062306a36Sopenharmony_ci	switch (rtt) {
48162306a36Sopenharmony_ci	case 0:
48262306a36Sopenharmony_ci		break;
48362306a36Sopenharmony_ci	case 1:
48462306a36Sopenharmony_ci		ra->ra_pages = 256;
48562306a36Sopenharmony_ci		break;
48662306a36Sopenharmony_ci	case 2:
48762306a36Sopenharmony_ci		ra->ra_pages = 512;
48862306a36Sopenharmony_ci		break;
48962306a36Sopenharmony_ci	default:
49062306a36Sopenharmony_ci		ra->ra_pages = 1024;
49162306a36Sopenharmony_ci		break;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	err = generic_file_read_iter(iocb, iter);
49562306a36Sopenharmony_ci	if (err < 0 && !tried && hmdfs_remote_need_reopen(info)) {
49662306a36Sopenharmony_ci		/* Read from a stale fid, try read again once. */
49762306a36Sopenharmony_ci		tried = true;
49862306a36Sopenharmony_ci		goto retry;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return err;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic inline bool hmdfs_is_file_unwritable(const struct hmdfs_inode_info *info,
50562306a36Sopenharmony_ci					    bool check_stash)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	return (check_stash && hmdfs_inode_is_stashing(info)) ||
50862306a36Sopenharmony_ci	       !hmdfs_is_node_online(info->conn);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic ssize_t __hmdfs_file_write_iter_remote(struct kiocb *iocb,
51262306a36Sopenharmony_ci					      struct iov_iter *iter,
51362306a36Sopenharmony_ci					      bool check_stash)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct file *filp = iocb->ki_filp;
51662306a36Sopenharmony_ci	struct inode *inode = file_inode(filp);
51762306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
51862306a36Sopenharmony_ci	ssize_t ret;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (hmdfs_is_file_unwritable(info, check_stash))
52162306a36Sopenharmony_ci		return -EAGAIN;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	ret = hmdfs_remote_check_and_reopen(info, filp);
52462306a36Sopenharmony_ci	if (ret)
52562306a36Sopenharmony_ci		return ret;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	inode_lock(inode);
52862306a36Sopenharmony_ci	if (hmdfs_is_file_unwritable(info, check_stash)) {
52962306a36Sopenharmony_ci		ret = -EAGAIN;
53062306a36Sopenharmony_ci		goto out;
53162306a36Sopenharmony_ci	}
53262306a36Sopenharmony_ci	ret = generic_write_checks(iocb, iter);
53362306a36Sopenharmony_ci	if (ret > 0)
53462306a36Sopenharmony_ci		ret = __generic_file_write_iter(iocb, iter);
53562306a36Sopenharmony_ciout:
53662306a36Sopenharmony_ci	inode_unlock(inode);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	if (ret > 0)
53962306a36Sopenharmony_ci		ret = generic_write_sync(iocb, ret);
54062306a36Sopenharmony_ci	return ret;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cissize_t hmdfs_file_write_iter_remote_nocheck(struct kiocb *iocb,
54462306a36Sopenharmony_ci					     struct iov_iter *iter)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	return __hmdfs_file_write_iter_remote(iocb, iter, false);
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic ssize_t hmdfs_file_write_iter_remote(struct kiocb *iocb,
55062306a36Sopenharmony_ci					    struct iov_iter *iter)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	return __hmdfs_file_write_iter_remote(iocb, iter, true);
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci/* hmdfs not support mmap write remote file */
55662306a36Sopenharmony_cistatic vm_fault_t hmdfs_page_mkwrite(struct vm_fault *vmf)
55762306a36Sopenharmony_ci{
55862306a36Sopenharmony_ci	return VM_FAULT_SIGBUS;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic const struct vm_operations_struct hmdfs_file_vm_ops = {
56262306a36Sopenharmony_ci	.fault = filemap_fault,
56362306a36Sopenharmony_ci	.map_pages = filemap_map_pages,
56462306a36Sopenharmony_ci	.page_mkwrite = hmdfs_page_mkwrite,
56562306a36Sopenharmony_ci};
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic int hmdfs_file_mmap_remote(struct file *file, struct vm_area_struct *vma)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	vma->vm_ops = &hmdfs_file_vm_ops;
57062306a36Sopenharmony_ci	file_accessed(file);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	return 0;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic int hmdfs_file_fsync_remote(struct file *file, loff_t start, loff_t end,
57662306a36Sopenharmony_ci				   int datasync)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(file_inode(file));
57962306a36Sopenharmony_ci	struct hmdfs_peer *conn = info->conn;
58062306a36Sopenharmony_ci	struct hmdfs_fid fid;
58162306a36Sopenharmony_ci	int err;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	trace_hmdfs_fsync_enter_remote(conn->sbi, conn->device_id,
58462306a36Sopenharmony_ci				       info->remote_ino, datasync);
58562306a36Sopenharmony_ci	/*
58662306a36Sopenharmony_ci	 * Continue regardless of whether file reopen fails or not,
58762306a36Sopenharmony_ci	 * because there may be no dirty page.
58862306a36Sopenharmony_ci	 */
58962306a36Sopenharmony_ci	hmdfs_remote_check_and_reopen(info, file);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	filemap_fdatawrite(file->f_mapping);
59262306a36Sopenharmony_ci	down_write(&info->wpage_sem);
59362306a36Sopenharmony_ci	err = file_write_and_wait_range(file, start, end);
59462306a36Sopenharmony_ci	up_write(&info->wpage_sem);
59562306a36Sopenharmony_ci	if (err) {
59662306a36Sopenharmony_ci		hmdfs_err("local fsync fail with %d", err);
59762306a36Sopenharmony_ci		goto out;
59862306a36Sopenharmony_ci	}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	hmdfs_remote_fetch_fid(info, &fid);
60162306a36Sopenharmony_ci	err = hmdfs_send_fsync(conn, &fid, start, end, datasync);
60262306a36Sopenharmony_ci	if (err)
60362306a36Sopenharmony_ci		hmdfs_err("send fsync fail with %d", err);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ciout:
60662306a36Sopenharmony_ci	trace_hmdfs_fsync_exit_remote(conn->sbi, conn->device_id,
60762306a36Sopenharmony_ci				      info->remote_ino,
60862306a36Sopenharmony_ci				      get_cmd_timeout(conn->sbi, F_FSYNC), err);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	/* Compatible with POSIX retcode */
61162306a36Sopenharmony_ci	if (err == -ETIME)
61262306a36Sopenharmony_ci		err = -EIO;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	return err;
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ciconst struct file_operations hmdfs_dev_file_fops_remote = {
61862306a36Sopenharmony_ci	.owner = THIS_MODULE,
61962306a36Sopenharmony_ci	.llseek = generic_file_llseek,
62062306a36Sopenharmony_ci	.read_iter = hmdfs_file_read_iter_remote,
62162306a36Sopenharmony_ci	.write_iter = hmdfs_file_write_iter_remote,
62262306a36Sopenharmony_ci	.mmap = hmdfs_file_mmap_remote,
62362306a36Sopenharmony_ci	.open = hmdfs_file_open_remote,
62462306a36Sopenharmony_ci	.release = hmdfs_file_release_remote,
62562306a36Sopenharmony_ci	.flush = hmdfs_file_flush,
62662306a36Sopenharmony_ci	.fsync = hmdfs_file_fsync_remote,
62762306a36Sopenharmony_ci	.splice_read = copy_splice_read,
62862306a36Sopenharmony_ci	.splice_write = iter_file_splice_write,
62962306a36Sopenharmony_ci};
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic void hmdfs_fill_page_zero(struct page *page)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	void *addr = NULL;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	addr = kmap(page);
63662306a36Sopenharmony_ci	memset(addr, 0, PAGE_SIZE);
63762306a36Sopenharmony_ci	kunmap(page);
63862306a36Sopenharmony_ci	SetPageUptodate(page);
63962306a36Sopenharmony_ci	unlock_page(page);
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cistatic int hmdfs_readpage_remote(struct file *file, struct page *page)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
64562306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
64662306a36Sopenharmony_ci	loff_t isize = i_size_read(inode);
64762306a36Sopenharmony_ci	pgoff_t end_index = (isize - 1) >> PAGE_SHIFT;
64862306a36Sopenharmony_ci	struct hmdfs_fid fid;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	if (!isize || page->index > end_index) {
65162306a36Sopenharmony_ci		hmdfs_fill_page_zero(page);
65262306a36Sopenharmony_ci		return 0;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (!isize || page->index > end_index) {
65662306a36Sopenharmony_ci		hmdfs_fill_page_zero(page);
65762306a36Sopenharmony_ci		return 0;
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	hmdfs_remote_fetch_fid(info, &fid);
66162306a36Sopenharmony_ci	return hmdfs_client_readpage(info->conn, &fid, page);
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cistatic int hmdfs_read_folio(struct file *file, struct folio *folio)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	struct page *page = &folio->page;
66762306a36Sopenharmony_ci	return hmdfs_readpage_remote(file, page);
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ciuint32_t hmdfs_get_writecount(struct page *page)
67162306a36Sopenharmony_ci{
67262306a36Sopenharmony_ci	uint32_t count = 0;
67362306a36Sopenharmony_ci	loff_t pos = (loff_t)page->index << HMDFS_PAGE_OFFSET;
67462306a36Sopenharmony_ci	struct inode *inode = page->mapping->host;
67562306a36Sopenharmony_ci	loff_t size = i_size_read(inode);
67662306a36Sopenharmony_ci	/*
67762306a36Sopenharmony_ci	 * If page offset is greater than i_size, this is possible when
67862306a36Sopenharmony_ci	 * writepage concurrent with truncate. In this case, we don't need to
67962306a36Sopenharmony_ci	 * do remote writepage since it'll be truncated after the page is
68062306a36Sopenharmony_ci	 * unlocked.
68162306a36Sopenharmony_ci	 */
68262306a36Sopenharmony_ci	if (pos >= size)
68362306a36Sopenharmony_ci		count = 0;
68462306a36Sopenharmony_ci	/*
68562306a36Sopenharmony_ci	 * If the page about to write is beyond i_size, we can't write beyond
68662306a36Sopenharmony_ci	 * i_size because remote file size will be wrong.
68762306a36Sopenharmony_ci	 */
68862306a36Sopenharmony_ci	else if (size < pos + HMDFS_PAGE_SIZE)
68962306a36Sopenharmony_ci		count = size - pos;
69062306a36Sopenharmony_ci	/* It's safe to write the whole page */
69162306a36Sopenharmony_ci	else
69262306a36Sopenharmony_ci		count = HMDFS_PAGE_SIZE;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	return count;
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_cistatic bool allow_cur_thread_wpage(struct hmdfs_inode_info *info,
69862306a36Sopenharmony_ci				   bool *rsem_held, bool sync_all)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	WARN_ON(!rsem_held);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	if (sync_all) {
70362306a36Sopenharmony_ci		*rsem_held = false;
70462306a36Sopenharmony_ci		return true;
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci	*rsem_held = down_read_trylock(&info->wpage_sem);
70762306a36Sopenharmony_ci	return *rsem_held;
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci/**
71162306a36Sopenharmony_ci * hmdfs_writepage_remote - writeback a dirty page to remote
71262306a36Sopenharmony_ci *
71362306a36Sopenharmony_ci * INFO:
71462306a36Sopenharmony_ci * When asked to WB_SYNC_ALL, this function should leave with both the page and
71562306a36Sopenharmony_ci * the radix tree node clean to achieve close-to-open consitency. Moreover,
71662306a36Sopenharmony_ci * this shall never return -EIO to help filemap to iterate all dirty pages.
71762306a36Sopenharmony_ci *
71862306a36Sopenharmony_ci * INFO:
71962306a36Sopenharmony_ci * When asked to WB_SYNC_NONE, this function should be mercy if faults(oom or
72062306a36Sopenharmony_ci * bad pipe) happended to enable subsequent r/w & wb.
72162306a36Sopenharmony_ci */
72262306a36Sopenharmony_cistatic int hmdfs_writepage_remote(struct page *page,
72362306a36Sopenharmony_ci				  struct writeback_control *wbc)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	struct inode *inode = page->mapping->host;
72662306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
72762306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = hmdfs_sb(inode->i_sb);
72862306a36Sopenharmony_ci	int ret = 0;
72962306a36Sopenharmony_ci	bool rsem_held = false;
73062306a36Sopenharmony_ci	bool sync = wbc->sync_mode == WB_SYNC_ALL;
73162306a36Sopenharmony_ci	struct hmdfs_writepage_context *param = NULL;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	if (!allow_cur_thread_wpage(info, &rsem_held, sync))
73462306a36Sopenharmony_ci		goto out_unlock;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	set_page_writeback(page);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	param = kzalloc(sizeof(*param), GFP_NOFS);
73962306a36Sopenharmony_ci	if (!param) {
74062306a36Sopenharmony_ci		ret = -ENOMEM;
74162306a36Sopenharmony_ci		goto out_endwb;
74262306a36Sopenharmony_ci	}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	if (sync && hmdfs_usr_sig_pending(current)) {
74562306a36Sopenharmony_ci		ClearPageUptodate(page);
74662306a36Sopenharmony_ci		goto out_free;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci	param->count = hmdfs_get_writecount(page);
74962306a36Sopenharmony_ci	if (!param->count)
75062306a36Sopenharmony_ci		goto out_free;
75162306a36Sopenharmony_ci	param->rsem_held = rsem_held;
75262306a36Sopenharmony_ci	hmdfs_remote_fetch_fid(info, &param->fid);
75362306a36Sopenharmony_ci	param->sync_all = sync;
75462306a36Sopenharmony_ci	param->caller = current;
75562306a36Sopenharmony_ci	get_task_struct(current);
75662306a36Sopenharmony_ci	param->page = page;
75762306a36Sopenharmony_ci	param->timeout = jiffies + msecs_to_jiffies(sbi->wb_timeout_ms);
75862306a36Sopenharmony_ci	INIT_DELAYED_WORK(&param->retry_dwork, hmdfs_remote_writepage_retry);
75962306a36Sopenharmony_ci	ret = hmdfs_remote_do_writepage(info->conn, param);
76062306a36Sopenharmony_ci	if (likely(!ret))
76162306a36Sopenharmony_ci		return 0;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	put_task_struct(current);
76462306a36Sopenharmony_ciout_free:
76562306a36Sopenharmony_ci	kfree(param);
76662306a36Sopenharmony_ciout_endwb:
76762306a36Sopenharmony_ci	end_page_writeback(page);
76862306a36Sopenharmony_ci	if (rsem_held)
76962306a36Sopenharmony_ci		up_read(&info->wpage_sem);
77062306a36Sopenharmony_ciout_unlock:
77162306a36Sopenharmony_ci	if (sync || !hmdfs_need_redirty_page(info, ret)) {
77262306a36Sopenharmony_ci		SetPageError(page);
77362306a36Sopenharmony_ci		mapping_set_error(page->mapping, ret);
77462306a36Sopenharmony_ci	} else {
77562306a36Sopenharmony_ci		redirty_page_for_writepage(wbc, page);
77662306a36Sopenharmony_ci	}
77762306a36Sopenharmony_ci	unlock_page(page);
77862306a36Sopenharmony_ci	return ret;
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic void hmdfs_account_dirty_pages(struct address_space *mapping)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	struct hmdfs_sb_info *sbi = mapping->host->i_sb->s_fs_info;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	if (!sbi->h_wb->dirty_writeback_control)
78662306a36Sopenharmony_ci		return;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	this_cpu_inc(*sbi->h_wb->bdp_ratelimits);
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic int hmdfs_write_begin_remote(struct file *file,
79262306a36Sopenharmony_ci				    struct address_space *mapping, loff_t pos,
79362306a36Sopenharmony_ci				    unsigned int len,
79462306a36Sopenharmony_ci				    struct page **pagep, void **fsdata)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	pgoff_t index = ((unsigned long long)pos) >> PAGE_SHIFT;
79762306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
79862306a36Sopenharmony_ci	struct page *page = NULL;
79962306a36Sopenharmony_ci	int ret = 0;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistart:
80262306a36Sopenharmony_ci	page = grab_cache_page_write_begin(mapping, index);
80362306a36Sopenharmony_ci	if (!page)
80462306a36Sopenharmony_ci		return -ENOMEM;
80562306a36Sopenharmony_ci	*pagep = page;
80662306a36Sopenharmony_ci	wait_on_page_writeback(page);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	// If this page will be covered completely.
80962306a36Sopenharmony_ci	if (len == HMDFS_PAGE_SIZE || PageUptodate(page))
81062306a36Sopenharmony_ci		return 0;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/*
81362306a36Sopenharmony_ci	 * If data existed in this page will covered,
81462306a36Sopenharmony_ci	 * we just need to clear this page.
81562306a36Sopenharmony_ci	 */
81662306a36Sopenharmony_ci	if (!((unsigned long long)pos & (HMDFS_PAGE_SIZE - 1)) &&
81762306a36Sopenharmony_ci	    (pos + len) >= i_size_read(inode)) {
81862306a36Sopenharmony_ci		zero_user_segment(page, len, HMDFS_PAGE_SIZE);
81962306a36Sopenharmony_ci		return 0;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci	/*
82262306a36Sopenharmony_ci	 * We need readpage before write date to this page.
82362306a36Sopenharmony_ci	 */
82462306a36Sopenharmony_ci	ret = hmdfs_readpage_remote(file, page);
82562306a36Sopenharmony_ci	if (!ret) {
82662306a36Sopenharmony_ci		if (PageLocked(page)) {
82762306a36Sopenharmony_ci			ret = folio_lock_killable(page_folio(page));
82862306a36Sopenharmony_ci			if (!ret)
82962306a36Sopenharmony_ci				unlock_page(page);
83062306a36Sopenharmony_ci		}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci		if (!ret && PageUptodate(page)) {
83362306a36Sopenharmony_ci			put_page(page);
83462306a36Sopenharmony_ci			goto start;
83562306a36Sopenharmony_ci		}
83662306a36Sopenharmony_ci		if (!ret)
83762306a36Sopenharmony_ci			ret = -EIO;
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci	put_page(page);
84062306a36Sopenharmony_ci	return ret;
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_cistatic int hmdfs_write_end_remote(struct file *file,
84462306a36Sopenharmony_ci				  struct address_space *mapping, loff_t pos,
84562306a36Sopenharmony_ci				  unsigned int len, unsigned int copied,
84662306a36Sopenharmony_ci				  struct page *page, void *fsdata)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	struct inode *inode = page->mapping->host;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	if (!PageUptodate(page)) {
85162306a36Sopenharmony_ci		if (unlikely(copied != len))
85262306a36Sopenharmony_ci			copied = 0;
85362306a36Sopenharmony_ci		else
85462306a36Sopenharmony_ci			SetPageUptodate(page);
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci	if (!copied)
85762306a36Sopenharmony_ci		goto unlock_out;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	if (!PageDirty(page)) {
86062306a36Sopenharmony_ci		hmdfs_account_dirty_pages(mapping);
86162306a36Sopenharmony_ci		set_page_dirty(page);
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	if (pos + copied > i_size_read(inode)) {
86562306a36Sopenharmony_ci		i_size_write(inode, pos + copied);
86662306a36Sopenharmony_ci		hmdfs_i(inode)->getattr_isize = HMDFS_STALE_REMOTE_ISIZE;
86762306a36Sopenharmony_ci	}
86862306a36Sopenharmony_ciunlock_out:
86962306a36Sopenharmony_ci	unlock_page(page);
87062306a36Sopenharmony_ci	put_page(page);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	/* hmdfs private writeback control */
87362306a36Sopenharmony_ci	hmdfs_balance_dirty_pages_ratelimited(mapping);
87462306a36Sopenharmony_ci	return copied;
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ciconst struct address_space_operations hmdfs_dev_file_aops_remote = {
87862306a36Sopenharmony_ci	.read_folio = hmdfs_read_folio,
87962306a36Sopenharmony_ci	.write_begin = hmdfs_write_begin_remote,
88062306a36Sopenharmony_ci	.write_end = hmdfs_write_end_remote,
88162306a36Sopenharmony_ci	.writepage = hmdfs_writepage_remote,
88262306a36Sopenharmony_ci	.dirty_folio = filemap_dirty_folio,
88362306a36Sopenharmony_ci};
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ciloff_t hmdfs_set_pos(unsigned long dev_id, unsigned long group_id,
88662306a36Sopenharmony_ci			    unsigned long offset)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	loff_t pos;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	pos = ((loff_t)dev_id << (POS_BIT_NUM - 1 - DEV_ID_BIT_NUM)) +
89162306a36Sopenharmony_ci	      ((loff_t)group_id << OFFSET_BIT_NUM) + offset;
89262306a36Sopenharmony_ci	if (dev_id)
89362306a36Sopenharmony_ci		pos |= ((loff_t)1 << (POS_BIT_NUM - 1));
89462306a36Sopenharmony_ci	return pos;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ciint analysis_dentry_file_from_con(struct hmdfs_sb_info *sbi,
89862306a36Sopenharmony_ci					 struct file *file,
89962306a36Sopenharmony_ci					 struct file *handler,
90062306a36Sopenharmony_ci					 struct dir_context *ctx)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	struct hmdfs_dentry_group *dentry_group = NULL;
90362306a36Sopenharmony_ci	loff_t pos = ctx->pos;
90462306a36Sopenharmony_ci	unsigned long dev_id = (unsigned long)((pos << 1) >> (POS_BIT_NUM - DEV_ID_BIT_NUM));
90562306a36Sopenharmony_ci	unsigned long group_id = (unsigned long)((pos << (1 + DEV_ID_BIT_NUM)) >>
90662306a36Sopenharmony_ci				 (POS_BIT_NUM - GROUP_ID_BIT_NUM));
90762306a36Sopenharmony_ci	loff_t offset = pos & OFFSET_BIT_MASK;
90862306a36Sopenharmony_ci	int group_num = 0;
90962306a36Sopenharmony_ci	char *dentry_name = NULL;
91062306a36Sopenharmony_ci	int iterate_result = 0;
91162306a36Sopenharmony_ci	int i, j;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	dentry_group = kzalloc(sizeof(*dentry_group), GFP_KERNEL);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	if (!dentry_group)
91662306a36Sopenharmony_ci		return -ENOMEM;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(handler)) {
91962306a36Sopenharmony_ci		kfree(dentry_group);
92062306a36Sopenharmony_ci		return -ENOENT;
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	group_num = get_dentry_group_cnt(file_inode(handler));
92462306a36Sopenharmony_ci	dentry_name = kzalloc(DENTRY_NAME_MAX_LEN, GFP_KERNEL);
92562306a36Sopenharmony_ci	if (!dentry_name) {
92662306a36Sopenharmony_ci		kfree(dentry_group);
92762306a36Sopenharmony_ci		return -ENOMEM;
92862306a36Sopenharmony_ci	}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	for (i = group_id; i < group_num; i++) {
93162306a36Sopenharmony_ci		int ret = hmdfs_metainfo_read(sbi, handler, dentry_group,
93262306a36Sopenharmony_ci					      sizeof(struct hmdfs_dentry_group),
93362306a36Sopenharmony_ci					      i);
93462306a36Sopenharmony_ci		if (ret != sizeof(struct hmdfs_dentry_group)) {
93562306a36Sopenharmony_ci			hmdfs_err("read dentry group failed ret:%d", ret);
93662306a36Sopenharmony_ci			goto done;
93762306a36Sopenharmony_ci		}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		for (j = offset; j < DENTRY_PER_GROUP; j++) {
94062306a36Sopenharmony_ci			int len;
94162306a36Sopenharmony_ci			int file_type = DT_UNKNOWN;
94262306a36Sopenharmony_ci			bool is_continue;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci			len = le16_to_cpu(dentry_group->nsl[j].namelen);
94562306a36Sopenharmony_ci			if (!test_bit_le(j, dentry_group->bitmap) || len == 0)
94662306a36Sopenharmony_ci				continue;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci			memset(dentry_name, 0, DENTRY_NAME_MAX_LEN);
94962306a36Sopenharmony_ci			// TODO: Support more file_type
95062306a36Sopenharmony_ci			if (S_ISDIR(le16_to_cpu(dentry_group->nsl[j].i_mode)))
95162306a36Sopenharmony_ci				file_type = DT_DIR;
95262306a36Sopenharmony_ci			else if (S_ISREG(le16_to_cpu(
95362306a36Sopenharmony_ci					 dentry_group->nsl[j].i_mode)))
95462306a36Sopenharmony_ci				file_type = DT_REG;
95562306a36Sopenharmony_ci			else if (S_ISLNK(le16_to_cpu(
95662306a36Sopenharmony_ci					 dentry_group->nsl[j].i_mode)))
95762306a36Sopenharmony_ci				file_type = DT_LNK;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci			strncat(dentry_name, dentry_group->filename[j], len);
96062306a36Sopenharmony_ci			pos = hmdfs_set_pos(dev_id, i, j);
96162306a36Sopenharmony_ci			is_continue =
96262306a36Sopenharmony_ci				dir_emit(ctx, dentry_name, len,
96362306a36Sopenharmony_ci					 pos + INUNUMBER_START, file_type);
96462306a36Sopenharmony_ci			if (!is_continue) {
96562306a36Sopenharmony_ci				ctx->pos = pos;
96662306a36Sopenharmony_ci				iterate_result = 1;
96762306a36Sopenharmony_ci				goto done;
96862306a36Sopenharmony_ci			}
96962306a36Sopenharmony_ci		}
97062306a36Sopenharmony_ci		offset = 0;
97162306a36Sopenharmony_ci	}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_cidone:
97462306a36Sopenharmony_ci	kfree(dentry_name);
97562306a36Sopenharmony_ci	kfree(dentry_group);
97662306a36Sopenharmony_ci	return iterate_result;
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ciint hmdfs_dev_readdir_from_con(struct hmdfs_peer *con, struct file *file,
98062306a36Sopenharmony_ci			       struct dir_context *ctx)
98162306a36Sopenharmony_ci{
98262306a36Sopenharmony_ci	int iterate_result = 0;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	iterate_result = analysis_dentry_file_from_con(
98562306a36Sopenharmony_ci		con->sbi, file, file->private_data, ctx);
98662306a36Sopenharmony_ci	return iterate_result;
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic int hmdfs_iterate_remote(struct file *file, struct dir_context *ctx)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	int err = 0;
99262306a36Sopenharmony_ci	loff_t start_pos = ctx->pos;
99362306a36Sopenharmony_ci	struct hmdfs_peer *con = NULL;
99462306a36Sopenharmony_ci	struct hmdfs_dentry_info *di = hmdfs_d(file->f_path.dentry);
99562306a36Sopenharmony_ci	bool is_local = !((ctx->pos) >> (POS_BIT_NUM - 1));
99662306a36Sopenharmony_ci	uint64_t dev_id = di->device_id;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	if (ctx->pos == -1)
99962306a36Sopenharmony_ci		return 0;
100062306a36Sopenharmony_ci	if (is_local)
100162306a36Sopenharmony_ci		ctx->pos = hmdfs_set_pos(dev_id, 0, 0);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	con = hmdfs_lookup_from_devid(file->f_inode->i_sb->s_fs_info, dev_id);
100462306a36Sopenharmony_ci	if (con) {
100562306a36Sopenharmony_ci		// ctx->pos = 0;
100662306a36Sopenharmony_ci		err = hmdfs_dev_readdir_from_con(con, file, ctx);
100762306a36Sopenharmony_ci		if (unlikely(!con)) {
100862306a36Sopenharmony_ci			hmdfs_err("con is null");
100962306a36Sopenharmony_ci			goto done;
101062306a36Sopenharmony_ci		}
101162306a36Sopenharmony_ci		peer_put(con);
101262306a36Sopenharmony_ci		if (err)
101362306a36Sopenharmony_ci			goto done;
101462306a36Sopenharmony_ci	}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_cidone:
101762306a36Sopenharmony_ci	if (err <= 0)
101862306a36Sopenharmony_ci		ctx->pos = -1;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	trace_hmdfs_iterate_remote(file->f_path.dentry, start_pos, ctx->pos,
102162306a36Sopenharmony_ci				   err);
102262306a36Sopenharmony_ci	return err;
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ciint hmdfs_dir_open_remote(struct inode *inode, struct file *file)
102662306a36Sopenharmony_ci{
102762306a36Sopenharmony_ci	struct hmdfs_inode_info *info = hmdfs_i(inode);
102862306a36Sopenharmony_ci	struct clearcache_item *cache_item = NULL;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (info->conn) {
103162306a36Sopenharmony_ci		if (!hmdfs_cache_revalidate(READ_ONCE(info->conn->conn_time),
103262306a36Sopenharmony_ci					    info->conn->device_id,
103362306a36Sopenharmony_ci					    file->f_path.dentry))
103462306a36Sopenharmony_ci			get_remote_dentry_file_sync(file->f_path.dentry,
103562306a36Sopenharmony_ci						    info->conn);
103662306a36Sopenharmony_ci		cache_item = hmdfs_find_cache_item(info->conn->device_id,
103762306a36Sopenharmony_ci						   file->f_path.dentry);
103862306a36Sopenharmony_ci		if (cache_item) {
103962306a36Sopenharmony_ci			file->private_data = cache_item->filp;
104062306a36Sopenharmony_ci			get_file(file->private_data);
104162306a36Sopenharmony_ci			kref_put(&cache_item->ref, release_cache_item);
104262306a36Sopenharmony_ci			return 0;
104362306a36Sopenharmony_ci		}
104462306a36Sopenharmony_ci		return -ENOENT;
104562306a36Sopenharmony_ci	}
104662306a36Sopenharmony_ci	return -ENOENT;
104762306a36Sopenharmony_ci}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_cistatic int hmdfs_dir_release_remote(struct inode *inode, struct file *file)
105062306a36Sopenharmony_ci{
105162306a36Sopenharmony_ci	if (file->private_data)
105262306a36Sopenharmony_ci		fput(file->private_data);
105362306a36Sopenharmony_ci	file->private_data = NULL;
105462306a36Sopenharmony_ci	return 0;
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ciconst struct file_operations hmdfs_dev_dir_ops_remote = {
105862306a36Sopenharmony_ci	.owner = THIS_MODULE,
105962306a36Sopenharmony_ci	.iterate_shared = hmdfs_iterate_remote,
106062306a36Sopenharmony_ci	.open = hmdfs_dir_open_remote,
106162306a36Sopenharmony_ci	.release = hmdfs_dir_release_remote,
106262306a36Sopenharmony_ci	.fsync = __generic_file_fsync,
106362306a36Sopenharmony_ci};
1064