162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/hmdfs/inode_remote.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/fs_stack.h> 962306a36Sopenharmony_ci#include <linux/namei.h> 1062306a36Sopenharmony_ci#include <linux/xattr.h> 1162306a36Sopenharmony_ci#include <linux/string.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "comm/socket_adapter.h" 1462306a36Sopenharmony_ci#include "hmdfs.h" 1562306a36Sopenharmony_ci#include "hmdfs_client.h" 1662306a36Sopenharmony_ci#include "hmdfs_dentryfile.h" 1762306a36Sopenharmony_ci#include "hmdfs_share.h" 1862306a36Sopenharmony_ci#include "hmdfs_trace.h" 1962306a36Sopenharmony_ci#include "authority/authentication.h" 2062306a36Sopenharmony_ci#include "stash.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct hmdfs_lookup_ret *lookup_remote_dentry(struct dentry *child_dentry, 2362306a36Sopenharmony_ci const struct qstr *qstr, 2462306a36Sopenharmony_ci uint64_t dev_id) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct hmdfs_lookup_ret *lookup_ret; 2762306a36Sopenharmony_ci struct hmdfs_dentry *dentry = NULL; 2862306a36Sopenharmony_ci struct clearcache_item *cache_item = NULL; 2962306a36Sopenharmony_ci struct hmdfs_dcache_lookup_ctx ctx; 3062306a36Sopenharmony_ci struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci cache_item = hmdfs_find_cache_item(dev_id, child_dentry->d_parent); 3362306a36Sopenharmony_ci if (!cache_item) 3462306a36Sopenharmony_ci return NULL; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci lookup_ret = kmalloc(sizeof(*lookup_ret), GFP_KERNEL); 3762306a36Sopenharmony_ci if (!lookup_ret) 3862306a36Sopenharmony_ci goto out; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci hmdfs_init_dcache_lookup_ctx(&ctx, sbi, qstr, cache_item->filp); 4162306a36Sopenharmony_ci dentry = hmdfs_find_dentry(child_dentry, &ctx); 4262306a36Sopenharmony_ci if (!dentry) { 4362306a36Sopenharmony_ci kfree(lookup_ret); 4462306a36Sopenharmony_ci lookup_ret = NULL; 4562306a36Sopenharmony_ci goto out; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci lookup_ret->i_mode = le16_to_cpu(dentry->i_mode); 4962306a36Sopenharmony_ci lookup_ret->i_size = le64_to_cpu(dentry->i_size); 5062306a36Sopenharmony_ci lookup_ret->i_mtime = le64_to_cpu(dentry->i_mtime); 5162306a36Sopenharmony_ci lookup_ret->i_mtime_nsec = le32_to_cpu(dentry->i_mtime_nsec); 5262306a36Sopenharmony_ci lookup_ret->i_ino = le64_to_cpu(dentry->i_ino); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci hmdfs_unlock_file(ctx.filp, get_dentry_group_pos(ctx.bidx), 5562306a36Sopenharmony_ci DENTRYGROUP_SIZE); 5662306a36Sopenharmony_ci kfree(ctx.page); 5762306a36Sopenharmony_ciout: 5862306a36Sopenharmony_ci kref_put(&cache_item->ref, release_cache_item); 5962306a36Sopenharmony_ci return lookup_ret; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* get_remote_inode_info - fill hmdfs_lookup_ret by info from remote getattr 6362306a36Sopenharmony_ci * 6462306a36Sopenharmony_ci * @dentry: local dentry 6562306a36Sopenharmony_ci * @hmdfs_peer: which remote devcie 6662306a36Sopenharmony_ci * @flags: lookup flags 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * return allocaed and initialized hmdfs_lookup_ret on success, and NULL on 6962306a36Sopenharmony_ci * failure. 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_cistruct hmdfs_lookup_ret *get_remote_inode_info(struct hmdfs_peer *con, 7262306a36Sopenharmony_ci struct dentry *dentry, 7362306a36Sopenharmony_ci unsigned int flags) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci int err = 0; 7662306a36Sopenharmony_ci struct hmdfs_lookup_ret *lookup_ret = NULL; 7762306a36Sopenharmony_ci struct hmdfs_getattr_ret *getattr_ret = NULL; 7862306a36Sopenharmony_ci unsigned int expected_flags = 0; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci lookup_ret = kmalloc(sizeof(*lookup_ret), GFP_KERNEL); 8162306a36Sopenharmony_ci if (!lookup_ret) 8262306a36Sopenharmony_ci return NULL; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci err = hmdfs_remote_getattr(con, dentry, flags, &getattr_ret); 8562306a36Sopenharmony_ci if (err) { 8662306a36Sopenharmony_ci hmdfs_debug("inode info get failed with err %d", err); 8762306a36Sopenharmony_ci kfree(lookup_ret); 8862306a36Sopenharmony_ci return NULL; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci /* make sure we got everything we need */ 9162306a36Sopenharmony_ci expected_flags = STATX_INO | STATX_SIZE | STATX_MODE | STATX_MTIME; 9262306a36Sopenharmony_ci if ((getattr_ret->stat.result_mask & expected_flags) != 9362306a36Sopenharmony_ci expected_flags) { 9462306a36Sopenharmony_ci hmdfs_debug("remote getattr failed with flag %x", 9562306a36Sopenharmony_ci getattr_ret->stat.result_mask); 9662306a36Sopenharmony_ci kfree(lookup_ret); 9762306a36Sopenharmony_ci kfree(getattr_ret); 9862306a36Sopenharmony_ci return NULL; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci lookup_ret->i_mode = getattr_ret->stat.mode; 10262306a36Sopenharmony_ci lookup_ret->i_size = getattr_ret->stat.size; 10362306a36Sopenharmony_ci lookup_ret->i_mtime = getattr_ret->stat.mtime.tv_sec; 10462306a36Sopenharmony_ci lookup_ret->i_mtime_nsec = getattr_ret->stat.mtime.tv_nsec; 10562306a36Sopenharmony_ci lookup_ret->i_ino = getattr_ret->stat.ino; 10662306a36Sopenharmony_ci kfree(getattr_ret); 10762306a36Sopenharmony_ci return lookup_ret; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void hmdfs_remote_readdir_work(struct work_struct *work) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct hmdfs_readdir_work *rw = 11362306a36Sopenharmony_ci container_of(to_delayed_work(work), struct hmdfs_readdir_work, 11462306a36Sopenharmony_ci dwork); 11562306a36Sopenharmony_ci struct dentry *dentry = rw->dentry; 11662306a36Sopenharmony_ci struct hmdfs_peer *con = rw->con; 11762306a36Sopenharmony_ci const struct cred *old_cred = hmdfs_override_creds(con->sbi->cred); 11862306a36Sopenharmony_ci bool empty = false; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci get_remote_dentry_file(dentry, con); 12162306a36Sopenharmony_ci hmdfs_d(dentry)->async_readdir_in_progress = 0; 12262306a36Sopenharmony_ci hmdfs_revert_creds(old_cred); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci spin_lock(&con->sbi->async_readdir_work_lock); 12562306a36Sopenharmony_ci list_del(&rw->head); 12662306a36Sopenharmony_ci empty = list_empty(&con->sbi->async_readdir_work_list); 12762306a36Sopenharmony_ci spin_unlock(&con->sbi->async_readdir_work_lock); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci dput(dentry); 13062306a36Sopenharmony_ci peer_put(con); 13162306a36Sopenharmony_ci kfree(rw); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (empty) 13462306a36Sopenharmony_ci wake_up_interruptible(&con->sbi->async_readdir_wq); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic void get_remote_dentry_file_in_wq(struct dentry *dentry, 13862306a36Sopenharmony_ci struct hmdfs_peer *con) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct hmdfs_readdir_work *rw = NULL; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* do nothing if async readdir is already in progress */ 14362306a36Sopenharmony_ci if (cmpxchg_relaxed(&hmdfs_d(dentry)->async_readdir_in_progress, 0, 14462306a36Sopenharmony_ci 1)) 14562306a36Sopenharmony_ci return; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci rw = kmalloc(sizeof(*rw), GFP_KERNEL); 14862306a36Sopenharmony_ci if (!rw) { 14962306a36Sopenharmony_ci hmdfs_d(dentry)->async_readdir_in_progress = 0; 15062306a36Sopenharmony_ci return; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci dget(dentry); 15462306a36Sopenharmony_ci peer_get(con); 15562306a36Sopenharmony_ci rw->dentry = dentry; 15662306a36Sopenharmony_ci rw->con = con; 15762306a36Sopenharmony_ci spin_lock(&con->sbi->async_readdir_work_lock); 15862306a36Sopenharmony_ci INIT_DELAYED_WORK(&rw->dwork, hmdfs_remote_readdir_work); 15962306a36Sopenharmony_ci list_add(&rw->head, &con->sbi->async_readdir_work_list); 16062306a36Sopenharmony_ci spin_unlock(&con->sbi->async_readdir_work_lock); 16162306a36Sopenharmony_ci queue_delayed_work(con->dentry_wq, &rw->dwork, 0); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_civoid get_remote_dentry_file_sync(struct dentry *dentry, struct hmdfs_peer *con) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci get_remote_dentry_file_in_wq(dentry, con); 16762306a36Sopenharmony_ci flush_workqueue(con->dentry_wq); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistruct hmdfs_lookup_ret *hmdfs_lookup_by_con(struct hmdfs_peer *con, 17162306a36Sopenharmony_ci struct dentry *dentry, 17262306a36Sopenharmony_ci struct qstr *qstr, 17362306a36Sopenharmony_ci unsigned int flags, 17462306a36Sopenharmony_ci const char *relative_path) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct hmdfs_lookup_ret *result = NULL; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * LOOKUP_REVAL means we found stale info from dentry file, thus 18062306a36Sopenharmony_ci * we need to use remote getattr. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci if (flags & LOOKUP_REVAL) { 18362306a36Sopenharmony_ci /* 18462306a36Sopenharmony_ci * HMDFS_LOOKUP_REVAL means we need to skip dentry cache 18562306a36Sopenharmony_ci * in lookup, because dentry cache in server might have 18662306a36Sopenharmony_ci * stale data. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci result = get_remote_inode_info(con, dentry, 18962306a36Sopenharmony_ci HMDFS_LOOKUP_REVAL); 19062306a36Sopenharmony_ci get_remote_dentry_file_in_wq(dentry->d_parent, con); 19162306a36Sopenharmony_ci return result; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* If cache file is still valid */ 19562306a36Sopenharmony_ci if (hmdfs_cache_revalidate(READ_ONCE(con->conn_time), 19662306a36Sopenharmony_ci con->device_id, dentry->d_parent)) { 19762306a36Sopenharmony_ci result = lookup_remote_dentry(dentry, qstr, 19862306a36Sopenharmony_ci con->device_id); 19962306a36Sopenharmony_ci /* 20062306a36Sopenharmony_ci * If lookup from cache file failed, use getattr to see 20162306a36Sopenharmony_ci * if remote have created the file. 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci if (!(flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) && 20462306a36Sopenharmony_ci !result) 20562306a36Sopenharmony_ci result = get_remote_inode_info(con, dentry, 0); 20662306a36Sopenharmony_ci /* If cache file expired, use getattr directly 20762306a36Sopenharmony_ci * except create and rename opt 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_ci } else { 21062306a36Sopenharmony_ci result = get_remote_inode_info(con, dentry, 0); 21162306a36Sopenharmony_ci get_remote_dentry_file_in_wq(dentry->d_parent, con); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return result; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* 21862306a36Sopenharmony_ci * hmdfs_update_inode_size - update inode size when finding aready existed 21962306a36Sopenharmony_ci * inode. 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci * First of all, if the file is opened for writing, we don't update inode size 22262306a36Sopenharmony_ci * here, because inode size is about to be changed after writing. 22362306a36Sopenharmony_ci * 22462306a36Sopenharmony_ci * If the file is not opened, simply update getattr_isize(not actual inode size, 22562306a36Sopenharmony_ci * just a value showed to user). This is safe because inode size will be 22662306a36Sopenharmony_ci * up-to-date after open. 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * If the file is opened for read: 22962306a36Sopenharmony_ci * a. getattr_isize == HMDFS_STALE_REMOTE_ISIZE 23062306a36Sopenharmony_ci * 1) i_size == new_size, nothing need to be done. 23162306a36Sopenharmony_ci * 2) i_size > new_size, we keep the i_size and set getattr_isize to new_size, 23262306a36Sopenharmony_ci * stale data might be readed in this case, which is fine because file is 23362306a36Sopenharmony_ci * opened before remote truncate the file. 23462306a36Sopenharmony_ci * 3) i_size < new_size, we drop the last page of the file if i_size is not 23562306a36Sopenharmony_ci * aligned to PAGE_SIZE, clear getattr_isize, and update i_size to 23662306a36Sopenharmony_ci * new_size. 23762306a36Sopenharmony_ci * b. getattr_isize != HMDFS_STALE_REMOTE_ISIZE, getattr_isize will only be set 23862306a36Sopenharmony_ci * after 2). 23962306a36Sopenharmony_ci * 4) getattr_isize > i_size, this situation is impossible. 24062306a36Sopenharmony_ci * 5) i_size >= new_size, this case is the same as 2). 24162306a36Sopenharmony_ci * 6) i_size < new_size, this case is the same as 3). 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_cistatic void hmdfs_update_inode_size(struct inode *inode, uint64_t new_size) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(inode); 24662306a36Sopenharmony_ci int writecount; 24762306a36Sopenharmony_ci uint64_t size; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci inode_lock(inode); 25062306a36Sopenharmony_ci size = info->getattr_isize; 25162306a36Sopenharmony_ci if (size == HMDFS_STALE_REMOTE_ISIZE) 25262306a36Sopenharmony_ci size = i_size_read(inode); 25362306a36Sopenharmony_ci if (size == new_size) { 25462306a36Sopenharmony_ci inode_unlock(inode); 25562306a36Sopenharmony_ci return; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci writecount = atomic_read(&inode->i_writecount); 25962306a36Sopenharmony_ci /* check if writing is in progress */ 26062306a36Sopenharmony_ci if (writecount > 0) { 26162306a36Sopenharmony_ci info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE; 26262306a36Sopenharmony_ci inode_unlock(inode); 26362306a36Sopenharmony_ci return; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* check if there is no one who opens the file */ 26762306a36Sopenharmony_ci if (kref_read(&info->ref) == 0) 26862306a36Sopenharmony_ci goto update_info; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* check if there is someone who opens the file for read */ 27162306a36Sopenharmony_ci if (writecount == 0) { 27262306a36Sopenharmony_ci uint64_t aligned_size; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* use inode size here instead of getattr_isize */ 27562306a36Sopenharmony_ci size = i_size_read(inode); 27662306a36Sopenharmony_ci if (new_size <= size) 27762306a36Sopenharmony_ci goto update_info; 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci * if the old inode size is not aligned to HMDFS_PAGE_SIZE, we 28062306a36Sopenharmony_ci * need to drop the last page of the inode, otherwise zero will 28162306a36Sopenharmony_ci * be returned while reading the new range in the page after 28262306a36Sopenharmony_ci * chaning inode size. 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci aligned_size = round_down(size, HMDFS_PAGE_SIZE); 28562306a36Sopenharmony_ci if (aligned_size != size) 28662306a36Sopenharmony_ci truncate_inode_pages(inode->i_mapping, aligned_size); 28762306a36Sopenharmony_ci i_size_write(inode, new_size); 28862306a36Sopenharmony_ci info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE; 28962306a36Sopenharmony_ci inode_unlock(inode); 29062306a36Sopenharmony_ci return; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ciupdate_info: 29462306a36Sopenharmony_ci info->getattr_isize = new_size; 29562306a36Sopenharmony_ci inode_unlock(inode); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic void hmdfs_update_inode(struct inode *inode, 29962306a36Sopenharmony_ci struct hmdfs_lookup_ret *lookup_result) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct hmdfs_time_t remote_mtime = { 30262306a36Sopenharmony_ci .tv_sec = lookup_result->i_mtime, 30362306a36Sopenharmony_ci .tv_nsec = lookup_result->i_mtime_nsec, 30462306a36Sopenharmony_ci }; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* 30762306a36Sopenharmony_ci * We only update mtime if the file is not opened for writing. If we do 30862306a36Sopenharmony_ci * update it before writing is about to start, user might see the mtime 30962306a36Sopenharmony_ci * up-and-down if system time in server and client do not match. However 31062306a36Sopenharmony_ci * mtime in client will eventually match server after timeout without 31162306a36Sopenharmony_ci * writing. 31262306a36Sopenharmony_ci */ 31362306a36Sopenharmony_ci if (!inode_is_open_for_write(inode)) 31462306a36Sopenharmony_ci inode->i_mtime = remote_mtime; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* 31762306a36Sopenharmony_ci * We don't care i_size of dir, and lock inode for dir 31862306a36Sopenharmony_ci * might cause deadlock. 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci if (S_ISREG(inode->i_mode)) 32162306a36Sopenharmony_ci hmdfs_update_inode_size(inode, lookup_result->i_size); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic void hmdfs_fill_inode_remote(struct inode *inode, struct inode *dir, 32562306a36Sopenharmony_ci umode_t mode) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci#ifdef CONFIG_HMDFS_FS_PERMISSION 32862306a36Sopenharmony_ci inode->i_uid = dir->i_uid; 32962306a36Sopenharmony_ci inode->i_gid = dir->i_gid; 33062306a36Sopenharmony_ci#endif 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistruct inode *fill_inode_remote(struct super_block *sb, struct hmdfs_peer *con, 33462306a36Sopenharmony_ci struct hmdfs_lookup_ret *res, struct inode *dir) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci int ret = 0; 33762306a36Sopenharmony_ci struct inode *inode = NULL; 33862306a36Sopenharmony_ci struct hmdfs_inode_info *info; 33962306a36Sopenharmony_ci umode_t mode = res->i_mode; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci inode = hmdfs_iget5_locked_remote(sb, con, res->i_ino); 34262306a36Sopenharmony_ci if (!inode) 34362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci info = hmdfs_i(inode); 34662306a36Sopenharmony_ci info->inode_type = HMDFS_LAYER_OTHER_REMOTE; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* the inode was found in cache */ 34962306a36Sopenharmony_ci if (!(inode->i_state & I_NEW)) { 35062306a36Sopenharmony_ci hmdfs_fill_inode_remote(inode, dir, mode); 35162306a36Sopenharmony_ci hmdfs_update_inode(inode, res); 35262306a36Sopenharmony_ci return inode; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci hmdfs_remote_init_stash_status(con, inode, mode); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci inode->__i_ctime.tv_sec = 0; 35862306a36Sopenharmony_ci inode->__i_ctime.tv_nsec = 0; 35962306a36Sopenharmony_ci inode->i_mtime.tv_sec = res->i_mtime; 36062306a36Sopenharmony_ci inode->i_mtime.tv_nsec = res->i_mtime_nsec; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci inode->i_uid = KUIDT_INIT((uid_t)1000); 36362306a36Sopenharmony_ci inode->i_gid = KGIDT_INIT((gid_t)1000); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (S_ISDIR(mode)) 36662306a36Sopenharmony_ci inode->i_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IXOTH; 36762306a36Sopenharmony_ci else if (S_ISREG(mode)) 36862306a36Sopenharmony_ci inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; 36962306a36Sopenharmony_ci else if (S_ISLNK(mode)) 37062306a36Sopenharmony_ci inode->i_mode = S_IFREG | S_IRWXU | S_IRWXG; 37162306a36Sopenharmony_ci else { 37262306a36Sopenharmony_ci ret = -EIO; 37362306a36Sopenharmony_ci goto bad_inode; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (S_ISREG(mode) || S_ISLNK(mode)) { 37762306a36Sopenharmony_ci inode->i_op = &hmdfs_dev_file_iops_remote; 37862306a36Sopenharmony_ci inode->i_fop = &hmdfs_dev_file_fops_remote; 37962306a36Sopenharmony_ci inode->i_size = res->i_size; 38062306a36Sopenharmony_ci set_nlink(inode, 1); 38162306a36Sopenharmony_ci } else if (S_ISDIR(mode)) { 38262306a36Sopenharmony_ci inode->i_op = &hmdfs_dev_dir_inode_ops_remote; 38362306a36Sopenharmony_ci inode->i_fop = &hmdfs_dev_dir_ops_remote; 38462306a36Sopenharmony_ci set_nlink(inode, 2); 38562306a36Sopenharmony_ci } else { 38662306a36Sopenharmony_ci ret = -EIO; 38762306a36Sopenharmony_ci goto bad_inode; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci inode->i_mapping->a_ops = &hmdfs_dev_file_aops_remote; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci hmdfs_fill_inode_remote(inode, dir, mode); 39362306a36Sopenharmony_ci unlock_new_inode(inode); 39462306a36Sopenharmony_ci return inode; 39562306a36Sopenharmony_cibad_inode: 39662306a36Sopenharmony_ci iget_failed(inode); 39762306a36Sopenharmony_ci return ERR_PTR(ret); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic struct dentry *hmdfs_lookup_remote_dentry(struct inode *parent_inode, 40162306a36Sopenharmony_ci struct dentry *child_dentry, 40262306a36Sopenharmony_ci int flags) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct dentry *ret = NULL; 40562306a36Sopenharmony_ci struct inode *inode = NULL; 40662306a36Sopenharmony_ci struct super_block *sb = parent_inode->i_sb; 40762306a36Sopenharmony_ci struct hmdfs_sb_info *sbi = sb->s_fs_info; 40862306a36Sopenharmony_ci struct hmdfs_lookup_ret *lookup_result = NULL; 40962306a36Sopenharmony_ci struct hmdfs_peer *con = NULL; 41062306a36Sopenharmony_ci char *file_name = NULL; 41162306a36Sopenharmony_ci int file_name_len = child_dentry->d_name.len; 41262306a36Sopenharmony_ci struct qstr qstr; 41362306a36Sopenharmony_ci struct hmdfs_dentry_info *gdi = hmdfs_d(child_dentry); 41462306a36Sopenharmony_ci uint64_t device_id = 0; 41562306a36Sopenharmony_ci char *relative_path = NULL; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci file_name = kzalloc(NAME_MAX + 1, GFP_KERNEL); 41862306a36Sopenharmony_ci if (!file_name) 41962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 42062306a36Sopenharmony_ci strncpy(file_name, child_dentry->d_name.name, file_name_len); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci qstr.name = file_name; 42362306a36Sopenharmony_ci qstr.len = strlen(file_name); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci device_id = gdi->device_id; 42662306a36Sopenharmony_ci con = hmdfs_lookup_from_devid(sbi, device_id); 42762306a36Sopenharmony_ci if (!con) { 42862306a36Sopenharmony_ci ret = ERR_PTR(-ESHUTDOWN); 42962306a36Sopenharmony_ci goto done; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci relative_path = hmdfs_get_dentry_relative_path(child_dentry->d_parent); 43362306a36Sopenharmony_ci if (unlikely(!relative_path)) { 43462306a36Sopenharmony_ci ret = ERR_PTR(-ENOMEM); 43562306a36Sopenharmony_ci hmdfs_err("get relative path failed %d", -ENOMEM); 43662306a36Sopenharmony_ci goto done; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci lookup_result = hmdfs_lookup_by_con(con, child_dentry, &qstr, flags, 44062306a36Sopenharmony_ci relative_path); 44162306a36Sopenharmony_ci if (lookup_result != NULL) { 44262306a36Sopenharmony_ci if (S_ISLNK(lookup_result->i_mode)) 44362306a36Sopenharmony_ci gdi->file_type = HM_SYMLINK; 44462306a36Sopenharmony_ci else if (in_share_dir(child_dentry)) 44562306a36Sopenharmony_ci gdi->file_type = HM_SHARE; 44662306a36Sopenharmony_ci inode = fill_inode_remote(sb, con, lookup_result, parent_inode); 44762306a36Sopenharmony_ci check_and_fixup_ownership_remote(parent_inode, 44862306a36Sopenharmony_ci inode, 44962306a36Sopenharmony_ci child_dentry); 45062306a36Sopenharmony_ci ret = d_splice_alias(inode, child_dentry); 45162306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(ret)) 45262306a36Sopenharmony_ci child_dentry = ret; 45362306a36Sopenharmony_ci } else { 45462306a36Sopenharmony_ci ret = ERR_PTR(-ENOENT); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cidone: 45862306a36Sopenharmony_ci if (con) 45962306a36Sopenharmony_ci peer_put(con); 46062306a36Sopenharmony_ci kfree(relative_path); 46162306a36Sopenharmony_ci kfree(lookup_result); 46262306a36Sopenharmony_ci kfree(file_name); 46362306a36Sopenharmony_ci return ret; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistruct dentry *hmdfs_lookup_remote(struct inode *parent_inode, 46762306a36Sopenharmony_ci struct dentry *child_dentry, 46862306a36Sopenharmony_ci unsigned int flags) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci int err = 0; 47162306a36Sopenharmony_ci struct dentry *ret = NULL; 47262306a36Sopenharmony_ci struct hmdfs_dentry_info *gdi = NULL; 47362306a36Sopenharmony_ci struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci trace_hmdfs_lookup_remote(parent_inode, child_dentry, flags); 47662306a36Sopenharmony_ci if (child_dentry->d_name.len > NAME_MAX) { 47762306a36Sopenharmony_ci err = -ENAMETOOLONG; 47862306a36Sopenharmony_ci ret = ERR_PTR(-ENAMETOOLONG); 47962306a36Sopenharmony_ci goto out; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci err = init_hmdfs_dentry_info(sbi, child_dentry, 48362306a36Sopenharmony_ci HMDFS_LAYER_OTHER_REMOTE); 48462306a36Sopenharmony_ci if (err) { 48562306a36Sopenharmony_ci ret = ERR_PTR(err); 48662306a36Sopenharmony_ci goto out; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci gdi = hmdfs_d(child_dentry); 48962306a36Sopenharmony_ci gdi->device_id = hmdfs_d(child_dentry->d_parent)->device_id; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (is_current_hmdfs_server_ctx()) 49262306a36Sopenharmony_ci goto out; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci ret = hmdfs_lookup_remote_dentry(parent_inode, child_dentry, flags); 49562306a36Sopenharmony_ci /* 49662306a36Sopenharmony_ci * don't return error if inode do not exist, so that vfs can continue 49762306a36Sopenharmony_ci * to create it. 49862306a36Sopenharmony_ci */ 49962306a36Sopenharmony_ci if (IS_ERR_OR_NULL(ret)) { 50062306a36Sopenharmony_ci err = PTR_ERR(ret); 50162306a36Sopenharmony_ci if (err == -ENOENT) 50262306a36Sopenharmony_ci ret = NULL; 50362306a36Sopenharmony_ci } else { 50462306a36Sopenharmony_ci child_dentry = ret; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ciout: 50862306a36Sopenharmony_ci if (!err) 50962306a36Sopenharmony_ci hmdfs_set_time(child_dentry, jiffies); 51062306a36Sopenharmony_ci trace_hmdfs_lookup_remote_end(parent_inode, child_dentry, err); 51162306a36Sopenharmony_ci return ret; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci/* delete dentry in cache file */ 51562306a36Sopenharmony_civoid delete_in_cache_file(uint64_t dev_id, struct dentry *dentry) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci struct clearcache_item *item = NULL; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci item = hmdfs_find_cache_item(dev_id, dentry->d_parent); 52062306a36Sopenharmony_ci if (item) { 52162306a36Sopenharmony_ci hmdfs_delete_dentry(dentry, item->filp); 52262306a36Sopenharmony_ci kref_put(&item->ref, release_cache_item); 52362306a36Sopenharmony_ci } else { 52462306a36Sopenharmony_ci hmdfs_info("find cache item failed, con:%llu", dev_id); 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ciint hmdfs_mkdir_remote_dentry(struct hmdfs_peer *conn, struct dentry *dentry, 52962306a36Sopenharmony_ci umode_t mode) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci int err = 0; 53262306a36Sopenharmony_ci char *dir_path = NULL; 53362306a36Sopenharmony_ci struct dentry *parent_dentry = dentry->d_parent; 53462306a36Sopenharmony_ci struct inode *parent_inode = d_inode(parent_dentry); 53562306a36Sopenharmony_ci struct super_block *sb = parent_inode->i_sb; 53662306a36Sopenharmony_ci const unsigned char *d_name = dentry->d_name.name; 53762306a36Sopenharmony_ci struct hmdfs_lookup_ret *mkdir_ret = NULL; 53862306a36Sopenharmony_ci struct inode *inode = NULL; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci mkdir_ret = kmalloc(sizeof(*mkdir_ret), GFP_KERNEL); 54162306a36Sopenharmony_ci if (!mkdir_ret) { 54262306a36Sopenharmony_ci err = -ENOMEM; 54362306a36Sopenharmony_ci return err; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci dir_path = hmdfs_get_dentry_relative_path(parent_dentry); 54662306a36Sopenharmony_ci if (!dir_path) { 54762306a36Sopenharmony_ci err = -EACCES; 54862306a36Sopenharmony_ci goto mkdir_out; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci err = hmdfs_client_start_mkdir(conn, dir_path, d_name, mode, mkdir_ret); 55162306a36Sopenharmony_ci if (err) { 55262306a36Sopenharmony_ci hmdfs_err("hmdfs_client_start_mkdir failed err = %d", err); 55362306a36Sopenharmony_ci goto mkdir_out; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci if (mkdir_ret) { 55662306a36Sopenharmony_ci inode = fill_inode_remote(sb, conn, mkdir_ret, parent_inode); 55762306a36Sopenharmony_ci check_and_fixup_ownership_remote(parent_inode, 55862306a36Sopenharmony_ci inode, 55962306a36Sopenharmony_ci dentry); 56062306a36Sopenharmony_ci if (!IS_ERR(inode)) 56162306a36Sopenharmony_ci d_add(dentry, inode); 56262306a36Sopenharmony_ci else 56362306a36Sopenharmony_ci err = PTR_ERR(inode); 56462306a36Sopenharmony_ci } else { 56562306a36Sopenharmony_ci err = -ENOENT; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cimkdir_out: 56962306a36Sopenharmony_ci kfree(dir_path); 57062306a36Sopenharmony_ci kfree(mkdir_ret); 57162306a36Sopenharmony_ci return err; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ciint hmdfs_mkdir_remote(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci int err = 0; 57762306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(dir); 57862306a36Sopenharmony_ci struct hmdfs_peer *con = info->conn; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (!con) { 58162306a36Sopenharmony_ci hmdfs_warning("qpb_debug: con is null!"); 58262306a36Sopenharmony_ci goto out; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci err = hmdfs_mkdir_remote_dentry(con, dentry, mode); 58662306a36Sopenharmony_ci if (!err) 58762306a36Sopenharmony_ci create_in_cache_file(con->device_id, dentry); 58862306a36Sopenharmony_ci else 58962306a36Sopenharmony_ci hmdfs_err("remote mkdir failed err = %d", err); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ciout: 59262306a36Sopenharmony_ci trace_hmdfs_mkdir_remote(dir, dentry, err); 59362306a36Sopenharmony_ci return err; 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ciint hmdfs_create_remote_dentry(struct hmdfs_peer *conn, struct dentry *dentry, 59762306a36Sopenharmony_ci umode_t mode, bool want_excl) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci int err = 0; 60062306a36Sopenharmony_ci char *dir_path = NULL; 60162306a36Sopenharmony_ci struct dentry *parent_dentry = dentry->d_parent; 60262306a36Sopenharmony_ci struct inode *parent_inode = d_inode(parent_dentry); 60362306a36Sopenharmony_ci struct super_block *sb = parent_inode->i_sb; 60462306a36Sopenharmony_ci const unsigned char *d_name = dentry->d_name.name; 60562306a36Sopenharmony_ci struct hmdfs_lookup_ret *create_ret = NULL; 60662306a36Sopenharmony_ci struct inode *inode = NULL; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci create_ret = kmalloc(sizeof(*create_ret), GFP_KERNEL); 60962306a36Sopenharmony_ci if (!create_ret) { 61062306a36Sopenharmony_ci err = -ENOMEM; 61162306a36Sopenharmony_ci return err; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci dir_path = hmdfs_get_dentry_relative_path(parent_dentry); 61462306a36Sopenharmony_ci if (!dir_path) { 61562306a36Sopenharmony_ci err = -EACCES; 61662306a36Sopenharmony_ci goto create_out; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci err = hmdfs_client_start_create(conn, dir_path, d_name, mode, 61962306a36Sopenharmony_ci want_excl, create_ret); 62062306a36Sopenharmony_ci if (err) { 62162306a36Sopenharmony_ci hmdfs_err("hmdfs_client_start_create failed err = %d", err); 62262306a36Sopenharmony_ci goto create_out; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci if (create_ret) { 62562306a36Sopenharmony_ci inode = fill_inode_remote(sb, conn, create_ret, parent_inode); 62662306a36Sopenharmony_ci check_and_fixup_ownership_remote(parent_inode, 62762306a36Sopenharmony_ci inode, 62862306a36Sopenharmony_ci dentry); 62962306a36Sopenharmony_ci if (!IS_ERR(inode)) 63062306a36Sopenharmony_ci d_add(dentry, inode); 63162306a36Sopenharmony_ci else 63262306a36Sopenharmony_ci err = PTR_ERR(inode); 63362306a36Sopenharmony_ci } else { 63462306a36Sopenharmony_ci err = -ENOENT; 63562306a36Sopenharmony_ci hmdfs_err("get remote inode info failed err = %d", err); 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cicreate_out: 63962306a36Sopenharmony_ci kfree(dir_path); 64062306a36Sopenharmony_ci kfree(create_ret); 64162306a36Sopenharmony_ci return err; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ciint hmdfs_create_remote(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, 64562306a36Sopenharmony_ci bool want_excl) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci int err = 0; 64862306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(dir); 64962306a36Sopenharmony_ci struct hmdfs_peer *con = info->conn; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (!con) { 65262306a36Sopenharmony_ci hmdfs_warning("qpb_debug: con is null!"); 65362306a36Sopenharmony_ci goto out; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci err = hmdfs_create_remote_dentry(con, dentry, mode, want_excl); 65762306a36Sopenharmony_ci if (!err) 65862306a36Sopenharmony_ci create_in_cache_file(con->device_id, dentry); 65962306a36Sopenharmony_ci else 66062306a36Sopenharmony_ci hmdfs_err("remote create failed err = %d", err); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ciout: 66362306a36Sopenharmony_ci trace_hmdfs_create_remote(dir, dentry, err); 66462306a36Sopenharmony_ci return err; 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ciint hmdfs_rmdir_remote_dentry(struct hmdfs_peer *conn, struct dentry *dentry) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci int error = 0; 67062306a36Sopenharmony_ci char *dir_path = NULL; 67162306a36Sopenharmony_ci const char *dentry_name = dentry->d_name.name; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci dir_path = hmdfs_get_dentry_relative_path(dentry->d_parent); 67462306a36Sopenharmony_ci if (!dir_path) { 67562306a36Sopenharmony_ci error = -EACCES; 67662306a36Sopenharmony_ci goto rmdir_out; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci error = hmdfs_client_start_rmdir(conn, dir_path, dentry_name); 68062306a36Sopenharmony_ci if (!error) 68162306a36Sopenharmony_ci delete_in_cache_file(conn->device_id, dentry); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cirmdir_out: 68462306a36Sopenharmony_ci kfree(dir_path); 68562306a36Sopenharmony_ci return error; 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ciint hmdfs_rmdir_remote(struct inode *dir, struct dentry *dentry) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci int err = 0; 69162306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(dentry->d_inode); 69262306a36Sopenharmony_ci struct hmdfs_peer *con = info->conn; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (!con) 69562306a36Sopenharmony_ci goto out; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) { 69862306a36Sopenharmony_ci err = -EACCES; 69962306a36Sopenharmony_ci goto out; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci err = hmdfs_rmdir_remote_dentry(con, dentry); 70362306a36Sopenharmony_ci /* drop dentry even remote failed 70462306a36Sopenharmony_ci * it maybe cause that one remote devices disconnect 70562306a36Sopenharmony_ci * when doing remote rmdir 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci d_drop(dentry); 70862306a36Sopenharmony_ciout: 70962306a36Sopenharmony_ci /* return connect device's errcode */ 71062306a36Sopenharmony_ci trace_hmdfs_rmdir_remote(dir, dentry, err); 71162306a36Sopenharmony_ci return err; 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ciint hmdfs_dev_unlink_from_con(struct hmdfs_peer *conn, struct dentry *dentry) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci int error = 0; 71762306a36Sopenharmony_ci char *dir_path = NULL; 71862306a36Sopenharmony_ci const char *dentry_name = dentry->d_name.name; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci dir_path = hmdfs_get_dentry_relative_path(dentry->d_parent); 72162306a36Sopenharmony_ci if (!dir_path) { 72262306a36Sopenharmony_ci error = -EACCES; 72362306a36Sopenharmony_ci goto unlink_out; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci error = hmdfs_client_start_unlink(conn, dir_path, dentry_name); 72662306a36Sopenharmony_ci if (!error) { 72762306a36Sopenharmony_ci delete_in_cache_file(conn->device_id, dentry); 72862306a36Sopenharmony_ci drop_nlink(d_inode(dentry)); 72962306a36Sopenharmony_ci d_drop(dentry); 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ciunlink_out: 73262306a36Sopenharmony_ci kfree(dir_path); 73362306a36Sopenharmony_ci return error; 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ciint hmdfs_unlink_remote(struct inode *dir, struct dentry *dentry) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(dentry->d_inode); 73962306a36Sopenharmony_ci struct hmdfs_peer *conn = info->conn; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) 74262306a36Sopenharmony_ci return -EACCES; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (!conn) 74562306a36Sopenharmony_ci return 0; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (conn->status != NODE_STAT_ONLINE) 74862306a36Sopenharmony_ci return 0; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci return hmdfs_dev_unlink_from_con(conn, dentry); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci/* rename dentry in cache file */ 75462306a36Sopenharmony_cistatic void rename_in_cache_file(uint64_t dev_id, struct dentry *old_dentry, 75562306a36Sopenharmony_ci struct dentry *new_dentry) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci struct clearcache_item *old_item = NULL; 75862306a36Sopenharmony_ci struct clearcache_item *new_item = NULL; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci old_item = hmdfs_find_cache_item(dev_id, old_dentry->d_parent); 76162306a36Sopenharmony_ci new_item = hmdfs_find_cache_item(dev_id, new_dentry->d_parent); 76262306a36Sopenharmony_ci if (old_item != NULL && new_item != NULL) { 76362306a36Sopenharmony_ci hmdfs_rename_dentry(old_dentry, new_dentry, old_item->filp, 76462306a36Sopenharmony_ci new_item->filp); 76562306a36Sopenharmony_ci } else if (old_item != NULL) { 76662306a36Sopenharmony_ci hmdfs_err("new cache item find failed!"); 76762306a36Sopenharmony_ci } else if (new_item != NULL) { 76862306a36Sopenharmony_ci hmdfs_err("old cache item find failed!"); 76962306a36Sopenharmony_ci } else { 77062306a36Sopenharmony_ci hmdfs_err("both cache item find failed!"); 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (old_item) 77462306a36Sopenharmony_ci kref_put(&old_item->ref, release_cache_item); 77562306a36Sopenharmony_ci if (new_item) 77662306a36Sopenharmony_ci kref_put(&new_item->ref, release_cache_item); 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ciint hmdfs_rename_remote(struct mnt_idmap *idmap, struct inode *old_dir, struct dentry *old_dentry, 78062306a36Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry, 78162306a36Sopenharmony_ci unsigned int flags) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci int err = 0; 78462306a36Sopenharmony_ci int ret = 0; 78562306a36Sopenharmony_ci const char *old_dentry_d_name = old_dentry->d_name.name; 78662306a36Sopenharmony_ci char *relative_old_dir_path = 0; 78762306a36Sopenharmony_ci const char *new_dentry_d_name = new_dentry->d_name.name; 78862306a36Sopenharmony_ci char *relative_new_dir_path = 0; 78962306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(old_dentry->d_inode); 79062306a36Sopenharmony_ci struct hmdfs_peer *con = info->conn; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci trace_hmdfs_rename_remote(old_dir, old_dentry, new_dir, new_dentry, 79362306a36Sopenharmony_ci flags); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (flags & ~RENAME_NOREPLACE) 79662306a36Sopenharmony_ci return -EINVAL; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (hmdfs_file_type(old_dentry->d_name.name) != HMDFS_TYPE_COMMON || 79962306a36Sopenharmony_ci hmdfs_file_type(new_dentry->d_name.name) != HMDFS_TYPE_COMMON) { 80062306a36Sopenharmony_ci return -EACCES; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (hmdfs_i(old_dir)->inode_type != hmdfs_i(new_dir)->inode_type) { 80462306a36Sopenharmony_ci hmdfs_err("in different view"); 80562306a36Sopenharmony_ci return -EPERM; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (hmdfs_d(old_dentry)->device_id != hmdfs_d(new_dentry)->device_id) 80962306a36Sopenharmony_ci return -EXDEV; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci relative_old_dir_path = 81262306a36Sopenharmony_ci hmdfs_get_dentry_relative_path(old_dentry->d_parent); 81362306a36Sopenharmony_ci relative_new_dir_path = 81462306a36Sopenharmony_ci hmdfs_get_dentry_relative_path(new_dentry->d_parent); 81562306a36Sopenharmony_ci if (!relative_old_dir_path || !relative_new_dir_path) { 81662306a36Sopenharmony_ci err = -EACCES; 81762306a36Sopenharmony_ci goto rename_out; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci if (S_ISREG(old_dentry->d_inode->i_mode)) { 82062306a36Sopenharmony_ci hmdfs_debug("send MSG to remote devID %llu", 82162306a36Sopenharmony_ci con->device_id); 82262306a36Sopenharmony_ci err = hmdfs_client_start_rename( 82362306a36Sopenharmony_ci con, relative_old_dir_path, old_dentry_d_name, 82462306a36Sopenharmony_ci relative_new_dir_path, new_dentry_d_name, 82562306a36Sopenharmony_ci flags); 82662306a36Sopenharmony_ci if (!err) 82762306a36Sopenharmony_ci rename_in_cache_file(con->device_id, old_dentry, 82862306a36Sopenharmony_ci new_dentry); 82962306a36Sopenharmony_ci } else if (S_ISDIR(old_dentry->d_inode->i_mode)) { 83062306a36Sopenharmony_ci if (con->status == NODE_STAT_ONLINE) { 83162306a36Sopenharmony_ci ret = hmdfs_client_start_rename( 83262306a36Sopenharmony_ci con, relative_old_dir_path, old_dentry_d_name, 83362306a36Sopenharmony_ci relative_new_dir_path, new_dentry_d_name, 83462306a36Sopenharmony_ci flags); 83562306a36Sopenharmony_ci if (!ret) 83662306a36Sopenharmony_ci rename_in_cache_file(con->device_id, old_dentry, 83762306a36Sopenharmony_ci new_dentry); 83862306a36Sopenharmony_ci else 83962306a36Sopenharmony_ci err = ret; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci if (!err) 84362306a36Sopenharmony_ci d_invalidate(old_dentry); 84462306a36Sopenharmony_cirename_out: 84562306a36Sopenharmony_ci kfree(relative_old_dir_path); 84662306a36Sopenharmony_ci kfree(relative_new_dir_path); 84762306a36Sopenharmony_ci return err; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int hmdfs_dir_setattr_remote(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *ia) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci // Do not support dir setattr 85362306a36Sopenharmony_ci return 0; 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ciconst struct inode_operations hmdfs_dev_dir_inode_ops_remote = { 85762306a36Sopenharmony_ci .lookup = hmdfs_lookup_remote, 85862306a36Sopenharmony_ci .mkdir = hmdfs_mkdir_remote, 85962306a36Sopenharmony_ci .create = hmdfs_create_remote, 86062306a36Sopenharmony_ci .rmdir = hmdfs_rmdir_remote, 86162306a36Sopenharmony_ci .unlink = hmdfs_unlink_remote, 86262306a36Sopenharmony_ci .rename = hmdfs_rename_remote, 86362306a36Sopenharmony_ci .setattr = hmdfs_dir_setattr_remote, 86462306a36Sopenharmony_ci .permission = hmdfs_permission, 86562306a36Sopenharmony_ci}; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic int hmdfs_setattr_remote(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *ia) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(d_inode(dentry)); 87062306a36Sopenharmony_ci struct hmdfs_peer *conn = info->conn; 87162306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 87262306a36Sopenharmony_ci char *send_buf = NULL; 87362306a36Sopenharmony_ci int err = 0; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (hmdfs_inode_is_stashing(info)) 87662306a36Sopenharmony_ci return -EAGAIN; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci send_buf = hmdfs_get_dentry_relative_path(dentry); 87962306a36Sopenharmony_ci if (!send_buf) { 88062306a36Sopenharmony_ci err = -ENOMEM; 88162306a36Sopenharmony_ci goto out_free; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci if (ia->ia_valid & ATTR_SIZE) { 88462306a36Sopenharmony_ci err = inode_newsize_ok(inode, ia->ia_size); 88562306a36Sopenharmony_ci if (err) 88662306a36Sopenharmony_ci goto out_free; 88762306a36Sopenharmony_ci truncate_setsize(inode, ia->ia_size); 88862306a36Sopenharmony_ci info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci if (ia->ia_valid & ATTR_MTIME) 89162306a36Sopenharmony_ci inode->i_mtime = ia->ia_mtime; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if ((ia->ia_valid & ATTR_SIZE) || (ia->ia_valid & ATTR_MTIME)) { 89462306a36Sopenharmony_ci struct setattr_info send_setattr_info = { 89562306a36Sopenharmony_ci .size = cpu_to_le64(ia->ia_size), 89662306a36Sopenharmony_ci .valid = cpu_to_le32(ia->ia_valid), 89762306a36Sopenharmony_ci .mtime = cpu_to_le64(ia->ia_mtime.tv_sec), 89862306a36Sopenharmony_ci .mtime_nsec = cpu_to_le32(ia->ia_mtime.tv_nsec), 89962306a36Sopenharmony_ci }; 90062306a36Sopenharmony_ci err = hmdfs_send_setattr(conn, send_buf, &send_setattr_info); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ciout_free: 90362306a36Sopenharmony_ci kfree(send_buf); 90462306a36Sopenharmony_ci return err; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ciint hmdfs_remote_getattr(struct hmdfs_peer *conn, struct dentry *dentry, 90862306a36Sopenharmony_ci unsigned int lookup_flags, 90962306a36Sopenharmony_ci struct hmdfs_getattr_ret **result) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci char *send_buf = NULL; 91262306a36Sopenharmony_ci struct hmdfs_getattr_ret *attr = NULL; 91362306a36Sopenharmony_ci int err = 0; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (dentry->d_sb != conn->sbi->sb || !result) 91662306a36Sopenharmony_ci return -EINVAL; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci attr = kzalloc(sizeof(*attr), GFP_KERNEL); 91962306a36Sopenharmony_ci if (!attr) 92062306a36Sopenharmony_ci return -ENOMEM; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci send_buf = hmdfs_get_dentry_relative_path(dentry); 92362306a36Sopenharmony_ci if (!send_buf) { 92462306a36Sopenharmony_ci kfree(attr); 92562306a36Sopenharmony_ci return -ENOMEM; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci err = hmdfs_send_getattr(conn, send_buf, lookup_flags, attr); 92962306a36Sopenharmony_ci kfree(send_buf); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (err) { 93262306a36Sopenharmony_ci kfree(attr); 93362306a36Sopenharmony_ci return err; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci *result = attr; 93762306a36Sopenharmony_ci return 0; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic int hmdfs_get_cached_attr_remote(struct mnt_idmap *idmap, const struct path *path, 94162306a36Sopenharmony_ci struct kstat *stat, u32 request_mask, 94262306a36Sopenharmony_ci unsigned int flags) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 94562306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(inode); 94662306a36Sopenharmony_ci uint64_t size = info->getattr_isize; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci stat->ino = inode->i_ino; 94962306a36Sopenharmony_ci stat->mtime = inode->i_mtime; 95062306a36Sopenharmony_ci stat->mode = inode->i_mode; 95162306a36Sopenharmony_ci stat->uid.val = inode->i_uid.val; 95262306a36Sopenharmony_ci stat->gid.val = inode->i_gid.val; 95362306a36Sopenharmony_ci if (size == HMDFS_STALE_REMOTE_ISIZE) 95462306a36Sopenharmony_ci size = i_size_read(inode); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci stat->size = size; 95762306a36Sopenharmony_ci return 0; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cissize_t hmdfs_remote_listxattr(struct dentry *dentry, char *list, size_t size) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 96362306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(inode); 96462306a36Sopenharmony_ci struct hmdfs_peer *conn = info->conn; 96562306a36Sopenharmony_ci char *send_buf = NULL; 96662306a36Sopenharmony_ci ssize_t res = 0; 96762306a36Sopenharmony_ci size_t r_size = size; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (!hmdfs_support_xattr(dentry)) 97062306a36Sopenharmony_ci return -EOPNOTSUPP; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (size > HMDFS_LISTXATTR_SIZE_MAX) 97362306a36Sopenharmony_ci r_size = HMDFS_LISTXATTR_SIZE_MAX; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci send_buf = hmdfs_get_dentry_relative_path(dentry); 97662306a36Sopenharmony_ci if (!send_buf) 97762306a36Sopenharmony_ci return -ENOMEM; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci res = hmdfs_send_listxattr(conn, send_buf, list, r_size); 98062306a36Sopenharmony_ci kfree(send_buf); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci if (res == -ERANGE && r_size != size) { 98362306a36Sopenharmony_ci hmdfs_info("no support listxattr size over than %d", 98462306a36Sopenharmony_ci HMDFS_LISTXATTR_SIZE_MAX); 98562306a36Sopenharmony_ci res = -E2BIG; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci return res; 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ciconst struct inode_operations hmdfs_dev_file_iops_remote = { 99262306a36Sopenharmony_ci .setattr = hmdfs_setattr_remote, 99362306a36Sopenharmony_ci .permission = hmdfs_permission, 99462306a36Sopenharmony_ci .getattr = hmdfs_get_cached_attr_remote, 99562306a36Sopenharmony_ci .listxattr = hmdfs_remote_listxattr, 99662306a36Sopenharmony_ci}; 997