• 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_DEVICE_CLOUD,
36 	DOMAIN_MERGE_VIEW,
37 	DOMAIN_CLOUD_MERGE_VIEW,
38 	DOMAIN_INVALID,
39 };
40 
41 union hmdfs_ino {
42 	const uint64_t ino_output;
43 	struct {
44 		uint64_t ino_raw : BIT_WIDE_INO_RAW;
45 		uint64_t dev_id : BIT_WIDE_DEVID;
46 		uint8_t domain : BIT_WIDE_DOMAIN;
47 	};
48 };
49 
read_ino_domain(uint64_t ino)50 static uint8_t read_ino_domain(uint64_t ino)
51 {
52 	union hmdfs_ino _ino = {
53 		.ino_output = ino,
54 	};
55 
56 	return _ino.domain;
57 }
58 
59 struct iget_args {
60 	/* The lower inode of local/merge/root(part) inode */
61 	struct inode *lo_i;
62 	/* The peer of remote inode */
63 	struct hmdfs_peer *peer;
64 	/* The ino of remote inode */
65 	uint64_t remote_ino;
66 
67 	/* The recordId of cloud inode */
68 	uint8_t *cloud_record_id;
69 	uint8_t *reserved;
70 
71 	/* Returned inode's ino */
72 	union hmdfs_ino ino;
73 };
74 
75 /**
76  * iget_test - whether or not the inode with matched hashval is the one we are
77  * looking for
78  *
79  * @inode: the local inode we found in inode cache with matched hashval
80  * @data: struct iget_args
81  */
iget_test(struct inode * inode,void * data)82 static int iget_test(struct inode *inode, void *data)
83 {
84 	struct hmdfs_inode_info *hii = hmdfs_i(inode);
85 	struct iget_args *ia = data;
86 	int res = 0;
87 
88 	WARN_ON(ia->ino.domain < DOMAIN_ROOT ||
89 		ia->ino.domain >= DOMAIN_INVALID);
90 
91 	if ((read_ino_domain(inode->i_ino) == DOMAIN_ROOT) ||
92 	    (read_ino_domain(inode->i_ino) != ia->ino.domain))
93 		return 0;
94 
95 	switch (ia->ino.domain) {
96 	case DOMAIN_MERGE_VIEW:
97 	case DOMAIN_CLOUD_MERGE_VIEW:
98 		res = (ia->lo_i == hii->lower_inode);
99 		break;
100 	case DOMAIN_DEVICE_LOCAL:
101 		res = (ia->lo_i == hii->lower_inode);
102 		break;
103 	case DOMAIN_DEVICE_REMOTE:
104 		res = (ia->peer == hii->conn &&
105 		       ia->remote_ino == hii->remote_ino);
106 		break;
107 	case DOMAIN_DEVICE_CLOUD:
108 		res = (ia->cloud_record_id &&
109 		       (memcmp(ia->cloud_record_id, hii->cloud_record_id,
110 			       CLOUD_RECORD_ID_LEN) == 0) &&
111 		       (ia->reserved[0] == hii->reserved[0]));
112 		break;
113 	}
114 
115 	return res;
116 }
117 
118 /**
119  * iget_set - initialize a inode with iget_args
120  *
121  * @sb: the superblock of current hmdfs instance
122  * @data: struct iget_args
123  */
iget_set(struct inode * inode,void * data)124 static int iget_set(struct inode *inode, void *data)
125 {
126 	struct hmdfs_inode_info *hii = hmdfs_i(inode);
127 	struct iget_args *ia = (struct iget_args *)data;
128 
129 	inode->i_ino = ia->ino.ino_output;
130 	inode_inc_iversion(inode);
131 
132 	hii->conn = ia->peer;
133 	hii->remote_ino = ia->remote_ino;
134 	hii->lower_inode = ia->lo_i;
135 
136 	if (ia->cloud_record_id) {
137 		memcpy(hii->cloud_record_id, ia->cloud_record_id, CLOUD_RECORD_ID_LEN);
138 		memcpy(hii->reserved, ia->reserved, CLOUD_DENTRY_RESERVED_LENGTH);
139 	}
140 
141 	return 0;
142 }
143 
make_ino_raw_dev_local(uint64_t lo_ino)144 static uint64_t make_ino_raw_dev_local(uint64_t lo_ino)
145 {
146 	if (!(lo_ino >> BIT_WIDE_INO_RAW))
147 		return lo_ino;
148 
149 	return lo_ino * GOLDEN_RATIO_64 >> BIT_WIDE_INO_RAW;
150 }
151 
make_ino_raw_dev_remote(uint64_t remote_ino)152 static uint64_t make_ino_raw_dev_remote(uint64_t remote_ino)
153 {
154 	return hash_long(remote_ino, BIT_WIDE_INO_RAW);
155 }
156 
157 /**
158  * hmdfs_iget5_locked_merge - obtain an inode for the merge-view
159  *
160  * @sb: superblock of current instance
161  * @fst_lo_i: the lower inode of it's first comrade
162  *
163  * Simply replace the lower's domain for a new ino.
164  */
hmdfs_iget5_locked_merge(struct super_block * sb,struct dentry * fst_lo_d)165 struct inode *hmdfs_iget5_locked_merge(struct super_block *sb,
166 				       struct dentry *fst_lo_d)
167 {
168 	struct iget_args ia = {
169 		.lo_i = d_inode(fst_lo_d),
170 		.peer = NULL,
171 		.remote_ino = 0,
172 		.cloud_record_id = NULL,
173 		.ino.ino_output = 0,
174 	};
175 
176 	if (unlikely(!d_inode(fst_lo_d))) {
177 		hmdfs_err("Received a invalid lower inode");
178 		return NULL;
179 	}
180 
181 	ia.ino.ino_raw = d_inode(fst_lo_d)->i_ino;
182 	ia.ino.dev_id = hmdfs_d(fst_lo_d)->device_id;
183 	ia.ino.domain = DOMAIN_MERGE_VIEW;
184 	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
185 }
186 
hmdfs_iget5_locked_cloud_merge(struct super_block * sb,struct dentry * fst_lo_d)187 struct inode *hmdfs_iget5_locked_cloud_merge(struct super_block *sb,
188 					     struct dentry *fst_lo_d)
189 {
190 	struct iget_args ia = {
191 		.lo_i = d_inode(fst_lo_d),
192 		.peer = NULL,
193 		.remote_ino = 0,
194 		.cloud_record_id = NULL,
195 		.ino.ino_output = 0,
196 	};
197 
198 	if (unlikely(!d_inode(fst_lo_d))) {
199 		hmdfs_err("Received a invalid lower inode");
200 		return NULL;
201 	}
202 
203 	ia.ino.ino_raw = d_inode(fst_lo_d)->i_ino;
204 	ia.ino.dev_id = hmdfs_d(fst_lo_d)->device_id;
205 	ia.ino.domain = DOMAIN_CLOUD_MERGE_VIEW;
206 	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
207 }
208 
209 /**
210  * hmdfs_iget5_locked_local - obtain an inode for the local-dev-view
211  *
212  * @sb: superblock of current instance
213  * @lo_i: the lower inode from local filesystem
214  *
215  * Hashing local inode's ino to generate our ino. We continue to compare the
216  * address of the lower_inode for uniqueness when collisions occurred.
217  */
hmdfs_iget5_locked_local(struct super_block * sb,struct inode * lo_i)218 struct inode *hmdfs_iget5_locked_local(struct super_block *sb,
219 				       struct inode *lo_i)
220 {
221 	struct iget_args ia = {
222 		.lo_i = lo_i,
223 		.peer = NULL,
224 		.remote_ino = 0,
225 		.cloud_record_id = NULL,
226 		.ino.ino_output = 0,
227 	};
228 
229 	if (unlikely(!lo_i)) {
230 		hmdfs_err("Received a invalid lower inode");
231 		return NULL;
232 	}
233 	ia.ino.ino_raw = make_ino_raw_dev_local(lo_i->i_ino);
234 	ia.ino.dev_id = 0;
235 	ia.ino.domain = DOMAIN_DEVICE_LOCAL;
236 	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
237 }
238 
239 /**
240  * hmdfs_iget5_locked_remote - obtain an inode for the remote-dev-view
241  *
242  * @sb: superblock of current instance
243  * @peer: corresponding device node
244  * @remote_ino: remote inode's ino
245  *
246  * Hash remote ino for ino's 32bit~1bit.
247  *
248  * Note that currenly implementation assume the each remote inode has unique
249  * ino. Thus the combination of the peer's unique dev_id and the remote_ino
250  * is enough to determine a unique remote inode.
251  */
hmdfs_iget5_locked_remote(struct super_block * sb,struct hmdfs_peer * peer,uint64_t remote_ino)252 struct inode *hmdfs_iget5_locked_remote(struct super_block *sb,
253 					struct hmdfs_peer *peer,
254 					uint64_t remote_ino)
255 {
256 	struct iget_args ia = {
257 		.lo_i = NULL,
258 		.peer = peer,
259 		.remote_ino = remote_ino,
260 		.cloud_record_id = NULL,
261 		.ino.ino_output = 0,
262 	};
263 
264 	if (unlikely(!peer)) {
265 		hmdfs_err("Received a invalid peer");
266 		return NULL;
267 	}
268 
269 	ia.ino.ino_raw = make_ino_raw_dev_remote(remote_ino);
270 	ia.ino.dev_id = peer->device_id;
271 	ia.ino.domain = DOMAIN_DEVICE_REMOTE;
272 	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
273 }
274 
275 /**
276  * hmdfs_iget5_locked_cloud - obtain an inode for the cloud-dev-view
277  *
278  * @sb: superblock of current instance
279  * @peer: corresponding device node
280  * @cloud_id: cloud file record id
281  *
282  * Hash remote ino for ino's 32bit~1bit.
283  *
284  * Note that currenly implementation assume the each remote inode has unique
285  * ino. Thus the combination of the peer's unique dev_id and the remote_ino
286  * is enough to determine a unique remote inode.
287  */
hmdfs_iget5_locked_cloud(struct super_block * sb,struct hmdfs_peer * peer,struct hmdfs_lookup_cloud_ret * res)288 struct inode *hmdfs_iget5_locked_cloud(struct super_block *sb,
289 				       struct hmdfs_peer *peer,
290 				       struct hmdfs_lookup_cloud_ret *res)
291 {
292 	struct iget_args ia = {
293 		.lo_i = NULL,
294 		.peer = peer,
295 		.remote_ino = 0,
296 		.cloud_record_id = res->record_id,
297 		.reserved = res->reserved,
298 		.ino.ino_output = 0,
299 	};
300 
301 	if (unlikely(!peer)) {
302 		hmdfs_err("Received a invalid peer");
303 		return NULL;
304 	}
305 
306 	ia.ino.ino_raw = make_ino_raw_cloud(res->record_id) + res->reserved[0];
307 	ia.ino.dev_id = peer->device_id;
308 	ia.ino.domain = DOMAIN_DEVICE_CLOUD;
309 	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
310 }
311 
hmdfs_iget_locked_root(struct super_block * sb,uint64_t root_ino,struct inode * lo_i,struct hmdfs_peer * peer)312 struct inode *hmdfs_iget_locked_root(struct super_block *sb, uint64_t root_ino,
313 				     struct inode *lo_i,
314 				     struct hmdfs_peer *peer)
315 {
316 	struct iget_args ia = {
317 		.lo_i = lo_i,
318 		.peer = peer,
319 		.remote_ino = 0,
320 		.cloud_record_id = NULL,
321 		.ino.ino_raw = root_ino,
322 		.ino.dev_id = peer ? peer->device_id : 0,
323 		.ino.domain = DOMAIN_ROOT,
324 	};
325 
326 	if (unlikely(root_ino < 0 || root_ino >= HMDFS_ROOT_INVALID)) {
327 		hmdfs_err("Root %llu is invalid", root_ino);
328 		return NULL;
329 	}
330 	if (unlikely(root_ino == HMDFS_ROOT_DEV_REMOTE && !peer)) {
331 		hmdfs_err("Root %llu received a invalid peer", root_ino);
332 		return NULL;
333 	}
334 
335 	return iget5_locked(sb, ia.ino.ino_output, iget_test, iget_set, &ia);
336 }
337