Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Impressum str_hash.h

  Sprache: C
 

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _BCACHEFS_STR_HASH_H
#define _BCACHEFS_STR_HASH_H

#include "btree_iter.h"
#include "btree_update.h"
#include "checksum.h"
#include "error.h"
#include "inode.h"
#include "siphash.h"
#include "subvolume.h"
#include "super.h"

#include <linux/crc32c.h>
#include <crypto/sha2.h>

static inline enum bch_str_hash_type
bch2_str_hash_opt_to_type(struct bch_fs *c, enum bch_str_hash_opts opt)
{
 switch (opt) {
 case BCH_STR_HASH_OPT_crc32c:
  return BCH_STR_HASH_crc32c;
 case BCH_STR_HASH_OPT_crc64:
  return BCH_STR_HASH_crc64;
 case BCH_STR_HASH_OPT_siphash:
  return c->sb.features & (1ULL << BCH_FEATURE_new_siphash)
   ? BCH_STR_HASH_siphash
   : BCH_STR_HASH_siphash_old;
 default:
      BUG();
 }
}

struct bch_hash_info {
 u32   inum_snapshot;
 u8   type;
 struct unicode_map *cf_encoding;
 /*
 * For crc32 or crc64 string hashes the first key value of
 * the siphash_key (k0) is used as the key.
 */

 SIPHASH_KEY siphash_key;
};

static inline struct bch_hash_info
bch2_hash_info_init(struct bch_fs *c, const struct bch_inode_unpacked *bi)
{
 struct bch_hash_info info = {
  .inum_snapshot = bi->bi_snapshot,
  .type  = INODE_STR_HASH(bi),
  .cf_encoding = bch2_inode_casefold(c, bi) ? c->cf_encoding : NULL,
  .siphash_key = { .k0 = bi->bi_hash_seed }
 };

 if (unlikely(info.type == BCH_STR_HASH_siphash_old)) {
  u8 digest[SHA256_DIGEST_SIZE];

  sha256((const u8 *)&bi->bi_hash_seed,
         sizeof(bi->bi_hash_seed), digest);
  memcpy(&info.siphash_key, digest, sizeof(info.siphash_key));
 }

 return info;
}

struct bch_str_hash_ctx {
 union {
  u32  crc32c;
  u64  crc64;
  SIPHASH_CTX siphash;
 };
};

static inline void bch2_str_hash_init(struct bch_str_hash_ctx *ctx,
         const struct bch_hash_info *info)
{
 switch (info->type) {
 case BCH_STR_HASH_crc32c:
  ctx->crc32c = crc32c(~0, &info->siphash_key.k0,
         sizeof(info->siphash_key.k0));
  break;
 case BCH_STR_HASH_crc64:
  ctx->crc64 = crc64_be(~0, &info->siphash_key.k0,
          sizeof(info->siphash_key.k0));
  break;
 case BCH_STR_HASH_siphash_old:
 case BCH_STR_HASH_siphash:
  SipHash24_Init(&ctx->siphash, &info->siphash_key);
  break;
 default:
  BUG();
 }
}

static inline void bch2_str_hash_update(struct bch_str_hash_ctx *ctx,
           const struct bch_hash_info *info,
           const void *data, size_t len)
{
 switch (info->type) {
 case BCH_STR_HASH_crc32c:
  ctx->crc32c = crc32c(ctx->crc32c, data, len);
  break;
 case BCH_STR_HASH_crc64:
  ctx->crc64 = crc64_be(ctx->crc64, data, len);
  break;
 case BCH_STR_HASH_siphash_old:
 case BCH_STR_HASH_siphash:
  SipHash24_Update(&ctx->siphash, data, len);
  break;
 default:
  BUG();
 }
}

static inline u64 bch2_str_hash_end(struct bch_str_hash_ctx *ctx,
       const struct bch_hash_info *info)
{
 switch (info->type) {
 case BCH_STR_HASH_crc32c:
  return ctx->crc32c;
 case BCH_STR_HASH_crc64:
  return ctx->crc64 >> 1;
 case BCH_STR_HASH_siphash_old:
 case BCH_STR_HASH_siphash:
  return SipHash24_End(&ctx->siphash) >> 1;
 default:
  BUG();
 }
}

struct bch_hash_desc {
 enum btree_id btree_id;
 u8  key_type;

 u64  (*hash_key)(const struct bch_hash_info *, const void *);
 u64  (*hash_bkey)(const struct bch_hash_info *, struct bkey_s_c);
 bool  (*cmp_key)(struct bkey_s_c, const void *);
 bool  (*cmp_bkey)(struct bkey_s_c, struct bkey_s_c);
 bool  (*is_visible)(subvol_inum inum, struct bkey_s_c);
};

static inline bool is_visible_key(struct bch_hash_desc desc, subvol_inum inum, struct bkey_s_c k)
{
 return k.k->type == desc.key_type &&
  (!desc.is_visible ||
   !inum.inum ||
   desc.is_visible(inum, k));
}

static __always_inline struct bkey_s_c
bch2_hash_lookup_in_snapshot(struct btree_trans *trans,
   struct btree_iter *iter,
   const struct bch_hash_desc desc,
   const struct bch_hash_info *info,
   subvol_inum inum, const void *key,
   enum btree_iter_update_trigger_flags flags,
   u32 snapshot)
{
 struct bkey_s_c k;
 int ret;

 for_each_btree_key_max_norestart(trans, *iter, desc.btree_id,
      SPOS(inum.inum, desc.hash_key(info, key), snapshot),
      POS(inum.inum, U64_MAX),
      BTREE_ITER_slots|flags, k, ret) {
  if (is_visible_key(desc, inum, k)) {
   if (!desc.cmp_key(k, key))
    return k;
  } else if (k.k->type == KEY_TYPE_hash_whiteout) {
   ;
  } else {
   /* hole, not found */
   break;
  }
 }
 bch2_trans_iter_exit(trans, iter);

 return bkey_s_c_err(ret ?: -BCH_ERR_ENOENT_str_hash_lookup);
}

static __always_inline struct bkey_s_c
bch2_hash_lookup(struct btree_trans *trans,
   struct btree_iter *iter,
   const struct bch_hash_desc desc,
   const struct bch_hash_info *info,
   subvol_inum inum, const void *key,
   enum btree_iter_update_trigger_flags flags)
{
 u32 snapshot;
 int ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
 if (ret)
  return bkey_s_c_err(ret);

 return bch2_hash_lookup_in_snapshot(trans, iter, desc, info, inum, key, flags, snapshot);
}

static __always_inline int
bch2_hash_hole(struct btree_trans *trans,
        struct btree_iter *iter,
        const struct bch_hash_desc desc,
        const struct bch_hash_info *info,
        subvol_inum inum, const void *key)
{
 struct bkey_s_c k;
 u32 snapshot;
 int ret;

 ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
 if (ret)
  return ret;

 for_each_btree_key_max_norestart(trans, *iter, desc.btree_id,
      SPOS(inum.inum, desc.hash_key(info, key), snapshot),
      POS(inum.inum, U64_MAX),
      BTREE_ITER_slots|BTREE_ITER_intent, k, ret)
  if (!is_visible_key(desc, inum, k))
   return 0;
 bch2_trans_iter_exit(trans, iter);

 return ret ?: -BCH_ERR_ENOSPC_str_hash_create;
}

static __always_inline
int bch2_hash_needs_whiteout(struct btree_trans *trans,
        const struct bch_hash_desc desc,
        const struct bch_hash_info *info,
        struct btree_iter *start)
{
 struct btree_iter iter;
 struct bkey_s_c k;
 int ret;

 bch2_trans_copy_iter(trans, &iter, start);

 bch2_btree_iter_advance(trans, &iter);

 for_each_btree_key_continue_norestart(trans, iter, BTREE_ITER_slots, k, ret) {
  if (k.k->type != desc.key_type &&
      k.k->type != KEY_TYPE_hash_whiteout)
   break;

  if (k.k->type == desc.key_type &&
      desc.hash_bkey(info, k) <= start->pos.offset) {
   ret = 1;
   break;
  }
 }

 bch2_trans_iter_exit(trans, &iter);
 return ret;
}

static __always_inline
struct bkey_s_c bch2_hash_set_or_get_in_snapshot(struct btree_trans *trans,
      struct btree_iter *iter,
      const struct bch_hash_desc desc,
      const struct bch_hash_info *info,
      subvol_inum inum, u32 snapshot,
      struct bkey_i *insert,
      enum btree_iter_update_trigger_flags flags)
{
 struct bch_fs *c = trans->c;
 struct btree_iter slot = {};
 struct bkey_s_c k;
 bool found = false;
 int ret;

 for_each_btree_key_max_norestart(trans, *iter, desc.btree_id,
      SPOS(insert->k.p.inode,
    desc.hash_bkey(info, bkey_i_to_s_c(insert)),
    snapshot),
      POS(insert->k.p.inode, U64_MAX),
      BTREE_ITER_slots|BTREE_ITER_intent|flags, k, ret) {
  if (is_visible_key(desc, inum, k)) {
   if (!desc.cmp_bkey(k, bkey_i_to_s_c(insert)))
    goto found;

   /* hash collision: */
   continue;
  }

  if (!slot.path && !(flags & STR_HASH_must_replace))
   bch2_trans_copy_iter(trans, &slot, iter);

  if (k.k->type != KEY_TYPE_hash_whiteout)
   goto not_found;
 }

 if (!ret)
  ret = bch_err_throw(c, ENOSPC_str_hash_create);
out:
 bch2_trans_iter_exit(trans, &slot);
 bch2_trans_iter_exit(trans, iter);
 return ret ? bkey_s_c_err(ret) : bkey_s_c_null;
found:
 found = true;
not_found:
 if (found && (flags & STR_HASH_must_create)) {
  bch2_trans_iter_exit(trans, &slot);
  return k;
 } else if (!found && (flags & STR_HASH_must_replace)) {
  ret = bch_err_throw(c, ENOENT_str_hash_set_must_replace);
 } else {
  if (!found && slot.path)
   swap(*iter, slot);

  insert->k.p = iter->pos;
  ret = bch2_trans_update(trans, iter, insert, flags);
 }

 goto out;
}

static __always_inline
int bch2_hash_set_in_snapshot(struct btree_trans *trans,
      const struct bch_hash_desc desc,
      const struct bch_hash_info *info,
      subvol_inum inum, u32 snapshot,
      struct bkey_i *insert,
      enum btree_iter_update_trigger_flags flags)
{
 struct btree_iter iter;
 struct bkey_s_c k = bch2_hash_set_or_get_in_snapshot(trans, &iter, desc, info, inum,
            snapshot, insert, flags);
 int ret = bkey_err(k);
 if (ret)
  return ret;
 if (k.k) {
  bch2_trans_iter_exit(trans, &iter);
  return bch_err_throw(trans->c, EEXIST_str_hash_set);
 }

 return 0;
}

static __always_inline
int bch2_hash_set(struct btree_trans *trans,
    const struct bch_hash_desc desc,
    const struct bch_hash_info *info,
    subvol_inum inum,
    struct bkey_i *insert,
    enum btree_iter_update_trigger_flags flags)
{
 insert->k.p.inode = inum.inum;

 u32 snapshot;
 return  bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot) ?:
  bch2_hash_set_in_snapshot(trans, desc, info, inum,
       snapshot, insert, flags);
}

static __always_inline
int bch2_hash_delete_at(struct btree_trans *trans,
   const struct bch_hash_desc desc,
   const struct bch_hash_info *info,
   struct btree_iter *iter,
   enum btree_iter_update_trigger_flags flags)
{
 struct bkey_i *delete;
 int ret;

 delete = bch2_trans_kmalloc(trans, sizeof(*delete));
 ret = PTR_ERR_OR_ZERO(delete);
 if (ret)
  return ret;

 ret = bch2_hash_needs_whiteout(trans, desc, info, iter);
 if (ret < 0)
  return ret;

 bkey_init(&delete->k);
 delete->k.p = iter->pos;
 delete->k.type = ret ? KEY_TYPE_hash_whiteout : KEY_TYPE_deleted;

 return bch2_trans_update(trans, iter, delete, flags);
}

static __always_inline
int bch2_hash_delete(struct btree_trans *trans,
       const struct bch_hash_desc desc,
       const struct bch_hash_info *info,
       subvol_inum inum, const void *key)
{
 struct btree_iter iter;
 struct bkey_s_c k = bch2_hash_lookup(trans, &iter, desc, info, inum, key,
          BTREE_ITER_intent);
 int ret = bkey_err(k);
 if (ret)
  return ret;

 ret = bch2_hash_delete_at(trans, desc, info, &iter, 0);
 bch2_trans_iter_exit(trans, &iter);
 return ret;
}

int bch2_repair_inode_hash_info(struct btree_trans *, struct bch_inode_unpacked *);

struct snapshots_seen;
int bch2_str_hash_repair_key(struct btree_trans *,
        struct snapshots_seen *,
        const struct bch_hash_desc *,
        struct bch_hash_info *,
        struct btree_iter *, struct bkey_s_c,
        struct btree_iter *, struct bkey_s_c,
        bool *);

int __bch2_str_hash_check_key(struct btree_trans *,
         struct snapshots_seen *,
         const struct bch_hash_desc *,
         struct bch_hash_info *,
         struct btree_iter *, struct bkey_s_c,
         bool *);

static inline int bch2_str_hash_check_key(struct btree_trans *trans,
       struct snapshots_seen *s,
       const struct bch_hash_desc *desc,
       struct bch_hash_info *hash_info,
       struct btree_iter *k_iter, struct bkey_s_c hash_k,
       bool *updated_before_k_pos)
{
 if (hash_k.k->type != desc->key_type)
  return 0;

 if (likely(desc->hash_bkey(hash_info, hash_k) == hash_k.k->p.offset))
  return 0;

 return __bch2_str_hash_check_key(trans, s, desc, hash_info, k_iter, hash_k,
      updated_before_k_pos);
}

#endif /* _BCACHEFS_STR_HASH_H */

Messung V0.5 in Prozent
C=95 H=92 G=93

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-06-08) ¤

*© Formatika GbR, Deutschland






Versionsinformation zu Columbo

Bemerkung:

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Anfrage:

Dauer der Verarbeitung:

Sekunden

sprechenden Kalenders






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002