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