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, ¶m->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(¶m->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