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