• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * fs/hmdfs/inode.c
4  *
5  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
6  */
7 
8 #include "hmdfs_device_view.h"
9 #include "inode.h"
10 #include "comm/connection.h"
11 
12 /**
13  * Rules to generate inode numbers:
14  *
15  * "/", "/device_view", "/merge_view", "/device_view/local", "/device_view/cid"
16  * = DOMAIN {3} : dev_id {29} : HMDFS_ROOT {32}
17  *
18  * "/device_view/cid/xxx"
19  * = DOMAIN {3} : dev_id {29} : hash(remote_ino){32}
20  *
21  * "/merge_view/xxx"
22  * = DOMAIN {3} : lower's dev_id {29} : lower's ino_raw {32}
23  */
24 
25 #define BIT_WIDE_TOTAL 64
26 
27 #define BIT_WIDE_DOMAIN 3
28 #define BIT_WIDE_DEVID 29
29 #define BIT_WIDE_INO_RAW 32
30 
31 enum DOMAIN {
32 	DOMAIN_ROOT,
33 	DOMAIN_DEVICE_LOCAL,
34 	DOMAIN_DEVICE_REMOTE,
35 	DOMAIN_MERGE_VIEW,
36 	DOMAIN_INVALID,
37 };
38 
39 union hmdfs_ino {
40 	const uint64_t ino_output;
41 	struct {
42 		uint64_t ino_raw : BIT_WIDE_INO_RAW;
43 		uint64_t dev_id : BIT_WIDE_DEVID;
44 		uint8_t domain : BIT_WIDE_DOMAIN;
45 	};
46 };
47 
read_ino_domain(uint64_t ino)48 static uint8_t read_ino_domain(uint64_t ino)
49 {
50 	union hmdfs_ino _ino = {
51 		.ino_output = ino,
52 	};
53 
54 	return _ino.domain;
55 }
56 
57 struct iget_args {
58 	/* The lower inode of local/merge/root(part) inode */
59 	struct inode *lo_i;
60 	/* The peer of remote inode */
61 	struct hmdfs_peer *peer;
62 	/* The ino of remote inode */
63 	uint64_t remote_ino;
64 
65 	/* Returned inode's ino */
66 	union hmdfs_ino ino;
67 };
68 
69 /**
70  * iget_test - whether or not the inode with matched hashval is the one we are
71  * looking for
72  *
73  * @inode: the local inode we found in inode cache with matched hashval
74  * @data: struct iget_args
75  */
iget_test(struct inode * inode,void * data)76 static int iget_test(struct inode *inode, void *data)
77 {
78 	struct hmdfs_inode_info *hii = hmdfs_i(inode);
79 	struct iget_args *ia = data;
80 	int res = 0;
81 
82 	WARN_ON(ia->ino.domain < DOMAIN_ROOT ||
83 		ia->ino.domain >= DOMAIN_INVALID);
84 
85 	if (read_ino_domain(inode->i_ino) == DOMAIN_ROOT)
86 		return 0;
87 
88 	switch (ia->ino.domain) {
89 	case DOMAIN_MERGE_VIEW:
90 		res = (ia->lo_i == hii->lower_inode);
91 		break;
92 	case DOMAIN_DEVICE_LOCAL:
93 		res = (ia->lo_i == hii->lower_inode);
94 		break;
95 	case DOMAIN_DEVICE_REMOTE:
96 		res = (ia->peer == hii->conn &&
97 		       ia->remote_ino == hii->remote_ino);
98 		break;
99 	}
100 
101 	return res;
102 }
103 
104 /**
105  * iget_set - initialize a inode with iget_args
106  *
107  * @sb: the superblock of current hmdfs instance
108  * @data: struct iget_args
109  */
iget_set(struct inode * inode,void * data)110 static int iget_set(struct inode *inode, void *data)
111 {
112 	struct hmdfs_inode_info *hii = hmdfs_i(inode);
113 	struct iget_args *ia = (struct iget_args *)data;
114 
115 	inode->i_ino = ia->ino.ino_output;
116 	inode_inc_iversion(inode);
117 
118 	hii->conn = ia->peer;
119 	hii->remote_ino = ia->remote_ino;
120 	hii->lower_inode = ia->lo_i;
121 
122 	return 0;
123 }
124 
make_ino_raw_dev_local(uint64_t lo_ino)125 static uint64_t make_ino_raw_dev_local(uint64_t lo_ino)
126 {
127 	if (!(lo_ino >> BIT_WIDE_INO_RAW))
128 		return lo_ino;
129 
130 	return lo_ino * GOLDEN_RATIO_64 >> BIT_WIDE_INO_RAW;
131 }
132 
make_ino_raw_dev_remote(uint64_t remote_ino)133 static uint64_t make_ino_raw_dev_remote(uint64_t remote_ino)
134 {
135 	return hash_long(remote_ino, BIT_WIDE_INO_RAW);
136 }
137 
138 /**
139  * hmdfs_iget5_locked_merge - obtain an inode for the merge-view
140  *
141  * @sb: superblock of current instance
142  * @fst_lo_i: the lower inode of it's first comrade
143  *
144  * Simply replace the lower's domain for a new ino.
145  */
hmdfs_iget5_locked_merge(struct super_block * sb,struct dentry * fst_lo_d)146 struct inode *hmdfs_iget5_locked_merge(struct super_block *sb,
147 				       struct dentry *fst_lo_d)
148 {
149 	struct iget_args ia = {
150 		.lo_i = d_inode(fst_lo_d),
151 		.peer = NULL,
152 		.remote_ino = 0,
153 		.ino.ino_output = 0,
154 	};
155 
156 	if (unlikely(!d_inode(fst_lo_d))) {
157 		hmdfs_err("Received a invalid lower inode");
158 		return NULL;
159 	}
160 
161 	ia.ino.ino_raw = d_inode(fst_lo_d)->i_ino;
162 	ia.ino.dev_id = hmdfs_d(fst_lo_d)->device_id;
163 	ia.ino.domain = DOMAIN_MERGE_VIEW;
164 	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
165 }
166 
167 /**
168  * hmdfs_iget5_locked_local - obtain an inode for the local-dev-view
169  *
170  * @sb: superblock of current instance
171  * @lo_i: the lower inode from local filesystem
172  *
173  * Hashing local inode's ino to generate our ino. We continue to compare the
174  * address of the lower_inode for uniqueness when collisions occurred.
175  */
hmdfs_iget5_locked_local(struct super_block * sb,struct inode * lo_i)176 struct inode *hmdfs_iget5_locked_local(struct super_block *sb,
177 				       struct inode *lo_i)
178 {
179 	struct iget_args ia = {
180 		.lo_i = lo_i,
181 		.peer = NULL,
182 		.remote_ino = 0,
183 		.ino.ino_output = 0,
184 	};
185 
186 	if (unlikely(!lo_i)) {
187 		hmdfs_err("Received a invalid lower inode");
188 		return NULL;
189 	}
190 	ia.ino.ino_raw = make_ino_raw_dev_local(lo_i->i_ino);
191 	ia.ino.dev_id = 0;
192 	ia.ino.domain = DOMAIN_DEVICE_LOCAL;
193 	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
194 }
195 
196 /**
197  * hmdfs_iget5_locked_remote - obtain an inode for the remote-dev-view
198  *
199  * @sb: superblock of current instance
200  * @peer: corresponding device node
201  * @remote_ino: remote inode's ino
202  *
203  * Hash remote ino for ino's 32bit~1bit.
204  *
205  * Note that currenly implementation assume the each remote inode has unique
206  * ino. Thus the combination of the peer's unique dev_id and the remote_ino
207  * is enough to determine a unique remote inode.
208  */
hmdfs_iget5_locked_remote(struct super_block * sb,struct hmdfs_peer * peer,uint64_t remote_ino)209 struct inode *hmdfs_iget5_locked_remote(struct super_block *sb,
210 					struct hmdfs_peer *peer,
211 					uint64_t remote_ino)
212 {
213 	struct iget_args ia = {
214 		.lo_i = NULL,
215 		.peer = peer,
216 		.remote_ino = remote_ino,
217 		.ino.ino_output = 0,
218 	};
219 
220 	if (unlikely(!peer)) {
221 		hmdfs_err("Received a invalid peer");
222 		return NULL;
223 	}
224 
225 	ia.ino.ino_raw = make_ino_raw_dev_remote(remote_ino);
226 	ia.ino.dev_id = peer->device_id;
227 	ia.ino.domain = DOMAIN_DEVICE_REMOTE;
228 	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
229 }
230 
hmdfs_iget_locked_root(struct super_block * sb,uint64_t root_ino,struct inode * lo_i,struct hmdfs_peer * peer)231 struct inode *hmdfs_iget_locked_root(struct super_block *sb, uint64_t root_ino,
232 				     struct inode *lo_i,
233 				     struct hmdfs_peer *peer)
234 {
235 	struct iget_args ia = {
236 		.lo_i = lo_i,
237 		.peer = peer,
238 		.remote_ino = 0,
239 		.ino.ino_raw = root_ino,
240 		.ino.dev_id = peer ? peer->device_id : 0,
241 		.ino.domain = DOMAIN_ROOT,
242 	};
243 
244 	if (unlikely(root_ino < 0 || root_ino >= HMDFS_ROOT_INVALID)) {
245 		hmdfs_err("Root %llu is invalid", root_ino);
246 		return NULL;
247 	}
248 	if (unlikely(root_ino == HMDFS_ROOT_DEV_REMOTE && !peer)) {
249 		hmdfs_err("Root %llu received a invalid peer", root_ino);
250 		return NULL;
251 	}
252 
253 	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
254 }
255