1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _BCACHEFS_STR_HASH_H
3 #define _BCACHEFS_STR_HASH_H
5 #include "btree_iter.h"
6 #include "btree_update.h"
11 #include "subvolume.h"
14 #include <linux/crc32c.h>
15 #include <crypto/hash.h>
16 #include <crypto/sha2.h>
18 static inline enum bch_str_hash_type
19 bch2_str_hash_opt_to_type(struct bch_fs
*c
, enum bch_str_hash_opts opt
)
22 case BCH_STR_HASH_OPT_crc32c
:
23 return BCH_STR_HASH_crc32c
;
24 case BCH_STR_HASH_OPT_crc64
:
25 return BCH_STR_HASH_crc64
;
26 case BCH_STR_HASH_OPT_siphash
:
27 return c
->sb
.features
& (1ULL << BCH_FEATURE_new_siphash
)
28 ? BCH_STR_HASH_siphash
29 : BCH_STR_HASH_siphash_old
;
35 struct bch_hash_info
{
38 * For crc32 or crc64 string hashes the first key value of
39 * the siphash_key (k0) is used as the key.
41 SIPHASH_KEY siphash_key
;
44 static inline struct bch_hash_info
45 bch2_hash_info_init(struct bch_fs
*c
, const struct bch_inode_unpacked
*bi
)
48 struct bch_hash_info info
= {
49 .type
= INODE_STR_HASH(bi
),
50 .siphash_key
= { .k0
= bi
->bi_hash_seed
}
53 if (unlikely(info
.type
== BCH_STR_HASH_siphash_old
)) {
54 SHASH_DESC_ON_STACK(desc
, c
->sha256
);
55 u8 digest
[SHA256_DIGEST_SIZE
];
57 desc
->tfm
= c
->sha256
;
59 crypto_shash_digest(desc
, (void *) &bi
->bi_hash_seed
,
60 sizeof(bi
->bi_hash_seed
), digest
);
61 memcpy(&info
.siphash_key
, digest
, sizeof(info
.siphash_key
));
67 struct bch_str_hash_ctx
{
75 static inline void bch2_str_hash_init(struct bch_str_hash_ctx
*ctx
,
76 const struct bch_hash_info
*info
)
79 case BCH_STR_HASH_crc32c
:
80 ctx
->crc32c
= crc32c(~0, &info
->siphash_key
.k0
,
81 sizeof(info
->siphash_key
.k0
));
83 case BCH_STR_HASH_crc64
:
84 ctx
->crc64
= crc64_be(~0, &info
->siphash_key
.k0
,
85 sizeof(info
->siphash_key
.k0
));
87 case BCH_STR_HASH_siphash_old
:
88 case BCH_STR_HASH_siphash
:
89 SipHash24_Init(&ctx
->siphash
, &info
->siphash_key
);
96 static inline void bch2_str_hash_update(struct bch_str_hash_ctx
*ctx
,
97 const struct bch_hash_info
*info
,
98 const void *data
, size_t len
)
100 switch (info
->type
) {
101 case BCH_STR_HASH_crc32c
:
102 ctx
->crc32c
= crc32c(ctx
->crc32c
, data
, len
);
104 case BCH_STR_HASH_crc64
:
105 ctx
->crc64
= crc64_be(ctx
->crc64
, data
, len
);
107 case BCH_STR_HASH_siphash_old
:
108 case BCH_STR_HASH_siphash
:
109 SipHash24_Update(&ctx
->siphash
, data
, len
);
116 static inline u64
bch2_str_hash_end(struct bch_str_hash_ctx
*ctx
,
117 const struct bch_hash_info
*info
)
119 switch (info
->type
) {
120 case BCH_STR_HASH_crc32c
:
122 case BCH_STR_HASH_crc64
:
123 return ctx
->crc64
>> 1;
124 case BCH_STR_HASH_siphash_old
:
125 case BCH_STR_HASH_siphash
:
126 return SipHash24_End(&ctx
->siphash
) >> 1;
132 struct bch_hash_desc
{
133 enum btree_id btree_id
;
136 u64 (*hash_key
)(const struct bch_hash_info
*, const void *);
137 u64 (*hash_bkey
)(const struct bch_hash_info
*, struct bkey_s_c
);
138 bool (*cmp_key
)(struct bkey_s_c
, const void *);
139 bool (*cmp_bkey
)(struct bkey_s_c
, struct bkey_s_c
);
140 bool (*is_visible
)(subvol_inum inum
, struct bkey_s_c
);
143 static inline bool is_visible_key(struct bch_hash_desc desc
, subvol_inum inum
, struct bkey_s_c k
)
145 return k
.k
->type
== desc
.key_type
&&
148 desc
.is_visible(inum
, k
));
151 static __always_inline
struct bkey_s_c
152 bch2_hash_lookup_in_snapshot(struct btree_trans
*trans
,
153 struct btree_iter
*iter
,
154 const struct bch_hash_desc desc
,
155 const struct bch_hash_info
*info
,
156 subvol_inum inum
, const void *key
,
157 enum btree_iter_update_trigger_flags flags
,
163 for_each_btree_key_upto_norestart(trans
, *iter
, desc
.btree_id
,
164 SPOS(inum
.inum
, desc
.hash_key(info
, key
), snapshot
),
165 POS(inum
.inum
, U64_MAX
),
166 BTREE_ITER_slots
|flags
, k
, ret
) {
167 if (is_visible_key(desc
, inum
, k
)) {
168 if (!desc
.cmp_key(k
, key
))
170 } else if (k
.k
->type
== KEY_TYPE_hash_whiteout
) {
173 /* hole, not found */
177 bch2_trans_iter_exit(trans
, iter
);
179 return bkey_s_c_err(ret
?: -BCH_ERR_ENOENT_str_hash_lookup
);
182 static __always_inline
struct bkey_s_c
183 bch2_hash_lookup(struct btree_trans
*trans
,
184 struct btree_iter
*iter
,
185 const struct bch_hash_desc desc
,
186 const struct bch_hash_info
*info
,
187 subvol_inum inum
, const void *key
,
188 enum btree_iter_update_trigger_flags flags
)
191 int ret
= bch2_subvolume_get_snapshot(trans
, inum
.subvol
, &snapshot
);
193 return bkey_s_c_err(ret
);
195 return bch2_hash_lookup_in_snapshot(trans
, iter
, desc
, info
, inum
, key
, flags
, snapshot
);
198 static __always_inline
int
199 bch2_hash_hole(struct btree_trans
*trans
,
200 struct btree_iter
*iter
,
201 const struct bch_hash_desc desc
,
202 const struct bch_hash_info
*info
,
203 subvol_inum inum
, const void *key
)
209 ret
= bch2_subvolume_get_snapshot(trans
, inum
.subvol
, &snapshot
);
213 for_each_btree_key_upto_norestart(trans
, *iter
, desc
.btree_id
,
214 SPOS(inum
.inum
, desc
.hash_key(info
, key
), snapshot
),
215 POS(inum
.inum
, U64_MAX
),
216 BTREE_ITER_slots
|BTREE_ITER_intent
, k
, ret
)
217 if (!is_visible_key(desc
, inum
, k
))
219 bch2_trans_iter_exit(trans
, iter
);
221 return ret
?: -BCH_ERR_ENOSPC_str_hash_create
;
224 static __always_inline
225 int bch2_hash_needs_whiteout(struct btree_trans
*trans
,
226 const struct bch_hash_desc desc
,
227 const struct bch_hash_info
*info
,
228 struct btree_iter
*start
)
230 struct btree_iter iter
;
234 bch2_trans_copy_iter(&iter
, start
);
236 bch2_btree_iter_advance(&iter
);
238 for_each_btree_key_continue_norestart(iter
, BTREE_ITER_slots
, k
, ret
) {
239 if (k
.k
->type
!= desc
.key_type
&&
240 k
.k
->type
!= KEY_TYPE_hash_whiteout
)
243 if (k
.k
->type
== desc
.key_type
&&
244 desc
.hash_bkey(info
, k
) <= start
->pos
.offset
) {
250 bch2_trans_iter_exit(trans
, &iter
);
254 static __always_inline
255 struct bkey_s_c
bch2_hash_set_or_get_in_snapshot(struct btree_trans
*trans
,
256 struct btree_iter
*iter
,
257 const struct bch_hash_desc desc
,
258 const struct bch_hash_info
*info
,
259 subvol_inum inum
, u32 snapshot
,
260 struct bkey_i
*insert
,
261 enum btree_iter_update_trigger_flags flags
)
263 struct btree_iter slot
= {};
268 for_each_btree_key_upto_norestart(trans
, *iter
, desc
.btree_id
,
269 SPOS(insert
->k
.p
.inode
,
270 desc
.hash_bkey(info
, bkey_i_to_s_c(insert
)),
272 POS(insert
->k
.p
.inode
, U64_MAX
),
273 BTREE_ITER_slots
|BTREE_ITER_intent
|flags
, k
, ret
) {
274 if (is_visible_key(desc
, inum
, k
)) {
275 if (!desc
.cmp_bkey(k
, bkey_i_to_s_c(insert
)))
278 /* hash collision: */
282 if (!slot
.path
&& !(flags
& STR_HASH_must_replace
))
283 bch2_trans_copy_iter(&slot
, iter
);
285 if (k
.k
->type
!= KEY_TYPE_hash_whiteout
)
290 ret
= -BCH_ERR_ENOSPC_str_hash_create
;
292 bch2_trans_iter_exit(trans
, &slot
);
293 bch2_trans_iter_exit(trans
, iter
);
294 return ret
? bkey_s_c_err(ret
) : bkey_s_c_null
;
298 if (found
&& (flags
& STR_HASH_must_create
)) {
299 bch2_trans_iter_exit(trans
, &slot
);
301 } else if (!found
&& (flags
& STR_HASH_must_replace
)) {
302 ret
= -BCH_ERR_ENOENT_str_hash_set_must_replace
;
304 if (!found
&& slot
.path
)
307 insert
->k
.p
= iter
->pos
;
308 ret
= bch2_trans_update(trans
, iter
, insert
, flags
);
314 static __always_inline
315 int bch2_hash_set_in_snapshot(struct btree_trans
*trans
,
316 const struct bch_hash_desc desc
,
317 const struct bch_hash_info
*info
,
318 subvol_inum inum
, u32 snapshot
,
319 struct bkey_i
*insert
,
320 enum btree_iter_update_trigger_flags flags
)
322 struct btree_iter iter
;
323 struct bkey_s_c k
= bch2_hash_set_or_get_in_snapshot(trans
, &iter
, desc
, info
, inum
,
324 snapshot
, insert
, flags
);
325 int ret
= bkey_err(k
);
329 bch2_trans_iter_exit(trans
, &iter
);
330 return -BCH_ERR_EEXIST_str_hash_set
;
336 static __always_inline
337 int bch2_hash_set(struct btree_trans
*trans
,
338 const struct bch_hash_desc desc
,
339 const struct bch_hash_info
*info
,
341 struct bkey_i
*insert
,
342 enum btree_iter_update_trigger_flags flags
)
344 insert
->k
.p
.inode
= inum
.inum
;
347 return bch2_subvolume_get_snapshot(trans
, inum
.subvol
, &snapshot
) ?:
348 bch2_hash_set_in_snapshot(trans
, desc
, info
, inum
,
349 snapshot
, insert
, flags
);
352 static __always_inline
353 int bch2_hash_delete_at(struct btree_trans
*trans
,
354 const struct bch_hash_desc desc
,
355 const struct bch_hash_info
*info
,
356 struct btree_iter
*iter
,
357 enum btree_iter_update_trigger_flags flags
)
359 struct bkey_i
*delete;
362 delete = bch2_trans_kmalloc(trans
, sizeof(*delete));
363 ret
= PTR_ERR_OR_ZERO(delete);
367 ret
= bch2_hash_needs_whiteout(trans
, desc
, info
, iter
);
371 bkey_init(&delete->k
);
372 delete->k
.p
= iter
->pos
;
373 delete->k
.type
= ret
? KEY_TYPE_hash_whiteout
: KEY_TYPE_deleted
;
375 return bch2_trans_update(trans
, iter
, delete, flags
);
378 static __always_inline
379 int bch2_hash_delete(struct btree_trans
*trans
,
380 const struct bch_hash_desc desc
,
381 const struct bch_hash_info
*info
,
382 subvol_inum inum
, const void *key
)
384 struct btree_iter iter
;
385 struct bkey_s_c k
= bch2_hash_lookup(trans
, &iter
, desc
, info
, inum
, key
,
387 int ret
= bkey_err(k
);
391 ret
= bch2_hash_delete_at(trans
, desc
, info
, &iter
, 0);
392 bch2_trans_iter_exit(trans
, &iter
);
396 #endif /* _BCACHEFS_STR_HASH_H */