162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/hmdfs/inode.h 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef INODE_H 962306a36Sopenharmony_ci#define INODE_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "hmdfs.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) 1462306a36Sopenharmony_ci#include <linux/iversion.h> 1562306a36Sopenharmony_ci#endif 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cienum { 1862306a36Sopenharmony_ci HMDFS_REMOTE_INODE_NONE = 0, 1962306a36Sopenharmony_ci HMDFS_REMOTE_INODE_STASHING, 2062306a36Sopenharmony_ci HMDFS_REMOTE_INODE_RESTORING, 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/***************************************************************************** 2462306a36Sopenharmony_ci * fid 2562306a36Sopenharmony_ci *****************************************************************************/ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Bits for fid_flags */ 2862306a36Sopenharmony_cienum { 2962306a36Sopenharmony_ci HMDFS_FID_NEED_OPEN = 0, 3062306a36Sopenharmony_ci HMDFS_FID_OPENING, 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct hmdfs_fid { 3462306a36Sopenharmony_ci __u64 ver; 3562306a36Sopenharmony_ci __u32 id; 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * Cache file is stored in file like following format: 4062306a36Sopenharmony_ci * ________________________________________________________________ 4162306a36Sopenharmony_ci * |meta file info| remote file(s) path | file content | 4262306a36Sopenharmony_ci * | head | path | data | 4362306a36Sopenharmony_ci * ↑ ↑ 4462306a36Sopenharmony_ci * path_offs data_offs 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_cistruct hmdfs_cache_info { 4762306a36Sopenharmony_ci /* Path start offset in file (HMDFS_STASH_BLK_SIZE aligned) */ 4862306a36Sopenharmony_ci __u32 path_offs; 4962306a36Sopenharmony_ci __u32 path_len; 5062306a36Sopenharmony_ci __u32 path_cnt; 5162306a36Sopenharmony_ci char *path_buf; 5262306a36Sopenharmony_ci /* Stricky remote file(hardlink)s' path, split by '\0' */ 5362306a36Sopenharmony_ci char *path; 5462306a36Sopenharmony_ci /* Data start offset in file (HMDFS_STASH_BLK_SIZE aligned) */ 5562306a36Sopenharmony_ci __u32 data_offs; 5662306a36Sopenharmony_ci /* # of pages need to be written to remote file during offline */ 5762306a36Sopenharmony_ci atomic64_t to_write_pgs; 5862306a36Sopenharmony_ci /* # of pages written to remote file during offline */ 5962306a36Sopenharmony_ci atomic64_t written_pgs; 6062306a36Sopenharmony_ci /* Stash file handler */ 6162306a36Sopenharmony_ci struct file *cache_file; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/***************************************************************************** 6562306a36Sopenharmony_ci * inode info and it's inline helpers 6662306a36Sopenharmony_ci *****************************************************************************/ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistruct hmdfs_inode_info { 6962306a36Sopenharmony_ci struct inode *lower_inode; // for local/merge inode 7062306a36Sopenharmony_ci struct hmdfs_peer *conn; // for remote inode 7162306a36Sopenharmony_ci struct kref ref; 7262306a36Sopenharmony_ci spinlock_t fid_lock; 7362306a36Sopenharmony_ci struct hmdfs_fid fid; 7462306a36Sopenharmony_ci unsigned long fid_flags; 7562306a36Sopenharmony_ci wait_queue_head_t fid_wq; 7662306a36Sopenharmony_ci __u8 inode_type; // deprecated: use ino system instead 7762306a36Sopenharmony_ci atomic_t write_opened; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* writeback list */ 8062306a36Sopenharmony_ci struct list_head wb_list; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#ifdef CONFIG_HMDFS_FS_PERMISSION 8362306a36Sopenharmony_ci __u16 perm; 8462306a36Sopenharmony_ci#endif 8562306a36Sopenharmony_ci /* 8662306a36Sopenharmony_ci * lookup remote file will generate a local inode, this store the 8762306a36Sopenharmony_ci * combination of remote inode number and generation in such situation. 8862306a36Sopenharmony_ci * the uniqueness of local inode can be determined. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci __u64 remote_ino; 9162306a36Sopenharmony_ci#define CLOUD_RECORD_ID_LEN 33 9262306a36Sopenharmony_ci __u8 cloud_record_id[CLOUD_RECORD_ID_LEN]; 9362306a36Sopenharmony_ci#define CLOUD_DENTRY_RESERVED_LENGTH 3 9462306a36Sopenharmony_ci __u8 reserved[CLOUD_DENTRY_RESERVED_LENGTH]; 9562306a36Sopenharmony_ci /* 9662306a36Sopenharmony_ci * if this value is not ULLONG_MAX, it means that remote getattr syscall 9762306a36Sopenharmony_ci * should return this value as inode size. 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci __u64 getattr_isize; 10062306a36Sopenharmony_ci /* 10162306a36Sopenharmony_ci * this value stores remote ctime, explicitly when remote file is opened 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci struct hmdfs_time_t remote_ctime; 10462306a36Sopenharmony_ci /* 10562306a36Sopenharmony_ci * this value stores the last time, aligned to dcache_precision, that 10662306a36Sopenharmony_ci * remote file was modified. It should be noted that this value won't 10762306a36Sopenharmony_ci * be effective if writecace_expire is set. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci struct hmdfs_time_t stable_ctime; 11062306a36Sopenharmony_ci /* 11162306a36Sopenharmony_ci * If this value is set nonzero, pagecache should be truncated if the 11262306a36Sopenharmony_ci * time that the file is opened is beyond the value. Furthermore, 11362306a36Sopenharmony_ci * the functionality of stable_ctime won't be effective. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci unsigned long writecache_expire; 11662306a36Sopenharmony_ci /* 11762306a36Sopenharmony_ci * This value record how many times the file has been written while file 11862306a36Sopenharmony_ci * is opened. 'writecache_expire' will set in close if this value is 11962306a36Sopenharmony_ci * nonzero. 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci atomic64_t write_counter; 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * will be linked to hmdfs_peer::wr_opened_inode_list 12462306a36Sopenharmony_ci * if the remote inode is writable-opened. And using 12562306a36Sopenharmony_ci * wr_opened_cnt to track possibly multiple writeable-open. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci struct list_head wr_opened_node; 12862306a36Sopenharmony_ci atomic_t wr_opened_cnt; 12962306a36Sopenharmony_ci spinlock_t stash_lock; 13062306a36Sopenharmony_ci unsigned int stash_status; 13162306a36Sopenharmony_ci struct hmdfs_cache_info *cache; 13262306a36Sopenharmony_ci /* link to hmdfs_peer::stashed_inode_list when stashing completes */ 13362306a36Sopenharmony_ci struct list_head stash_node; 13462306a36Sopenharmony_ci /* 13562306a36Sopenharmony_ci * The flush/fsync thread will hold the write lock while threads 13662306a36Sopenharmony_ci * calling writepage will hold the read lock. We use rwlock to 13762306a36Sopenharmony_ci * eliminate the cases that flush/fsync operations are done with 13862306a36Sopenharmony_ci * re-dirtied pages remain dirty. 13962306a36Sopenharmony_ci * 14062306a36Sopenharmony_ci * Here is the explanation in detail: 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * During `writepage()`, the state of a re-dirtied page will switch 14362306a36Sopenharmony_ci * to the following states in sequence: 14462306a36Sopenharmony_ci * s1: page dirty + tree dirty 14562306a36Sopenharmony_ci * s2: page dirty + tree dirty <tag_pages_for_writeback> 14662306a36Sopenharmony_ci * s3: page clean + tree dirty <clear_page_dirty_for_io> 14762306a36Sopenharmony_ci * s4: page clean + tree clean + write back <set_page_writeback> 14862306a36Sopenharmony_ci * s5: page dirty + tree dirty + write back <redirty_page_for_writepage> 14962306a36Sopenharmony_ci * s6: page dirty + tree dirty <end_page_writeback> 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * A page upon s4 will thus be ignored by the concurrent 15262306a36Sopenharmony_ci * `do_writepages()` contained by `close()`, `fsync()`, making it's 15362306a36Sopenharmony_ci * state inconsistent. 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * To avoid such situation, we use per-file rwsems to prevent 15662306a36Sopenharmony_ci * concurrent in-flight `writepage` during `close()` or `fsync()`. 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * Minimal overhead is brought in since rsems allow concurrent 15962306a36Sopenharmony_ci * `writepage` while `close()` or `fsync()` is natural to wait for 16062306a36Sopenharmony_ci * in-flight `writepage()`s to complete. 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci * NOTE that in the worst case, a process may wait for wsem for TIMEOUT 16362306a36Sopenharmony_ci * even if a signal is pending. But we've to wait there to iterate all 16462306a36Sopenharmony_ci * pages and make sure that no dirty page should remain. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci struct rw_semaphore wpage_sem; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci // The real inode shared with vfs. ALWAYS PUT IT AT THE BOTTOM. 16962306a36Sopenharmony_ci struct inode vfs_inode; 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistruct hmdfs_readdir_work { 17362306a36Sopenharmony_ci struct list_head head; 17462306a36Sopenharmony_ci struct dentry *dentry; 17562306a36Sopenharmony_ci struct hmdfs_peer *con; 17662306a36Sopenharmony_ci struct delayed_work dwork; 17762306a36Sopenharmony_ci}; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic inline struct hmdfs_inode_info *hmdfs_i(struct inode *inode) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci return container_of(inode, struct hmdfs_inode_info, vfs_inode); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic inline bool hmdfs_inode_is_stashing(const struct hmdfs_inode_info *info) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci const struct hmdfs_sb_info *sbi = hmdfs_sb(info->vfs_inode.i_sb); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* Refer to comments in hmdfs_stash_remote_inode() */ 18962306a36Sopenharmony_ci return (hmdfs_is_stash_enabled(sbi) && 19062306a36Sopenharmony_ci smp_load_acquire(&info->stash_status)); // protect 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic inline void hmdfs_remote_fetch_fid(struct hmdfs_inode_info *info, 19462306a36Sopenharmony_ci struct hmdfs_fid *fid) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci spin_lock(&info->fid_lock); 19762306a36Sopenharmony_ci *fid = info->fid; 19862306a36Sopenharmony_ci spin_unlock(&info->fid_lock); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/***************************************************************************** 20262306a36Sopenharmony_ci * ino allocator 20362306a36Sopenharmony_ci *****************************************************************************/ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cienum HMDFS_ROOT { 20662306a36Sopenharmony_ci HMDFS_ROOT_ANCESTOR = 1, // / 20762306a36Sopenharmony_ci HMDFS_ROOT_DEV, // /device_view 20862306a36Sopenharmony_ci HMDFS_ROOT_DEV_LOCAL, // /device_view/local 20962306a36Sopenharmony_ci HMDFS_ROOT_DEV_REMOTE, // /device_view/remote 21062306a36Sopenharmony_ci HMDFS_ROOT_DEV_CLOUD, // /device_view/cloud 21162306a36Sopenharmony_ci HMDFS_ROOT_MERGE, // /merge_view 21262306a36Sopenharmony_ci HMDFS_ROOT_MERGE_CLOUD, // /cloud_merge_view 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci HMDFS_ROOT_INVALID, 21562306a36Sopenharmony_ci}; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci// delete layer, directory layer, not overlay layer 21862306a36Sopenharmony_cienum HMDFS_LAYER_TYPE { 21962306a36Sopenharmony_ci HMDFS_LAYER_ZERO = 0, // / 22062306a36Sopenharmony_ci HMDFS_LAYER_FIRST_DEVICE, // /device_view 22162306a36Sopenharmony_ci HMDFS_LAYER_SECOND_LOCAL, // /device_view/local 22262306a36Sopenharmony_ci HMDFS_LAYER_SECOND_REMOTE, // /device_view/remote 22362306a36Sopenharmony_ci HMDFS_LAYER_SECOND_CLOUD, // /device_view/cloud 22462306a36Sopenharmony_ci HMDFS_LAYER_OTHER_LOCAL, // /device_view/local/xx 22562306a36Sopenharmony_ci HMDFS_LAYER_OTHER_REMOTE, // /device_view/remote/xx 22662306a36Sopenharmony_ci HMDFS_LAYER_OTHER_CLOUD, // /device_view/cloud/xx 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci HMDFS_LAYER_FIRST_MERGE, // /merge_view 22962306a36Sopenharmony_ci HMDFS_LAYER_OTHER_MERGE, // /merge_view/xxx 23062306a36Sopenharmony_ci HMDFS_LAYER_FIRST_MERGE_CLOUD, // /cloud_merge_view 23162306a36Sopenharmony_ci HMDFS_LAYER_OTHER_MERGE_CLOUD, // /coud_merge_view/xxx 23262306a36Sopenharmony_ci HMDFS_LAYER_INVALID, 23362306a36Sopenharmony_ci}; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistruct inode *hmdfs_iget_locked_root(struct super_block *sb, uint64_t root_ino, 23662306a36Sopenharmony_ci struct inode *lo_i, 23762306a36Sopenharmony_ci struct hmdfs_peer *peer); 23862306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_merge(struct super_block *sb, 23962306a36Sopenharmony_ci struct dentry *fst_lo_d); 24062306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_cloud_merge(struct super_block *sb, 24162306a36Sopenharmony_ci struct dentry *fst_lo_d); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_local(struct super_block *sb, 24462306a36Sopenharmony_ci struct inode *lo_i); 24562306a36Sopenharmony_cistruct hmdfs_peer; 24662306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_remote(struct super_block *sb, 24762306a36Sopenharmony_ci struct hmdfs_peer *peer, 24862306a36Sopenharmony_ci uint64_t remote_ino); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistruct hmdfs_lookup_cloud_ret { 25162306a36Sopenharmony_ci uint64_t i_size; 25262306a36Sopenharmony_ci uint64_t i_mtime; 25362306a36Sopenharmony_ci uint8_t record_id[CLOUD_RECORD_ID_LEN]; 25462306a36Sopenharmony_ci uint8_t reserved[CLOUD_DENTRY_RESERVED_LENGTH]; 25562306a36Sopenharmony_ci uint16_t i_mode; 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistruct inode *hmdfs_iget5_locked_cloud(struct super_block *sb, 25962306a36Sopenharmony_ci struct hmdfs_peer *peer, 26062306a36Sopenharmony_ci struct hmdfs_lookup_cloud_ret *res); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_civoid hmdfs_update_upper_file(struct file *upper_file, struct file *lower_file); 26362306a36Sopenharmony_ciuint32_t make_ino_raw_cloud(uint8_t *cloud_id); 26462306a36Sopenharmony_ci#endif // INODE_H 265