162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/hmdfs/inode.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "hmdfs_device_view.h" 962306a36Sopenharmony_ci#include "inode.h" 1062306a36Sopenharmony_ci#include "comm/connection.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/** 1362306a36Sopenharmony_ci * Rules to generate inode numbers: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * "/", "/device_view", "/merge_view", "/device_view/local", "/device_view/cid" 1662306a36Sopenharmony_ci * = DOMAIN {3} : dev_id {29} : HMDFS_ROOT {32} 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * "/device_view/cid/xxx" 1962306a36Sopenharmony_ci * = DOMAIN {3} : dev_id {29} : hash(remote_ino){32} 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * "/merge_view/xxx" 2262306a36Sopenharmony_ci * = DOMAIN {3} : lower's dev_id {29} : lower's ino_raw {32} 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define BIT_WIDE_TOTAL 64 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define BIT_WIDE_DOMAIN 3 2862306a36Sopenharmony_ci#define BIT_WIDE_DEVID 29 2962306a36Sopenharmony_ci#define BIT_WIDE_INO_RAW 32 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cienum DOMAIN { 3262306a36Sopenharmony_ci DOMAIN_ROOT, 3362306a36Sopenharmony_ci DOMAIN_DEVICE_LOCAL, 3462306a36Sopenharmony_ci DOMAIN_DEVICE_REMOTE, 3562306a36Sopenharmony_ci DOMAIN_DEVICE_CLOUD, 3662306a36Sopenharmony_ci DOMAIN_MERGE_VIEW, 3762306a36Sopenharmony_ci DOMAIN_CLOUD_MERGE_VIEW, 3862306a36Sopenharmony_ci DOMAIN_INVALID, 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciunion hmdfs_ino { 4262306a36Sopenharmony_ci const uint64_t ino_output; 4362306a36Sopenharmony_ci struct { 4462306a36Sopenharmony_ci uint64_t ino_raw : BIT_WIDE_INO_RAW; 4562306a36Sopenharmony_ci uint64_t dev_id : BIT_WIDE_DEVID; 4662306a36Sopenharmony_ci uint8_t domain : BIT_WIDE_DOMAIN; 4762306a36Sopenharmony_ci }; 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic uint8_t read_ino_domain(uint64_t ino) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci union hmdfs_ino _ino = { 5362306a36Sopenharmony_ci .ino_output = ino, 5462306a36Sopenharmony_ci }; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return _ino.domain; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistruct iget_args { 6062306a36Sopenharmony_ci /* The lower inode of local/merge/root(part) inode */ 6162306a36Sopenharmony_ci struct inode *lo_i; 6262306a36Sopenharmony_ci /* The peer of remote inode */ 6362306a36Sopenharmony_ci struct hmdfs_peer *peer; 6462306a36Sopenharmony_ci /* The ino of remote inode */ 6562306a36Sopenharmony_ci uint64_t remote_ino; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* The recordId of cloud inode */ 6862306a36Sopenharmony_ci uint8_t *cloud_record_id; 6962306a36Sopenharmony_ci uint8_t *reserved; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* Returned inode's ino */ 7262306a36Sopenharmony_ci union hmdfs_ino ino; 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/** 7662306a36Sopenharmony_ci * iget_test - whether or not the inode with matched hashval is the one we are 7762306a36Sopenharmony_ci * looking for 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * @inode: the local inode we found in inode cache with matched hashval 8062306a36Sopenharmony_ci * @data: struct iget_args 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_cistatic int iget_test(struct inode *inode, void *data) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct hmdfs_inode_info *hii = hmdfs_i(inode); 8562306a36Sopenharmony_ci struct iget_args *ia = data; 8662306a36Sopenharmony_ci int res = 0; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci WARN_ON(ia->ino.domain < DOMAIN_ROOT || 8962306a36Sopenharmony_ci ia->ino.domain >= DOMAIN_INVALID); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (read_ino_domain(inode->i_ino) == DOMAIN_ROOT) 9262306a36Sopenharmony_ci return 1; 9362306a36Sopenharmony_ci if (read_ino_domain(inode->i_ino) != ia->ino.domain) 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci switch (ia->ino.domain) { 9762306a36Sopenharmony_ci case DOMAIN_MERGE_VIEW: 9862306a36Sopenharmony_ci case DOMAIN_CLOUD_MERGE_VIEW: 9962306a36Sopenharmony_ci res = (ia->lo_i == hii->lower_inode); 10062306a36Sopenharmony_ci break; 10162306a36Sopenharmony_ci case DOMAIN_DEVICE_LOCAL: 10262306a36Sopenharmony_ci res = (ia->lo_i == hii->lower_inode); 10362306a36Sopenharmony_ci break; 10462306a36Sopenharmony_ci case DOMAIN_DEVICE_REMOTE: 10562306a36Sopenharmony_ci res = (ia->peer == hii->conn && 10662306a36Sopenharmony_ci ia->remote_ino == hii->remote_ino); 10762306a36Sopenharmony_ci break; 10862306a36Sopenharmony_ci case DOMAIN_DEVICE_CLOUD: 10962306a36Sopenharmony_ci res = (ia->cloud_record_id && 11062306a36Sopenharmony_ci (memcmp(ia->cloud_record_id, hii->cloud_record_id, 11162306a36Sopenharmony_ci CLOUD_RECORD_ID_LEN) == 0) && 11262306a36Sopenharmony_ci (ia->reserved[0] == hii->reserved[0])); 11362306a36Sopenharmony_ci break; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return res; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/** 12062306a36Sopenharmony_ci * iget_set - initialize a inode with iget_args 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci * @sb: the superblock of current hmdfs instance 12362306a36Sopenharmony_ci * @data: struct iget_args 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_cistatic int iget_set(struct inode *inode, void *data) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct hmdfs_inode_info *hii = hmdfs_i(inode); 12862306a36Sopenharmony_ci struct iget_args *ia = (struct iget_args *)data; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci inode->i_ino = ia->ino.ino_output; 13162306a36Sopenharmony_ci inode_inc_iversion(inode); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci hii->conn = ia->peer; 13462306a36Sopenharmony_ci hii->remote_ino = ia->remote_ino; 13562306a36Sopenharmony_ci hii->lower_inode = ia->lo_i; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (ia->cloud_record_id) { 13862306a36Sopenharmony_ci memcpy(hii->cloud_record_id, ia->cloud_record_id, CLOUD_RECORD_ID_LEN); 13962306a36Sopenharmony_ci memcpy(hii->reserved, ia->reserved, CLOUD_DENTRY_RESERVED_LENGTH); 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic uint64_t make_ino_raw_dev_local(uint64_t lo_ino) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci if (!(lo_ino >> BIT_WIDE_INO_RAW)) 14862306a36Sopenharmony_ci return lo_ino; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return lo_ino * GOLDEN_RATIO_64 >> BIT_WIDE_INO_RAW; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic uint64_t make_ino_raw_dev_remote(uint64_t remote_ino) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci return hash_long(remote_ino, BIT_WIDE_INO_RAW); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/** 15962306a36Sopenharmony_ci * hmdfs_iget5_locked_merge - obtain an inode for the merge-view 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * @sb: superblock of current instance 16262306a36Sopenharmony_ci * @fst_lo_i: the lower inode of it's first comrade 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * Simply replace the lower's domain for a new ino. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_merge(struct super_block *sb, 16762306a36Sopenharmony_ci struct dentry *fst_lo_d) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct iget_args ia = { 17062306a36Sopenharmony_ci .lo_i = d_inode(fst_lo_d), 17162306a36Sopenharmony_ci .peer = NULL, 17262306a36Sopenharmony_ci .remote_ino = 0, 17362306a36Sopenharmony_ci .cloud_record_id = NULL, 17462306a36Sopenharmony_ci .ino.ino_output = 0, 17562306a36Sopenharmony_ci }; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (unlikely(!d_inode(fst_lo_d))) { 17862306a36Sopenharmony_ci hmdfs_err("Received a invalid lower inode"); 17962306a36Sopenharmony_ci return NULL; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci if (unlikely(!hmdfs_d(fst_lo_d))) { 18262306a36Sopenharmony_ci hmdfs_err("Received a invalid fsdata"); 18362306a36Sopenharmony_ci return NULL; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci ia.ino.ino_raw = d_inode(fst_lo_d)->i_ino; 18762306a36Sopenharmony_ci ia.ino.dev_id = hmdfs_d(fst_lo_d)->device_id; 18862306a36Sopenharmony_ci ia.ino.domain = DOMAIN_MERGE_VIEW; 18962306a36Sopenharmony_ci return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia); 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_cloud_merge(struct super_block *sb, 19362306a36Sopenharmony_ci struct dentry *fst_lo_d) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct iget_args ia = { 19662306a36Sopenharmony_ci .lo_i = d_inode(fst_lo_d), 19762306a36Sopenharmony_ci .peer = NULL, 19862306a36Sopenharmony_ci .remote_ino = 0, 19962306a36Sopenharmony_ci .cloud_record_id = NULL, 20062306a36Sopenharmony_ci .ino.ino_output = 0, 20162306a36Sopenharmony_ci }; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (unlikely(!d_inode(fst_lo_d))) { 20462306a36Sopenharmony_ci hmdfs_err("Received a invalid lower inode"); 20562306a36Sopenharmony_ci return NULL; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci if (unlikely(!hmdfs_d(fst_lo_d))) { 20862306a36Sopenharmony_ci hmdfs_err("Received a invalid fsdata"); 20962306a36Sopenharmony_ci return NULL; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci ia.ino.ino_raw = d_inode(fst_lo_d)->i_ino; 21362306a36Sopenharmony_ci ia.ino.dev_id = hmdfs_d(fst_lo_d)->device_id; 21462306a36Sopenharmony_ci ia.ino.domain = DOMAIN_CLOUD_MERGE_VIEW; 21562306a36Sopenharmony_ci return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/** 21962306a36Sopenharmony_ci * hmdfs_iget5_locked_local - obtain an inode for the local-dev-view 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci * @sb: superblock of current instance 22262306a36Sopenharmony_ci * @lo_i: the lower inode from local filesystem 22362306a36Sopenharmony_ci * 22462306a36Sopenharmony_ci * Hashing local inode's ino to generate our ino. We continue to compare the 22562306a36Sopenharmony_ci * address of the lower_inode for uniqueness when collisions occurred. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_local(struct super_block *sb, 22862306a36Sopenharmony_ci struct inode *lo_i) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct iget_args ia = { 23162306a36Sopenharmony_ci .lo_i = lo_i, 23262306a36Sopenharmony_ci .peer = NULL, 23362306a36Sopenharmony_ci .remote_ino = 0, 23462306a36Sopenharmony_ci .cloud_record_id = NULL, 23562306a36Sopenharmony_ci .ino.ino_output = 0, 23662306a36Sopenharmony_ci }; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (unlikely(!lo_i)) { 23962306a36Sopenharmony_ci hmdfs_err("Received a invalid lower inode"); 24062306a36Sopenharmony_ci return NULL; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci ia.ino.ino_raw = make_ino_raw_dev_local(lo_i->i_ino); 24362306a36Sopenharmony_ci ia.ino.dev_id = 0; 24462306a36Sopenharmony_ci ia.ino.domain = DOMAIN_DEVICE_LOCAL; 24562306a36Sopenharmony_ci return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/** 24962306a36Sopenharmony_ci * hmdfs_iget5_locked_remote - obtain an inode for the remote-dev-view 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci * @sb: superblock of current instance 25262306a36Sopenharmony_ci * @peer: corresponding device node 25362306a36Sopenharmony_ci * @remote_ino: remote inode's ino 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * Hash remote ino for ino's 32bit~1bit. 25662306a36Sopenharmony_ci * 25762306a36Sopenharmony_ci * Note that currenly implementation assume the each remote inode has unique 25862306a36Sopenharmony_ci * ino. Thus the combination of the peer's unique dev_id and the remote_ino 25962306a36Sopenharmony_ci * is enough to determine a unique remote inode. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_remote(struct super_block *sb, 26262306a36Sopenharmony_ci struct hmdfs_peer *peer, 26362306a36Sopenharmony_ci uint64_t remote_ino) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct iget_args ia = { 26662306a36Sopenharmony_ci .lo_i = NULL, 26762306a36Sopenharmony_ci .peer = peer, 26862306a36Sopenharmony_ci .remote_ino = remote_ino, 26962306a36Sopenharmony_ci .cloud_record_id = NULL, 27062306a36Sopenharmony_ci .ino.ino_output = 0, 27162306a36Sopenharmony_ci }; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (unlikely(!peer)) { 27462306a36Sopenharmony_ci hmdfs_err("Received a invalid peer"); 27562306a36Sopenharmony_ci return NULL; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci ia.ino.ino_raw = make_ino_raw_dev_remote(remote_ino); 27962306a36Sopenharmony_ci ia.ino.dev_id = peer->device_id; 28062306a36Sopenharmony_ci ia.ino.domain = DOMAIN_DEVICE_REMOTE; 28162306a36Sopenharmony_ci return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/** 28562306a36Sopenharmony_ci * hmdfs_iget5_locked_cloud - obtain an inode for the cloud-dev-view 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * @sb: superblock of current instance 28862306a36Sopenharmony_ci * @peer: corresponding device node 28962306a36Sopenharmony_ci * @cloud_id: cloud file record id 29062306a36Sopenharmony_ci * 29162306a36Sopenharmony_ci * Hash remote ino for ino's 32bit~1bit. 29262306a36Sopenharmony_ci * 29362306a36Sopenharmony_ci * Note that currenly implementation assume the each remote inode has unique 29462306a36Sopenharmony_ci * ino. Thus the combination of the peer's unique dev_id and the remote_ino 29562306a36Sopenharmony_ci * is enough to determine a unique remote inode. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_cloud(struct super_block *sb, 29862306a36Sopenharmony_ci struct hmdfs_peer *peer, 29962306a36Sopenharmony_ci struct hmdfs_lookup_cloud_ret *res) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct iget_args ia = { 30262306a36Sopenharmony_ci .lo_i = NULL, 30362306a36Sopenharmony_ci .peer = peer, 30462306a36Sopenharmony_ci .remote_ino = 0, 30562306a36Sopenharmony_ci .cloud_record_id = res->record_id, 30662306a36Sopenharmony_ci .reserved = res->reserved, 30762306a36Sopenharmony_ci .ino.ino_output = 0, 30862306a36Sopenharmony_ci }; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (unlikely(!peer)) { 31162306a36Sopenharmony_ci hmdfs_err("Received a invalid peer"); 31262306a36Sopenharmony_ci return NULL; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci ia.ino.ino_raw = make_ino_raw_cloud(res->record_id) + res->reserved[0]; 31662306a36Sopenharmony_ci ia.ino.dev_id = peer->device_id; 31762306a36Sopenharmony_ci ia.ino.domain = DOMAIN_DEVICE_CLOUD; 31862306a36Sopenharmony_ci return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistruct inode *hmdfs_iget_locked_root(struct super_block *sb, uint64_t root_ino, 32262306a36Sopenharmony_ci struct inode *lo_i, 32362306a36Sopenharmony_ci struct hmdfs_peer *peer) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct iget_args ia = { 32662306a36Sopenharmony_ci .lo_i = lo_i, 32762306a36Sopenharmony_ci .peer = peer, 32862306a36Sopenharmony_ci .remote_ino = 0, 32962306a36Sopenharmony_ci .cloud_record_id = NULL, 33062306a36Sopenharmony_ci .ino.ino_raw = root_ino, 33162306a36Sopenharmony_ci .ino.dev_id = peer ? peer->device_id : 0, 33262306a36Sopenharmony_ci .ino.domain = DOMAIN_ROOT, 33362306a36Sopenharmony_ci }; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (unlikely(root_ino < 0 || root_ino >= HMDFS_ROOT_INVALID)) { 33662306a36Sopenharmony_ci hmdfs_err("Root %llu is invalid", root_ino); 33762306a36Sopenharmony_ci return NULL; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci if (unlikely(root_ino == HMDFS_ROOT_DEV_REMOTE && !peer)) { 34062306a36Sopenharmony_ci hmdfs_err("Root %llu received a invalid peer", root_ino); 34162306a36Sopenharmony_ci return NULL; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_civoid hmdfs_update_upper_file(struct file *upper_file, struct file *lower_file) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci loff_t upper_size = i_size_read(upper_file->f_inode); 35162306a36Sopenharmony_ci loff_t lower_size = i_size_read(lower_file->f_inode); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (upper_file->f_inode->i_mapping && upper_size != lower_size) { 35462306a36Sopenharmony_ci i_size_write(upper_file->f_inode, lower_size); 35562306a36Sopenharmony_ci truncate_inode_pages(upper_file->f_inode->i_mapping, 0); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci}