162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/hmdfs/main.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "hmdfs.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/ctype.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/statfs.h> 1462306a36Sopenharmony_ci#include <linux/xattr.h> 1562306a36Sopenharmony_ci#include <linux/idr.h> 1662306a36Sopenharmony_ci#if KERNEL_VERSION(5, 9, 0) < LINUX_VERSION_CODE 1762306a36Sopenharmony_ci#include <linux/prandom.h> 1862306a36Sopenharmony_ci#else 1962306a36Sopenharmony_ci#include <linux/random.h> 2062306a36Sopenharmony_ci#endif 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "authority/authentication.h" 2362306a36Sopenharmony_ci#include "hmdfs_server.h" 2462306a36Sopenharmony_ci#include "comm/device_node.h" 2562306a36Sopenharmony_ci#include "comm/message_verify.h" 2662306a36Sopenharmony_ci#include "comm/protocol.h" 2762306a36Sopenharmony_ci#include "comm/socket_adapter.h" 2862306a36Sopenharmony_ci#include "hmdfs_merge_view.h" 2962306a36Sopenharmony_ci#include "server_writeback.h" 3062306a36Sopenharmony_ci#include "hmdfs_share.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "comm/node_cb.h" 3362306a36Sopenharmony_ci#include "stash.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 3662306a36Sopenharmony_ci#include "hmdfs_trace.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define HMDFS_BOOT_COOKIE_RAND_SHIFT 33 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define HMDFS_SB_SEQ_FROM 1 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct hmdfs_mount_priv { 4362306a36Sopenharmony_ci const char *dev_name; 4462306a36Sopenharmony_ci const char *raw_data; 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct syncfs_item { 4862306a36Sopenharmony_ci struct list_head list; 4962306a36Sopenharmony_ci struct completion done; 5062306a36Sopenharmony_ci bool need_abort; 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic DEFINE_IDA(hmdfs_sb_seq); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic inline int hmdfs_alloc_sb_seq(void) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci return ida_simple_get(&hmdfs_sb_seq, HMDFS_SB_SEQ_FROM, 0, GFP_KERNEL); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic inline void hmdfs_free_sb_seq(unsigned int seq) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci if (!seq) 6362306a36Sopenharmony_ci return; 6462306a36Sopenharmony_ci ida_simple_remove(&hmdfs_sb_seq, seq); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int hmdfs_xattr_local_get(struct dentry *dentry, const char *name, 6862306a36Sopenharmony_ci void *value, size_t size) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct path lower_path; 7162306a36Sopenharmony_ci ssize_t res = 0; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci hmdfs_get_lower_path(dentry, &lower_path); 7462306a36Sopenharmony_ci res = vfs_getxattr(&nop_mnt_idmap, lower_path.dentry, name, value, size); 7562306a36Sopenharmony_ci hmdfs_put_lower_path(&lower_path); 7662306a36Sopenharmony_ci return res; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int hmdfs_xattr_remote_get(struct dentry *dentry, const char *name, 8062306a36Sopenharmony_ci void *value, size_t size) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 8362306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(inode); 8462306a36Sopenharmony_ci struct hmdfs_peer *conn = info->conn; 8562306a36Sopenharmony_ci char *send_buf = NULL; 8662306a36Sopenharmony_ci ssize_t res = 0; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci send_buf = hmdfs_get_dentry_relative_path(dentry); 8962306a36Sopenharmony_ci if (!send_buf) 9062306a36Sopenharmony_ci return -ENOMEM; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci res = hmdfs_send_getxattr(conn, send_buf, name, value, size); 9362306a36Sopenharmony_ci kfree(send_buf); 9462306a36Sopenharmony_ci return res; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int hmdfs_xattr_merge_get(struct dentry *dentry, const char *name, 9862306a36Sopenharmony_ci void *value, size_t size) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci int err = 0; 10162306a36Sopenharmony_ci struct dentry *lower_dentry = hmdfs_get_lo_d(dentry, HMDFS_DEVID_LOCAL); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (!lower_dentry) { 10462306a36Sopenharmony_ci err = -EOPNOTSUPP; 10562306a36Sopenharmony_ci goto out; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci err = hmdfs_xattr_local_get(lower_dentry, name, value, size); 10862306a36Sopenharmony_ciout: 10962306a36Sopenharmony_ci dput(lower_dentry); 11062306a36Sopenharmony_ci return err; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int hmdfs_xattr_get(const struct xattr_handler *handler, 11462306a36Sopenharmony_ci struct dentry *dentry, struct inode *inode, 11562306a36Sopenharmony_ci const char *name, void *value, size_t size) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci int res = 0; 11862306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(inode); 11962306a36Sopenharmony_ci size_t r_size = size; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (!hmdfs_support_xattr(dentry)) 12262306a36Sopenharmony_ci return -EOPNOTSUPP; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) 12562306a36Sopenharmony_ci return -EOPNOTSUPP; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (size > HMDFS_XATTR_SIZE_MAX) 12862306a36Sopenharmony_ci r_size = HMDFS_XATTR_SIZE_MAX; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (info->inode_type == HMDFS_LAYER_OTHER_LOCAL) 13162306a36Sopenharmony_ci res = hmdfs_xattr_local_get(dentry, name, value, r_size); 13262306a36Sopenharmony_ci else if (info->inode_type == HMDFS_LAYER_OTHER_REMOTE) 13362306a36Sopenharmony_ci res = hmdfs_xattr_remote_get(dentry, name, value, r_size); 13462306a36Sopenharmony_ci else if (info->inode_type == HMDFS_LAYER_OTHER_MERGE || 13562306a36Sopenharmony_ci info->inode_type == HMDFS_LAYER_OTHER_MERGE_CLOUD) 13662306a36Sopenharmony_ci res = hmdfs_xattr_merge_get(dentry, name, value, r_size); 13762306a36Sopenharmony_ci else 13862306a36Sopenharmony_ci res = -EOPNOTSUPP; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (res == -ERANGE && r_size != size) { 14162306a36Sopenharmony_ci hmdfs_info("no support xattr value size over than: %d", 14262306a36Sopenharmony_ci HMDFS_XATTR_SIZE_MAX); 14362306a36Sopenharmony_ci res = -E2BIG; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return res; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic int hmdfs_xattr_local_set(struct dentry *dentry, const char *name, 15062306a36Sopenharmony_ci const void *value, size_t size, int flags) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct path lower_path; 15362306a36Sopenharmony_ci int res = 0; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci hmdfs_get_lower_path(dentry, &lower_path); 15662306a36Sopenharmony_ci kuid_t tmp_uid = hmdfs_override_inode_uid(d_inode(lower_path.dentry)); 15762306a36Sopenharmony_ci if (value) { 15862306a36Sopenharmony_ci res = vfs_setxattr(&nop_mnt_idmap, lower_path.dentry, name, value, size, flags); 15962306a36Sopenharmony_ci } else { 16062306a36Sopenharmony_ci WARN_ON(flags != XATTR_REPLACE); 16162306a36Sopenharmony_ci res = vfs_removexattr(&nop_mnt_idmap, lower_path.dentry, name); 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci hmdfs_revert_inode_uid(d_inode(lower_path.dentry), tmp_uid); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci hmdfs_put_lower_path(&lower_path); 16662306a36Sopenharmony_ci return res; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int hmdfs_xattr_remote_set(struct dentry *dentry, const char *name, 17062306a36Sopenharmony_ci const void *value, size_t size, int flags) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 17362306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(inode); 17462306a36Sopenharmony_ci struct hmdfs_peer *conn = info->conn; 17562306a36Sopenharmony_ci char *send_buf = NULL; 17662306a36Sopenharmony_ci int res = 0; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci send_buf = hmdfs_get_dentry_relative_path(dentry); 17962306a36Sopenharmony_ci if (!send_buf) 18062306a36Sopenharmony_ci return -ENOMEM; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci res = hmdfs_send_setxattr(conn, send_buf, name, value, size, flags); 18362306a36Sopenharmony_ci kfree(send_buf); 18462306a36Sopenharmony_ci return res; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic int hmdfs_xattr_merge_set(struct dentry *dentry, const char *name, 18862306a36Sopenharmony_ci const void *value, size_t size, int flags) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci int err = 0; 19162306a36Sopenharmony_ci struct dentry *lower_dentry = hmdfs_get_lo_d(dentry, HMDFS_DEVID_LOCAL); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (!lower_dentry) { 19462306a36Sopenharmony_ci err = -EOPNOTSUPP; 19562306a36Sopenharmony_ci goto out; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci err = hmdfs_xattr_local_set(lower_dentry, name, value, size, flags); 19862306a36Sopenharmony_ciout: 19962306a36Sopenharmony_ci dput(lower_dentry); 20062306a36Sopenharmony_ci return err; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int hmdfs_xattr_set(const struct xattr_handler *handler, struct mnt_idmap *idmap, 20462306a36Sopenharmony_ci struct dentry *dentry, struct inode *inode, 20562306a36Sopenharmony_ci const char *name, const void *value, 20662306a36Sopenharmony_ci size_t size, int flags) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(inode); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (!hmdfs_support_xattr(dentry)) 21162306a36Sopenharmony_ci return -EOPNOTSUPP; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (size > HMDFS_XATTR_SIZE_MAX) { 21462306a36Sopenharmony_ci hmdfs_info("no support too long xattr value: %zu", size); 21562306a36Sopenharmony_ci return -E2BIG; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (info->inode_type == HMDFS_LAYER_OTHER_LOCAL) 21962306a36Sopenharmony_ci return hmdfs_xattr_local_set(dentry, name, value, size, flags); 22062306a36Sopenharmony_ci else if (info->inode_type == HMDFS_LAYER_OTHER_REMOTE) 22162306a36Sopenharmony_ci return hmdfs_xattr_remote_set(dentry, name, value, size, flags); 22262306a36Sopenharmony_ci else if (info->inode_type == HMDFS_LAYER_OTHER_MERGE || 22362306a36Sopenharmony_ci info->inode_type == HMDFS_LAYER_OTHER_MERGE_CLOUD) 22462306a36Sopenharmony_ci return hmdfs_xattr_merge_set(dentry, name, value, size, flags); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return -EOPNOTSUPP; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ciconst struct xattr_handler hmdfs_xattr_handler = { 23062306a36Sopenharmony_ci .prefix = "", /* catch all */ 23162306a36Sopenharmony_ci .get = hmdfs_xattr_get, 23262306a36Sopenharmony_ci .set = hmdfs_xattr_set, 23362306a36Sopenharmony_ci}; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic const struct xattr_handler *hmdfs_xattr_handlers[] = { 23662306a36Sopenharmony_ci &hmdfs_xattr_handler, 23762306a36Sopenharmony_ci}; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci#define HMDFS_NODE_EVT_CB_DELAY 2 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistruct kmem_cache *hmdfs_inode_cachep; 24262306a36Sopenharmony_cistruct kmem_cache *hmdfs_dentry_cachep; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic void i_callback(struct rcu_head *head) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct inode *inode = container_of(head, struct inode, i_rcu); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci kmem_cache_free(hmdfs_inode_cachep, 24962306a36Sopenharmony_ci container_of(inode, struct hmdfs_inode_info, 25062306a36Sopenharmony_ci vfs_inode)); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic void hmdfs_destroy_inode(struct inode *inode) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci call_rcu(&inode->i_rcu, i_callback); 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic void hmdfs_evict_inode(struct inode *inode) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(inode); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci truncate_inode_pages(&inode->i_data, 0); 26362306a36Sopenharmony_ci clear_inode(inode); 26462306a36Sopenharmony_ci if (info->inode_type == HMDFS_LAYER_FIRST_DEVICE || 26562306a36Sopenharmony_ci info->inode_type == HMDFS_LAYER_SECOND_REMOTE) 26662306a36Sopenharmony_ci return; 26762306a36Sopenharmony_ci if (info->inode_type == HMDFS_LAYER_ZERO || 26862306a36Sopenharmony_ci info->inode_type == HMDFS_LAYER_OTHER_LOCAL || 26962306a36Sopenharmony_ci info->inode_type == HMDFS_LAYER_SECOND_LOCAL) { 27062306a36Sopenharmony_ci iput(info->lower_inode); 27162306a36Sopenharmony_ci info->lower_inode = NULL; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_civoid hmdfs_put_super(struct super_block *sb) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct hmdfs_sb_info *sbi = hmdfs_sb(sb); 27862306a36Sopenharmony_ci struct super_block *lower_sb = sbi->lower_sb; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci hmdfs_info("local_dst is %s, local_src is %s", sbi->local_dst, 28162306a36Sopenharmony_ci sbi->local_src); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci hmdfs_cfn_destroy(sbi); 28462306a36Sopenharmony_ci hmdfs_unregister_sysfs(sbi); 28562306a36Sopenharmony_ci hmdfs_connections_stop(sbi); 28662306a36Sopenharmony_ci hmdfs_clear_share_table(sbi); 28762306a36Sopenharmony_ci hmdfs_destroy_server_writeback(sbi); 28862306a36Sopenharmony_ci hmdfs_exit_stash(sbi); 28962306a36Sopenharmony_ci atomic_dec(&lower_sb->s_active); 29062306a36Sopenharmony_ci put_cred(sbi->cred); 29162306a36Sopenharmony_ci if (sbi->system_cred) 29262306a36Sopenharmony_ci put_cred(sbi->system_cred); 29362306a36Sopenharmony_ci hmdfs_destroy_writeback(sbi); 29462306a36Sopenharmony_ci kfree(sbi->local_src); 29562306a36Sopenharmony_ci kfree(sbi->local_dst); 29662306a36Sopenharmony_ci kfree(sbi->real_dst); 29762306a36Sopenharmony_ci kfree(sbi->cache_dir); 29862306a36Sopenharmony_ci kfree(sbi->cloud_dir); 29962306a36Sopenharmony_ci kfifo_free(&sbi->notify_fifo); 30062306a36Sopenharmony_ci sb->s_fs_info = NULL; 30162306a36Sopenharmony_ci sbi->lower_sb = NULL; 30262306a36Sopenharmony_ci hmdfs_release_sysfs(sbi); 30362306a36Sopenharmony_ci /* After all access are completed */ 30462306a36Sopenharmony_ci hmdfs_free_sb_seq(sbi->seq); 30562306a36Sopenharmony_ci kfree(sbi->s_server_statis); 30662306a36Sopenharmony_ci kfree(sbi->s_client_statis); 30762306a36Sopenharmony_ci kfree(sbi); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic struct inode *hmdfs_alloc_inode(struct super_block *sb) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct hmdfs_inode_info *gi = 31362306a36Sopenharmony_ci kmem_cache_alloc(hmdfs_inode_cachep, GFP_KERNEL); 31462306a36Sopenharmony_ci if (!gi) 31562306a36Sopenharmony_ci return NULL; 31662306a36Sopenharmony_ci memset(gi, 0, offsetof(struct hmdfs_inode_info, vfs_inode)); 31762306a36Sopenharmony_ci INIT_LIST_HEAD(&gi->wb_list); 31862306a36Sopenharmony_ci init_rwsem(&gi->wpage_sem); 31962306a36Sopenharmony_ci gi->getattr_isize = HMDFS_STALE_REMOTE_ISIZE; 32062306a36Sopenharmony_ci atomic64_set(&gi->write_counter, 0); 32162306a36Sopenharmony_ci gi->fid.id = HMDFS_INODE_INVALID_FILE_ID; 32262306a36Sopenharmony_ci spin_lock_init(&gi->fid_lock); 32362306a36Sopenharmony_ci INIT_LIST_HEAD(&gi->wr_opened_node); 32462306a36Sopenharmony_ci atomic_set(&gi->wr_opened_cnt, 0); 32562306a36Sopenharmony_ci init_waitqueue_head(&gi->fid_wq); 32662306a36Sopenharmony_ci INIT_LIST_HEAD(&gi->stash_node); 32762306a36Sopenharmony_ci spin_lock_init(&gi->stash_lock); 32862306a36Sopenharmony_ci return &gi->vfs_inode; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int hmdfs_remote_statfs(struct dentry *dentry, struct kstatfs *buf) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci int error = 0; 33462306a36Sopenharmony_ci int ret = 0; 33562306a36Sopenharmony_ci char *dir_path = NULL; 33662306a36Sopenharmony_ci char *name_path = NULL; 33762306a36Sopenharmony_ci struct hmdfs_peer *con = NULL; 33862306a36Sopenharmony_ci struct hmdfs_sb_info *sbi = hmdfs_sb(dentry->d_inode->i_sb); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci dir_path = hmdfs_get_dentry_relative_path(dentry->d_parent); 34162306a36Sopenharmony_ci if (!dir_path) { 34262306a36Sopenharmony_ci error = -EACCES; 34362306a36Sopenharmony_ci goto rmdir_out; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci name_path = hmdfs_connect_path(dir_path, dentry->d_name.name); 34762306a36Sopenharmony_ci if (!name_path) { 34862306a36Sopenharmony_ci error = -EACCES; 34962306a36Sopenharmony_ci goto rmdir_out; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci mutex_lock(&sbi->connections.node_lock); 35262306a36Sopenharmony_ci list_for_each_entry(con, &sbi->connections.node_list, list) { 35362306a36Sopenharmony_ci if (con->status == NODE_STAT_ONLINE) { 35462306a36Sopenharmony_ci peer_get(con); 35562306a36Sopenharmony_ci mutex_unlock(&sbi->connections.node_lock); 35662306a36Sopenharmony_ci hmdfs_debug("send MSG to remote devID %llu", 35762306a36Sopenharmony_ci con->device_id); 35862306a36Sopenharmony_ci ret = hmdfs_send_statfs(con, name_path, buf); 35962306a36Sopenharmony_ci if (ret != 0) 36062306a36Sopenharmony_ci error = ret; 36162306a36Sopenharmony_ci peer_put(con); 36262306a36Sopenharmony_ci mutex_lock(&sbi->connections.node_lock); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci mutex_unlock(&sbi->connections.node_lock); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cirmdir_out: 36862306a36Sopenharmony_ci kfree(dir_path); 36962306a36Sopenharmony_ci kfree(name_path); 37062306a36Sopenharmony_ci return error; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int hmdfs_statfs(struct dentry *dentry, struct kstatfs *buf) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci int err = 0; 37662306a36Sopenharmony_ci struct path lower_path; 37762306a36Sopenharmony_ci struct hmdfs_inode_info *info = hmdfs_i(dentry->d_inode); 37862306a36Sopenharmony_ci struct super_block *sb = d_inode(dentry)->i_sb; 37962306a36Sopenharmony_ci struct hmdfs_sb_info *sbi = sb->s_fs_info; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci trace_hmdfs_statfs(dentry, info->inode_type); 38262306a36Sopenharmony_ci // merge_view & merge_view/xxx & device_view assigned src_inode info 38362306a36Sopenharmony_ci if (hmdfs_i_merge(info) || 38462306a36Sopenharmony_ci (info->inode_type == HMDFS_LAYER_SECOND_REMOTE)) { 38562306a36Sopenharmony_ci err = kern_path(sbi->local_src, 0, &lower_path); 38662306a36Sopenharmony_ci if (err) 38762306a36Sopenharmony_ci goto out; 38862306a36Sopenharmony_ci err = vfs_statfs(&lower_path, buf); 38962306a36Sopenharmony_ci path_put(&lower_path); 39062306a36Sopenharmony_ci } else if (!IS_ERR_OR_NULL(info->lower_inode)) { 39162306a36Sopenharmony_ci hmdfs_get_lower_path(dentry, &lower_path); 39262306a36Sopenharmony_ci err = vfs_statfs(&lower_path, buf); 39362306a36Sopenharmony_ci hmdfs_put_lower_path(&lower_path); 39462306a36Sopenharmony_ci } else { 39562306a36Sopenharmony_ci err = hmdfs_remote_statfs(dentry, buf); 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci buf->f_type = HMDFS_SUPER_MAGIC; 39962306a36Sopenharmony_ciout: 40062306a36Sopenharmony_ci return err; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic int hmdfs_show_options(struct seq_file *m, struct dentry *root) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct hmdfs_sb_info *sbi = hmdfs_sb(root->d_sb); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (sbi->s_case_sensitive) 40862306a36Sopenharmony_ci seq_puts(m, ",sensitive"); 40962306a36Sopenharmony_ci else 41062306a36Sopenharmony_ci seq_puts(m, ",insensitive"); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (sbi->s_merge_switch) 41362306a36Sopenharmony_ci seq_puts(m, ",merge_enable"); 41462306a36Sopenharmony_ci else 41562306a36Sopenharmony_ci seq_puts(m, ",merge_disable"); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci seq_printf(m, ",ra_pages=%lu", root->d_sb->s_bdi->ra_pages); 41862306a36Sopenharmony_ci seq_printf(m, ",user_id=%u", sbi->user_id); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (sbi->cache_dir) 42162306a36Sopenharmony_ci seq_printf(m, ",cache_dir=%s", sbi->cache_dir); 42262306a36Sopenharmony_ci if (sbi->real_dst) 42362306a36Sopenharmony_ci seq_printf(m, ",real_dst=%s", sbi->real_dst); 42462306a36Sopenharmony_ci if (sbi->cloud_dir) 42562306a36Sopenharmony_ci seq_printf(m, ",cloud_dir=%s", sbi->cloud_dir); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci seq_printf(m, ",%soffline_stash", sbi->s_offline_stash ? "" : "no_"); 42862306a36Sopenharmony_ci seq_printf(m, ",%sdentry_cache", sbi->s_dentry_cache ? "" : "no_"); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci return 0; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic int hmdfs_sync_fs(struct super_block *sb, int wait) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci int time_left; 43662306a36Sopenharmony_ci int err = 0; 43762306a36Sopenharmony_ci struct hmdfs_peer *con = NULL; 43862306a36Sopenharmony_ci struct hmdfs_sb_info *sbi = hmdfs_sb(sb); 43962306a36Sopenharmony_ci int syncfs_timeout = get_cmd_timeout(sbi, F_SYNCFS); 44062306a36Sopenharmony_ci struct syncfs_item item, *entry = NULL, *tmp = NULL; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (!wait) 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci trace_hmdfs_syncfs_enter(sbi); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci spin_lock(&sbi->hsi.list_lock); 44862306a36Sopenharmony_ci if (!sbi->hsi.is_executing) { 44962306a36Sopenharmony_ci sbi->hsi.is_executing = true; 45062306a36Sopenharmony_ci item.need_abort = false; 45162306a36Sopenharmony_ci spin_unlock(&sbi->hsi.list_lock); 45262306a36Sopenharmony_ci } else { 45362306a36Sopenharmony_ci init_completion(&item.done); 45462306a36Sopenharmony_ci list_add_tail(&item.list, &sbi->hsi.wait_list); 45562306a36Sopenharmony_ci spin_unlock(&sbi->hsi.list_lock); 45662306a36Sopenharmony_ci wait_for_completion(&item.done); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (item.need_abort) 46062306a36Sopenharmony_ci goto out; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* 46362306a36Sopenharmony_ci * Syncfs can not concurrent in hmdfs_sync_fs. Because we should make 46462306a36Sopenharmony_ci * sure all remote syncfs calls return back or timeout by waiting, 46562306a36Sopenharmony_ci * during the waiting period we must protect @sbi->remote_syncfs_count 46662306a36Sopenharmony_ci * and @sbi->remote_syncfs_ret from concurrent executing. 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci spin_lock(&sbi->hsi.v_lock); 47062306a36Sopenharmony_ci sbi->hsi.version++; 47162306a36Sopenharmony_ci /* 47262306a36Sopenharmony_ci * Attention: We put @sbi->hsi.remote_ret and @sbi->hsi.wait_count 47362306a36Sopenharmony_ci * into spinlock protection area to avoid following scenario caused 47462306a36Sopenharmony_ci * by out-of-order execution: 47562306a36Sopenharmony_ci * 47662306a36Sopenharmony_ci * synfs syncfs_cb 47762306a36Sopenharmony_ci * sbi->hsi.remote_ret = 0; 47862306a36Sopenharmony_ci * atomic_set(&sbi->hsi.wait_count, 0); 47962306a36Sopenharmony_ci * lock 48062306a36Sopenharmony_ci * version == old_version 48162306a36Sopenharmony_ci * sbi->hsi.remote_ret = resp->ret_code 48262306a36Sopenharmony_ci * atomic_dec(&sbi->hsi.wait_count); 48362306a36Sopenharmony_ci * unlock 48462306a36Sopenharmony_ci * lock 48562306a36Sopenharmony_ci * version = old_version + 1 48662306a36Sopenharmony_ci * unlock 48762306a36Sopenharmony_ci * 48862306a36Sopenharmony_ci * @sbi->hsi.remote_ret and @sbi->hsi.wait_count can be assigned 48962306a36Sopenharmony_ci * before spin lock which may compete with syncfs_cb(), making 49062306a36Sopenharmony_ci * these two values' assignment protected by spinlock can fix this. 49162306a36Sopenharmony_ci */ 49262306a36Sopenharmony_ci sbi->hsi.remote_ret = 0; 49362306a36Sopenharmony_ci atomic_set(&sbi->hsi.wait_count, 0); 49462306a36Sopenharmony_ci spin_unlock(&sbi->hsi.v_lock); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci mutex_lock(&sbi->connections.node_lock); 49762306a36Sopenharmony_ci list_for_each_entry(con, &sbi->connections.node_list, list) { 49862306a36Sopenharmony_ci /* 49962306a36Sopenharmony_ci * Dirty data does not need to be synchronized to remote 50062306a36Sopenharmony_ci * devices that go offline normally. It's okay to drop 50162306a36Sopenharmony_ci * them. 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_ci if (con->status != NODE_STAT_ONLINE) 50462306a36Sopenharmony_ci continue; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci peer_get(con); 50762306a36Sopenharmony_ci mutex_unlock(&sbi->connections.node_lock); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* 51062306a36Sopenharmony_ci * There exists a gap between sync_inodes_sb() and sync_fs() 51162306a36Sopenharmony_ci * which may race with remote writing, leading error count 51262306a36Sopenharmony_ci * on @sb_dirty_count. The dirty data produced during the 51362306a36Sopenharmony_ci * gap period won't be synced in next syncfs operation. 51462306a36Sopenharmony_ci * To avoid this, we have to invoke sync_inodes_sb() again 51562306a36Sopenharmony_ci * after getting @con->sb_dirty_count. 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_ci con->old_sb_dirty_count = atomic64_read(&con->sb_dirty_count); 51862306a36Sopenharmony_ci sync_inodes_sb(sb); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (!con->old_sb_dirty_count) { 52162306a36Sopenharmony_ci peer_put(con); 52262306a36Sopenharmony_ci mutex_lock(&sbi->connections.node_lock); 52362306a36Sopenharmony_ci continue; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci err = hmdfs_send_syncfs(con, syncfs_timeout); 52762306a36Sopenharmony_ci if (err) { 52862306a36Sopenharmony_ci hmdfs_warning("send syncfs failed with %d on node %llu", 52962306a36Sopenharmony_ci err, con->device_id); 53062306a36Sopenharmony_ci sbi->hsi.remote_ret = err; 53162306a36Sopenharmony_ci peer_put(con); 53262306a36Sopenharmony_ci mutex_lock(&sbi->connections.node_lock); 53362306a36Sopenharmony_ci continue; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci atomic_inc(&sbi->hsi.wait_count); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci peer_put(con); 53962306a36Sopenharmony_ci mutex_lock(&sbi->connections.node_lock); 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci mutex_unlock(&sbi->connections.node_lock); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* 54462306a36Sopenharmony_ci * Async work in background will make sure @sbi->remote_syncfs_count 54562306a36Sopenharmony_ci * decreased to zero finally whether syncfs success or fail. 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_ci time_left = wait_event_interruptible( 54862306a36Sopenharmony_ci sbi->hsi.wq, atomic_read(&sbi->hsi.wait_count) == 0); 54962306a36Sopenharmony_ci if (time_left < 0) { 55062306a36Sopenharmony_ci hmdfs_warning("syncfs is interrupted by external signal"); 55162306a36Sopenharmony_ci err = -EINTR; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (!err && sbi->hsi.remote_ret) 55562306a36Sopenharmony_ci err = sbi->hsi.remote_ret; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* Abandon syncfs processes in pending_list */ 55862306a36Sopenharmony_ci list_for_each_entry_safe(entry, tmp, &sbi->hsi.pending_list, list) { 55962306a36Sopenharmony_ci entry->need_abort = true; 56062306a36Sopenharmony_ci complete(&entry->done); 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci INIT_LIST_HEAD(&sbi->hsi.pending_list); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* Pick the last syncfs process in wait_list */ 56562306a36Sopenharmony_ci spin_lock(&sbi->hsi.list_lock); 56662306a36Sopenharmony_ci if (list_empty(&sbi->hsi.wait_list)) { 56762306a36Sopenharmony_ci sbi->hsi.is_executing = false; 56862306a36Sopenharmony_ci } else { 56962306a36Sopenharmony_ci entry = list_last_entry(&sbi->hsi.wait_list, struct syncfs_item, 57062306a36Sopenharmony_ci list); 57162306a36Sopenharmony_ci list_del_init(&entry->list); 57262306a36Sopenharmony_ci list_splice_init(&sbi->hsi.wait_list, &sbi->hsi.pending_list); 57362306a36Sopenharmony_ci entry->need_abort = false; 57462306a36Sopenharmony_ci complete(&entry->done); 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci spin_unlock(&sbi->hsi.list_lock); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ciout: 57962306a36Sopenharmony_ci trace_hmdfs_syncfs_exit(sbi, atomic_read(&sbi->hsi.wait_count), 58062306a36Sopenharmony_ci get_cmd_timeout(sbi, F_SYNCFS), err); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* TODO: Return synfs err back to syscall */ 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return err; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistruct super_operations hmdfs_sops = { 58862306a36Sopenharmony_ci .alloc_inode = hmdfs_alloc_inode, 58962306a36Sopenharmony_ci .destroy_inode = hmdfs_destroy_inode, 59062306a36Sopenharmony_ci .evict_inode = hmdfs_evict_inode, 59162306a36Sopenharmony_ci .put_super = hmdfs_put_super, 59262306a36Sopenharmony_ci .statfs = hmdfs_statfs, 59362306a36Sopenharmony_ci .show_options = hmdfs_show_options, 59462306a36Sopenharmony_ci .sync_fs = hmdfs_sync_fs, 59562306a36Sopenharmony_ci}; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic void init_once(void *obj) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci struct hmdfs_inode_info *i = obj; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci inode_init_once(&i->vfs_inode); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic int __init hmdfs_init_caches(void) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci int err = -ENOMEM; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci hmdfs_inode_cachep = 60962306a36Sopenharmony_ci kmem_cache_create("hmdfs_inode_cache", 61062306a36Sopenharmony_ci sizeof(struct hmdfs_inode_info), 0, 61162306a36Sopenharmony_ci SLAB_RECLAIM_ACCOUNT, init_once); 61262306a36Sopenharmony_ci if (unlikely(!hmdfs_inode_cachep)) 61362306a36Sopenharmony_ci goto out; 61462306a36Sopenharmony_ci hmdfs_dentry_cachep = 61562306a36Sopenharmony_ci kmem_cache_create("hmdfs_dentry_cache", 61662306a36Sopenharmony_ci sizeof(struct hmdfs_dentry_info), 0, 61762306a36Sopenharmony_ci SLAB_RECLAIM_ACCOUNT, NULL); 61862306a36Sopenharmony_ci if (unlikely(!hmdfs_dentry_cachep)) 61962306a36Sopenharmony_ci goto out_des_ino; 62062306a36Sopenharmony_ci hmdfs_dentry_merge_cachep = 62162306a36Sopenharmony_ci kmem_cache_create("hmdfs_dentry_merge_cache", 62262306a36Sopenharmony_ci sizeof(struct hmdfs_dentry_info_merge), 0, 62362306a36Sopenharmony_ci SLAB_RECLAIM_ACCOUNT, NULL); 62462306a36Sopenharmony_ci if (unlikely(!hmdfs_dentry_merge_cachep)) 62562306a36Sopenharmony_ci goto out_des_dc; 62662306a36Sopenharmony_ci return 0; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ciout_des_dc: 62962306a36Sopenharmony_ci kmem_cache_destroy(hmdfs_dentry_cachep); 63062306a36Sopenharmony_ciout_des_ino: 63162306a36Sopenharmony_ci kmem_cache_destroy(hmdfs_inode_cachep); 63262306a36Sopenharmony_ciout: 63362306a36Sopenharmony_ci return err; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic void hmdfs_destroy_caches(void) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci rcu_barrier(); 63962306a36Sopenharmony_ci kmem_cache_destroy(hmdfs_inode_cachep); 64062306a36Sopenharmony_ci hmdfs_inode_cachep = NULL; 64162306a36Sopenharmony_ci kmem_cache_destroy(hmdfs_dentry_cachep); 64262306a36Sopenharmony_ci hmdfs_dentry_cachep = NULL; 64362306a36Sopenharmony_ci kmem_cache_destroy(hmdfs_dentry_merge_cachep); 64462306a36Sopenharmony_ci hmdfs_dentry_merge_cachep = NULL; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ciuint64_t path_hash(const char *path, int len, bool case_sense) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci uint64_t res = 0; 65062306a36Sopenharmony_ci const char *kp = path; 65162306a36Sopenharmony_ci char c; 65262306a36Sopenharmony_ci /* Mocklisp hash function. */ 65362306a36Sopenharmony_ci while (*kp) { 65462306a36Sopenharmony_ci c = *kp; 65562306a36Sopenharmony_ci if (!case_sense) 65662306a36Sopenharmony_ci c = tolower(c); 65762306a36Sopenharmony_ci res = (res << 5) - res + (uint64_t)(c); 65862306a36Sopenharmony_ci kp++; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci return res; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic char *get_full_path(struct path *path) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci char *buf, *tmp; 66662306a36Sopenharmony_ci char *ret = NULL; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci buf = kmalloc(PATH_MAX, GFP_KERNEL); 66962306a36Sopenharmony_ci if (!buf) 67062306a36Sopenharmony_ci goto out; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci tmp = d_path(path, buf, PATH_MAX); 67362306a36Sopenharmony_ci if (IS_ERR(tmp)) 67462306a36Sopenharmony_ci goto out; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci ret = kstrdup(tmp, GFP_KERNEL); 67762306a36Sopenharmony_ciout: 67862306a36Sopenharmony_ci kfree(buf); 67962306a36Sopenharmony_ci return ret; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic void hmdfs_init_cmd_timeout(struct hmdfs_sb_info *sbi) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci memset(sbi->s_cmd_timeout, 0xff, sizeof(sbi->s_cmd_timeout)); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci set_cmd_timeout(sbi, F_OPEN, TIMEOUT_COMMON); 68762306a36Sopenharmony_ci set_cmd_timeout(sbi, F_RELEASE, TIMEOUT_NONE); 68862306a36Sopenharmony_ci set_cmd_timeout(sbi, F_READPAGE, TIMEOUT_COMMON); 68962306a36Sopenharmony_ci set_cmd_timeout(sbi, F_WRITEPAGE, TIMEOUT_COMMON); 69062306a36Sopenharmony_ci set_cmd_timeout(sbi, F_ITERATE, TIMEOUT_30S); 69162306a36Sopenharmony_ci set_cmd_timeout(sbi, F_CREATE, TIMEOUT_COMMON); 69262306a36Sopenharmony_ci set_cmd_timeout(sbi, F_MKDIR, TIMEOUT_COMMON); 69362306a36Sopenharmony_ci set_cmd_timeout(sbi, F_RMDIR, TIMEOUT_COMMON); 69462306a36Sopenharmony_ci set_cmd_timeout(sbi, F_UNLINK, TIMEOUT_COMMON); 69562306a36Sopenharmony_ci set_cmd_timeout(sbi, F_RENAME, TIMEOUT_COMMON); 69662306a36Sopenharmony_ci set_cmd_timeout(sbi, F_SETATTR, TIMEOUT_COMMON); 69762306a36Sopenharmony_ci set_cmd_timeout(sbi, F_STATFS, TIMEOUT_COMMON); 69862306a36Sopenharmony_ci set_cmd_timeout(sbi, F_CONNECT_REKEY, TIMEOUT_NONE); 69962306a36Sopenharmony_ci set_cmd_timeout(sbi, F_DROP_PUSH, TIMEOUT_NONE); 70062306a36Sopenharmony_ci set_cmd_timeout(sbi, F_GETATTR, TIMEOUT_COMMON); 70162306a36Sopenharmony_ci set_cmd_timeout(sbi, F_FSYNC, TIMEOUT_90S); 70262306a36Sopenharmony_ci set_cmd_timeout(sbi, F_SYNCFS, TIMEOUT_30S); 70362306a36Sopenharmony_ci set_cmd_timeout(sbi, F_GETXATTR, TIMEOUT_COMMON); 70462306a36Sopenharmony_ci set_cmd_timeout(sbi, F_SETXATTR, TIMEOUT_COMMON); 70562306a36Sopenharmony_ci set_cmd_timeout(sbi, F_LISTXATTR, TIMEOUT_COMMON); 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic int hmdfs_init_sbi(struct hmdfs_sb_info *sbi) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci int ret; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci ret = kfifo_alloc(&sbi->notify_fifo, PAGE_SIZE, GFP_KERNEL); 71362306a36Sopenharmony_ci if (ret) 71462306a36Sopenharmony_ci goto out; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* 71762306a36Sopenharmony_ci * We have to use dynamic memory since struct server/client_statistic 71862306a36Sopenharmony_ci * are DECLARED in hmdfs.h but DEFINED in socket_adapter.h. 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_ci sbi->s_server_statis = 72162306a36Sopenharmony_ci kzalloc(sizeof(*sbi->s_server_statis) * F_SIZE, GFP_KERNEL); 72262306a36Sopenharmony_ci sbi->s_client_statis = 72362306a36Sopenharmony_ci kzalloc(sizeof(*sbi->s_client_statis) * F_SIZE, GFP_KERNEL); 72462306a36Sopenharmony_ci if (!sbi->s_server_statis || !sbi->s_client_statis) { 72562306a36Sopenharmony_ci ret = -ENOMEM; 72662306a36Sopenharmony_ci goto out; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci ret = hmdfs_alloc_sb_seq(); 73062306a36Sopenharmony_ci if (ret < 0) { 73162306a36Sopenharmony_ci hmdfs_err("no sb seq available err %d", ret); 73262306a36Sopenharmony_ci goto out; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci sbi->seq = ret; 73562306a36Sopenharmony_ci ret = 0; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci spin_lock_init(&sbi->notify_fifo_lock); 73862306a36Sopenharmony_ci mutex_init(&sbi->cmd_handler_mutex); 73962306a36Sopenharmony_ci sbi->s_case_sensitive = false; 74062306a36Sopenharmony_ci sbi->s_features = HMDFS_FEATURE_READPAGES | 74162306a36Sopenharmony_ci HMDFS_FEATURE_READPAGES_OPEN | 74262306a36Sopenharmony_ci HMDFS_ATOMIC_OPEN; 74362306a36Sopenharmony_ci sbi->s_merge_switch = false; 74462306a36Sopenharmony_ci sbi->s_cloud_disk_switch = false; 74562306a36Sopenharmony_ci sbi->dcache_threshold = DEFAULT_DCACHE_THRESHOLD; 74662306a36Sopenharmony_ci sbi->dcache_precision = DEFAULT_DCACHE_PRECISION; 74762306a36Sopenharmony_ci sbi->dcache_timeout = DEFAULT_DCACHE_TIMEOUT; 74862306a36Sopenharmony_ci sbi->write_cache_timeout = DEFAULT_WRITE_CACHE_TIMEOUT; 74962306a36Sopenharmony_ci hmdfs_init_cmd_timeout(sbi); 75062306a36Sopenharmony_ci sbi->async_cb_delay = HMDFS_NODE_EVT_CB_DELAY; 75162306a36Sopenharmony_ci sbi->async_req_max_active = DEFAULT_SRV_REQ_MAX_ACTIVE; 75262306a36Sopenharmony_ci sbi->s_offline_stash = true; 75362306a36Sopenharmony_ci sbi->s_dentry_cache = true; 75462306a36Sopenharmony_ci sbi->wb_timeout_ms = HMDFS_DEF_WB_TIMEOUT_MS; 75562306a36Sopenharmony_ci sbi->s_readpages_nr = HMDFS_READPAGES_NR_DEF; 75662306a36Sopenharmony_ci /* Initialize before hmdfs_register_sysfs() */ 75762306a36Sopenharmony_ci atomic_set(&sbi->connections.conn_seq, 0); 75862306a36Sopenharmony_ci mutex_init(&sbi->connections.node_lock); 75962306a36Sopenharmony_ci INIT_LIST_HEAD(&sbi->connections.node_list); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci ret = hmdfs_init_share_table(sbi); 76262306a36Sopenharmony_ci if (ret) 76362306a36Sopenharmony_ci goto out; 76462306a36Sopenharmony_ci init_waitqueue_head(&sbi->async_readdir_wq); 76562306a36Sopenharmony_ci INIT_LIST_HEAD(&sbi->async_readdir_msg_list); 76662306a36Sopenharmony_ci INIT_LIST_HEAD(&sbi->async_readdir_work_list); 76762306a36Sopenharmony_ci spin_lock_init(&sbi->async_readdir_msg_lock); 76862306a36Sopenharmony_ci spin_lock_init(&sbi->async_readdir_work_lock); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci return 0; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ciout: 77362306a36Sopenharmony_ci return ret; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_civoid hmdfs_client_resp_statis(struct hmdfs_sb_info *sbi, u8 cmd, 77762306a36Sopenharmony_ci enum hmdfs_resp_type type, unsigned long start, 77862306a36Sopenharmony_ci unsigned long end) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci unsigned long duration; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci switch (type) { 78362306a36Sopenharmony_ci case HMDFS_RESP_DELAY: 78462306a36Sopenharmony_ci sbi->s_client_statis[cmd].delay_resp_cnt++; 78562306a36Sopenharmony_ci break; 78662306a36Sopenharmony_ci case HMDFS_RESP_TIMEOUT: 78762306a36Sopenharmony_ci sbi->s_client_statis[cmd].timeout_cnt++; 78862306a36Sopenharmony_ci break; 78962306a36Sopenharmony_ci case HMDFS_RESP_NORMAL: 79062306a36Sopenharmony_ci duration = end - start; 79162306a36Sopenharmony_ci sbi->s_client_statis[cmd].total += duration; 79262306a36Sopenharmony_ci sbi->s_client_statis[cmd].resp_cnt++; 79362306a36Sopenharmony_ci if (sbi->s_client_statis[cmd].max < duration) 79462306a36Sopenharmony_ci sbi->s_client_statis[cmd].max = duration; 79562306a36Sopenharmony_ci break; 79662306a36Sopenharmony_ci default: 79762306a36Sopenharmony_ci hmdfs_err("Wrong cmd %d with resp type %d", cmd, type); 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic int hmdfs_update_dst(struct hmdfs_sb_info *sbi) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci int err = 0; 80462306a36Sopenharmony_ci const char *path_local = UPDATE_LOCAL_DST; 80562306a36Sopenharmony_ci int len = 0; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci sbi->real_dst = kstrdup(sbi->local_dst, GFP_KERNEL); 80862306a36Sopenharmony_ci if (!sbi->real_dst) { 80962306a36Sopenharmony_ci err = -ENOMEM; 81062306a36Sopenharmony_ci goto out_err; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci kfree(sbi->local_dst); 81362306a36Sopenharmony_ci sbi->local_dst = NULL; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci len = strlen(sbi->real_dst) + strlen(path_local) + 1; 81662306a36Sopenharmony_ci if (len > PATH_MAX) { 81762306a36Sopenharmony_ci err = -EINVAL; 81862306a36Sopenharmony_ci goto out_err; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci sbi->local_dst = kmalloc(len, GFP_KERNEL); 82162306a36Sopenharmony_ci if (!sbi->local_dst) { 82262306a36Sopenharmony_ci err = -ENOMEM; 82362306a36Sopenharmony_ci goto out_err; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci snprintf(sbi->local_dst, strlen(sbi->real_dst) + strlen(path_local) + 1, 82662306a36Sopenharmony_ci "%s%s", sbi->real_dst, path_local); 82762306a36Sopenharmony_ciout_err: 82862306a36Sopenharmony_ci return err; 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci/* 83262306a36Sopenharmony_ci * Generate boot cookie like following format: 83362306a36Sopenharmony_ci * 83462306a36Sopenharmony_ci * | random | boot time(ms) | 0x00 | 83562306a36Sopenharmony_ci * |--------|-----------------|-------| 83662306a36Sopenharmony_ci * 16 33 15 (bits) 83762306a36Sopenharmony_ci * 83862306a36Sopenharmony_ci * This will make sure boot cookie is unique in a period 83962306a36Sopenharmony_ci * 2^33 / 1000 / 3600 / 24 = 99.4(days). 84062306a36Sopenharmony_ci */ 84162306a36Sopenharmony_ciuint64_t hmdfs_gen_boot_cookie(void) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci uint64_t now; 84462306a36Sopenharmony_ci uint16_t rand; 84562306a36Sopenharmony_ci struct rnd_state rnd_state; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci now = ktime_to_ms(ktime_get()); 84862306a36Sopenharmony_ci prandom_bytes_state(&rnd_state, (void *)&rand, 2); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci now &= (1ULL << HMDFS_BOOT_COOKIE_RAND_SHIFT) - 1; 85162306a36Sopenharmony_ci now |= ((uint64_t)rand << HMDFS_BOOT_COOKIE_RAND_SHIFT); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci return now << HMDFS_FID_VER_BOOT_COOKIE_SHIFT; 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_cistatic int hmdfs_fill_super(struct super_block *sb, void *data, int silent) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci struct hmdfs_mount_priv *priv = (struct hmdfs_mount_priv *)data; 85962306a36Sopenharmony_ci const char *dev_name = priv->dev_name; 86062306a36Sopenharmony_ci const char *raw_data = priv->raw_data; 86162306a36Sopenharmony_ci struct hmdfs_sb_info *sbi; 86262306a36Sopenharmony_ci int err = 0; 86362306a36Sopenharmony_ci struct inode *root_inode; 86462306a36Sopenharmony_ci struct path lower_path; 86562306a36Sopenharmony_ci struct super_block *lower_sb; 86662306a36Sopenharmony_ci struct dentry *root_dentry; 86762306a36Sopenharmony_ci char ctrl_path[CTRL_PATH_MAX_LEN]; 86862306a36Sopenharmony_ci uint64_t ctrl_hash; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (!raw_data) 87162306a36Sopenharmony_ci return -EINVAL; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); 87462306a36Sopenharmony_ci if (!sbi) { 87562306a36Sopenharmony_ci err = -ENOMEM; 87662306a36Sopenharmony_ci goto out_err; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci err = hmdfs_init_sbi(sbi); 87962306a36Sopenharmony_ci if (err) 88062306a36Sopenharmony_ci goto out_freesbi; 88162306a36Sopenharmony_ci sbi->sb = sb; 88262306a36Sopenharmony_ci err = hmdfs_parse_options(sbi, raw_data); 88362306a36Sopenharmony_ci if (err) 88462306a36Sopenharmony_ci goto out_freesbi; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci sb->s_fs_info = sbi; 88762306a36Sopenharmony_ci sb->s_magic = HMDFS_SUPER_MAGIC; 88862306a36Sopenharmony_ci sb->s_xattr = hmdfs_xattr_handlers; 88962306a36Sopenharmony_ci sb->s_op = &hmdfs_sops; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci sbi->boot_cookie = hmdfs_gen_boot_cookie(); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci err = hmdfs_init_writeback(sbi); 89462306a36Sopenharmony_ci if (err) 89562306a36Sopenharmony_ci goto out_freesbi; 89662306a36Sopenharmony_ci err = hmdfs_init_server_writeback(sbi); 89762306a36Sopenharmony_ci if (err) 89862306a36Sopenharmony_ci goto out_freesbi; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci err = hmdfs_init_stash(sbi); 90162306a36Sopenharmony_ci if (err) 90262306a36Sopenharmony_ci goto out_freesbi; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci // add ctrl sysfs node 90562306a36Sopenharmony_ci ctrl_hash = path_hash(sbi->local_dst, strlen(sbi->local_dst), true); 90662306a36Sopenharmony_ci scnprintf(ctrl_path, CTRL_PATH_MAX_LEN, "%llu", ctrl_hash); 90762306a36Sopenharmony_ci hmdfs_debug("hash %llu", ctrl_hash); 90862306a36Sopenharmony_ci err = hmdfs_register_sysfs(ctrl_path, sbi); 90962306a36Sopenharmony_ci if (err) 91062306a36Sopenharmony_ci goto out_freesbi; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci err = hmdfs_update_dst(sbi); 91362306a36Sopenharmony_ci if (err) 91462306a36Sopenharmony_ci goto out_unreg_sysfs; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, 91762306a36Sopenharmony_ci &lower_path); 91862306a36Sopenharmony_ci if (err) { 91962306a36Sopenharmony_ci hmdfs_err("open dev failed, errno = %d", err); 92062306a36Sopenharmony_ci goto out_unreg_sysfs; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci lower_sb = lower_path.dentry->d_sb; 92462306a36Sopenharmony_ci atomic_inc(&lower_sb->s_active); 92562306a36Sopenharmony_ci sbi->lower_sb = lower_sb; 92662306a36Sopenharmony_ci sbi->local_src = get_full_path(&lower_path); 92762306a36Sopenharmony_ci if (!sbi->local_src) { 92862306a36Sopenharmony_ci hmdfs_err("get local_src failed!"); 92962306a36Sopenharmony_ci goto out_sput; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci sb->s_time_gran = lower_sb->s_time_gran; 93362306a36Sopenharmony_ci sb->s_maxbytes = lower_sb->s_maxbytes; 93462306a36Sopenharmony_ci sb->s_stack_depth = lower_sb->s_stack_depth + 1; 93562306a36Sopenharmony_ci if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { 93662306a36Sopenharmony_ci hmdfs_err("maximum fs stacking depth exceeded"); 93762306a36Sopenharmony_ci err = -EINVAL; 93862306a36Sopenharmony_ci goto out_sput; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci root_inode = fill_root_inode(sb, sbi, d_inode(lower_path.dentry)); 94162306a36Sopenharmony_ci if (IS_ERR(root_inode)) { 94262306a36Sopenharmony_ci err = PTR_ERR(root_inode); 94362306a36Sopenharmony_ci goto out_sput; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci hmdfs_root_inode_perm_init(root_inode); 94662306a36Sopenharmony_ci sb->s_root = root_dentry = d_make_root(root_inode); 94762306a36Sopenharmony_ci if (!root_dentry) { 94862306a36Sopenharmony_ci err = -ENOMEM; 94962306a36Sopenharmony_ci goto out_sput; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci if (sbi->s_cloud_disk_switch) 95262306a36Sopenharmony_ci err = init_hmdfs_dentry_info(sbi, root_dentry, HMDFS_LAYER_SECOND_LOCAL); 95362306a36Sopenharmony_ci else 95462306a36Sopenharmony_ci err = init_hmdfs_dentry_info(sbi, root_dentry, HMDFS_LAYER_ZERO); 95562306a36Sopenharmony_ci if (err) 95662306a36Sopenharmony_ci goto out_freeroot; 95762306a36Sopenharmony_ci hmdfs_set_lower_path(root_dentry, &lower_path); 95862306a36Sopenharmony_ci sbi->cred = get_cred(current_cred()); 95962306a36Sopenharmony_ci INIT_LIST_HEAD(&sbi->client_cache); 96062306a36Sopenharmony_ci INIT_LIST_HEAD(&sbi->server_cache); 96162306a36Sopenharmony_ci INIT_LIST_HEAD(&sbi->to_delete); 96262306a36Sopenharmony_ci mutex_init(&sbi->cache_list_lock); 96362306a36Sopenharmony_ci hmdfs_cfn_load(sbi); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* Initialize syncfs info */ 96662306a36Sopenharmony_ci spin_lock_init(&sbi->hsi.v_lock); 96762306a36Sopenharmony_ci init_waitqueue_head(&sbi->hsi.wq); 96862306a36Sopenharmony_ci sbi->hsi.version = 0; 96962306a36Sopenharmony_ci sbi->hsi.is_executing = false; 97062306a36Sopenharmony_ci INIT_LIST_HEAD(&sbi->hsi.wait_list); 97162306a36Sopenharmony_ci INIT_LIST_HEAD(&sbi->hsi.pending_list); 97262306a36Sopenharmony_ci spin_lock_init(&sbi->hsi.list_lock); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci return err; 97562306a36Sopenharmony_ciout_freeroot: 97662306a36Sopenharmony_ci dput(sb->s_root); 97762306a36Sopenharmony_ci sb->s_root = NULL; 97862306a36Sopenharmony_ciout_sput: 97962306a36Sopenharmony_ci atomic_dec(&lower_sb->s_active); 98062306a36Sopenharmony_ci path_put(&lower_path); 98162306a36Sopenharmony_ciout_unreg_sysfs: 98262306a36Sopenharmony_ci hmdfs_unregister_sysfs(sbi); 98362306a36Sopenharmony_ci hmdfs_release_sysfs(sbi); 98462306a36Sopenharmony_ciout_freesbi: 98562306a36Sopenharmony_ci if (sbi) { 98662306a36Sopenharmony_ci sb->s_fs_info = NULL; 98762306a36Sopenharmony_ci hmdfs_clear_share_table(sbi); 98862306a36Sopenharmony_ci hmdfs_exit_stash(sbi); 98962306a36Sopenharmony_ci hmdfs_destroy_writeback(sbi); 99062306a36Sopenharmony_ci hmdfs_destroy_server_writeback(sbi); 99162306a36Sopenharmony_ci kfifo_free(&sbi->notify_fifo); 99262306a36Sopenharmony_ci hmdfs_free_sb_seq(sbi->seq); 99362306a36Sopenharmony_ci kfree(sbi->local_src); 99462306a36Sopenharmony_ci kfree(sbi->local_dst); 99562306a36Sopenharmony_ci kfree(sbi->real_dst); 99662306a36Sopenharmony_ci kfree(sbi->cache_dir); 99762306a36Sopenharmony_ci kfree(sbi->cloud_dir); 99862306a36Sopenharmony_ci kfree(sbi->s_server_statis); 99962306a36Sopenharmony_ci kfree(sbi->s_client_statis); 100062306a36Sopenharmony_ci kfree(sbi); 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ciout_err: 100362306a36Sopenharmony_ci return err; 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic struct dentry *hmdfs_mount(struct file_system_type *fs_type, int flags, 100762306a36Sopenharmony_ci const char *dev_name, void *raw_data) 100862306a36Sopenharmony_ci{ 100962306a36Sopenharmony_ci struct hmdfs_mount_priv priv = { 101062306a36Sopenharmony_ci .dev_name = dev_name, 101162306a36Sopenharmony_ci .raw_data = raw_data, 101262306a36Sopenharmony_ci }; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci /* hmdfs needs a valid dev_name to get the lower_sb's metadata */ 101562306a36Sopenharmony_ci if (!dev_name || !*dev_name) 101662306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 101762306a36Sopenharmony_ci return mount_nodev(fs_type, flags, &priv, hmdfs_fill_super); 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cistatic void hmdfs_cancel_async_readdir(struct hmdfs_sb_info *sbi) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci struct sendmsg_wait_queue *msg_wq = NULL; 102462306a36Sopenharmony_ci struct hmdfs_readdir_work *rw = NULL; 102562306a36Sopenharmony_ci struct hmdfs_readdir_work *tmp = NULL; 102662306a36Sopenharmony_ci struct list_head del_work; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci /* cancel work that are not running */ 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci INIT_LIST_HEAD(&del_work); 103162306a36Sopenharmony_ci spin_lock(&sbi->async_readdir_work_lock); 103262306a36Sopenharmony_ci list_for_each_entry_safe(rw, tmp, &sbi->async_readdir_work_list, head) { 103362306a36Sopenharmony_ci if (cancel_delayed_work(&rw->dwork)) 103462306a36Sopenharmony_ci list_move(&rw->head, &del_work); 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci spin_unlock(&sbi->async_readdir_work_lock); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci list_for_each_entry_safe(rw, tmp, &del_work, head) { 103962306a36Sopenharmony_ci dput(rw->dentry); 104062306a36Sopenharmony_ci peer_put(rw->con); 104162306a36Sopenharmony_ci kfree(rw); 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci /* wake up async readdir that are waiting for remote */ 104562306a36Sopenharmony_ci spin_lock(&sbi->async_readdir_msg_lock); 104662306a36Sopenharmony_ci sbi->async_readdir_prohibit = true; 104762306a36Sopenharmony_ci list_for_each_entry(msg_wq, &sbi->async_readdir_msg_list, async_msg) 104862306a36Sopenharmony_ci hmdfs_response_wakeup(msg_wq, -EINTR, 0, NULL); 104962306a36Sopenharmony_ci spin_unlock(&sbi->async_readdir_msg_lock); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* wait for all async readdir to finish */ 105262306a36Sopenharmony_ci if (!list_empty(&sbi->async_readdir_work_list)) 105362306a36Sopenharmony_ci wait_event_interruptible_timeout(sbi->async_readdir_wq, 105462306a36Sopenharmony_ci (list_empty(&sbi->async_readdir_work_list)), HZ); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci WARN_ON(!(list_empty(&sbi->async_readdir_work_list))); 105762306a36Sopenharmony_ci} 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic void hmdfs_kill_super(struct super_block *sb) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci struct hmdfs_sb_info *sbi = hmdfs_sb(sb); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* 106462306a36Sopenharmony_ci * async readdir is holding ref for dentry, not for vfsmount. Thus 106562306a36Sopenharmony_ci * shrink_dcache_for_umount() will warn about dentry still in use 106662306a36Sopenharmony_ci * if async readdir is not done. 106762306a36Sopenharmony_ci */ 106862306a36Sopenharmony_ci if (sbi) 106962306a36Sopenharmony_ci hmdfs_cancel_async_readdir(sbi); 107062306a36Sopenharmony_ci kill_anon_super(sb); 107162306a36Sopenharmony_ci} 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_cistatic struct file_system_type hmdfs_fs_type = { 107462306a36Sopenharmony_ci .owner = THIS_MODULE, 107562306a36Sopenharmony_ci .name = "hmdfs", 107662306a36Sopenharmony_ci .mount = hmdfs_mount, 107762306a36Sopenharmony_ci .kill_sb = hmdfs_kill_super, 107862306a36Sopenharmony_ci}; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_cistatic int __init hmdfs_init(void) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci int err = 0; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci err = hmdfs_init_caches(); 108562306a36Sopenharmony_ci if (err) 108662306a36Sopenharmony_ci goto out_err; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci hmdfs_node_evt_cb_init(); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci hmdfs_stash_add_node_evt_cb(); 109162306a36Sopenharmony_ci hmdfs_client_add_node_evt_cb(); 109262306a36Sopenharmony_ci hmdfs_server_add_node_evt_cb(); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci err = register_filesystem(&hmdfs_fs_type); 109562306a36Sopenharmony_ci if (err) { 109662306a36Sopenharmony_ci hmdfs_err("hmdfs register failed!"); 109762306a36Sopenharmony_ci goto out_err; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci err = hmdfs_init_configfs(); 110162306a36Sopenharmony_ci if (err) 110262306a36Sopenharmony_ci goto out_err; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci err = hmdfs_sysfs_init(); 110562306a36Sopenharmony_ci if (err) 110662306a36Sopenharmony_ci goto out_err; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci hmdfs_message_verify_init(); 110962306a36Sopenharmony_ci return 0; 111062306a36Sopenharmony_ciout_err: 111162306a36Sopenharmony_ci hmdfs_sysfs_exit(); 111262306a36Sopenharmony_ci hmdfs_exit_configfs(); 111362306a36Sopenharmony_ci unregister_filesystem(&hmdfs_fs_type); 111462306a36Sopenharmony_ci hmdfs_destroy_caches(); 111562306a36Sopenharmony_ci hmdfs_err("hmdfs init failed!"); 111662306a36Sopenharmony_ci return err; 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_cistatic void __exit hmdfs_exit(void) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci hmdfs_sysfs_exit(); 112262306a36Sopenharmony_ci hmdfs_exit_configfs(); 112362306a36Sopenharmony_ci unregister_filesystem(&hmdfs_fs_type); 112462306a36Sopenharmony_ci ida_destroy(&hmdfs_sb_seq); 112562306a36Sopenharmony_ci hmdfs_destroy_caches(); 112662306a36Sopenharmony_ci hmdfs_info("hmdfs exited!"); 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cimodule_init(hmdfs_init); 113062306a36Sopenharmony_cimodule_exit(hmdfs_exit); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL_GPL(hmdfs_recv_mesg_callback); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 113562306a36Sopenharmony_ciMODULE_AUTHOR("LongPing.WEI, Jingjing.Mao"); 113662306a36Sopenharmony_ciMODULE_DESCRIPTION("Harmony distributed file system"); 1137