Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/fs/bcachefs/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 21 kB image not shown  

Quelle  replicas.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0

#include "bcachefs.h"
#include "buckets.h"
#include "disk_accounting.h"
#include "journal.h"
#include "replicas.h"
#include "super-io.h"

#include <linux/sort.h>

static int bch2_cpu_replicas_to_sb_replicas(struct bch_fs *,
         struct bch_replicas_cpu *);

/* Some (buggy!) compilers don't allow memcmp to be passed as a pointer */
static int bch2_memcmp(const void *l, const void *r,  const void *priv)
{
 size_t size = (size_t) priv;
 return memcmp(l, r, size);
}

/* Replicas tracking - in memory: */

static void verify_replicas_entry(struct bch_replicas_entry_v1 *e)
{
#ifdef CONFIG_BCACHEFS_DEBUG
 BUG_ON(!e->nr_devs);
 BUG_ON(e->nr_required > 1 &&
        e->nr_required >= e->nr_devs);

 for (unsigned i = 0; i + 1 < e->nr_devs; i++)
  BUG_ON(e->devs[i] >= e->devs[i + 1]);
#endif
}

void bch2_replicas_entry_sort(struct bch_replicas_entry_v1 *e)
{
 bubble_sort(e->devs, e->nr_devs, u8_cmp);
}

static void bch2_cpu_replicas_sort(struct bch_replicas_cpu *r)
{
 eytzinger0_sort_r(r->entries, r->nr, r->entry_size,
     bch2_memcmp, NULL, (void *)(size_t)r->entry_size);
}

static void bch2_replicas_entry_v0_to_text(struct printbuf *out,
        struct bch_replicas_entry_v0 *e)
{
 bch2_prt_data_type(out, e->data_type);

 prt_printf(out, ": %u [", e->nr_devs);
 for (unsigned i = 0; i < e->nr_devs; i++)
  prt_printf(out, i ? " %u" : "%u", e->devs[i]);
 prt_printf(out, "]");
}

void bch2_replicas_entry_to_text(struct printbuf *out,
     struct bch_replicas_entry_v1 *e)
{
 bch2_prt_data_type(out, e->data_type);

 prt_printf(out, ": %u/%u [", e->nr_required, e->nr_devs);
 for (unsigned i = 0; i < e->nr_devs; i++)
  prt_printf(out, i ? " %u" : "%u", e->devs[i]);
 prt_printf(out, "]");
}

static int bch2_replicas_entry_sb_validate(struct bch_replicas_entry_v1 *r,
        struct bch_sb *sb,
        struct printbuf *err)
{
 if (!r->nr_devs) {
  prt_printf(err, "no devices in entry ");
  goto bad;
 }

 if (r->nr_required > 1 &&
     r->nr_required >= r->nr_devs) {
  prt_printf(err, "bad nr_required in entry ");
  goto bad;
 }

 for (unsigned i = 0; i < r->nr_devs; i++)
  if (r->devs[i] != BCH_SB_MEMBER_INVALID &&
      !bch2_member_exists(sb, r->devs[i])) {
   prt_printf(err, "invalid device %u in entry ", r->devs[i]);
   goto bad;
  }

 return 0;
bad:
 bch2_replicas_entry_to_text(err, r);
 return -BCH_ERR_invalid_replicas_entry;
}

int bch2_replicas_entry_validate(struct bch_replicas_entry_v1 *r,
     struct bch_fs *c,
     struct printbuf *err)
{
 if (!r->nr_devs) {
  prt_printf(err, "no devices in entry ");
  goto bad;
 }

 if (r->nr_required > 1 &&
     r->nr_required >= r->nr_devs) {
  prt_printf(err, "bad nr_required in entry ");
  goto bad;
 }

 for (unsigned i = 0; i < r->nr_devs; i++)
  if (r->devs[i] != BCH_SB_MEMBER_INVALID &&
      !bch2_dev_exists(c, r->devs[i])) {
   prt_printf(err, "invalid device %u in entry ", r->devs[i]);
   goto bad;
  }

 return 0;
bad:
 bch2_replicas_entry_to_text(err, r);
 return bch_err_throw(c, invalid_replicas_entry);
}

void bch2_cpu_replicas_to_text(struct printbuf *out,
          struct bch_replicas_cpu *r)
{
 struct bch_replicas_entry_v1 *e;
 bool first = true;

 for_each_cpu_replicas_entry(r, e) {
  if (!first)
   prt_printf(out, " ");
  first = false;

  bch2_replicas_entry_to_text(out, e);
 }
}

static void extent_to_replicas(struct bkey_s_c k,
          struct bch_replicas_entry_v1 *r)
{
 struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
 const union bch_extent_entry *entry;
 struct extent_ptr_decoded p;

 r->nr_required = 1;

 bkey_for_each_ptr_decode(k.k, ptrs, p, entry) {
  if (p.ptr.cached)
   continue;

  if (!p.has_ec)
   replicas_entry_add_dev(r, p.ptr.dev);
  else
   r->nr_required = 0;
 }
}

static void stripe_to_replicas(struct bkey_s_c k,
          struct bch_replicas_entry_v1 *r)
{
 struct bkey_s_c_stripe s = bkey_s_c_to_stripe(k);
 const struct bch_extent_ptr *ptr;

 r->nr_required = s.v->nr_blocks - s.v->nr_redundant;

 for (ptr = s.v->ptrs;
      ptr < s.v->ptrs + s.v->nr_blocks;
      ptr++)
  replicas_entry_add_dev(r, ptr->dev);
}

void bch2_bkey_to_replicas(struct bch_replicas_entry_v1 *e,
      struct bkey_s_c k)
{
 e->nr_devs = 0;

 switch (k.k->type) {
 case KEY_TYPE_btree_ptr:
 case KEY_TYPE_btree_ptr_v2:
  e->data_type = BCH_DATA_btree;
  extent_to_replicas(k, e);
  break;
 case KEY_TYPE_extent:
 case KEY_TYPE_reflink_v:
  e->data_type = BCH_DATA_user;
  extent_to_replicas(k, e);
  break;
 case KEY_TYPE_stripe:
  e->data_type = BCH_DATA_parity;
  stripe_to_replicas(k, e);
  break;
 }

 bch2_replicas_entry_sort(e);
}

void bch2_devlist_to_replicas(struct bch_replicas_entry_v1 *e,
         enum bch_data_type data_type,
         struct bch_devs_list devs)
{
 BUG_ON(!data_type ||
        data_type == BCH_DATA_sb ||
        data_type >= BCH_DATA_NR);

 e->data_type = data_type;
 e->nr_devs = 0;
 e->nr_required = 1;

 darray_for_each(devs, i)
  replicas_entry_add_dev(e, *i);

 bch2_replicas_entry_sort(e);
}

static struct bch_replicas_cpu
cpu_replicas_add_entry(struct bch_fs *c,
         struct bch_replicas_cpu *old,
         struct bch_replicas_entry_v1 *new_entry)
{
 struct bch_replicas_cpu new = {
  .nr  = old->nr + 1,
  .entry_size = max_t(unsigned, old->entry_size,
     replicas_entry_bytes(new_entry)),
 };

 new.entries = kcalloc(new.nr, new.entry_size, GFP_KERNEL);
 if (!new.entries)
  return new;

 for (unsigned i = 0; i < old->nr; i++)
  memcpy(cpu_replicas_entry(&new, i),
         cpu_replicas_entry(old, i),
         old->entry_size);

 memcpy(cpu_replicas_entry(&new, old->nr),
        new_entry,
        replicas_entry_bytes(new_entry));

 bch2_cpu_replicas_sort(&new);
 return new;
}

static inline int __replicas_entry_idx(struct bch_replicas_cpu *r,
           struct bch_replicas_entry_v1 *search)
{
 int idx, entry_size = replicas_entry_bytes(search);

 if (unlikely(entry_size > r->entry_size))
  return -1;

#define entry_cmp(_l, _r) memcmp(_l, _r, entry_size)
 idx = eytzinger0_find(r->entries, r->nr, r->entry_size,
         entry_cmp, search);
#undef entry_cmp

 return idx < r->nr ? idx : -1;
}

int bch2_replicas_entry_idx(struct bch_fs *c,
       struct bch_replicas_entry_v1 *search)
{
 bch2_replicas_entry_sort(search);

 return __replicas_entry_idx(&c->replicas, search);
}

static bool __replicas_has_entry(struct bch_replicas_cpu *r,
     struct bch_replicas_entry_v1 *search)
{
 return __replicas_entry_idx(r, search) >= 0;
}

bool bch2_replicas_marked_locked(struct bch_fs *c,
     struct bch_replicas_entry_v1 *search)
{
 verify_replicas_entry(search);

 return !search->nr_devs ||
  (__replicas_has_entry(&c->replicas, search) &&
   (likely((!c->replicas_gc.entries)) ||
    __replicas_has_entry(&c->replicas_gc, search)));
}

bool bch2_replicas_marked(struct bch_fs *c,
     struct bch_replicas_entry_v1 *search)
{
 percpu_down_read(&c->mark_lock);
 bool ret = bch2_replicas_marked_locked(c, search);
 percpu_up_read(&c->mark_lock);

 return ret;
}

noinline
static int bch2_mark_replicas_slowpath(struct bch_fs *c,
    struct bch_replicas_entry_v1 *new_entry)
{
 struct bch_replicas_cpu new_r, new_gc;
 int ret = 0;

 verify_replicas_entry(new_entry);

 memset(&new_r, 0, sizeof(new_r));
 memset(&new_gc, 0, sizeof(new_gc));

 mutex_lock(&c->sb_lock);

 if (c->replicas_gc.entries &&
     !__replicas_has_entry(&c->replicas_gc, new_entry)) {
  new_gc = cpu_replicas_add_entry(c, &c->replicas_gc, new_entry);
  if (!new_gc.entries) {
   ret = bch_err_throw(c, ENOMEM_cpu_replicas);
   goto err;
  }
 }

 if (!__replicas_has_entry(&c->replicas, new_entry)) {
  new_r = cpu_replicas_add_entry(c, &c->replicas, new_entry);
  if (!new_r.entries) {
   ret = bch_err_throw(c, ENOMEM_cpu_replicas);
   goto err;
  }

  ret = bch2_cpu_replicas_to_sb_replicas(c, &new_r);
  if (ret)
   goto err;
 }

 if (!new_r.entries &&
     !new_gc.entries)
  goto out;

 /* allocations done, now commit: */

 if (new_r.entries)
  bch2_write_super(c);

 /* don't update in memory replicas until changes are persistent */
 percpu_down_write(&c->mark_lock);
 if (new_r.entries)
  swap(c->replicas, new_r);
 if (new_gc.entries)
  swap(new_gc, c->replicas_gc);
 percpu_up_write(&c->mark_lock);
out:
 mutex_unlock(&c->sb_lock);

 kfree(new_r.entries);
 kfree(new_gc.entries);

 return ret;
err:
 bch_err_msg(c, ret, "adding replicas entry");
 goto out;
}

int bch2_mark_replicas(struct bch_fs *c, struct bch_replicas_entry_v1 *r)
{
 return likely(bch2_replicas_marked(c, r))
  ? 0 : bch2_mark_replicas_slowpath(c, r);
}

/*
 * Old replicas_gc mechanism: only used for journal replicas entries now, should
 * die at some point:
 */


int bch2_replicas_gc_end(struct bch_fs *c, int ret)
{
 lockdep_assert_held(&c->replicas_gc_lock);

 mutex_lock(&c->sb_lock);
 percpu_down_write(&c->mark_lock);

 ret =   ret ?:
  bch2_cpu_replicas_to_sb_replicas(c, &c->replicas_gc);
 if (!ret)
  swap(c->replicas, c->replicas_gc);

 kfree(c->replicas_gc.entries);
 c->replicas_gc.entries = NULL;

 percpu_up_write(&c->mark_lock);

 if (!ret)
  bch2_write_super(c);

 mutex_unlock(&c->sb_lock);

 return ret;
}

int bch2_replicas_gc_start(struct bch_fs *c, unsigned typemask)
{
 struct bch_replicas_entry_v1 *e;
 unsigned i = 0;

 lockdep_assert_held(&c->replicas_gc_lock);

 mutex_lock(&c->sb_lock);
 BUG_ON(c->replicas_gc.entries);

 c->replicas_gc.nr  = 0;
 c->replicas_gc.entry_size = 0;

 for_each_cpu_replicas_entry(&c->replicas, e) {
  /* Preserve unknown data types */
  if (e->data_type >= BCH_DATA_NR ||
      !((1 << e->data_type) & typemask)) {
   c->replicas_gc.nr++;
   c->replicas_gc.entry_size =
    max_t(unsigned, c->replicas_gc.entry_size,
          replicas_entry_bytes(e));
  }
 }

 c->replicas_gc.entries = kcalloc(c->replicas_gc.nr,
      c->replicas_gc.entry_size,
      GFP_KERNEL);
 if (!c->replicas_gc.entries) {
  mutex_unlock(&c->sb_lock);
  bch_err(c, "error allocating c->replicas_gc");
  return bch_err_throw(c, ENOMEM_replicas_gc);
 }

 for_each_cpu_replicas_entry(&c->replicas, e)
  if (e->data_type >= BCH_DATA_NR ||
      !((1 << e->data_type) & typemask))
   memcpy(cpu_replicas_entry(&c->replicas_gc, i++),
          e, c->replicas_gc.entry_size);

 bch2_cpu_replicas_sort(&c->replicas_gc);
 mutex_unlock(&c->sb_lock);

 return 0;
}

/*
 * New much simpler mechanism for clearing out unneeded replicas entries - drop
 * replicas entries that have 0 sectors used.
 *
 * However, we don't track sector counts for journal usage, so this doesn't drop
 * any BCH_DATA_journal entries; the old bch2_replicas_gc_(start|end) mechanism
 * is retained for that.
 */

int bch2_replicas_gc2(struct bch_fs *c)
{
 struct bch_replicas_cpu new = { 0 };
 unsigned nr;
 int ret = 0;

 bch2_accounting_mem_gc(c);
retry:
 nr  = READ_ONCE(c->replicas.nr);
 new.entry_size = READ_ONCE(c->replicas.entry_size);
 new.entries = kcalloc(nr, new.entry_size, GFP_KERNEL);
 if (!new.entries) {
  bch_err(c, "error allocating c->replicas_gc");
  return bch_err_throw(c, ENOMEM_replicas_gc);
 }

 mutex_lock(&c->sb_lock);
 percpu_down_write(&c->mark_lock);

 if (nr   != c->replicas.nr ||
     new.entry_size != c->replicas.entry_size) {
  percpu_up_write(&c->mark_lock);
  mutex_unlock(&c->sb_lock);
  kfree(new.entries);
  goto retry;
 }

 for (unsigned i = 0; i < c->replicas.nr; i++) {
  struct bch_replicas_entry_v1 *e =
   cpu_replicas_entry(&c->replicas, i);

  struct disk_accounting_pos k = {
   .type = BCH_DISK_ACCOUNTING_replicas,
  };

  unsafe_memcpy(&k.replicas, e, replicas_entry_bytes(e),
         "embedded variable length struct");

  struct bpos p = disk_accounting_pos_to_bpos(&k);

  struct bch_accounting_mem *acc = &c->accounting;
  bool kill = eytzinger0_find(acc->k.data, acc->k.nr, sizeof(acc->k.data[0]),
         accounting_pos_cmp, &p) >= acc->k.nr;

  if (e->data_type == BCH_DATA_journal || !kill)
   memcpy(cpu_replicas_entry(&newnew.nr++),
          e, new.entry_size);
 }

 bch2_cpu_replicas_sort(&new);

 ret = bch2_cpu_replicas_to_sb_replicas(c, &new);

 if (!ret)
  swap(c->replicas, new);

 kfree(new.entries);

 percpu_up_write(&c->mark_lock);

 if (!ret)
  bch2_write_super(c);

 mutex_unlock(&c->sb_lock);

 return ret;
}

/* Replicas tracking - superblock: */

static int
__bch2_sb_replicas_to_cpu_replicas(struct bch_sb_field_replicas *sb_r,
       struct bch_replicas_cpu *cpu_r)
{
 struct bch_replicas_entry_v1 *e, *dst;
 unsigned nr = 0, entry_size = 0, idx = 0;

 for_each_replicas_entry(sb_r, e) {
  entry_size = max_t(unsigned, entry_size,
       replicas_entry_bytes(e));
  nr++;
 }

 cpu_r->entries = kcalloc(nr, entry_size, GFP_KERNEL);
 if (!cpu_r->entries)
  return -BCH_ERR_ENOMEM_cpu_replicas;

 cpu_r->nr  = nr;
 cpu_r->entry_size = entry_size;

 for_each_replicas_entry(sb_r, e) {
  dst = cpu_replicas_entry(cpu_r, idx++);
  memcpy(dst, e, replicas_entry_bytes(e));
  bch2_replicas_entry_sort(dst);
 }

 return 0;
}

static int
__bch2_sb_replicas_v0_to_cpu_replicas(struct bch_sb_field_replicas_v0 *sb_r,
          struct bch_replicas_cpu *cpu_r)
{
 struct bch_replicas_entry_v0 *e;
 unsigned nr = 0, entry_size = 0, idx = 0;

 for_each_replicas_entry(sb_r, e) {
  entry_size = max_t(unsigned, entry_size,
       replicas_entry_bytes(e));
  nr++;
 }

 entry_size += sizeof(struct bch_replicas_entry_v1) -
  sizeof(struct bch_replicas_entry_v0);

 cpu_r->entries = kcalloc(nr, entry_size, GFP_KERNEL);
 if (!cpu_r->entries)
  return -BCH_ERR_ENOMEM_cpu_replicas;

 cpu_r->nr  = nr;
 cpu_r->entry_size = entry_size;

 for_each_replicas_entry(sb_r, e) {
  struct bch_replicas_entry_v1 *dst =
   cpu_replicas_entry(cpu_r, idx++);

  dst->data_type = e->data_type;
  dst->nr_devs = e->nr_devs;
  dst->nr_required = 1;
  memcpy(dst->devs, e->devs, e->nr_devs);
  bch2_replicas_entry_sort(dst);
 }

 return 0;
}

int bch2_sb_replicas_to_cpu_replicas(struct bch_fs *c)
{
 struct bch_sb_field_replicas *sb_v1;
 struct bch_sb_field_replicas_v0 *sb_v0;
 struct bch_replicas_cpu new_r = { 0, 0, NULL };
 int ret = 0;

 if ((sb_v1 = bch2_sb_field_get(c->disk_sb.sb, replicas)))
  ret = __bch2_sb_replicas_to_cpu_replicas(sb_v1, &new_r);
 else if ((sb_v0 = bch2_sb_field_get(c->disk_sb.sb, replicas_v0)))
  ret = __bch2_sb_replicas_v0_to_cpu_replicas(sb_v0, &new_r);
 if (ret)
  return ret;

 bch2_cpu_replicas_sort(&new_r);

 percpu_down_write(&c->mark_lock);
 swap(c->replicas, new_r);
 percpu_up_write(&c->mark_lock);

 kfree(new_r.entries);

 return 0;
}

static int bch2_cpu_replicas_to_sb_replicas_v0(struct bch_fs *c,
            struct bch_replicas_cpu *r)
{
 struct bch_sb_field_replicas_v0 *sb_r;
 struct bch_replicas_entry_v0 *dst;
 struct bch_replicas_entry_v1 *src;
 size_t bytes;

 bytes = sizeof(struct bch_sb_field_replicas);

 for_each_cpu_replicas_entry(r, src)
  bytes += replicas_entry_bytes(src) - 1;

 sb_r = bch2_sb_field_resize(&c->disk_sb, replicas_v0,
   DIV_ROUND_UP(bytes, sizeof(u64)));
 if (!sb_r)
  return bch_err_throw(c, ENOSPC_sb_replicas);

 bch2_sb_field_delete(&c->disk_sb, BCH_SB_FIELD_replicas);
 sb_r = bch2_sb_field_get(c->disk_sb.sb, replicas_v0);

 memset(&sb_r->entries, 0,
        vstruct_end(&sb_r->field) -
        (void *) &sb_r->entries);

 dst = sb_r->entries;
 for_each_cpu_replicas_entry(r, src) {
  dst->data_type = src->data_type;
  dst->nr_devs = src->nr_devs;
  memcpy(dst->devs, src->devs, src->nr_devs);

  dst = replicas_entry_next(dst);

  BUG_ON((void *) dst > vstruct_end(&sb_r->field));
 }

 return 0;
}

static int bch2_cpu_replicas_to_sb_replicas(struct bch_fs *c,
         struct bch_replicas_cpu *r)
{
 struct bch_sb_field_replicas *sb_r;
 struct bch_replicas_entry_v1 *dst, *src;
 bool need_v1 = false;
 size_t bytes;

 bytes = sizeof(struct bch_sb_field_replicas);

 for_each_cpu_replicas_entry(r, src) {
  bytes += replicas_entry_bytes(src);
  if (src->nr_required != 1)
   need_v1 = true;
 }

 if (!need_v1)
  return bch2_cpu_replicas_to_sb_replicas_v0(c, r);

 sb_r = bch2_sb_field_resize(&c->disk_sb, replicas,
   DIV_ROUND_UP(bytes, sizeof(u64)));
 if (!sb_r)
  return bch_err_throw(c, ENOSPC_sb_replicas);

 bch2_sb_field_delete(&c->disk_sb, BCH_SB_FIELD_replicas_v0);
 sb_r = bch2_sb_field_get(c->disk_sb.sb, replicas);

 memset(&sb_r->entries, 0,
        vstruct_end(&sb_r->field) -
        (void *) &sb_r->entries);

 dst = sb_r->entries;
 for_each_cpu_replicas_entry(r, src) {
  memcpy(dst, src, replicas_entry_bytes(src));

  dst = replicas_entry_next(dst);

  BUG_ON((void *) dst > vstruct_end(&sb_r->field));
 }

 return 0;
}

static int bch2_cpu_replicas_validate(struct bch_replicas_cpu *cpu_r,
          struct bch_sb *sb,
          struct printbuf *err)
{
 unsigned i;

 sort_r(cpu_r->entries,
        cpu_r->nr,
        cpu_r->entry_size,
        bch2_memcmp, NULL,
        (void *)(size_t)cpu_r->entry_size);

 for (i = 0; i < cpu_r->nr; i++) {
  struct bch_replicas_entry_v1 *e =
   cpu_replicas_entry(cpu_r, i);

  int ret = bch2_replicas_entry_sb_validate(e, sb, err);
  if (ret)
   return ret;

  if (i + 1 < cpu_r->nr) {
   struct bch_replicas_entry_v1 *n =
    cpu_replicas_entry(cpu_r, i + 1);

   BUG_ON(memcmp(e, n, cpu_r->entry_size) > 0);

   if (!memcmp(e, n, cpu_r->entry_size)) {
    prt_printf(err, "duplicate replicas entry ");
    bch2_replicas_entry_to_text(err, e);
    return -BCH_ERR_invalid_sb_replicas;
   }
  }
 }

 return 0;
}

static int bch2_sb_replicas_validate(struct bch_sb *sb, struct bch_sb_field *f,
         enum bch_validate_flags flags, struct printbuf *err)
{
 struct bch_sb_field_replicas *sb_r = field_to_type(f, replicas);
 struct bch_replicas_cpu cpu_r;
 int ret;

 ret = __bch2_sb_replicas_to_cpu_replicas(sb_r, &cpu_r);
 if (ret)
  return ret;

 ret = bch2_cpu_replicas_validate(&cpu_r, sb, err);
 kfree(cpu_r.entries);
 return ret;
}

static void bch2_sb_replicas_to_text(struct printbuf *out,
         struct bch_sb *sb,
         struct bch_sb_field *f)
{
 struct bch_sb_field_replicas *r = field_to_type(f, replicas);
 struct bch_replicas_entry_v1 *e;
 bool first = true;

 for_each_replicas_entry(r, e) {
  if (!first)
   prt_printf(out, " ");
  first = false;

  bch2_replicas_entry_to_text(out, e);
 }
 prt_newline(out);
}

const struct bch_sb_field_ops bch_sb_field_ops_replicas = {
 .validate = bch2_sb_replicas_validate,
 .to_text = bch2_sb_replicas_to_text,
};

static int bch2_sb_replicas_v0_validate(struct bch_sb *sb, struct bch_sb_field *f,
     enum bch_validate_flags flags, struct printbuf *err)
{
 struct bch_sb_field_replicas_v0 *sb_r = field_to_type(f, replicas_v0);
 struct bch_replicas_cpu cpu_r;
 int ret;

 ret = __bch2_sb_replicas_v0_to_cpu_replicas(sb_r, &cpu_r);
 if (ret)
  return ret;

 ret = bch2_cpu_replicas_validate(&cpu_r, sb, err);
 kfree(cpu_r.entries);
 return ret;
}

static void bch2_sb_replicas_v0_to_text(struct printbuf *out,
     struct bch_sb *sb,
     struct bch_sb_field *f)
{
 struct bch_sb_field_replicas_v0 *sb_r = field_to_type(f, replicas_v0);
 struct bch_replicas_entry_v0 *e;
 bool first = true;

 for_each_replicas_entry(sb_r, e) {
  if (!first)
   prt_printf(out, " ");
  first = false;

  bch2_replicas_entry_v0_to_text(out, e);
 }
 prt_newline(out);
}

const struct bch_sb_field_ops bch_sb_field_ops_replicas_v0 = {
 .validate = bch2_sb_replicas_v0_validate,
 .to_text = bch2_sb_replicas_v0_to_text,
};

/* Query replicas: */

bool bch2_have_enough_devs(struct bch_fs *c, struct bch_devs_mask devs,
      unsigned flags, bool print)
{
 struct bch_replicas_entry_v1 *e;
 bool ret = true;

 percpu_down_read(&c->mark_lock);
 for_each_cpu_replicas_entry(&c->replicas, e) {
  unsigned nr_online = 0, nr_failed = 0, dflags = 0;
  bool metadata = e->data_type < BCH_DATA_user;

  if (e->data_type == BCH_DATA_cached)
   continue;

  scoped_guard(rcu)
   for (unsigned i = 0; i < e->nr_devs; i++) {
    if (e->devs[i] == BCH_SB_MEMBER_INVALID) {
     nr_failed++;
     continue;
    }

    nr_online += test_bit(e->devs[i], devs.d);

    struct bch_dev *ca = bch2_dev_rcu_noerror(c, e->devs[i]);
    nr_failed += !ca || ca->mi.state == BCH_MEMBER_STATE_failed;
   }

  if (nr_online + nr_failed == e->nr_devs)
   continue;

  if (nr_online < e->nr_required)
   dflags |= metadata
    ? BCH_FORCE_IF_METADATA_LOST
    : BCH_FORCE_IF_DATA_LOST;

  if (nr_online < e->nr_devs)
   dflags |= metadata
    ? BCH_FORCE_IF_METADATA_DEGRADED
    : BCH_FORCE_IF_DATA_DEGRADED;

  if (dflags & ~flags) {
   if (print) {
    struct printbuf buf = PRINTBUF;

    bch2_replicas_entry_to_text(&buf, e);
    bch_err(c, "insufficient devices online (%u) for replicas entry %s",
     nr_online, buf.buf);
    printbuf_exit(&buf);
   }
   ret = false;
   break;
  }

 }
 percpu_up_read(&c->mark_lock);

 return ret;
}

unsigned bch2_sb_dev_has_data(struct bch_sb *sb, unsigned dev)
{
 struct bch_sb_field_replicas *replicas;
 struct bch_sb_field_replicas_v0 *replicas_v0;
 unsigned data_has = 0;

 replicas = bch2_sb_field_get(sb, replicas);
 replicas_v0 = bch2_sb_field_get(sb, replicas_v0);

 if (replicas) {
  struct bch_replicas_entry_v1 *r;

  for_each_replicas_entry(replicas, r) {
   if (r->data_type >= sizeof(data_has) * 8)
    continue;

   for (unsigned i = 0; i < r->nr_devs; i++)
    if (r->devs[i] == dev)
     data_has |= 1 << r->data_type;
  }

 } else if (replicas_v0) {
  struct bch_replicas_entry_v0 *r;

  for_each_replicas_entry_v0(replicas_v0, r) {
   if (r->data_type >= sizeof(data_has) * 8)
    continue;

   for (unsigned i = 0; i < r->nr_devs; i++)
    if (r->devs[i] == dev)
     data_has |= 1 << r->data_type;
  }
 }


 return data_has;
}

unsigned bch2_dev_has_data(struct bch_fs *c, struct bch_dev *ca)
{
 mutex_lock(&c->sb_lock);
 unsigned ret = bch2_sb_dev_has_data(c->disk_sb.sb, ca->dev_idx);
 mutex_unlock(&c->sb_lock);

 return ret;
}

void bch2_fs_replicas_exit(struct bch_fs *c)
{
 kfree(c->replicas.entries);
 kfree(c->replicas_gc.entries);
}

Messung V0.5
C=99 H=89 G=94

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.